blob: 7d5debbc74dada115ae5ca17b89d802f82008285 [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
Sebastien Marchand53801a32019-01-25 16:26:1110#include "base/bind.h"
sorin5cb1f5492014-09-23 04:07:4411#include "base/macros.h"
sorin9797aba2015-04-17 17:15:0312#include "base/memory/ref_counted.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"
Francois Dorayff8a6452017-07-27 17:11:5816#include "base/test/scoped_task_environment.h"
gab7966d312016-05-11 20:35:0117#include "base/threading/thread_task_runner_handle.h"
Sorin Jianu86ee558e2019-02-18 17:01:5018#include "components/update_client/net/url_loader_post_interceptor.h"
sorinb120440b2015-04-27 16:34:1519#include "components/update_client/test_configurator.h"
sorin395c2ac2014-09-16 21:31:0720#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";
sorin395c2ac2014-09-16 21:31:0728
sorin1bc5eff2016-02-17 18:45:1729// TODO(sorin): refactor as a utility function for unit tests.
30base::FilePath test_file(const char* file) {
31 base::FilePath path;
Avi Drissmanf617d012018-05-02 18:48:5332 base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
sorin1bc5eff2016-02-17 18:45:1733 return path.AppendASCII("components")
34 .AppendASCII("test")
35 .AppendASCII("data")
36 .AppendASCII("update_client")
37 .AppendASCII(file);
38}
39
sorin395c2ac2014-09-16 21:31:0740} // namespace
41
Sorin Jianud907dbf62018-02-21 17:18:2942class RequestSenderTest : public testing::Test,
43 public ::testing::WithParamInterface<bool> {
sorin395c2ac2014-09-16 21:31:0744 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();
Francois Dorayff8a6452017-07-27 17:11:5859
60 base::test::ScopedTaskEnvironment scoped_task_environment_;
sorin395c2ac2014-09-16 21:31:0761
sorin9797aba2015-04-17 17:15:0362 scoped_refptr<TestConfigurator> config_;
dchengd0fc6aa92016-04-22 18:03:1263 std::unique_ptr<RequestSender> request_sender_;
sorin395c2ac2014-09-16 21:31:0764
Antonio Gomesb6162502018-06-28 20:21:5565 std::unique_ptr<URLLoaderPostInterceptor> post_interceptor_;
sorin395c2ac2014-09-16 21:31:0766
sorin519656c2017-04-28 22:39:3467 int error_ = 0;
sorin1bc5eff2016-02-17 18:45:1768 std::string response_;
sorin395c2ac2014-09-16 21:31:0769
70 private:
Sorin Jianua8ef73d2017-11-02 16:55:1771 base::OnceClosure quit_closure_;
sorin395c2ac2014-09-16 21:31:0772
73 DISALLOW_COPY_AND_ASSIGN(RequestSenderTest);
74};
75
Victor Costan1559fac2019-02-13 13:29:5076INSTANTIATE_TEST_SUITE_P(IsForeground, RequestSenderTest, ::testing::Bool());
Sorin Jianud907dbf62018-02-21 17:18:2977
Francois Dorayff8a6452017-07-27 17:11:5878RequestSenderTest::RequestSenderTest()
79 : scoped_task_environment_(
80 base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
sorin395c2ac2014-09-16 21:31:0781
sorin1bc5eff2016-02-17 18:45:1782RequestSenderTest::~RequestSenderTest() {}
sorin395c2ac2014-09-16 21:31:0783
84void RequestSenderTest::SetUp() {
Sorin Jianucc048f892017-07-26 02:05:5485 config_ = base::MakeRefCounted<TestConfigurator>();
Sorin Jianu015681f2018-04-04 16:43:3386 request_sender_ = std::make_unique<RequestSender>(config_);
87
Antonio Gomesb6162502018-06-28 20:21:5588 std::vector<GURL> urls;
89 urls.push_back(GURL(kUrl1));
90 urls.push_back(GURL(kUrl2));
91
92 post_interceptor_ = std::make_unique<URLLoaderPostInterceptor>(
93 urls, config_->test_url_loader_factory());
94 EXPECT_TRUE(post_interceptor_);
sorin395c2ac2014-09-16 21:31:0795}
96
97void RequestSenderTest::TearDown() {
sorin519656c2017-04-28 22:39:3498 request_sender_ = nullptr;
sorin395c2ac2014-09-16 21:31:0799
Antonio Gomesb6162502018-06-28 20:21:55100 post_interceptor_.reset();
sorin395c2ac2014-09-16 21:31:07101
Sorin Jianuf805c222017-09-20 22:36:21102 // Run the threads until they are idle to allow the clean up
103 // of the network interceptors on the IO thread.
104 scoped_task_environment_.RunUntilIdle();
sorin9797aba2015-04-17 17:15:03105 config_ = nullptr;
sorin395c2ac2014-09-16 21:31:07106}
107
108void RequestSenderTest::RunThreads() {
109 base::RunLoop runloop;
110 quit_closure_ = runloop.QuitClosure();
111 runloop.Run();
sorin395c2ac2014-09-16 21:31:07112}
113
114void RequestSenderTest::Quit() {
115 if (!quit_closure_.is_null())
Sorin Jianua8ef73d2017-11-02 16:55:17116 std::move(quit_closure_).Run();
sorin395c2ac2014-09-16 21:31:07117}
118
sorin1bc5eff2016-02-17 18:45:17119void RequestSenderTest::RequestSenderComplete(int error,
sorinfccbf2d2016-04-04 20:34:34120 const std::string& response,
121 int retry_after_sec) {
sorin1bc5eff2016-02-17 18:45:17122 error_ = error;
123 response_ = response;
124
sorin395c2ac2014-09-16 21:31:07125 Quit();
126}
127
128// Tests that when a request to the first url succeeds, the subsequent urls are
129// not tried.
Sorin Jianud907dbf62018-02-21 17:18:29130TEST_P(RequestSenderTest, RequestSendSuccess) {
Sorin Jianu015681f2018-04-04 16:43:33131 EXPECT_TRUE(
Antonio Gomesb6162502018-06-28 20:21:55132 post_interceptor_->ExpectRequest(std::make_unique<PartialMatch>("test"),
133 test_file("updatecheck_reply_1.xml")));
sorin395c2ac2014-09-16 21:31:07134
Sorin Jianud907dbf62018-02-21 17:18:29135 const bool is_foreground = GetParam();
Sorin Jianua8ef73d2017-11-02 16:55:17136 request_sender_->Send(
Sorin Jianu015681f2018-04-04 16:43:33137 {GURL(kUrl1), GURL(kUrl2)},
138 {{"X-Goog-Update-Interactivity", is_foreground ? "fg" : "bg"}}, "test",
139 false,
Sorin Jianua8ef73d2017-11-02 16:55:17140 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
141 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07142 RunThreads();
143
Antonio Gomesb6162502018-06-28 20:21:55144 EXPECT_EQ(1, post_interceptor_->GetHitCount())
145 << post_interceptor_->GetRequestsAsString();
146 EXPECT_EQ(1, post_interceptor_->GetCount())
147 << post_interceptor_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07148
Antonio Gomesb6162502018-06-28 20:21:55149 EXPECT_EQ(0, post_interceptor_->GetHitCountForURL(GURL(kUrl2)))
150 << post_interceptor_->GetRequestsAsString();
sorin30474f02017-04-27 00:45:48151
sorin1bc5eff2016-02-17 18:45:17152 // Sanity check the request.
Antonio Gomesb6162502018-06-28 20:21:55153 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(0).c_str());
sorin1bc5eff2016-02-17 18:45:17154
155 // Check the response post conditions.
156 EXPECT_EQ(0, error_);
157 EXPECT_TRUE(base::StartsWith(response_,
158 "<?xml version='1.0' encoding='UTF-8'?>",
159 base::CompareCase::SENSITIVE));
sorin519656c2017-04-28 22:39:34160 EXPECT_EQ(505ul, response_.size());
Sorin Jianuf805c222017-09-20 22:36:21161
Sorin Jianud907dbf62018-02-21 17:18:29162 // Check the interactivity header value.
163 const auto extra_request_headers =
Antonio Gomesb6162502018-06-28 20:21:55164 std::get<1>(post_interceptor_->GetRequests()[0]);
Sorin Jianu1ab71d12018-03-12 18:11:39165 EXPECT_TRUE(extra_request_headers.HasHeader("X-Goog-Update-Interactivity"));
Sorin Jianud907dbf62018-02-21 17:18:29166 std::string header;
Sorin Jianu1ab71d12018-03-12 18:11:39167 extra_request_headers.GetHeader("X-Goog-Update-Interactivity", &header);
Sorin Jianud907dbf62018-02-21 17:18:29168 EXPECT_STREQ(is_foreground ? "fg" : "bg", header.c_str());
sorin395c2ac2014-09-16 21:31:07169}
170
171// Tests that the request succeeds using the second url after the first url
172// has failed.
173TEST_F(RequestSenderTest, RequestSendSuccessWithFallback) {
Antonio Gomesb6162502018-06-28 20:21:55174 EXPECT_TRUE(post_interceptor_->ExpectRequest(
175 std::make_unique<PartialMatch>("test"), net::HTTP_FORBIDDEN));
176 EXPECT_TRUE(
177 post_interceptor_->ExpectRequest(std::make_unique<PartialMatch>("test")));
sorin395c2ac2014-09-16 21:31:07178
Sorin Jianua8ef73d2017-11-02 16:55:17179 request_sender_->Send(
Sorin Jianu015681f2018-04-04 16:43:33180 {GURL(kUrl1), GURL(kUrl2)}, {}, "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17181 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
182 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07183 RunThreads();
184
Antonio Gomesb6162502018-06-28 20:21:55185 EXPECT_EQ(2, post_interceptor_->GetHitCount())
186 << post_interceptor_->GetRequestsAsString();
187 EXPECT_EQ(2, post_interceptor_->GetCount())
188 << post_interceptor_->GetRequestsAsString();
189 EXPECT_EQ(1, post_interceptor_->GetHitCountForURL(GURL(kUrl1)))
190 << post_interceptor_->GetRequestsAsString();
191 EXPECT_EQ(1, post_interceptor_->GetHitCountForURL(GURL(kUrl2)))
192 << post_interceptor_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07193
Antonio Gomesb6162502018-06-28 20:21:55194 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(0).c_str());
195 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(1).c_str());
sorin1bc5eff2016-02-17 18:45:17196 EXPECT_EQ(0, error_);
sorin395c2ac2014-09-16 21:31:07197}
198
199// Tests that the request fails when both urls have failed.
200TEST_F(RequestSenderTest, RequestSendFailed) {
Antonio Gomesb6162502018-06-28 20:21:55201 EXPECT_TRUE(post_interceptor_->ExpectRequest(
202 std::make_unique<PartialMatch>("test"), net::HTTP_FORBIDDEN));
203 EXPECT_TRUE(post_interceptor_->ExpectRequest(
204 std::make_unique<PartialMatch>("test"), net::HTTP_FORBIDDEN));
sorin395c2ac2014-09-16 21:31:07205
sorin519656c2017-04-28 22:39:34206 const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
Jinho Bangda4e4282018-01-03 13:21:23207 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17208 request_sender_->Send(
Sorin Jianua64a1e52018-02-28 16:53:34209 urls, {}, "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17210 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
211 base::Unretained(this)));
sorin395c2ac2014-09-16 21:31:07212 RunThreads();
213
Antonio Gomesb6162502018-06-28 20:21:55214 EXPECT_EQ(2, post_interceptor_->GetHitCount())
215 << post_interceptor_->GetRequestsAsString();
216 EXPECT_EQ(2, post_interceptor_->GetCount())
217 << post_interceptor_->GetRequestsAsString();
218 EXPECT_EQ(1, post_interceptor_->GetHitCountForURL(GURL(kUrl1)))
219 << post_interceptor_->GetRequestsAsString();
220 EXPECT_EQ(1, post_interceptor_->GetHitCountForURL(GURL(kUrl2)))
221 << post_interceptor_->GetRequestsAsString();
sorin395c2ac2014-09-16 21:31:07222
Antonio Gomesb6162502018-06-28 20:21:55223 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(0).c_str());
224 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(1).c_str());
sorin1bc5eff2016-02-17 18:45:17225 EXPECT_EQ(403, error_);
sorin395c2ac2014-09-16 21:31:07226}
227
sorin5cabcf0b2015-06-09 00:54:44228// Tests that the request fails when no urls are provided.
229TEST_F(RequestSenderTest, RequestSendFailedNoUrls) {
230 std::vector<GURL> urls;
Jinho Bangda4e4282018-01-03 13:21:23231 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17232 request_sender_->Send(
Sorin Jianuc303bf42018-09-07 16:19:33233 urls, {}, "test", false,
Sorin Jianua8ef73d2017-11-02 16:55:17234 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
235 base::Unretained(this)));
sorin5cabcf0b2015-06-09 00:54:44236 RunThreads();
237
Sorin Jianu888ec292018-06-01 15:35:42238 EXPECT_EQ(-10002, error_);
sorin1bc5eff2016-02-17 18:45:17239}
240
241// Tests that a CUP request fails if the response is not signed.
242TEST_F(RequestSenderTest, RequestSendCupError) {
Sorin Jianu015681f2018-04-04 16:43:33243 EXPECT_TRUE(
Antonio Gomesb6162502018-06-28 20:21:55244 post_interceptor_->ExpectRequest(std::make_unique<PartialMatch>("test"),
245 test_file("updatecheck_reply_1.xml")));
sorin1bc5eff2016-02-17 18:45:17246
sorin519656c2017-04-28 22:39:34247 const std::vector<GURL> urls = {GURL(kUrl1)};
Jinho Bangda4e4282018-01-03 13:21:23248 request_sender_ = std::make_unique<RequestSender>(config_);
Sorin Jianua8ef73d2017-11-02 16:55:17249 request_sender_->Send(
Sorin Jianua64a1e52018-02-28 16:53:34250 urls, {}, "test", true,
Sorin Jianua8ef73d2017-11-02 16:55:17251 base::BindOnce(&RequestSenderTest::RequestSenderComplete,
252 base::Unretained(this)));
sorin1bc5eff2016-02-17 18:45:17253 RunThreads();
254
Antonio Gomesb6162502018-06-28 20:21:55255 EXPECT_EQ(1, post_interceptor_->GetHitCount())
256 << post_interceptor_->GetRequestsAsString();
257 EXPECT_EQ(1, post_interceptor_->GetCount())
258 << post_interceptor_->GetRequestsAsString();
sorin1bc5eff2016-02-17 18:45:17259
Antonio Gomesb6162502018-06-28 20:21:55260 EXPECT_STREQ("test", post_interceptor_->GetRequestBody(0).c_str());
Sorin Jianu888ec292018-06-01 15:35:42261 EXPECT_EQ(-10000, error_);
sorin1bc5eff2016-02-17 18:45:17262 EXPECT_TRUE(response_.empty());
sorin5cabcf0b2015-06-09 00:54:44263}
264
sorin52ac0882015-01-24 01:15:00265} // namespace update_client