blob: a7c5550217d3c4825ba01b4794c901abd51235d8 [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"
sorin395c2ac2014-09-16 21:31:0711#include "base/run_loop.h"
sorin1bc5eff2016-02-17 18:45:1712#include "base/strings/string_util.h"
skyostilb0daa012015-06-02 19:03:4813#include "base/thread_task_runner_handle.h"
sorinb120440b2015-04-27 16:34:1514#include "components/update_client/test_configurator.h"
15#include "components/update_client/url_request_post_interceptor.h"
sorin395c2ac2014-09-16 21:31:0716#include "net/url_request/url_fetcher.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
sorin52ac0882015-01-24 01:15:0019namespace update_client {
sorin395c2ac2014-09-16 21:31:0720
21namespace {
22
23const char kUrl1[] = "https://localhost2/path1";
24const char kUrl2[] = "https://localhost2/path2";
25const char kUrlPath1[] = "path1";
26const char kUrlPath2[] = "path2";
27
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;
31 PathService::Get(base::DIR_SOURCE_ROOT, &path);
32 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
41class RequestSenderTest : public testing::Test {
42 public:
43 RequestSenderTest();
dcheng30a1b1542014-10-29 21:27:5044 ~RequestSenderTest() override;
sorin395c2ac2014-09-16 21:31:0745
46 // Overrides from testing::Test.
dcheng30a1b1542014-10-29 21:27:5047 void SetUp() override;
48 void TearDown() override;
sorin395c2ac2014-09-16 21:31:0749
sorinfccbf2d2016-04-04 20:34:3450 void RequestSenderComplete(int error,
51 const std::string& response,
52 int retry_after_sec);
sorin395c2ac2014-09-16 21:31:0753
54 protected:
55 void Quit();
56 void RunThreads();
57 void RunThreadsUntilIdle();
58
sorin9797aba2015-04-17 17:15:0359 scoped_refptr<TestConfigurator> config_;
dchengd0fc6aa92016-04-22 18:03:1260 std::unique_ptr<RequestSender> request_sender_;
61 std::unique_ptr<InterceptorFactory> interceptor_factory_;
sorin395c2ac2014-09-16 21:31:0762
sorin5cabcf0b2015-06-09 00:54:4463 URLRequestPostInterceptor* post_interceptor_1_; // Owned by the factory.
64 URLRequestPostInterceptor* post_interceptor_2_; // Owned by the factory.
sorin395c2ac2014-09-16 21:31:0765
sorin1bc5eff2016-02-17 18:45:1766 int error_;
67 std::string response_;
sorin395c2ac2014-09-16 21:31:0768
69 private:
70 base::MessageLoopForIO loop_;
71 base::Closure quit_closure_;
72
73 DISALLOW_COPY_AND_ASSIGN(RequestSenderTest);
74};
75
76RequestSenderTest::RequestSenderTest()
sorin1bc5eff2016-02-17 18:45:1777 : post_interceptor_1_(nullptr), post_interceptor_2_(nullptr), error_(0) {}
sorin395c2ac2014-09-16 21:31:0778
sorin1bc5eff2016-02-17 18:45:1779RequestSenderTest::~RequestSenderTest() {}
sorin395c2ac2014-09-16 21:31:0780
81void RequestSenderTest::SetUp() {
skyostilb0daa012015-06-02 19:03:4882 config_ = new TestConfigurator(base::ThreadTaskRunnerHandle::Get(),
83 base::ThreadTaskRunnerHandle::Get());
sorin395c2ac2014-09-16 21:31:0784 interceptor_factory_.reset(
skyostilb0daa012015-06-02 19:03:4885 new InterceptorFactory(base::ThreadTaskRunnerHandle::Get()));
sorin5cabcf0b2015-06-09 00:54:4486 post_interceptor_1_ =
sorin395c2ac2014-09-16 21:31:0787 interceptor_factory_->CreateInterceptorForPath(kUrlPath1);
sorin5cabcf0b2015-06-09 00:54:4488 post_interceptor_2_ =
sorin395c2ac2014-09-16 21:31:0789 interceptor_factory_->CreateInterceptorForPath(kUrlPath2);
sorin5cabcf0b2015-06-09 00:54:4490 EXPECT_TRUE(post_interceptor_1_);
91 EXPECT_TRUE(post_interceptor_2_);
sorin395c2ac2014-09-16 21:31:0792
93 request_sender_.reset();
94}
95
96void RequestSenderTest::TearDown() {
97 request_sender_.reset();
98
sorin5cabcf0b2015-06-09 00:54:4499 post_interceptor_1_ = nullptr;
100 post_interceptor_2_ = nullptr;
sorin395c2ac2014-09-16 21:31:07101
102 interceptor_factory_.reset();
103
sorin9797aba2015-04-17 17:15:03104 config_ = nullptr;
sorin395c2ac2014-09-16 21:31:07105
106 RunThreadsUntilIdle();
107}
108
109void RequestSenderTest::RunThreads() {
110 base::RunLoop runloop;
111 quit_closure_ = runloop.QuitClosure();
112 runloop.Run();
113
114 // Since some tests need to drain currently enqueued tasks such as network
115 // intercepts on the IO thread, run the threads until they are
116 // idle. The component updater service won't loop again until the loop count
117 // is set and the service is started.
118 RunThreadsUntilIdle();
119}
120
121void RequestSenderTest::RunThreadsUntilIdle() {
122 base::RunLoop().RunUntilIdle();
123}
124
125void RequestSenderTest::Quit() {
126 if (!quit_closure_.is_null())
127 quit_closure_.Run();
128}
129
sorin1bc5eff2016-02-17 18:45:17130void RequestSenderTest::RequestSenderComplete(int error,
sorinfccbf2d2016-04-04 20:34:34131 const std::string& response,
132 int retry_after_sec) {
sorin1bc5eff2016-02-17 18:45:17133 error_ = error;
134 response_ = response;
135
sorin395c2ac2014-09-16 21:31:07136 Quit();
137}
138
139// Tests that when a request to the first url succeeds, the subsequent urls are
140// not tried.
141TEST_F(RequestSenderTest, RequestSendSuccess) {
sorin1bc5eff2016-02-17 18:45:17142 EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
143 new PartialMatch("test"), test_file("updatecheck_reply_1.xml")));
sorin395c2ac2014-09-16 21:31:07144
145 std::vector<GURL> urls;
146 urls.push_back(GURL(kUrl1));
147 urls.push_back(GURL(kUrl2));
sorin958b5d32016-01-09 02:00:20148 request_sender_.reset(new RequestSender(config_));
sorin1bc5eff2016-02-17 18:45:17149 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07150 base::Bind(&RequestSenderTest::RequestSenderComplete,
151 base::Unretained(this)));
152 RunThreads();
153
sorin5cabcf0b2015-06-09 00:54:44154 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
155 << post_interceptor_1_->GetRequestsAsString();
156 EXPECT_EQ(1, post_interceptor_1_->GetCount())
157 << post_interceptor_1_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07158
sorin1bc5eff2016-02-17 18:45:17159 // Sanity check the request.
sorin5cabcf0b2015-06-09 00:54:44160 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17161
162 // Check the response post conditions.
163 EXPECT_EQ(0, error_);
164 EXPECT_TRUE(base::StartsWith(response_,
165 "<?xml version='1.0' encoding='UTF-8'?>",
166 base::CompareCase::SENSITIVE));
167 EXPECT_EQ(443ul, response_.size());
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) {
sorin5cabcf0b2015-06-09 00:54:44173 EXPECT_TRUE(
174 post_interceptor_1_->ExpectRequest(new PartialMatch("test"), 403));
175 EXPECT_TRUE(post_interceptor_2_->ExpectRequest(new PartialMatch("test")));
sorin395c2ac2014-09-16 21:31:07176
177 std::vector<GURL> urls;
178 urls.push_back(GURL(kUrl1));
179 urls.push_back(GURL(kUrl2));
sorin958b5d32016-01-09 02:00:20180 request_sender_.reset(new RequestSender(config_));
sorin1bc5eff2016-02-17 18:45:17181 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07182 base::Bind(&RequestSenderTest::RequestSenderComplete,
183 base::Unretained(this)));
184 RunThreads();
185
sorin5cabcf0b2015-06-09 00:54:44186 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
187 << post_interceptor_1_->GetRequestsAsString();
188 EXPECT_EQ(1, post_interceptor_1_->GetCount())
189 << post_interceptor_1_->GetRequestsAsString();
190 EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
191 << post_interceptor_2_->GetRequestsAsString();
192 EXPECT_EQ(1, post_interceptor_2_->GetCount())
193 << post_interceptor_2_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07194
sorin5cabcf0b2015-06-09 00:54:44195 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
196 EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17197 EXPECT_EQ(0, error_);
sorin395c2ac2014-09-16 21:31:07198}
199
200// Tests that the request fails when both urls have failed.
201TEST_F(RequestSenderTest, RequestSendFailed) {
sorin5cabcf0b2015-06-09 00:54:44202 EXPECT_TRUE(
203 post_interceptor_1_->ExpectRequest(new PartialMatch("test"), 403));
204 EXPECT_TRUE(
205 post_interceptor_2_->ExpectRequest(new PartialMatch("test"), 403));
sorin395c2ac2014-09-16 21:31:07206
207 std::vector<GURL> urls;
208 urls.push_back(GURL(kUrl1));
209 urls.push_back(GURL(kUrl2));
sorin958b5d32016-01-09 02:00:20210 request_sender_.reset(new RequestSender(config_));
sorin1bc5eff2016-02-17 18:45:17211 request_sender_->Send(false, "test", urls,
sorin395c2ac2014-09-16 21:31:07212 base::Bind(&RequestSenderTest::RequestSenderComplete,
213 base::Unretained(this)));
214 RunThreads();
215
sorin5cabcf0b2015-06-09 00:54:44216 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
217 << post_interceptor_1_->GetRequestsAsString();
218 EXPECT_EQ(1, post_interceptor_1_->GetCount())
219 << post_interceptor_1_->GetRequestsAsString();
220 EXPECT_EQ(1, post_interceptor_2_->GetHitCount())
221 << post_interceptor_2_->GetRequestsAsString();
222 EXPECT_EQ(1, post_interceptor_2_->GetCount())
223 << post_interceptor_2_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07224
sorin5cabcf0b2015-06-09 00:54:44225 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
226 EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
sorin1bc5eff2016-02-17 18:45:17227 EXPECT_EQ(403, error_);
sorin395c2ac2014-09-16 21:31:07228}
229
sorin5cabcf0b2015-06-09 00:54:44230// Tests that the request fails when no urls are provided.
231TEST_F(RequestSenderTest, RequestSendFailedNoUrls) {
232 std::vector<GURL> urls;
sorin958b5d32016-01-09 02:00:20233 request_sender_.reset(new RequestSender(config_));
sorin1bc5eff2016-02-17 18:45:17234 request_sender_->Send(false, "test", urls,
sorin5cabcf0b2015-06-09 00:54:44235 base::Bind(&RequestSenderTest::RequestSenderComplete,
236 base::Unretained(this)));
237 RunThreads();
238
sorin1bc5eff2016-02-17 18:45:17239 EXPECT_EQ(-1, error_);
240}
241
242// Tests that a CUP request fails if the response is not signed.
243TEST_F(RequestSenderTest, RequestSendCupError) {
244 EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
245 new PartialMatch("test"), test_file("updatecheck_reply_1.xml")));
246
247 std::vector<GURL> urls;
248 urls.push_back(GURL(kUrl1));
249 request_sender_.reset(new RequestSender(config_));
250 request_sender_->Send(true, "test", urls,
251 base::Bind(&RequestSenderTest::RequestSenderComplete,
252 base::Unretained(this)));
253 RunThreads();
254
255 EXPECT_EQ(1, post_interceptor_1_->GetHitCount())
256 << post_interceptor_1_->GetRequestsAsString();
257 EXPECT_EQ(1, post_interceptor_1_->GetCount())
258 << post_interceptor_1_->GetRequestsAsString();
259
260 EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
261 EXPECT_EQ(RequestSender::kErrorResponseNotTrusted, error_);
262 EXPECT_TRUE(response_.empty());
sorin5cabcf0b2015-06-09 00:54:44263}
264
sorin52ac0882015-01-24 01:15:00265} // namespace update_client