blob: f480cac3a66d52d6d6ae659c08d0fe50cfbb68d8 [file] [log] [blame]
sorin395c2ac2014-09-16 21:31:071// Copyright 2014 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
dchengd0fc6aa92016-04-22 18:03:125#include "components/update_client/request_sender.h"
6
7#include <memory>
Sorin Jianua8ef73d2017-11-02 16:55:178#include <utility>
dchengd0fc6aa92016-04-22 18:03:129
sorin5cb1f5492014-09-23 04:07:4410#include "base/macros.h"
sorin9797aba2015-04-17 17:15:0311#include "base/memory/ref_counted.h"
davidben74f67442016-10-01 01:45:2212#include "base/path_service.h"
sorin395c2ac2014-09-16 21:31:0713#include "base/run_loop.h"
sorin1bc5eff2016-02-17 18:45:1714#include "base/strings/string_util.h"
Francois Dorayff8a6452017-07-27 17:11:5815#include "base/test/scoped_task_environment.h"
gab7966d312016-05-11 20:35:0116#include "base/threading/thread_task_runner_handle.h"
sorinb120440b2015-04-27 16:34:1517#include "components/update_client/test_configurator.h"
18#include "components/update_client/url_request_post_interceptor.h"
sorin395c2ac2014-09-16 21:31:0719#include "net/url_request/url_fetcher.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
sorin52ac0882015-01-24 01:15:0022namespace update_client {
sorin395c2ac2014-09-16 21:31:0723
24namespace {
25
26const char kUrl1[] = "https://localhost2/path1";
27const char kUrl2[] = "https://localhost2/path2";
28const char kUrlPath1[] = "path1";
29const char kUrlPath2[] = "path2";
30
sorin1bc5eff2016-02-17 18:45:1731// TODO(sorin): refactor as a utility function for unit tests.
32base::FilePath test_file(const char* file) {
33 base::FilePath path;
Avi Drissmanf617d012018-05-02 18:48:5334 base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
sorin1bc5eff2016-02-17 18:45:1735 return path.AppendASCII("components")
36 .AppendASCII("test")
37 .AppendASCII("data")
38 .AppendASCII("update_client")
39 .AppendASCII(file);
40}
41
sorin395c2ac2014-09-16 21:31:0742} // namespace
43
Sorin Jianud907dbf62018-02-21 17:18:2944class RequestSenderTest : public testing::Test,
45 public ::testing::WithParamInterface<bool> {
sorin395c2ac2014-09-16 21:31:0746 public:
47 RequestSenderTest();
dcheng30a1b1542014-10-29 21:27:5048 ~RequestSenderTest() override;
sorin395c2ac2014-09-16 21:31:0749
50 // Overrides from testing::Test.
dcheng30a1b1542014-10-29 21:27:5051 void SetUp() override;
52 void TearDown() override;
sorin395c2ac2014-09-16 21:31:0753
sorinfccbf2d2016-04-04 20:34:3454 void RequestSenderComplete(int error,
55 const std::string& response,
56 int retry_after_sec);
sorin395c2ac2014-09-16 21:31:0757
58 protected:
59 void Quit();
60 void RunThreads();
Francois Dorayff8a6452017-07-27 17:11:5861
62 base::test::ScopedTaskEnvironment scoped_task_environment_;
sorin395c2ac2014-09-16 21:31:0763
sorin9797aba2015-04-17 17:15:0364 scoped_refptr<TestConfigurator> config_;
dchengd0fc6aa92016-04-22 18:03:1265 std::unique_ptr<RequestSender> request_sender_;
66 std::unique_ptr<InterceptorFactory> interceptor_factory_;
sorin395c2ac2014-09-16 21:31:0767
Sorin Jianu015681f2018-04-04 16:43:3368 scoped_refptr<URLRequestPostInterceptor> post_interceptor_1_;
69 scoped_refptr<URLRequestPostInterceptor> post_interceptor_2_;
sorin395c2ac2014-09-16 21:31:0770
sorin519656c2017-04-28 22:39:3471 int error_ = 0;
sorin1bc5eff2016-02-17 18:45:1772 std::string response_;
sorin395c2ac2014-09-16 21:31:0773
74 private:
Sorin Jianua8ef73d2017-11-02 16:55:1775 base::OnceClosure quit_closure_;
sorin395c2ac2014-09-16 21:31:0776
77 DISALLOW_COPY_AND_ASSIGN(RequestSenderTest);
78};
79
Sorin Jianud907dbf62018-02-21 17:18:2980INSTANTIATE_TEST_CASE_P(IsForeground, RequestSenderTest, ::testing::Bool());
81
Francois Dorayff8a6452017-07-27 17:11:5882RequestSenderTest::RequestSenderTest()
83 : scoped_task_environment_(
84 base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
sorin395c2ac2014-09-16 21:31:0785
sorin1bc5eff2016-02-17 18:45:1786RequestSenderTest::~RequestSenderTest() {}
sorin395c2ac2014-09-16 21:31:0787
88void RequestSenderTest::SetUp() {
Sorin Jianucc048f892017-07-26 02:05:5489 config_ = base::MakeRefCounted<TestConfigurator>();
Sorin Jianu015681f2018-04-04 16:43:3390 request_sender_ = std::make_unique<RequestSender>(config_);
91
sorin519656c2017-04-28 22:39:3492 interceptor_factory_ =
Jinho Bangda4e4282018-01-03 13:21:2393 std::make_unique<InterceptorFactory>(base::ThreadTaskRunnerHandle::Get());
sorin5cabcf0b2015-06-09 00:54:4494 post_interceptor_1_ =
sorin395c2ac2014-09-16 21:31:0795 interceptor_factory_->CreateInterceptorForPath(kUrlPath1);
sorin5cabcf0b2015-06-09 00:54:4496 post_interceptor_2_ =
sorin395c2ac2014-09-16 21:31:0797 interceptor_factory_->CreateInterceptorForPath(kUrlPath2);
sorin5cabcf0b2015-06-09 00:54:4498 EXPECT_TRUE(post_interceptor_1_);
99 EXPECT_TRUE(post_interceptor_2_);
sorin395c2ac2014-09-16 21:31:07100}
101
102void RequestSenderTest::TearDown() {
sorin519656c2017-04-28 22:39:34103 request_sender_ = nullptr;
sorin395c2ac2014-09-16 21:31:07104
sorin5cabcf0b2015-06-09 00:54:44105 post_interceptor_1_ = nullptr;
106 post_interceptor_2_ = nullptr;
sorin395c2ac2014-09-16 21:31:07107
sorin519656c2017-04-28 22:39:34108 interceptor_factory_ = nullptr;
sorin395c2ac2014-09-16 21:31:07109
Sorin Jianuf805c222017-09-20 22:36:21110 // Run the threads until they are idle to allow the clean up
111 // of the network interceptors on the IO thread.
112 scoped_task_environment_.RunUntilIdle();
sorin9797aba2015-04-17 17:15:03113 config_ = nullptr;
sorin395c2ac2014-09-16 21:31:07114}
115
116void RequestSenderTest::RunThreads() {
117 base::RunLoop runloop;
118 quit_closure_ = runloop.QuitClosure();
119 runloop.Run();
sorin395c2ac2014-09-16 21:31:07120}
121
122void RequestSenderTest::Quit() {
123 if (!quit_closure_.is_null())
Sorin Jianua8ef73d2017-11-02 16:55:17124 std::move(quit_closure_).Run();
sorin395c2ac2014-09-16 21:31:07125}
126
sorin1bc5eff2016-02-17 18:45:17127void RequestSenderTest::RequestSenderComplete(int error,
sorinfccbf2d2016-04-04 20:34:34128 const std::string& response,
129 int retry_after_sec) {
sorin1bc5eff2016-02-17 18:45:17130 error_ = error;
131 response_ = response;
132
sorin395c2ac2014-09-16 21:31:07133 Quit();
134}
135
136// Tests that when a request to the first url succeeds, the subsequent urls are
137// not tried.
Sorin Jianud907dbf62018-02-21 17:18:29138TEST_P(RequestSenderTest, RequestSendSuccess) {
Sorin Jianu015681f2018-04-04 16:43:33139 EXPECT_TRUE(
140 post_interceptor_1_->ExpectRequest(std::make_unique<PartialMatch>("test"),
141 test_file("updatecheck_reply_1.xml")));
sorin395c2ac2014-09-16 21:31:07142
Sorin Jianud907dbf62018-02-21 17:18:29143 const bool is_foreground = GetParam();
Sorin Jianua8ef73d2017-11-02 16:55:17144 request_sender_->Send(
Sorin Jianu015681f2018-04-04 16:43:33145 {GURL(kUrl1), GURL(kUrl2)},
146 {{"X-Goog-Update-Interactivity", is_foreground ? "fg" : "bg"}}, "test",
147 false,
Sorin Jianua8ef73d2017-11-02 16:55:17148 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
149 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07150 RunThreads();
151
sorin5cabcf0b2015-06-09 00:54:44152 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
153 << post_interceptor_1_->GetRequestsAsString();
154 EXPECT_EQ(1, post_interceptor_1_->GetCount())
155 << post_interceptor_1_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07156
sorin30474f02017-04-27 00:45:48157 EXPECT_EQ(0, post_interceptor_2_->GetHitCount())
158 << post_interceptor_2_->GetRequestsAsString();
159 EXPECT_EQ(0, post_interceptor_2_->GetCount())
160 << post_interceptor_2_->GetRequestsAsString();
161
sorin1bc5eff2016-02-17 18:45:17162 // Sanity check the request.
Sorin Jianud907dbf62018-02-21 17:18:29163 EXPECT_STREQ("test", post_interceptor_1_->GetRequestBody(0).c_str());
sorin1bc5eff2016-02-17 18:45:17164
165 // Check the response post conditions.
166 EXPECT_EQ(0, error_);
167 EXPECT_TRUE(base::StartsWith(response_,
168 "<?xml version='1.0' encoding='UTF-8'?>",
169 base::CompareCase::SENSITIVE));
sorin519656c2017-04-28 22:39:34170 EXPECT_EQ(505ul, response_.size());
Sorin Jianuf805c222017-09-20 22:36:21171
Sorin Jianud907dbf62018-02-21 17:18:29172 // Check the interactivity header value.
173 const auto extra_request_headers =
174 post_interceptor_1_->GetRequests()[0].second;
Sorin Jianu1ab71d12018-03-12 18:11:39175 EXPECT_TRUE(extra_request_headers.HasHeader("X-Goog-Update-Interactivity"));
Sorin Jianud907dbf62018-02-21 17:18:29176 std::string header;
Sorin Jianu1ab71d12018-03-12 18:11:39177 extra_request_headers.GetHeader("X-Goog-Update-Interactivity", &header);
Sorin Jianud907dbf62018-02-21 17:18:29178 EXPECT_STREQ(is_foreground ? "fg" : "bg", header.c_str());
sorin395c2ac2014-09-16 21:31:07179}
180
181// Tests that the request succeeds using the second url after the first url
182// has failed.
183TEST_F(RequestSenderTest, RequestSendSuccessWithFallback) {
Sorin Jianu015681f2018-04-04 16:43:33184 EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
185 std::make_unique<PartialMatch>("test"), 403));
186 EXPECT_TRUE(post_interceptor_2_->ExpectRequest(
187 std::make_unique<PartialMatch>("test")));
sorin395c2ac2014-09-16 21:31:07188
Sorin Jianua8ef73d2017-11-02 16:55:17189 request_sender_->Send(
Sorin Jianu015681f2018-04-04 16:43:33190 {GURL(kUrl1), GURL(kUrl2)}, {}, "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17191 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
192 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07193 RunThreads();
194
sorin5cabcf0b2015-06-09 00:54:44195 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
196 << post_interceptor_1_->GetRequestsAsString();
197 EXPECT_EQ(1, post_interceptor_1_->GetCount())
198 << post_interceptor_1_->GetRequestsAsString();
199 EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
200 << post_interceptor_2_->GetRequestsAsString();
201 EXPECT_EQ(1, post_interceptor_2_->GetCount())
202 << post_interceptor_2_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07203
Sorin Jianud907dbf62018-02-21 17:18:29204 EXPECT_STREQ("test", post_interceptor_1_->GetRequestBody(0).c_str());
205 EXPECT_STREQ("test", post_interceptor_2_->GetRequestBody(0).c_str());
sorin1bc5eff2016-02-17 18:45:17206 EXPECT_EQ(0, error_);
sorin395c2ac2014-09-16 21:31:07207}
208
209// Tests that the request fails when both urls have failed.
210TEST_F(RequestSenderTest, RequestSendFailed) {
Sorin Jianu015681f2018-04-04 16:43:33211 EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
212 std::make_unique<PartialMatch>("test"), 403));
213 EXPECT_TRUE(post_interceptor_2_->ExpectRequest(
214 std::make_unique<PartialMatch>("test"), 403));
sorin395c2ac2014-09-16 21:31:07215
sorin519656c2017-04-28 22:39:34216 const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
Jinho Bangda4e4282018-01-03 13:21:23217 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17218 request_sender_->Send(
Sorin Jianua64a1e52018-02-28 16:53:34219 urls, {}, "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17220 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
221 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07222 RunThreads();
223
sorin5cabcf0b2015-06-09 00:54:44224 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
225 << post_interceptor_1_->GetRequestsAsString();
226 EXPECT_EQ(1, post_interceptor_1_->GetCount())
227 << post_interceptor_1_->GetRequestsAsString();
228 EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
229 << post_interceptor_2_->GetRequestsAsString();
230 EXPECT_EQ(1, post_interceptor_2_->GetCount())
231 << post_interceptor_2_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07232
Sorin Jianud907dbf62018-02-21 17:18:29233 EXPECT_STREQ("test", post_interceptor_1_->GetRequestBody(0).c_str());
234 EXPECT_STREQ("test", post_interceptor_2_->GetRequestBody(0).c_str());
sorin1bc5eff2016-02-17 18:45:17235 EXPECT_EQ(403, error_);
sorin395c2ac2014-09-16 21:31:07236}
237
sorin5cabcf0b2015-06-09 00:54:44238// Tests that the request fails when no urls are provided.
239TEST_F(RequestSenderTest, RequestSendFailedNoUrls) {
240 std::vector<GURL> urls;
Jinho Bangda4e4282018-01-03 13:21:23241 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17242 request_sender_->Send(
Sorin Jianua64a1e52018-02-28 16:53:34243 urls, std::map<std::string, std::string>(), "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17244 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
245 base::Unretained(this)));
sorin5cabcf0b2015-06-09 00:54:44246 RunThreads();
247
sorin1bc5eff2016-02-17 18:45:17248 EXPECT_EQ(-1, error_);
249}
250
251// Tests that a CUP request fails if the response is not signed.
252TEST_F(RequestSenderTest, RequestSendCupError) {
Sorin Jianu015681f2018-04-04 16:43:33253 EXPECT_TRUE(
254 post_interceptor_1_->ExpectRequest(std::make_unique<PartialMatch>("test"),
255 test_file("updatecheck_reply_1.xml")));
sorin1bc5eff2016-02-17 18:45:17256
sorin519656c2017-04-28 22:39:34257 const std::vector<GURL> urls = {GURL(kUrl1)};
Jinho Bangda4e4282018-01-03 13:21:23258 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17259 request_sender_->Send(
Sorin Jianua64a1e52018-02-28 16:53:34260 urls, {}, "test", true,
Sorin Jianua8ef73d2017-11-02 16:55:17261 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
262 base::Unretained(this)));
sorin1bc5eff2016-02-17 18:45:17263 RunThreads();
264
265 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
266 << post_interceptor_1_->GetRequestsAsString();
267 EXPECT_EQ(1, post_interceptor_1_->GetCount())
268 << post_interceptor_1_->GetRequestsAsString();
269
Sorin Jianud907dbf62018-02-21 17:18:29270 EXPECT_STREQ("test", post_interceptor_1_->GetRequestBody(0).c_str());
sorin1bc5eff2016-02-17 18:45:17271 EXPECT_EQ(RequestSender::kErrorResponseNotTrusted, error_);
272 EXPECT_TRUE(response_.empty());
sorin5cabcf0b2015-06-09 00:54:44273}
274
sorin52ac0882015-01-24 01:15:00275} // namespace update_client