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