blob: e0b891461fd90eb6507cf39ac9aa6cee5ed0c580 [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"
sorin9797aba2015-04-17 17:15:0310#include "base/memory/ref_counted.h"
davidben74f67442016-10-01 01:45:2211#include "base/path_service.h"
sorin395c2ac2014-09-16 21:31:0712#include "base/run_loop.h"
sorin1bc5eff2016-02-17 18:45:1713#include "base/strings/string_util.h"
fdoraycb664bc2017-02-13 16:45:0214#include "base/test/scoped_task_scheduler.h"
gab7966d312016-05-11 20:35:0115#include "base/threading/thread_task_runner_handle.h"
sorinb120440b2015-04-27 16:34:1516#include "components/update_client/test_configurator.h"
17#include "components/update_client/url_request_post_interceptor.h"
sorin395c2ac2014-09-16 21:31:0718#include "net/url_request/url_fetcher.h"
19#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";
27const char kUrlPath1[] = "path1";
28const char kUrlPath2[] = "path2";
29
sorin1bc5eff2016-02-17 18:45:1730// TODO(sorin): refactor as a utility function for unit tests.
31base::FilePath test_file(const char* file) {
32 base::FilePath path;
33 PathService::Get(base::DIR_SOURCE_ROOT, &path);
34 return path.AppendASCII("components")
35 .AppendASCII("test")
36 .AppendASCII("data")
37 .AppendASCII("update_client")
38 .AppendASCII(file);
39}
40
sorin395c2ac2014-09-16 21:31:0741} // namespace
42
43class RequestSenderTest : public testing::Test {
44 public:
45 RequestSenderTest();
dcheng30a1b1542014-10-29 21:27:5046 ~RequestSenderTest() override;
sorin395c2ac2014-09-16 21:31:0747
48 // Overrides from testing::Test.
dcheng30a1b1542014-10-29 21:27:5049 void SetUp() override;
50 void TearDown() override;
sorin395c2ac2014-09-16 21:31:0751
sorinfccbf2d2016-04-04 20:34:3452 void RequestSenderComplete(int error,
53 const std::string& response,
54 int retry_after_sec);
sorin395c2ac2014-09-16 21:31:0755
56 protected:
57 void Quit();
58 void RunThreads();
59 void RunThreadsUntilIdle();
60
sorin9797aba2015-04-17 17:15:0361 scoped_refptr<TestConfigurator> config_;
dchengd0fc6aa92016-04-22 18:03:1262 std::unique_ptr<RequestSender> request_sender_;
63 std::unique_ptr<InterceptorFactory> interceptor_factory_;
sorin395c2ac2014-09-16 21:31:0764
sorin5cabcf0b2015-06-09 00:54:4465 URLRequestPostInterceptor* post_interceptor_1_; // Owned by the factory.
66 URLRequestPostInterceptor* post_interceptor_2_; // Owned by the factory.
sorin395c2ac2014-09-16 21:31:0767
sorin1bc5eff2016-02-17 18:45:1768 int error_;
69 std::string response_;
sorin395c2ac2014-09-16 21:31:0770
71 private:
72 base::MessageLoopForIO loop_;
fdoraycb664bc2017-02-13 16:45:0273 base::test::ScopedTaskScheduler scoped_task_scheduler_;
sorin395c2ac2014-09-16 21:31:0774 base::Closure quit_closure_;
75
76 DISALLOW_COPY_AND_ASSIGN(RequestSenderTest);
77};
78
79RequestSenderTest::RequestSenderTest()
fdoraycb664bc2017-02-13 16:45:0280 : post_interceptor_1_(nullptr),
81 post_interceptor_2_(nullptr),
82 error_(0),
83 scoped_task_scheduler_(&loop_) {}
sorin395c2ac2014-09-16 21:31:0784
sorin1bc5eff2016-02-17 18:45:1785RequestSenderTest::~RequestSenderTest() {}
sorin395c2ac2014-09-16 21:31:0786
87void RequestSenderTest::SetUp() {
skyostilb0daa012015-06-02 19:03:4888 config_ = new TestConfigurator(base::ThreadTaskRunnerHandle::Get(),
89 base::ThreadTaskRunnerHandle::Get());
sorin395c2ac2014-09-16 21:31:0790 interceptor_factory_.reset(
skyostilb0daa012015-06-02 19:03:4891 new InterceptorFactory(base::ThreadTaskRunnerHandle::Get()));
sorin5cabcf0b2015-06-09 00:54:4492 post_interceptor_1_ =
sorin395c2ac2014-09-16 21:31:0793 interceptor_factory_->CreateInterceptorForPath(kUrlPath1);
sorin5cabcf0b2015-06-09 00:54:4494 post_interceptor_2_ =
sorin395c2ac2014-09-16 21:31:0795 interceptor_factory_->CreateInterceptorForPath(kUrlPath2);
sorin5cabcf0b2015-06-09 00:54:4496 EXPECT_TRUE(post_interceptor_1_);
97 EXPECT_TRUE(post_interceptor_2_);
sorin395c2ac2014-09-16 21:31:0798
99 request_sender_.reset();
100}
101
102void RequestSenderTest::TearDown() {
103 request_sender_.reset();
104
sorin5cabcf0b2015-06-09 00:54:44105 post_interceptor_1_ = nullptr;
106 post_interceptor_2_ = nullptr;
sorin395c2ac2014-09-16 21:31:07107
108 interceptor_factory_.reset();
109
sorin9797aba2015-04-17 17:15:03110 config_ = nullptr;
sorin395c2ac2014-09-16 21:31:07111
112 RunThreadsUntilIdle();
113}
114
115void RequestSenderTest::RunThreads() {
116 base::RunLoop runloop;
117 quit_closure_ = runloop.QuitClosure();
118 runloop.Run();
119
120 // Since some tests need to drain currently enqueued tasks such as network
121 // intercepts on the IO thread, run the threads until they are
122 // idle. The component updater service won't loop again until the loop count
123 // is set and the service is started.
124 RunThreadsUntilIdle();
125}
126
127void RequestSenderTest::RunThreadsUntilIdle() {
128 base::RunLoop().RunUntilIdle();
129}
130
131void RequestSenderTest::Quit() {
132 if (!quit_closure_.is_null())
133 quit_closure_.Run();
134}
135
sorin1bc5eff2016-02-17 18:45:17136void RequestSenderTest::RequestSenderComplete(int error,
sorinfccbf2d2016-04-04 20:34:34137 const std::string& response,
138 int retry_after_sec) {
sorin1bc5eff2016-02-17 18:45:17139 error_ = error;
140 response_ = response;
141
sorin395c2ac2014-09-16 21:31:07142 Quit();
143}
144
145// Tests that when a request to the first url succeeds, the subsequent urls are
146// not tried.
147TEST_F(RequestSenderTest, RequestSendSuccess) {
sorin1bc5eff2016-02-17 18:45:17148 EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
149 new PartialMatch("test"), test_file("updatecheck_reply_1.xml")));
sorin395c2ac2014-09-16 21:31:07150
151 std::vector<GURL> urls;
152 urls.push_back(GURL(kUrl1));
153 urls.push_back(GURL(kUrl2));
sorin958b5d32016-01-09 02:00:20154 request_sender_.reset(new RequestSender(config_));
sorin1bc5eff2016-02-17 18:45:17155 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07156 base::Bind(&RequestSenderTest::RequestSenderComplete,
157 base::Unretained(this)));
158 RunThreads();
159
sorin5cabcf0b2015-06-09 00:54:44160 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
161 << post_interceptor_1_->GetRequestsAsString();
162 EXPECT_EQ(1, post_interceptor_1_->GetCount())
163 << post_interceptor_1_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07164
sorin1bc5eff2016-02-17 18:45:17165 // Sanity check the request.
sorin5cabcf0b2015-06-09 00:54:44166 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17167
168 // Check the response post conditions.
169 EXPECT_EQ(0, error_);
170 EXPECT_TRUE(base::StartsWith(response_,
171 "<?xml version='1.0' encoding='UTF-8'?>",
172 base::CompareCase::SENSITIVE));
173 EXPECT_EQ(443ul, response_.size());
sorin395c2ac2014-09-16 21:31:07174}
175
176// Tests that the request succeeds using the second url after the first url
177// has failed.
178TEST_F(RequestSenderTest, RequestSendSuccessWithFallback) {
sorin5cabcf0b2015-06-09 00:54:44179 EXPECT_TRUE(
180 post_interceptor_1_->ExpectRequest(new PartialMatch("test"), 403));
181 EXPECT_TRUE(post_interceptor_2_->ExpectRequest(new PartialMatch("test")));
sorin395c2ac2014-09-16 21:31:07182
183 std::vector<GURL> urls;
184 urls.push_back(GURL(kUrl1));
185 urls.push_back(GURL(kUrl2));
sorin958b5d32016-01-09 02:00:20186 request_sender_.reset(new RequestSender(config_));
sorin1bc5eff2016-02-17 18:45:17187 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07188 base::Bind(&RequestSenderTest::RequestSenderComplete,
189 base::Unretained(this)));
190 RunThreads();
191
sorin5cabcf0b2015-06-09 00:54:44192 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
193 << post_interceptor_1_->GetRequestsAsString();
194 EXPECT_EQ(1, post_interceptor_1_->GetCount())
195 << post_interceptor_1_->GetRequestsAsString();
196 EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
197 << post_interceptor_2_->GetRequestsAsString();
198 EXPECT_EQ(1, post_interceptor_2_->GetCount())
199 << post_interceptor_2_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07200
sorin5cabcf0b2015-06-09 00:54:44201 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
202 EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17203 EXPECT_EQ(0, error_);
sorin395c2ac2014-09-16 21:31:07204}
205
206// Tests that the request fails when both urls have failed.
207TEST_F(RequestSenderTest, RequestSendFailed) {
sorin5cabcf0b2015-06-09 00:54:44208 EXPECT_TRUE(
209 post_interceptor_1_->ExpectRequest(new PartialMatch("test"), 403));
210 EXPECT_TRUE(
211 post_interceptor_2_->ExpectRequest(new PartialMatch("test"), 403));
sorin395c2ac2014-09-16 21:31:07212
213 std::vector<GURL> urls;
214 urls.push_back(GURL(kUrl1));
215 urls.push_back(GURL(kUrl2));
sorin958b5d32016-01-09 02:00:20216 request_sender_.reset(new RequestSender(config_));
sorin1bc5eff2016-02-17 18:45:17217 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07218 base::Bind(&RequestSenderTest::RequestSenderComplete,
219 base::Unretained(this)));
220 RunThreads();
221
sorin5cabcf0b2015-06-09 00:54:44222 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
223 << post_interceptor_1_->GetRequestsAsString();
224 EXPECT_EQ(1, post_interceptor_1_->GetCount())
225 << post_interceptor_1_->GetRequestsAsString();
226 EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
227 << post_interceptor_2_->GetRequestsAsString();
228 EXPECT_EQ(1, post_interceptor_2_->GetCount())
229 << post_interceptor_2_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07230
sorin5cabcf0b2015-06-09 00:54:44231 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
232 EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17233 EXPECT_EQ(403, error_);
sorin395c2ac2014-09-16 21:31:07234}
235
sorin5cabcf0b2015-06-09 00:54:44236// Tests that the request fails when no urls are provided.
237TEST_F(RequestSenderTest, RequestSendFailedNoUrls) {
238 std::vector<GURL> urls;
sorin958b5d32016-01-09 02:00:20239 request_sender_.reset(new RequestSender(config_));
sorin1bc5eff2016-02-17 18:45:17240 request_sender_->Send(false, "test", urls,
sorin5cabcf0b2015-06-09 00:54:44241 base::Bind(&RequestSenderTest::RequestSenderComplete,
242 base::Unretained(this)));
243 RunThreads();
244
sorin1bc5eff2016-02-17 18:45:17245 EXPECT_EQ(-1, error_);
246}
247
248// Tests that a CUP request fails if the response is not signed.
249TEST_F(RequestSenderTest, RequestSendCupError) {
250 EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
251 new PartialMatch("test"), test_file("updatecheck_reply_1.xml")));
252
253 std::vector<GURL> urls;
254 urls.push_back(GURL(kUrl1));
255 request_sender_.reset(new RequestSender(config_));
256 request_sender_->Send(true, "test", urls,
257 base::Bind(&RequestSenderTest::RequestSenderComplete,
258 base::Unretained(this)));
259 RunThreads();
260
261 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
262 << post_interceptor_1_->GetRequestsAsString();
263 EXPECT_EQ(1, post_interceptor_1_->GetCount())
264 << post_interceptor_1_->GetRequestsAsString();
265
266 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
267 EXPECT_EQ(RequestSender::kErrorResponseNotTrusted, error_);
268 EXPECT_TRUE(response_.empty());
sorin5cabcf0b2015-06-09 00:54:44269}
270
sorin52ac0882015-01-24 01:15:00271} // namespace update_client