blob: ec79ea1d6bd992d7a69a7417b5ffc3bd8389ccce [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>
8
sorin5cb1f5492014-09-23 04:07:449#include "base/macros.h"
sorin519656c2017-04-28 22:39:3410#include "base/memory/ptr_util.h"
sorin9797aba2015-04-17 17:15:0311#include "base/memory/ref_counted.h"
gabf64a25e2017-05-12 19:42:5612#include "base/message_loop/message_loop.h"
davidben74f67442016-10-01 01:45:2213#include "base/path_service.h"
sorin395c2ac2014-09-16 21:31:0714#include "base/run_loop.h"
sorin1bc5eff2016-02-17 18:45:1715#include "base/strings/string_util.h"
fdoraycb664bc2017-02-13 16:45:0216#include "base/test/scoped_task_scheduler.h"
gab7966d312016-05-11 20:35:0117#include "base/threading/thread_task_runner_handle.h"
sorinb120440b2015-04-27 16:34:1518#include "components/update_client/test_configurator.h"
19#include "components/update_client/url_request_post_interceptor.h"
sorin395c2ac2014-09-16 21:31:0720#include "net/url_request/url_fetcher.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
sorin52ac0882015-01-24 01:15:0023namespace update_client {
sorin395c2ac2014-09-16 21:31:0724
25namespace {
26
27const char kUrl1[] = "https://localhost2/path1";
28const char kUrl2[] = "https://localhost2/path2";
29const char kUrlPath1[] = "path1";
30const char kUrlPath2[] = "path2";
31
sorin1bc5eff2016-02-17 18:45:1732// TODO(sorin): refactor as a utility function for unit tests.
33base::FilePath test_file(const char* file) {
34 base::FilePath path;
35 PathService::Get(base::DIR_SOURCE_ROOT, &path);
36 return path.AppendASCII("components")
37 .AppendASCII("test")
38 .AppendASCII("data")
39 .AppendASCII("update_client")
40 .AppendASCII(file);
41}
42
sorin395c2ac2014-09-16 21:31:0743} // namespace
44
45class RequestSenderTest : public testing::Test {
46 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();
61 void RunThreadsUntilIdle();
62
sorin9797aba2015-04-17 17:15:0363 scoped_refptr<TestConfigurator> config_;
dchengd0fc6aa92016-04-22 18:03:1264 std::unique_ptr<RequestSender> request_sender_;
65 std::unique_ptr<InterceptorFactory> interceptor_factory_;
sorin395c2ac2014-09-16 21:31:0766
sorin519656c2017-04-28 22:39:3467 // Owned by the factory.
68 URLRequestPostInterceptor* post_interceptor_1_ = nullptr;
69 URLRequestPostInterceptor* post_interceptor_2_ = nullptr;
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:
75 base::MessageLoopForIO loop_;
fdoraycb664bc2017-02-13 16:45:0276 base::test::ScopedTaskScheduler scoped_task_scheduler_;
sorin395c2ac2014-09-16 21:31:0777 base::Closure quit_closure_;
78
79 DISALLOW_COPY_AND_ASSIGN(RequestSenderTest);
80};
81
sorin519656c2017-04-28 22:39:3482RequestSenderTest::RequestSenderTest() : scoped_task_scheduler_(&loop_) {}
sorin395c2ac2014-09-16 21:31:0783
sorin1bc5eff2016-02-17 18:45:1784RequestSenderTest::~RequestSenderTest() {}
sorin395c2ac2014-09-16 21:31:0785
86void RequestSenderTest::SetUp() {
Sorin Jianucc048f892017-07-26 02:05:5487 config_ = base::MakeRefCounted<TestConfigurator>();
sorin519656c2017-04-28 22:39:3488 interceptor_factory_ =
89 base::MakeUnique<InterceptorFactory>(base::ThreadTaskRunnerHandle::Get());
sorin5cabcf0b2015-06-09 00:54:4490 post_interceptor_1_ =
sorin395c2ac2014-09-16 21:31:0791 interceptor_factory_->CreateInterceptorForPath(kUrlPath1);
sorin5cabcf0b2015-06-09 00:54:4492 post_interceptor_2_ =
sorin395c2ac2014-09-16 21:31:0793 interceptor_factory_->CreateInterceptorForPath(kUrlPath2);
sorin5cabcf0b2015-06-09 00:54:4494 EXPECT_TRUE(post_interceptor_1_);
95 EXPECT_TRUE(post_interceptor_2_);
sorin395c2ac2014-09-16 21:31:0796
sorin519656c2017-04-28 22:39:3497 request_sender_ = nullptr;
sorin395c2ac2014-09-16 21:31:0798}
99
100void RequestSenderTest::TearDown() {
sorin519656c2017-04-28 22:39:34101 request_sender_ = nullptr;
sorin395c2ac2014-09-16 21:31:07102
sorin5cabcf0b2015-06-09 00:54:44103 post_interceptor_1_ = nullptr;
104 post_interceptor_2_ = nullptr;
sorin395c2ac2014-09-16 21:31:07105
sorin519656c2017-04-28 22:39:34106 interceptor_factory_ = nullptr;
sorin395c2ac2014-09-16 21:31:07107
sorin9797aba2015-04-17 17:15:03108 config_ = nullptr;
sorin395c2ac2014-09-16 21:31:07109
110 RunThreadsUntilIdle();
111}
112
113void RequestSenderTest::RunThreads() {
114 base::RunLoop runloop;
115 quit_closure_ = runloop.QuitClosure();
116 runloop.Run();
117
118 // Since some tests need to drain currently enqueued tasks such as network
119 // intercepts on the IO thread, run the threads until they are
120 // idle. The component updater service won't loop again until the loop count
121 // is set and the service is started.
122 RunThreadsUntilIdle();
123}
124
125void RequestSenderTest::RunThreadsUntilIdle() {
126 base::RunLoop().RunUntilIdle();
127}
128
129void RequestSenderTest::Quit() {
130 if (!quit_closure_.is_null())
131 quit_closure_.Run();
132}
133
sorin1bc5eff2016-02-17 18:45:17134void RequestSenderTest::RequestSenderComplete(int error,
sorinfccbf2d2016-04-04 20:34:34135 const std::string& response,
136 int retry_after_sec) {
sorin1bc5eff2016-02-17 18:45:17137 error_ = error;
138 response_ = response;
139
sorin395c2ac2014-09-16 21:31:07140 Quit();
141}
142
143// Tests that when a request to the first url succeeds, the subsequent urls are
144// not tried.
145TEST_F(RequestSenderTest, RequestSendSuccess) {
sorin1bc5eff2016-02-17 18:45:17146 EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
147 new PartialMatch("test"), test_file("updatecheck_reply_1.xml")));
sorin395c2ac2014-09-16 21:31:07148
sorin519656c2017-04-28 22:39:34149 const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
150 request_sender_ = base::MakeUnique<RequestSender>(config_);
sorin1bc5eff2016-02-17 18:45:17151 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07152 base::Bind(&RequestSenderTest::RequestSenderComplete,
153 base::Unretained(this)));
154 RunThreads();
155
sorin5cabcf0b2015-06-09 00:54:44156 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
157 << post_interceptor_1_->GetRequestsAsString();
158 EXPECT_EQ(1, post_interceptor_1_->GetCount())
159 << post_interceptor_1_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07160
sorin30474f02017-04-27 00:45:48161 EXPECT_EQ(0, post_interceptor_2_->GetHitCount())
162 << post_interceptor_2_->GetRequestsAsString();
163 EXPECT_EQ(0, post_interceptor_2_->GetCount())
164 << post_interceptor_2_->GetRequestsAsString();
165
sorin1bc5eff2016-02-17 18:45:17166 // Sanity check the request.
sorin5cabcf0b2015-06-09 00:54:44167 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17168
169 // Check the response post conditions.
170 EXPECT_EQ(0, error_);
171 EXPECT_TRUE(base::StartsWith(response_,
172 "<?xml version='1.0' encoding='UTF-8'?>",
173 base::CompareCase::SENSITIVE));
sorin519656c2017-04-28 22:39:34174 EXPECT_EQ(505ul, response_.size());
sorin395c2ac2014-09-16 21:31:07175}
176
177// Tests that the request succeeds using the second url after the first url
178// has failed.
179TEST_F(RequestSenderTest, RequestSendSuccessWithFallback) {
sorin5cabcf0b2015-06-09 00:54:44180 EXPECT_TRUE(
181 post_interceptor_1_->ExpectRequest(new PartialMatch("test"), 403));
182 EXPECT_TRUE(post_interceptor_2_->ExpectRequest(new PartialMatch("test")));
sorin395c2ac2014-09-16 21:31:07183
sorin519656c2017-04-28 22:39:34184 const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
185 request_sender_ = base::MakeUnique<RequestSender>(config_);
sorin1bc5eff2016-02-17 18:45:17186 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07187 base::Bind(&RequestSenderTest::RequestSenderComplete,
188 base::Unretained(this)));
189 RunThreads();
190
sorin5cabcf0b2015-06-09 00:54:44191 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
192 << post_interceptor_1_->GetRequestsAsString();
193 EXPECT_EQ(1, post_interceptor_1_->GetCount())
194 << post_interceptor_1_->GetRequestsAsString();
195 EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
196 << post_interceptor_2_->GetRequestsAsString();
197 EXPECT_EQ(1, post_interceptor_2_->GetCount())
198 << post_interceptor_2_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07199
sorin5cabcf0b2015-06-09 00:54:44200 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
201 EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17202 EXPECT_EQ(0, error_);
sorin395c2ac2014-09-16 21:31:07203}
204
205// Tests that the request fails when both urls have failed.
206TEST_F(RequestSenderTest, RequestSendFailed) {
sorin5cabcf0b2015-06-09 00:54:44207 EXPECT_TRUE(
208 post_interceptor_1_->ExpectRequest(new PartialMatch("test"), 403));
209 EXPECT_TRUE(
210 post_interceptor_2_->ExpectRequest(new PartialMatch("test"), 403));
sorin395c2ac2014-09-16 21:31:07211
sorin519656c2017-04-28 22:39:34212 const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
213 request_sender_ = base::MakeUnique<RequestSender>(config_);
sorin1bc5eff2016-02-17 18:45:17214 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07215 base::Bind(&RequestSenderTest::RequestSenderComplete,
216 base::Unretained(this)));
217 RunThreads();
218
sorin5cabcf0b2015-06-09 00:54:44219 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
220 << post_interceptor_1_->GetRequestsAsString();
221 EXPECT_EQ(1, post_interceptor_1_->GetCount())
222 << post_interceptor_1_->GetRequestsAsString();
223 EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
224 << post_interceptor_2_->GetRequestsAsString();
225 EXPECT_EQ(1, post_interceptor_2_->GetCount())
226 << post_interceptor_2_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07227
sorin5cabcf0b2015-06-09 00:54:44228 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
229 EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17230 EXPECT_EQ(403, error_);
sorin395c2ac2014-09-16 21:31:07231}
232
sorin5cabcf0b2015-06-09 00:54:44233// Tests that the request fails when no urls are provided.
234TEST_F(RequestSenderTest, RequestSendFailedNoUrls) {
235 std::vector<GURL> urls;
sorin519656c2017-04-28 22:39:34236 request_sender_ = base::MakeUnique<RequestSender>(config_);
sorin1bc5eff2016-02-17 18:45:17237 request_sender_->Send(false, "test", urls,
sorin5cabcf0b2015-06-09 00:54:44238 base::Bind(&RequestSenderTest::RequestSenderComplete,
239 base::Unretained(this)));
240 RunThreads();
241
sorin1bc5eff2016-02-17 18:45:17242 EXPECT_EQ(-1, error_);
243}
244
245// Tests that a CUP request fails if the response is not signed.
246TEST_F(RequestSenderTest, RequestSendCupError) {
247 EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
248 new PartialMatch("test"), test_file("updatecheck_reply_1.xml")));
249
sorin519656c2017-04-28 22:39:34250 const std::vector<GURL> urls = {GURL(kUrl1)};
251 request_sender_ = base::MakeUnique<RequestSender>(config_);
sorin1bc5eff2016-02-17 18:45:17252 request_sender_->Send(true, "test", urls,
253 base::Bind(&RequestSenderTest::RequestSenderComplete,
254 base::Unretained(this)));
255 RunThreads();
256
257 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
258 << post_interceptor_1_->GetRequestsAsString();
259 EXPECT_EQ(1, post_interceptor_1_->GetCount())
260 << post_interceptor_1_->GetRequestsAsString();
261
262 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
263 EXPECT_EQ(RequestSender::kErrorResponseNotTrusted, error_);
264 EXPECT_TRUE(response_.empty());
sorin5cabcf0b2015-06-09 00:54:44265}
266
sorin52ac0882015-01-24 01:15:00267} // namespace update_client