1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/net/network_diagnostics/http_request_manager.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/memory/scoped_refptr.h"
11 #include "base/memory/weak_ptr.h"
12 #include "content/public/test/browser_task_environment.h"
13 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
14 #include "services/network/test/test_url_loader_factory.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace chromeos {
18 namespace network_diagnostics {
19
20 namespace {
21
22 const char kFakeUrl[] =
23 "https://abcdefgh-ccd-testing-v4.metric.gstatic.com/generate_204";
24 const int timeout_ms = 500;
25
26 } // namespace
27
28 class HttpRequestManagerTest : public ::testing::Test {
29 public:
HttpRequestManagerTest()30 HttpRequestManagerTest()
31 : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
32 shared_url_loader_factory_(
33 base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
34 &test_url_loader_factory_)) {
35 http_request_manager_ = std::make_unique<HttpRequestManager>(
36 /*profile=*/nullptr);
37 http_request_manager_->SetURLLoaderFactoryForTesting(
38 shared_url_loader_factory_);
39 }
40 HttpRequestManagerTest(const HttpRequestManagerTest&) = delete;
41 HttpRequestManagerTest& operator=(const HttpRequestManagerTest&) = delete;
42
VerifyConnected(bool connected)43 void VerifyConnected(bool connected) {
44 EXPECT_EQ(expected_connected_, connected);
45 callback_invoked_ = true;
46 }
47
48 protected:
VerifyCallbackInvoked(bool callback_invoked)49 void VerifyCallbackInvoked(bool callback_invoked) {
50 EXPECT_EQ(callback_invoked_, callback_invoked);
51 }
52
ResetCallbackInvoked()53 void ResetCallbackInvoked() { callback_invoked_ = false; }
54
ResetHttpRequestManager()55 void ResetHttpRequestManager() { http_request_manager_.reset(); }
56
SetExpectedConnectionResult(bool expected_connected)57 void SetExpectedConnectionResult(bool expected_connected) {
58 expected_connected_ = expected_connected;
59 }
60
task_environment()61 content::BrowserTaskEnvironment& task_environment() {
62 return task_environment_;
63 }
64
http_request_manager()65 HttpRequestManager* http_request_manager() {
66 return http_request_manager_.get();
67 }
68
test_url_loader_factory()69 network::TestURLLoaderFactory& test_url_loader_factory() {
70 return test_url_loader_factory_;
71 }
72
weak_ptr()73 base::WeakPtr<HttpRequestManagerTest> weak_ptr() {
74 return weak_factory_.GetWeakPtr();
75 }
76
77 private:
78 content::BrowserTaskEnvironment task_environment_;
79 std::unique_ptr<HttpRequestManager> http_request_manager_;
80 network::TestURLLoaderFactory test_url_loader_factory_;
81 scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
82 bool expected_connected_ = false;
83 bool callback_invoked_ = false;
84 base::WeakPtrFactory<HttpRequestManagerTest> weak_factory_{this};
85 };
86
TEST_F(HttpRequestManagerTest,TestSuccessfulConnection)87 TEST_F(HttpRequestManagerTest, TestSuccessfulConnection) {
88 SetExpectedConnectionResult(true);
89 http_request_manager()->MakeRequest(
90 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
91 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
92 EXPECT_EQ(1, test_url_loader_factory().NumPending());
93 EXPECT_TRUE(test_url_loader_factory().SimulateResponseForPendingRequest(
94 kFakeUrl, /*content=*/"", net::HTTP_NO_CONTENT));
95 VerifyCallbackInvoked(true);
96 }
97
TEST_F(HttpRequestManagerTest,TestUnsuccessfulConnection)98 TEST_F(HttpRequestManagerTest, TestUnsuccessfulConnection) {
99 SetExpectedConnectionResult(false);
100 http_request_manager()->MakeRequest(
101 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
102 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
103 EXPECT_EQ(1, test_url_loader_factory().NumPending());
104 EXPECT_TRUE(test_url_loader_factory().SimulateResponseForPendingRequest(
105 kFakeUrl, /*content=*/"", net::HTTP_BAD_REQUEST));
106 VerifyCallbackInvoked(true);
107 }
108
TEST_F(HttpRequestManagerTest,TestTimeoutExceeded)109 TEST_F(HttpRequestManagerTest, TestTimeoutExceeded) {
110 SetExpectedConnectionResult(false);
111 http_request_manager()->MakeRequest(
112 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
113 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
114 EXPECT_EQ(1, test_url_loader_factory().NumPending());
115 // Advance the clock by |timeout_ms| + 1 milliseconds.
116 task_environment().FastForwardBy(
117 base::TimeDelta::FromMilliseconds(timeout_ms + 1));
118 // HTTP requests time out after |timeout_ms| milliseconds.
119 EXPECT_EQ(0, test_url_loader_factory().NumPending());
120 VerifyCallbackInvoked(true);
121 }
122
TEST_F(HttpRequestManagerTest,TestRetryHttpRequest)123 TEST_F(HttpRequestManagerTest, TestRetryHttpRequest) {
124 SetExpectedConnectionResult(true);
125 http_request_manager()->MakeRequest(
126 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
127 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
128 EXPECT_EQ(1, test_url_loader_factory().NumPending());
129 EXPECT_TRUE(test_url_loader_factory().SimulateResponseForPendingRequest(
130 kFakeUrl, /*content=*/"", net::HTTP_INTERNAL_SERVER_ERROR));
131 // HTTP requests are retried on HTTP 5XX errors, hence it is expected there is
132 // a pending request.
133 EXPECT_EQ(1, test_url_loader_factory().NumPending());
134 EXPECT_TRUE(test_url_loader_factory().SimulateResponseForPendingRequest(
135 kFakeUrl, /*content=*/"", net::HTTP_NO_CONTENT));
136 EXPECT_EQ(0, test_url_loader_factory().NumPending());
137 VerifyCallbackInvoked(true);
138 }
139
TEST_F(HttpRequestManagerTest,TestOverlappingRequests)140 TEST_F(HttpRequestManagerTest, TestOverlappingRequests) {
141 SetExpectedConnectionResult(true);
142 http_request_manager()->MakeRequest(
143 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
144 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
145 EXPECT_EQ(1, test_url_loader_factory().NumPending());
146 // Advance the the clock by |timeout_ms| - 1 milliseconds, ensuring the
147 // request has not timed out.
148 task_environment().FastForwardBy(
149 base::TimeDelta::FromMilliseconds(timeout_ms - 1));
150 // Launch another HTTP request.
151 http_request_manager()->MakeRequest(
152 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
153 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
154 // Only one request is expected because the first request was cancelled when
155 // the second one was created.
156 EXPECT_EQ(1, test_url_loader_factory().NumPending());
157 EXPECT_TRUE(test_url_loader_factory().SimulateResponseForPendingRequest(
158 kFakeUrl, /*content=*/"", net::HTTP_NO_CONTENT));
159 EXPECT_EQ(0, test_url_loader_factory().NumPending());
160 VerifyCallbackInvoked(true);
161 }
162
TEST_F(HttpRequestManagerTest,TestNonOverlappingRequests)163 TEST_F(HttpRequestManagerTest, TestNonOverlappingRequests) {
164 SetExpectedConnectionResult(false);
165 http_request_manager()->MakeRequest(
166 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
167 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
168 EXPECT_EQ(1, test_url_loader_factory().NumPending());
169 EXPECT_TRUE(test_url_loader_factory().SimulateResponseForPendingRequest(
170 kFakeUrl, /*content=*/"", net::HTTP_BAD_REQUEST));
171 EXPECT_EQ(0, test_url_loader_factory().NumPending());
172 VerifyCallbackInvoked(true);
173
174 ResetCallbackInvoked();
175 // Advance the clock by |timeout_ms| + 1 milliseconds to simulate that the
176 // second request does not overlap with the first.
177 task_environment().FastForwardBy(
178 base::TimeDelta::FromMilliseconds(timeout_ms + 1));
179 SetExpectedConnectionResult(true);
180 http_request_manager()->MakeRequest(
181 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
182 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
183 EXPECT_EQ(1, test_url_loader_factory().NumPending());
184 EXPECT_TRUE(test_url_loader_factory().SimulateResponseForPendingRequest(
185 kFakeUrl, /*content=*/"", net::HTTP_NO_CONTENT));
186 VerifyCallbackInvoked(true);
187 }
188
TEST_F(HttpRequestManagerTest,TestManagerDestroyedWhenRequestPending)189 TEST_F(HttpRequestManagerTest, TestManagerDestroyedWhenRequestPending) {
190 // A connection result will not be returned in this scenario and
191 // VerifyConnected() should be invoked.
192 http_request_manager()->MakeRequest(
193 GURL(kFakeUrl), base::TimeDelta::FromMilliseconds(timeout_ms),
194 base::BindOnce(&HttpRequestManagerTest::VerifyConnected, weak_ptr()));
195 EXPECT_EQ(1, test_url_loader_factory().NumPending());
196 ResetHttpRequestManager();
197 // Http request canceled.
198 EXPECT_EQ(0, test_url_loader_factory().NumPending());
199 VerifyCallbackInvoked(false);
200 }
201
202 } // namespace network_diagnostics
203 } // namespace chromeos
204