update_checker_unittest.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// 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
5#include "base/bind.h"
6#include "base/bind_helpers.h"
7#include "base/compiler_specific.h"
8#include "base/files/file_util.h"
9#include "base/macros.h"
10#include "base/memory/ref_counted.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/message_loop/message_loop.h"
13#include "base/path_service.h"
14#include "base/run_loop.h"
15#include "base/version.h"
16#include "components/component_updater/crx_update_item.h"
17#include "components/component_updater/test/test_configurator.h"
18#include "components/component_updater/test/url_request_post_interceptor.h"
19#include "components/component_updater/update_checker.h"
20#include "net/url_request/url_fetcher.h"
21#include "net/url_request/url_request_test_util.h"
22#include "testing/gtest/include/gtest/gtest.h"
23#include "url/gurl.h"
24
25namespace component_updater {
26
27namespace {
28
29base::FilePath test_file(const char* file) {
30  base::FilePath path;
31  PathService::Get(base::DIR_SOURCE_ROOT, &path);
32  return path.AppendASCII("components").AppendASCII("test").AppendASCII("data")
33      .AppendASCII("component_updater").AppendASCII(file);
34}
35
36}  // namespace
37
38class UpdateCheckerTest : public testing::Test {
39 public:
40  UpdateCheckerTest();
41  virtual ~UpdateCheckerTest();
42
43  // Overrides from testing::Test.
44  virtual void SetUp() OVERRIDE;
45  virtual void TearDown() OVERRIDE;
46
47  void UpdateCheckComplete(const GURL& original_url,
48                           int error,
49                           const std::string& error_message,
50                           const UpdateResponse::Results& results);
51
52 protected:
53  void Quit();
54  void RunThreads();
55  void RunThreadsUntilIdle();
56
57  CrxUpdateItem BuildCrxUpdateItem();
58
59  scoped_ptr<TestConfigurator> config_;
60
61  scoped_ptr<UpdateChecker> update_checker_;
62
63  scoped_ptr<InterceptorFactory> interceptor_factory_;
64  URLRequestPostInterceptor* post_interceptor_;  // Owned by the factory.
65
66  GURL original_url_;
67  int error_;
68  std::string error_message_;
69  UpdateResponse::Results results_;
70
71 private:
72  base::MessageLoopForIO loop_;
73  base::Closure quit_closure_;
74
75  DISALLOW_COPY_AND_ASSIGN(UpdateCheckerTest);
76};
77
78UpdateCheckerTest::UpdateCheckerTest() : post_interceptor_(NULL), error_(0) {
79  net::URLFetcher::SetEnableInterceptionForTests(true);
80}
81
82UpdateCheckerTest::~UpdateCheckerTest() {
83  net::URLFetcher::SetEnableInterceptionForTests(false);
84}
85
86void UpdateCheckerTest::SetUp() {
87  config_.reset(new TestConfigurator(base::MessageLoopProxy::current(),
88                                     base::MessageLoopProxy::current()));
89  interceptor_factory_.reset(
90      new InterceptorFactory(base::MessageLoopProxy::current()));
91  post_interceptor_ = interceptor_factory_->CreateInterceptor();
92  EXPECT_TRUE(post_interceptor_);
93
94  update_checker_.reset();
95
96  error_ = 0;
97  error_message_.clear();
98  results_ = UpdateResponse::Results();
99}
100
101void UpdateCheckerTest::TearDown() {
102  update_checker_.reset();
103
104  post_interceptor_ = NULL;
105  interceptor_factory_.reset();
106
107  config_.reset();
108
109  // The PostInterceptor requires the message loop to run to destruct correctly.
110  // TODO(sorin): This is fragile and should be fixed.
111  RunThreadsUntilIdle();
112}
113
114void UpdateCheckerTest::RunThreads() {
115  base::RunLoop runloop;
116  quit_closure_ = runloop.QuitClosure();
117  runloop.Run();
118
119  // Since some tests need to drain currently enqueued tasks such as network
120  // intercepts on the IO thread, run the threads until they are
121  // idle. The component updater service won't loop again until the loop count
122  // is set and the service is started.
123  RunThreadsUntilIdle();
124}
125
126void UpdateCheckerTest::RunThreadsUntilIdle() {
127  base::RunLoop().RunUntilIdle();
128}
129
130void UpdateCheckerTest::Quit() {
131  if (!quit_closure_.is_null())
132    quit_closure_.Run();
133}
134
135void UpdateCheckerTest::UpdateCheckComplete(
136    const GURL& original_url,
137    int error,
138    const std::string& error_message,
139    const UpdateResponse::Results& results) {
140  original_url_ = original_url;
141  error_ = error;
142  error_message_ = error_message;
143  results_ = results;
144  Quit();
145}
146
147CrxUpdateItem UpdateCheckerTest::BuildCrxUpdateItem() {
148  CrxComponent crx_component;
149  crx_component.name = "test_jebg";
150  crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
151  crx_component.installer = NULL;
152  crx_component.version = base::Version("0.9");
153  crx_component.fingerprint = "fp1";
154
155  CrxUpdateItem crx_update_item;
156  crx_update_item.status = CrxUpdateItem::kNew;
157  crx_update_item.id = "jebgalgnebhfojomionfpkfelancnnkf";
158  crx_update_item.component = crx_component;
159
160  return crx_update_item;
161}
162
163TEST_F(UpdateCheckerTest, UpdateCheckSuccess) {
164  EXPECT_TRUE(post_interceptor_->ExpectRequest(
165      new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
166
167  update_checker_ = UpdateChecker::Create(*config_).Pass();
168
169  CrxUpdateItem item(BuildCrxUpdateItem());
170  std::vector<CrxUpdateItem*> items_to_check;
171  items_to_check.push_back(&item);
172
173  update_checker_->CheckForUpdates(
174      items_to_check,
175      "extra=\"params\"",
176      base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
177                 base::Unretained(this)));
178
179  RunThreads();
180
181  EXPECT_EQ(1, post_interceptor_->GetHitCount())
182      << post_interceptor_->GetRequestsAsString();
183  EXPECT_EQ(1, post_interceptor_->GetCount())
184      << post_interceptor_->GetRequestsAsString();
185
186  // Sanity check the request.
187  EXPECT_NE(
188      string::npos,
189      post_interceptor_->GetRequests()[0].find(
190          "request protocol=\"3.0\" extra=\"params\""));
191  EXPECT_NE(
192      string::npos,
193      post_interceptor_->GetRequests()[0].find(
194          "app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">"
195          "<updatecheck /><packages><package fp=\"fp1\"/></packages></app>"));
196
197  EXPECT_NE(string::npos,
198            post_interceptor_->GetRequests()[0].find("<hw physmemory="));
199
200  // Sanity check the arguments of the callback after parsing.
201  EXPECT_EQ(config_->UpdateUrl().front(), original_url_);
202  EXPECT_EQ(0, error_);
203  EXPECT_TRUE(error_message_.empty());
204  EXPECT_EQ(1ul, results_.list.size());
205  EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf",
206               results_.list[0].extension_id.c_str());
207  EXPECT_STREQ("1.0", results_.list[0].manifest.version.c_str());
208}
209
210// Simulates a 403 server response error.
211TEST_F(UpdateCheckerTest, UpdateCheckError) {
212  EXPECT_TRUE(
213      post_interceptor_->ExpectRequest(new PartialMatch("updatecheck"), 403));
214
215  update_checker_ = UpdateChecker::Create(*config_).Pass();
216
217  CrxUpdateItem item(BuildCrxUpdateItem());
218  std::vector<CrxUpdateItem*> items_to_check;
219  items_to_check.push_back(&item);
220
221  update_checker_->CheckForUpdates(
222      items_to_check,
223      "",
224      base::Bind(&UpdateCheckerTest::UpdateCheckComplete,
225                 base::Unretained(this)));
226
227  RunThreads();
228
229  EXPECT_EQ(1, post_interceptor_->GetHitCount())
230      << post_interceptor_->GetRequestsAsString();
231  EXPECT_EQ(1, post_interceptor_->GetCount())
232      << post_interceptor_->GetRequestsAsString();
233
234  EXPECT_EQ(config_->UpdateUrl().front(), original_url_);
235  EXPECT_EQ(403, error_);
236  EXPECT_STREQ("network error", error_message_.c_str());
237  EXPECT_EQ(0ul, results_.list.size());
238}
239
240}  // namespace component_updater
241