blob: e2eb26316d8d690e11a171410725bd4877b16d7a [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"
Antonio Gomesb6162502018-06-28 20:21:5518#include "components/update_client/url_loader_post_interceptor.h"
sorin395c2ac2014-09-16 21:31:0719#include "testing/gtest/include/gtest/gtest.h"
20
sorin52ac0882015-01-24 01:15:0021namespace update_client {
sorin395c2ac2014-09-16 21:31:0722
23namespace {
24
25const char kUrl1[] = "https://localhost2/path1";
26const char kUrl2[] = "https://localhost2/path2";
sorin395c2ac2014-09-16 21:31:0727
sorin1bc5eff2016-02-17 18:45:1728// TODO(sorin): refactor as a utility function for unit tests.
29base::FilePath test_file(const char* file) {
30 base::FilePath path;
Avi Drissmanf617d012018-05-02 18:48:5331 base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
sorin1bc5eff2016-02-17 18:45:1732 return path.AppendASCII("components")
33 .AppendASCII("test")
34 .AppendASCII("data")
35 .AppendASCII("update_client")
36 .AppendASCII(file);
37}
38
sorin395c2ac2014-09-16 21:31:0739} // namespace
40
Sorin Jianud907dbf62018-02-21 17:18:2941class RequestSenderTest : public testing::Test,
42 public ::testing::WithParamInterface<bool> {
sorin395c2ac2014-09-16 21:31:0743 public:
44 RequestSenderTest();
dcheng30a1b1542014-10-29 21:27:5045 ~RequestSenderTest() override;
sorin395c2ac2014-09-16 21:31:0746
47 // Overrides from testing::Test.
dcheng30a1b1542014-10-29 21:27:5048 void SetUp() override;
49 void TearDown() override;
sorin395c2ac2014-09-16 21:31:0750
sorinfccbf2d2016-04-04 20:34:3451 void RequestSenderComplete(int error,
52 const std::string& response,
53 int retry_after_sec);
sorin395c2ac2014-09-16 21:31:0754
55 protected:
56 void Quit();
57 void RunThreads();
Francois Dorayff8a6452017-07-27 17:11:5858
59 base::test::ScopedTaskEnvironment scoped_task_environment_;
sorin395c2ac2014-09-16 21:31:0760
sorin9797aba2015-04-17 17:15:0361 scoped_refptr<TestConfigurator> config_;
dchengd0fc6aa92016-04-22 18:03:1262 std::unique_ptr<RequestSender> request_sender_;
sorin395c2ac2014-09-16 21:31:0763
Antonio Gomesb6162502018-06-28 20:21:5564 std::unique_ptr<URLLoaderPostInterceptor> post_interceptor_;
sorin395c2ac2014-09-16 21:31:0765
sorin519656c2017-04-28 22:39:3466 int error_ = 0;
sorin1bc5eff2016-02-17 18:45:1767 std::string response_;
sorin395c2ac2014-09-16 21:31:0768
69 private:
Sorin Jianua8ef73d2017-11-02 16:55:1770 base::OnceClosure quit_closure_;
sorin395c2ac2014-09-16 21:31:0771
72 DISALLOW_COPY_AND_ASSIGN(RequestSenderTest);
73};
74
Sorin Jianud907dbf62018-02-21 17:18:2975INSTANTIATE_TEST_CASE_P(IsForeground, RequestSenderTest, ::testing::Bool());
76
Francois Dorayff8a6452017-07-27 17:11:5877RequestSenderTest::RequestSenderTest()
78 : scoped_task_environment_(
79 base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
sorin395c2ac2014-09-16 21:31:0780
sorin1bc5eff2016-02-17 18:45:1781RequestSenderTest::~RequestSenderTest() {}
sorin395c2ac2014-09-16 21:31:0782
83void RequestSenderTest::SetUp() {
Sorin Jianucc048f892017-07-26 02:05:5484 config_ = base::MakeRefCounted<TestConfigurator>();
Sorin Jianu015681f2018-04-04 16:43:3385 request_sender_ = std::make_unique<RequestSender>(config_);
86
Antonio Gomesb6162502018-06-28 20:21:5587 std::vector<GURL> urls;
88 urls.push_back(GURL(kUrl1));
89 urls.push_back(GURL(kUrl2));
90
91 post_interceptor_ = std::make_unique<URLLoaderPostInterceptor>(
92 urls, config_->test_url_loader_factory());
93 EXPECT_TRUE(post_interceptor_);
sorin395c2ac2014-09-16 21:31:0794}
95
96void RequestSenderTest::TearDown() {
sorin519656c2017-04-28 22:39:3497 request_sender_ = nullptr;
sorin395c2ac2014-09-16 21:31:0798
Antonio Gomesb6162502018-06-28 20:21:5599 post_interceptor_.reset();
sorin395c2ac2014-09-16 21:31:07100
Sorin Jianuf805c222017-09-20 22:36:21101 // Run the threads until they are idle to allow the clean up
102 // of the network interceptors on the IO thread.
103 scoped_task_environment_.RunUntilIdle();
sorin9797aba2015-04-17 17:15:03104 config_ = nullptr;
sorin395c2ac2014-09-16 21:31:07105}
106
107void RequestSenderTest::RunThreads() {
108 base::RunLoop runloop;
109 quit_closure_ = runloop.QuitClosure();
110 runloop.Run();
sorin395c2ac2014-09-16 21:31:07111}
112
113void RequestSenderTest::Quit() {
114 if (!quit_closure_.is_null())
Sorin Jianua8ef73d2017-11-02 16:55:17115 std::move(quit_closure_).Run();
sorin395c2ac2014-09-16 21:31:07116}
117
sorin1bc5eff2016-02-17 18:45:17118void RequestSenderTest::RequestSenderComplete(int error,
sorinfccbf2d2016-04-04 20:34:34119 const std::string& response,
120 int retry_after_sec) {
sorin1bc5eff2016-02-17 18:45:17121 error_ = error;
122 response_ = response;
123
sorin395c2ac2014-09-16 21:31:07124 Quit();
125}
126
127// Tests that when a request to the first url succeeds, the subsequent urls are
128// not tried.
Sorin Jianud907dbf62018-02-21 17:18:29129TEST_P(RequestSenderTest, RequestSendSuccess) {
Sorin Jianu015681f2018-04-04 16:43:33130 EXPECT_TRUE(
Antonio Gomesb6162502018-06-28 20:21:55131 post_interceptor_->ExpectRequest(std::make_unique<PartialMatch>("test"),
132 test_file("updatecheck_reply_1.xml")));
sorin395c2ac2014-09-16 21:31:07133
Sorin Jianud907dbf62018-02-21 17:18:29134 const bool is_foreground = GetParam();
Sorin Jianua8ef73d2017-11-02 16:55:17135 request_sender_->Send(
Sorin Jianu015681f2018-04-04 16:43:33136 {GURL(kUrl1), GURL(kUrl2)},
137 {{"X-Goog-Update-Interactivity", is_foreground ? "fg" : "bg"}}, "test",
138 false,
Sorin Jianua8ef73d2017-11-02 16:55:17139 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
140 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07141 RunThreads();
142
Antonio Gomesb6162502018-06-28 20:21:55143 EXPECT_EQ(1, post_interceptor_->GetHitCount())
144 << post_interceptor_->GetRequestsAsString();
145 EXPECT_EQ(1, post_interceptor_->GetCount())
146 << post_interceptor_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07147
Antonio Gomesb6162502018-06-28 20:21:55148 EXPECT_EQ(0, post_interceptor_->GetHitCountForURL(GURL(kUrl2)))
149 << post_interceptor_->GetRequestsAsString();
sorin30474f02017-04-27 00:45:48150
sorin1bc5eff2016-02-17 18:45:17151 // Sanity check the request.
Antonio Gomesb6162502018-06-28 20:21:55152 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(0).c_str());
sorin1bc5eff2016-02-17 18:45:17153
154 // Check the response post conditions.
155 EXPECT_EQ(0, error_);
156 EXPECT_TRUE(base::StartsWith(response_,
157 "<?xml version='1.0' encoding='UTF-8'?>",
158 base::CompareCase::SENSITIVE));
sorin519656c2017-04-28 22:39:34159 EXPECT_EQ(505ul, response_.size());
Sorin Jianuf805c222017-09-20 22:36:21160
Sorin Jianud907dbf62018-02-21 17:18:29161 // Check the interactivity header value.
162 const auto extra_request_headers =
Antonio Gomesb6162502018-06-28 20:21:55163 std::get<1>(post_interceptor_->GetRequests()[0]);
Sorin Jianu1ab71d12018-03-12 18:11:39164 EXPECT_TRUE(extra_request_headers.HasHeader("X-Goog-Update-Interactivity"));
Sorin Jianud907dbf62018-02-21 17:18:29165 std::string header;
Sorin Jianu1ab71d12018-03-12 18:11:39166 extra_request_headers.GetHeader("X-Goog-Update-Interactivity", &header);
Sorin Jianud907dbf62018-02-21 17:18:29167 EXPECT_STREQ(is_foreground ? "fg" : "bg", header.c_str());
sorin395c2ac2014-09-16 21:31:07168}
169
170// Tests that the request succeeds using the second url after the first url
171// has failed.
172TEST_F(RequestSenderTest, RequestSendSuccessWithFallback) {
Antonio Gomesb6162502018-06-28 20:21:55173 EXPECT_TRUE(post_interceptor_->ExpectRequest(
174 std::make_unique<PartialMatch>("test"), net::HTTP_FORBIDDEN));
175 EXPECT_TRUE(
176 post_interceptor_->ExpectRequest(std::make_unique<PartialMatch>("test")));
sorin395c2ac2014-09-16 21:31:07177
Sorin Jianua8ef73d2017-11-02 16:55:17178 request_sender_->Send(
Sorin Jianu015681f2018-04-04 16:43:33179 {GURL(kUrl1), GURL(kUrl2)}, {}, "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17180 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
181 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07182 RunThreads();
183
Antonio Gomesb6162502018-06-28 20:21:55184 EXPECT_EQ(2, post_interceptor_->GetHitCount())
185 << post_interceptor_->GetRequestsAsString();
186 EXPECT_EQ(2, post_interceptor_->GetCount())
187 << post_interceptor_->GetRequestsAsString();
188 EXPECT_EQ(1, post_interceptor_->GetHitCountForURL(GURL(kUrl1)))
189 << post_interceptor_->GetRequestsAsString();
190 EXPECT_EQ(1, post_interceptor_->GetHitCountForURL(GURL(kUrl2)))
191 << post_interceptor_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07192
Antonio Gomesb6162502018-06-28 20:21:55193 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(0).c_str());
194 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(1).c_str());
sorin1bc5eff2016-02-17 18:45:17195 EXPECT_EQ(0, error_);
sorin395c2ac2014-09-16 21:31:07196}
197
198// Tests that the request fails when both urls have failed.
199TEST_F(RequestSenderTest, RequestSendFailed) {
Antonio Gomesb6162502018-06-28 20:21:55200 EXPECT_TRUE(post_interceptor_->ExpectRequest(
201 std::make_unique<PartialMatch>("test"), net::HTTP_FORBIDDEN));
202 EXPECT_TRUE(post_interceptor_->ExpectRequest(
203 std::make_unique<PartialMatch>("test"), net::HTTP_FORBIDDEN));
sorin395c2ac2014-09-16 21:31:07204
sorin519656c2017-04-28 22:39:34205 const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
Jinho Bangda4e4282018-01-03 13:21:23206 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17207 request_sender_->Send(
Sorin Jianua64a1e52018-02-28 16:53:34208 urls, {}, "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17209 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
210 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07211 RunThreads();
212
Antonio Gomesb6162502018-06-28 20:21:55213 EXPECT_EQ(2, post_interceptor_->GetHitCount())
214 << post_interceptor_->GetRequestsAsString();
215 EXPECT_EQ(2, post_interceptor_->GetCount())
216 << post_interceptor_->GetRequestsAsString();
217 EXPECT_EQ(1, post_interceptor_->GetHitCountForURL(GURL(kUrl1)))
218 << post_interceptor_->GetRequestsAsString();
219 EXPECT_EQ(1, post_interceptor_->GetHitCountForURL(GURL(kUrl2)))
220 << post_interceptor_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07221
Antonio Gomesb6162502018-06-28 20:21:55222 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(0).c_str());
223 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(1).c_str());
sorin1bc5eff2016-02-17 18:45:17224 EXPECT_EQ(403, error_);
sorin395c2ac2014-09-16 21:31:07225}
226
sorin5cabcf0b2015-06-09 00:54:44227// Tests that the request fails when no urls are provided.
228TEST_F(RequestSenderTest, RequestSendFailedNoUrls) {
229 std::vector<GURL> urls;
Jinho Bangda4e4282018-01-03 13:21:23230 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17231 request_sender_->Send(
Sorin Jianua64a1e52018-02-28 16:53:34232 urls, std::map<std::string, std::string>(), "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17233 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
234 base::Unretained(this)));
sorin5cabcf0b2015-06-09 00:54:44235 RunThreads();
236
Sorin Jianu888ec292018-06-01 15:35:42237 EXPECT_EQ(-10002, error_);
sorin1bc5eff2016-02-17 18:45:17238}
239
240// Tests that a CUP request fails if the response is not signed.
241TEST_F(RequestSenderTest, RequestSendCupError) {
Sorin Jianu015681f2018-04-04 16:43:33242 EXPECT_TRUE(
Antonio Gomesb6162502018-06-28 20:21:55243 post_interceptor_->ExpectRequest(std::make_unique<PartialMatch>("test"),
244 test_file("updatecheck_reply_1.xml")));
sorin1bc5eff2016-02-17 18:45:17245
sorin519656c2017-04-28 22:39:34246 const std::vector<GURL> urls = {GURL(kUrl1)};
Jinho Bangda4e4282018-01-03 13:21:23247 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17248 request_sender_->Send(
Sorin Jianua64a1e52018-02-28 16:53:34249 urls, {}, "test", true,
Sorin Jianua8ef73d2017-11-02 16:55:17250 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
251 base::Unretained(this)));
sorin1bc5eff2016-02-17 18:45:17252 RunThreads();
253
Antonio Gomesb6162502018-06-28 20:21:55254 EXPECT_EQ(1, post_interceptor_->GetHitCount())
255 << post_interceptor_->GetRequestsAsString();
256 EXPECT_EQ(1, post_interceptor_->GetCount())
257 << post_interceptor_->GetRequestsAsString();
sorin1bc5eff2016-02-17 18:45:17258
Antonio Gomesb6162502018-06-28 20:21:55259 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(0).c_str());
Sorin Jianu888ec292018-06-01 15:35:42260 EXPECT_EQ(-10000, error_);
sorin1bc5eff2016-02-17 18:45:17261 EXPECT_TRUE(response_.empty());
sorin5cabcf0b2015-06-09 00:54:44262}
263
sorin52ac0882015-01-24 01:15:00264} // namespace update_client