OLD | NEW |
| (Empty) |
1 // Copyright 2015 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/files/file_path.h" | |
8 #include "base/files/file_util.h" | |
9 #include "base/location.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/thread_task_runner_handle.h" | |
16 #include "base/values.h" | |
17 #include "base/version.h" | |
18 #include "components/update_client/crx_update_item.h" | |
19 #include "components/update_client/ping_manager.h" | |
20 #include "components/update_client/test/test_configurator.h" | |
21 #include "components/update_client/test/test_installer.h" | |
22 #include "components/update_client/update_checker.h" | |
23 #include "components/update_client/update_client_internal.h" | |
24 #include "content/public/browser/browser_thread.h" | |
25 #include "content/public/test/test_browser_thread_bundle.h" | |
26 #include "testing/gmock/include/gmock/gmock.h" | |
27 #include "testing/gtest/include/gtest/gtest.h" | |
28 #include "url/gurl.h" | |
29 | |
30 namespace update_client { | |
31 | |
32 namespace { | |
33 | |
34 using base::FilePath; | |
35 | |
36 // Makes a copy of the file specified by |from_path| in a temporary directory | |
37 // and returns the path of the copy. Returns true if successful. Cleans up if | |
38 // there was an error creating the copy. | |
39 bool MakeTestFile(const FilePath& from_path, FilePath* to_path) { | |
40 FilePath temp_dir; | |
41 bool result = | |
42 CreateNewTempDirectory(FILE_PATH_LITERAL("update_client"), &temp_dir); | |
43 if (!result) | |
44 return false; | |
45 | |
46 FilePath temp_file; | |
47 result = CreateTemporaryFileInDir(temp_dir, &temp_file); | |
48 if (!result) | |
49 return false; | |
50 | |
51 result = CopyFile(from_path, temp_file); | |
52 if (!result) { | |
53 DeleteFile(temp_file, false); | |
54 return false; | |
55 } | |
56 | |
57 *to_path = temp_file; | |
58 return true; | |
59 } | |
60 | |
61 using Events = UpdateClient::Observer::Events; | |
62 | |
63 class MockObserver : public UpdateClient::Observer { | |
64 public: | |
65 MOCK_METHOD2(OnEvent, void(Events event, const std::string&)); | |
66 }; | |
67 | |
68 class FakePingManagerImpl : public PingManager { | |
69 public: | |
70 explicit FakePingManagerImpl(const Configurator& config); | |
71 ~FakePingManagerImpl() override; | |
72 | |
73 void OnUpdateComplete(const CrxUpdateItem* item) override; | |
74 | |
75 const std::vector<CrxUpdateItem>& items() const; | |
76 | |
77 private: | |
78 std::vector<CrxUpdateItem> items_; | |
79 DISALLOW_COPY_AND_ASSIGN(FakePingManagerImpl); | |
80 }; | |
81 | |
82 FakePingManagerImpl::FakePingManagerImpl(const Configurator& config) | |
83 : PingManager(config) { | |
84 } | |
85 | |
86 FakePingManagerImpl::~FakePingManagerImpl() { | |
87 } | |
88 | |
89 void FakePingManagerImpl::OnUpdateComplete(const CrxUpdateItem* item) { | |
90 items_.push_back(*item); | |
91 } | |
92 | |
93 const std::vector<CrxUpdateItem>& FakePingManagerImpl::items() const { | |
94 return items_; | |
95 } | |
96 | |
97 } // namespace | |
98 | |
99 using ::testing::_; | |
100 using ::testing::AnyNumber; | |
101 using ::testing::DoAll; | |
102 using ::testing::InSequence; | |
103 using ::testing::Invoke; | |
104 using ::testing::Mock; | |
105 using ::testing::Return; | |
106 | |
107 using content::BrowserThread; | |
108 | |
109 using std::string; | |
110 | |
111 class UpdateClientTest : public testing::Test { | |
112 public: | |
113 UpdateClientTest(); | |
114 ~UpdateClientTest() override; | |
115 | |
116 void SetUp() override; | |
117 void TearDown() override; | |
118 | |
119 protected: | |
120 void RunThreads(); | |
121 | |
122 // Returns the full path to a test file. | |
123 static base::FilePath TestFilePath(const char* file); | |
124 | |
125 content::TestBrowserThreadBundle thread_bundle_; | |
126 | |
127 base::RunLoop runloop_; | |
128 base::Closure quit_closure_; | |
129 | |
130 scoped_refptr<update_client::TestConfigurator> config_; | |
131 | |
132 private: | |
133 DISALLOW_COPY_AND_ASSIGN(UpdateClientTest); | |
134 }; | |
135 | |
136 UpdateClientTest::UpdateClientTest() | |
137 : config_(new TestConfigurator( | |
138 BrowserThread::GetBlockingPool() | |
139 ->GetSequencedTaskRunnerWithShutdownBehavior( | |
140 BrowserThread::GetBlockingPool()->GetSequenceToken(), | |
141 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN), | |
142 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))) { | |
143 } | |
144 | |
145 UpdateClientTest::~UpdateClientTest() { | |
146 } | |
147 | |
148 void UpdateClientTest::SetUp() { | |
149 quit_closure_ = runloop_.QuitClosure(); | |
150 } | |
151 | |
152 void UpdateClientTest::TearDown() { | |
153 } | |
154 | |
155 void UpdateClientTest::RunThreads() { | |
156 runloop_.Run(); | |
157 } | |
158 | |
159 base::FilePath UpdateClientTest::TestFilePath(const char* file) { | |
160 base::FilePath path; | |
161 PathService::Get(base::DIR_SOURCE_ROOT, &path); | |
162 return path.AppendASCII("components") | |
163 .AppendASCII("test") | |
164 .AppendASCII("data") | |
165 .AppendASCII("update_client") | |
166 .AppendASCII(file); | |
167 } | |
168 | |
169 // Tests the scenario where one update check is done for one CRX. The CRX | |
170 // has no update. | |
171 TEST_F(UpdateClientTest, OneCrxNoUpdate) { | |
172 class DataCallbackFake { | |
173 public: | |
174 static void Callback(const std::vector<std::string>& ids, | |
175 std::vector<CrxComponent>* components) { | |
176 CrxComponent crx; | |
177 crx.name = "test_jebg"; | |
178 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); | |
179 crx.version = Version("0.9"); | |
180 crx.installer = new TestInstaller; | |
181 components->push_back(crx); | |
182 } | |
183 }; | |
184 | |
185 class CompletionCallbackFake { | |
186 public: | |
187 static void Callback(const base::Closure& quit_closure, int error) { | |
188 EXPECT_EQ(0, error); | |
189 quit_closure.Run(); | |
190 } | |
191 }; | |
192 | |
193 class FakeUpdateChecker : public UpdateChecker { | |
194 public: | |
195 static scoped_ptr<UpdateChecker> Create(const Configurator& config) { | |
196 return scoped_ptr<UpdateChecker>(new FakeUpdateChecker()); | |
197 } | |
198 | |
199 bool CheckForUpdates( | |
200 const std::vector<CrxUpdateItem*>& items_to_check, | |
201 const std::string& additional_attributes, | |
202 const UpdateCheckCallback& update_check_callback) override { | |
203 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
204 FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", | |
205 UpdateResponse::Results())); | |
206 return true; | |
207 } | |
208 }; | |
209 | |
210 class FakeCrxDownloader : public CrxDownloader { | |
211 public: | |
212 static scoped_ptr<CrxDownloader> Create( | |
213 bool is_background_download, | |
214 net::URLRequestContextGetter* context_getter, | |
215 const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner, | |
216 const scoped_refptr<base::SingleThreadTaskRunner>& | |
217 background_task_runner) { | |
218 return scoped_ptr<CrxDownloader>(new FakeCrxDownloader()); | |
219 } | |
220 | |
221 private: | |
222 FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {} | |
223 ~FakeCrxDownloader() override {} | |
224 | |
225 void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } | |
226 }; | |
227 | |
228 class FakePingManager : public FakePingManagerImpl { | |
229 public: | |
230 explicit FakePingManager(const Configurator& config) | |
231 : FakePingManagerImpl(config) {} | |
232 ~FakePingManager() override { EXPECT_TRUE(items().empty()); } | |
233 }; | |
234 | |
235 scoped_ptr<PingManager> ping_manager(new FakePingManager(*config_)); | |
236 scoped_ptr<UpdateClient> update_client(new UpdateClientImpl( | |
237 config_, ping_manager.Pass(), &FakeUpdateChecker::Create, | |
238 &FakeCrxDownloader::Create)); | |
239 | |
240 MockObserver observer; | |
241 InSequence seq; | |
242 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
243 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
244 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, | |
245 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
246 | |
247 update_client->AddObserver(&observer); | |
248 | |
249 std::vector<std::string> ids; | |
250 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); | |
251 | |
252 update_client->Update( | |
253 ids, base::Bind(&DataCallbackFake::Callback), | |
254 base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); | |
255 | |
256 RunThreads(); | |
257 | |
258 update_client->RemoveObserver(&observer); | |
259 } | |
260 | |
261 // Tests the scenario where two CRXs are checked for updates. On CRX has | |
262 // an update, the other CRX does not. | |
263 TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) { | |
264 class DataCallbackFake { | |
265 public: | |
266 static void Callback(const std::vector<std::string>& ids, | |
267 std::vector<CrxComponent>* components) { | |
268 CrxComponent crx1; | |
269 crx1.name = "test_jebg"; | |
270 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); | |
271 crx1.version = Version("0.9"); | |
272 crx1.installer = new TestInstaller; | |
273 | |
274 CrxComponent crx2; | |
275 crx2.name = "test_abag"; | |
276 crx2.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash)); | |
277 crx2.version = Version("2.2"); | |
278 crx2.installer = new TestInstaller; | |
279 | |
280 components->push_back(crx1); | |
281 components->push_back(crx2); | |
282 } | |
283 }; | |
284 | |
285 class CompletionCallbackFake { | |
286 public: | |
287 static void Callback(const base::Closure& quit_closure, int error) { | |
288 EXPECT_EQ(0, error); | |
289 quit_closure.Run(); | |
290 } | |
291 }; | |
292 | |
293 class FakeUpdateChecker : public UpdateChecker { | |
294 public: | |
295 static scoped_ptr<UpdateChecker> Create(const Configurator& config) { | |
296 return scoped_ptr<UpdateChecker>(new FakeUpdateChecker()); | |
297 } | |
298 | |
299 bool CheckForUpdates( | |
300 const std::vector<CrxUpdateItem*>& items_to_check, | |
301 const std::string& additional_attributes, | |
302 const UpdateCheckCallback& update_check_callback) override { | |
303 /* | |
304 Fake the following response: | |
305 | |
306 <?xml version='1.0' encoding='UTF-8'?> | |
307 <response protocol='3.0'> | |
308 <app appid='jebgalgnebhfojomionfpkfelancnnkf'> | |
309 <updatecheck status='ok'> | |
310 <urls> | |
311 <url codebase='http://localhost/download/'/> | |
312 </urls> | |
313 <manifest version='1.0' prodversionmin='11.0.1.0'> | |
314 <packages> | |
315 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'/> | |
316 </packages> | |
317 </manifest> | |
318 </updatecheck> | |
319 </app> | |
320 </response> | |
321 */ | |
322 UpdateResponse::Result::Manifest::Package package; | |
323 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; | |
324 | |
325 UpdateResponse::Result result; | |
326 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; | |
327 result.crx_urls.push_back(GURL("http://localhost/download/")); | |
328 result.manifest.version = "1.0"; | |
329 result.manifest.browser_min_version = "11.0.1.0"; | |
330 result.manifest.packages.push_back(package); | |
331 | |
332 UpdateResponse::Results results; | |
333 results.list.push_back(result); | |
334 | |
335 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
336 FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); | |
337 return true; | |
338 } | |
339 }; | |
340 | |
341 class FakeCrxDownloader : public CrxDownloader { | |
342 public: | |
343 static scoped_ptr<CrxDownloader> Create( | |
344 bool is_background_download, | |
345 net::URLRequestContextGetter* context_getter, | |
346 const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner, | |
347 const scoped_refptr<base::SingleThreadTaskRunner>& | |
348 background_task_runner) { | |
349 return scoped_ptr<CrxDownloader>(new FakeCrxDownloader()); | |
350 } | |
351 | |
352 private: | |
353 FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {} | |
354 ~FakeCrxDownloader() override {} | |
355 | |
356 void DoStartDownload(const GURL& url) override { | |
357 DownloadMetrics download_metrics; | |
358 download_metrics.url = url; | |
359 download_metrics.downloader = DownloadMetrics::kNone; | |
360 download_metrics.error = 0; | |
361 download_metrics.downloaded_bytes = 1843; | |
362 download_metrics.total_bytes = 1843; | |
363 download_metrics.download_time_ms = 1000; | |
364 | |
365 FilePath path; | |
366 EXPECT_TRUE(MakeTestFile( | |
367 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); | |
368 | |
369 Result result; | |
370 result.error = 0; | |
371 result.response = path; | |
372 result.downloaded_bytes = 1843; | |
373 result.total_bytes = 1843; | |
374 | |
375 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
376 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, | |
377 base::Unretained(this), result)); | |
378 | |
379 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
380 FROM_HERE, | |
381 base::Bind(&FakeCrxDownloader::OnDownloadComplete, | |
382 base::Unretained(this), true, result, download_metrics)); | |
383 } | |
384 }; | |
385 | |
386 class FakePingManager : public FakePingManagerImpl { | |
387 public: | |
388 explicit FakePingManager(const Configurator& config) | |
389 : FakePingManagerImpl(config) {} | |
390 ~FakePingManager() override { | |
391 const auto& ping_items = items(); | |
392 EXPECT_EQ(1U, ping_items.size()); | |
393 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); | |
394 EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); | |
395 EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); | |
396 EXPECT_EQ(0, ping_items[0].error_category); | |
397 EXPECT_EQ(0, ping_items[0].error_code); | |
398 } | |
399 }; | |
400 | |
401 scoped_ptr<PingManager> ping_manager(new FakePingManager(*config_)); | |
402 scoped_ptr<UpdateClient> update_client(new UpdateClientImpl( | |
403 config_, ping_manager.Pass(), &FakeUpdateChecker::Create, | |
404 &FakeCrxDownloader::Create)); | |
405 | |
406 MockObserver observer; | |
407 { | |
408 InSequence seq; | |
409 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
410 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
411 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, | |
412 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
413 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
414 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
415 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, | |
416 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
417 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, | |
418 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
419 } | |
420 { | |
421 InSequence seq; | |
422 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
423 "abagagagagagagagagagagagagagagag")).Times(1); | |
424 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, | |
425 "abagagagagagagagagagagagagagagag")).Times(1); | |
426 } | |
427 | |
428 update_client->AddObserver(&observer); | |
429 | |
430 std::vector<std::string> ids; | |
431 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); | |
432 ids.push_back(std::string("abagagagagagagagagagagagagagagag")); | |
433 | |
434 update_client->Update( | |
435 ids, base::Bind(&DataCallbackFake::Callback), | |
436 base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); | |
437 | |
438 RunThreads(); | |
439 | |
440 update_client->RemoveObserver(&observer); | |
441 } | |
442 | |
443 // Tests the update check for two CRXs scenario. Both CRXs have updates. | |
444 TEST_F(UpdateClientTest, TwoCrxUpdate) { | |
445 class DataCallbackFake { | |
446 public: | |
447 static void Callback(const std::vector<std::string>& ids, | |
448 std::vector<CrxComponent>* components) { | |
449 CrxComponent crx1; | |
450 crx1.name = "test_jebg"; | |
451 crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); | |
452 crx1.version = Version("0.9"); | |
453 crx1.installer = new TestInstaller; | |
454 | |
455 CrxComponent crx2; | |
456 crx2.name = "test_ihfo"; | |
457 crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); | |
458 crx2.version = Version("0.8"); | |
459 crx2.installer = new TestInstaller; | |
460 | |
461 components->push_back(crx1); | |
462 components->push_back(crx2); | |
463 } | |
464 }; | |
465 | |
466 class CompletionCallbackFake { | |
467 public: | |
468 static void Callback(const base::Closure& quit_closure, int error) { | |
469 EXPECT_EQ(0, error); | |
470 quit_closure.Run(); | |
471 } | |
472 }; | |
473 | |
474 class FakeUpdateChecker : public UpdateChecker { | |
475 public: | |
476 static scoped_ptr<UpdateChecker> Create(const Configurator& config) { | |
477 return scoped_ptr<UpdateChecker>(new FakeUpdateChecker()); | |
478 } | |
479 | |
480 bool CheckForUpdates( | |
481 const std::vector<CrxUpdateItem*>& items_to_check, | |
482 const std::string& additional_attributes, | |
483 const UpdateCheckCallback& update_check_callback) override { | |
484 /* | |
485 Fake the following response: | |
486 | |
487 <?xml version='1.0' encoding='UTF-8'?> | |
488 <response protocol='3.0'> | |
489 <app appid='jebgalgnebhfojomionfpkfelancnnkf'> | |
490 <updatecheck status='ok'> | |
491 <urls> | |
492 <url codebase='http://localhost/download/'/> | |
493 </urls> | |
494 <manifest version='1.0' prodversionmin='11.0.1.0'> | |
495 <packages> | |
496 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'/> | |
497 </packages> | |
498 </manifest> | |
499 </updatecheck> | |
500 </app> | |
501 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> | |
502 <updatecheck status='ok'> | |
503 <urls> | |
504 <url codebase='http://localhost/download/'/> | |
505 </urls> | |
506 <manifest version='1.0' prodversionmin='11.0.1.0'> | |
507 <packages> | |
508 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'/> | |
509 </packages> | |
510 </manifest> | |
511 </updatecheck> | |
512 </app> | |
513 </response> | |
514 */ | |
515 UpdateResponse::Result::Manifest::Package package1; | |
516 package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; | |
517 | |
518 UpdateResponse::Result result1; | |
519 result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; | |
520 result1.crx_urls.push_back(GURL("http://localhost/download/")); | |
521 result1.manifest.version = "1.0"; | |
522 result1.manifest.browser_min_version = "11.0.1.0"; | |
523 result1.manifest.packages.push_back(package1); | |
524 | |
525 UpdateResponse::Result::Manifest::Package package2; | |
526 package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; | |
527 | |
528 UpdateResponse::Result result2; | |
529 result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; | |
530 result2.crx_urls.push_back(GURL("http://localhost/download/")); | |
531 result2.manifest.version = "1.0"; | |
532 result2.manifest.browser_min_version = "11.0.1.0"; | |
533 result2.manifest.packages.push_back(package2); | |
534 | |
535 UpdateResponse::Results results; | |
536 results.list.push_back(result1); | |
537 results.list.push_back(result2); | |
538 | |
539 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
540 FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); | |
541 return true; | |
542 } | |
543 }; | |
544 | |
545 class FakeCrxDownloader : public CrxDownloader { | |
546 public: | |
547 static scoped_ptr<CrxDownloader> Create( | |
548 bool is_background_download, | |
549 net::URLRequestContextGetter* context_getter, | |
550 const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner, | |
551 const scoped_refptr<base::SingleThreadTaskRunner>& | |
552 background_task_runner) { | |
553 return scoped_ptr<CrxDownloader>(new FakeCrxDownloader()); | |
554 } | |
555 | |
556 private: | |
557 FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {} | |
558 ~FakeCrxDownloader() override {} | |
559 | |
560 void DoStartDownload(const GURL& url) override { | |
561 DownloadMetrics download_metrics; | |
562 FilePath path; | |
563 Result result; | |
564 if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") { | |
565 download_metrics.url = url; | |
566 download_metrics.downloader = DownloadMetrics::kNone; | |
567 download_metrics.error = 0; | |
568 download_metrics.downloaded_bytes = 1843; | |
569 download_metrics.total_bytes = 1843; | |
570 download_metrics.download_time_ms = 1000; | |
571 | |
572 EXPECT_TRUE(MakeTestFile( | |
573 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); | |
574 | |
575 result.error = 0; | |
576 result.response = path; | |
577 result.downloaded_bytes = 1843; | |
578 result.total_bytes = 1843; | |
579 } else if (url.path() == | |
580 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { | |
581 download_metrics.url = url; | |
582 download_metrics.downloader = DownloadMetrics::kNone; | |
583 download_metrics.error = 0; | |
584 download_metrics.downloaded_bytes = 53638; | |
585 download_metrics.total_bytes = 53638; | |
586 download_metrics.download_time_ms = 2000; | |
587 | |
588 EXPECT_TRUE(MakeTestFile( | |
589 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); | |
590 | |
591 result.error = 0; | |
592 result.response = path; | |
593 result.downloaded_bytes = 53638; | |
594 result.total_bytes = 53638; | |
595 } else { | |
596 NOTREACHED(); | |
597 } | |
598 | |
599 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
600 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, | |
601 base::Unretained(this), result)); | |
602 | |
603 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
604 FROM_HERE, | |
605 base::Bind(&FakeCrxDownloader::OnDownloadComplete, | |
606 base::Unretained(this), true, result, download_metrics)); | |
607 } | |
608 }; | |
609 | |
610 class FakePingManager : public FakePingManagerImpl { | |
611 public: | |
612 explicit FakePingManager(const Configurator& config) | |
613 : FakePingManagerImpl(config) {} | |
614 ~FakePingManager() override { | |
615 const auto& ping_items = items(); | |
616 EXPECT_EQ(2U, ping_items.size()); | |
617 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); | |
618 EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); | |
619 EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); | |
620 EXPECT_EQ(0, ping_items[0].error_category); | |
621 EXPECT_EQ(0, ping_items[0].error_code); | |
622 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); | |
623 EXPECT_TRUE(base::Version("0.8").Equals(ping_items[1].previous_version)); | |
624 EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].next_version)); | |
625 EXPECT_EQ(0, ping_items[1].error_category); | |
626 EXPECT_EQ(0, ping_items[1].error_code); | |
627 } | |
628 }; | |
629 | |
630 scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config_)); | |
631 scoped_ptr<UpdateClient> update_client(new UpdateClientImpl( | |
632 config_, ping_manager.Pass(), &FakeUpdateChecker::Create, | |
633 &FakeCrxDownloader::Create)); | |
634 | |
635 MockObserver observer; | |
636 { | |
637 InSequence seq; | |
638 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
639 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
640 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, | |
641 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
642 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
643 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
644 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, | |
645 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
646 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, | |
647 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
648 } | |
649 { | |
650 InSequence seq; | |
651 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
652 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
653 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, | |
654 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
655 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT, | |
656 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
657 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
658 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
659 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, | |
660 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
661 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, | |
662 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
663 } | |
664 | |
665 update_client->AddObserver(&observer); | |
666 | |
667 std::vector<std::string> ids; | |
668 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); | |
669 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); | |
670 | |
671 update_client->Update( | |
672 ids, base::Bind(&DataCallbackFake::Callback), | |
673 base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); | |
674 | |
675 RunThreads(); | |
676 | |
677 update_client->RemoveObserver(&observer); | |
678 } | |
679 | |
680 // Tests the differential update scenario for one CRX. | |
681 TEST_F(UpdateClientTest, OneCrxDiffUpdate) { | |
682 class DataCallbackFake { | |
683 public: | |
684 static void Callback(const std::vector<std::string>& ids, | |
685 std::vector<CrxComponent>* components) { | |
686 static int num_calls = 0; | |
687 | |
688 // Must use the same stateful installer object. | |
689 static scoped_refptr<CrxInstaller> installer( | |
690 new VersionedTestInstaller()); | |
691 | |
692 ++num_calls; | |
693 | |
694 CrxComponent crx; | |
695 crx.name = "test_ihfo"; | |
696 crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); | |
697 crx.installer = installer; | |
698 if (num_calls == 1) { | |
699 crx.version = Version("0.8"); | |
700 } else if (num_calls == 2) { | |
701 crx.version = Version("1.0"); | |
702 } else { | |
703 NOTREACHED(); | |
704 } | |
705 | |
706 components->push_back(crx); | |
707 } | |
708 }; | |
709 | |
710 class CompletionCallbackFake { | |
711 public: | |
712 static void Callback(const base::Closure& quit_closure, int error) { | |
713 EXPECT_EQ(0, error); | |
714 quit_closure.Run(); | |
715 } | |
716 }; | |
717 | |
718 class FakeUpdateChecker : public UpdateChecker { | |
719 public: | |
720 static scoped_ptr<UpdateChecker> Create(const Configurator& config) { | |
721 return scoped_ptr<UpdateChecker>(new FakeUpdateChecker()); | |
722 } | |
723 | |
724 bool CheckForUpdates( | |
725 const std::vector<CrxUpdateItem*>& items_to_check, | |
726 const std::string& additional_attributes, | |
727 const UpdateCheckCallback& update_check_callback) override { | |
728 static int num_call = 0; | |
729 ++num_call; | |
730 | |
731 UpdateResponse::Results results; | |
732 | |
733 if (num_call == 1) { | |
734 /* | |
735 Fake the following response: | |
736 <?xml version='1.0' encoding='UTF-8'?> | |
737 <response protocol='3.0'> | |
738 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> | |
739 <updatecheck status='ok'> | |
740 <urls> | |
741 <url codebase='http://localhost/download/'/> | |
742 </urls> | |
743 <manifest version='1.0' prodversionmin='11.0.1.0'> | |
744 <packages> | |
745 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'/> | |
746 </packages> | |
747 </manifest> | |
748 </updatecheck> | |
749 </app> | |
750 </response> | |
751 */ | |
752 UpdateResponse::Result::Manifest::Package package; | |
753 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; | |
754 package.fingerprint = "1"; | |
755 UpdateResponse::Result result; | |
756 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; | |
757 result.crx_urls.push_back(GURL("http://localhost/download/")); | |
758 result.manifest.version = "1.0"; | |
759 result.manifest.browser_min_version = "11.0.1.0"; | |
760 result.manifest.packages.push_back(package); | |
761 results.list.push_back(result); | |
762 } else if (num_call == 2) { | |
763 /* | |
764 Fake the following response: | |
765 <?xml version='1.0' encoding='UTF-8'?> | |
766 <response protocol='3.0'> | |
767 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> | |
768 <updatecheck status='ok'> | |
769 <urls> | |
770 <url codebase='http://localhost/download/'/> | |
771 <url codebasediff='http://localhost/download/'/> | |
772 </urls> | |
773 <manifest version='2.0' prodversionmin='11.0.1.0'> | |
774 <packages> | |
775 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx' | |
776 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx' | |
777 fp='22'/> | |
778 </packages> | |
779 </manifest> | |
780 </updatecheck> | |
781 </app> | |
782 </response> | |
783 */ | |
784 UpdateResponse::Result::Manifest::Package package; | |
785 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"; | |
786 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"; | |
787 package.fingerprint = "22"; | |
788 UpdateResponse::Result result; | |
789 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; | |
790 result.crx_urls.push_back(GURL("http://localhost/download/")); | |
791 result.crx_diffurls.push_back(GURL("http://localhost/download/")); | |
792 result.manifest.version = "2.0"; | |
793 result.manifest.browser_min_version = "11.0.1.0"; | |
794 result.manifest.packages.push_back(package); | |
795 results.list.push_back(result); | |
796 } else { | |
797 NOTREACHED(); | |
798 } | |
799 | |
800 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
801 FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); | |
802 return true; | |
803 } | |
804 }; | |
805 | |
806 class FakeCrxDownloader : public CrxDownloader { | |
807 public: | |
808 static scoped_ptr<CrxDownloader> Create( | |
809 bool is_background_download, | |
810 net::URLRequestContextGetter* context_getter, | |
811 const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner, | |
812 const scoped_refptr<base::SingleThreadTaskRunner>& | |
813 background_task_runner) { | |
814 return scoped_ptr<CrxDownloader>(new FakeCrxDownloader()); | |
815 } | |
816 | |
817 private: | |
818 FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {} | |
819 ~FakeCrxDownloader() override {} | |
820 | |
821 void DoStartDownload(const GURL& url) override { | |
822 DownloadMetrics download_metrics; | |
823 FilePath path; | |
824 Result result; | |
825 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { | |
826 download_metrics.url = url; | |
827 download_metrics.downloader = DownloadMetrics::kNone; | |
828 download_metrics.error = 0; | |
829 download_metrics.downloaded_bytes = 53638; | |
830 download_metrics.total_bytes = 53638; | |
831 download_metrics.download_time_ms = 2000; | |
832 | |
833 EXPECT_TRUE(MakeTestFile( | |
834 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); | |
835 | |
836 result.error = 0; | |
837 result.response = path; | |
838 result.downloaded_bytes = 53638; | |
839 result.total_bytes = 53638; | |
840 } else if (url.path() == | |
841 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") { | |
842 download_metrics.url = url; | |
843 download_metrics.downloader = DownloadMetrics::kNone; | |
844 download_metrics.error = 0; | |
845 download_metrics.downloaded_bytes = 2105; | |
846 download_metrics.total_bytes = 2105; | |
847 download_metrics.download_time_ms = 1000; | |
848 | |
849 EXPECT_TRUE(MakeTestFile( | |
850 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path)); | |
851 | |
852 result.error = 0; | |
853 result.response = path; | |
854 result.downloaded_bytes = 2105; | |
855 result.total_bytes = 2105; | |
856 } else { | |
857 NOTREACHED(); | |
858 } | |
859 | |
860 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
861 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, | |
862 base::Unretained(this), result)); | |
863 | |
864 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
865 FROM_HERE, | |
866 base::Bind(&FakeCrxDownloader::OnDownloadComplete, | |
867 base::Unretained(this), true, result, download_metrics)); | |
868 } | |
869 }; | |
870 | |
871 class FakePingManager : public FakePingManagerImpl { | |
872 public: | |
873 explicit FakePingManager(const Configurator& config) | |
874 : FakePingManagerImpl(config) {} | |
875 ~FakePingManager() override { | |
876 const auto& ping_items = items(); | |
877 EXPECT_EQ(2U, ping_items.size()); | |
878 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id); | |
879 EXPECT_TRUE(base::Version("0.8").Equals(ping_items[0].previous_version)); | |
880 EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); | |
881 EXPECT_EQ(0, ping_items[0].error_category); | |
882 EXPECT_EQ(0, ping_items[0].error_code); | |
883 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); | |
884 EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].previous_version)); | |
885 EXPECT_TRUE(base::Version("2.0").Equals(ping_items[1].next_version)); | |
886 EXPECT_EQ(0, ping_items[1].diff_error_category); | |
887 EXPECT_EQ(0, ping_items[1].diff_error_code); | |
888 } | |
889 }; | |
890 | |
891 scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config_)); | |
892 scoped_ptr<UpdateClient> update_client(new UpdateClientImpl( | |
893 config_, ping_manager.Pass(), &FakeUpdateChecker::Create, | |
894 &FakeCrxDownloader::Create)); | |
895 | |
896 MockObserver observer; | |
897 { | |
898 InSequence seq; | |
899 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
900 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
901 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, | |
902 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
903 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
904 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
905 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, | |
906 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
907 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, | |
908 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
909 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
910 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
911 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, | |
912 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
913 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
914 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
915 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, | |
916 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
917 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, | |
918 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
919 } | |
920 | |
921 update_client->AddObserver(&observer); | |
922 | |
923 std::vector<std::string> ids; | |
924 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); | |
925 | |
926 { | |
927 base::RunLoop runloop; | |
928 update_client->Update( | |
929 ids, base::Bind(&DataCallbackFake::Callback), | |
930 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); | |
931 runloop.Run(); | |
932 } | |
933 | |
934 { | |
935 base::RunLoop runloop; | |
936 update_client->Update( | |
937 ids, base::Bind(&DataCallbackFake::Callback), | |
938 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); | |
939 runloop.Run(); | |
940 } | |
941 | |
942 update_client->RemoveObserver(&observer); | |
943 } | |
944 | |
945 // Tests the update scenario for one CRX where the CRX installer returns | |
946 // an error. | |
947 TEST_F(UpdateClientTest, OneCrxInstallError) { | |
948 class MockInstaller : public CrxInstaller { | |
949 public: | |
950 MOCK_METHOD1(OnUpdateError, void(int error)); | |
951 MOCK_METHOD2(Install, | |
952 bool(const base::DictionaryValue& manifest, | |
953 const base::FilePath& unpack_path)); | |
954 MOCK_METHOD2(GetInstalledFile, | |
955 bool(const std::string& file, base::FilePath* installed_file)); | |
956 MOCK_METHOD0(Uninstall, bool()); | |
957 | |
958 static void OnInstall(const base::DictionaryValue& manifest, | |
959 const base::FilePath& unpack_path) { | |
960 base::DeleteFile(unpack_path, true); | |
961 } | |
962 | |
963 protected: | |
964 ~MockInstaller() override {} | |
965 }; | |
966 | |
967 class DataCallbackFake { | |
968 public: | |
969 static void Callback(const std::vector<std::string>& ids, | |
970 std::vector<CrxComponent>* components) { | |
971 scoped_refptr<MockInstaller> installer(new MockInstaller()); | |
972 | |
973 EXPECT_CALL(*installer, OnUpdateError(_)).Times(0); | |
974 EXPECT_CALL(*installer, Install(_, _)) | |
975 .WillOnce(DoAll(Invoke(MockInstaller::OnInstall), Return(false))); | |
976 EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0); | |
977 EXPECT_CALL(*installer, Uninstall()).Times(0); | |
978 | |
979 CrxComponent crx; | |
980 crx.name = "test_jebg"; | |
981 crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); | |
982 crx.version = Version("0.9"); | |
983 crx.installer = installer; | |
984 components->push_back(crx); | |
985 } | |
986 }; | |
987 | |
988 class CompletionCallbackFake { | |
989 public: | |
990 static void Callback(const base::Closure& quit_closure, int error) { | |
991 EXPECT_EQ(0, error); | |
992 quit_closure.Run(); | |
993 } | |
994 }; | |
995 | |
996 class FakeUpdateChecker : public UpdateChecker { | |
997 public: | |
998 static scoped_ptr<UpdateChecker> Create(const Configurator& config) { | |
999 return scoped_ptr<UpdateChecker>(new FakeUpdateChecker()); | |
1000 } | |
1001 | |
1002 bool CheckForUpdates( | |
1003 const std::vector<CrxUpdateItem*>& items_to_check, | |
1004 const std::string& additional_attributes, | |
1005 const UpdateCheckCallback& update_check_callback) override { | |
1006 /* | |
1007 Fake the following response: | |
1008 | |
1009 <?xml version='1.0' encoding='UTF-8'?> | |
1010 <response protocol='3.0'> | |
1011 <app appid='jebgalgnebhfojomionfpkfelancnnkf'> | |
1012 <updatecheck status='ok'> | |
1013 <urls> | |
1014 <url codebase='http://localhost/download/'/> | |
1015 </urls> | |
1016 <manifest version='1.0' prodversionmin='11.0.1.0'> | |
1017 <packages> | |
1018 <package name='jebgalgnebhfojomionfpkfelancnnkf.crx'/> | |
1019 </packages> | |
1020 </manifest> | |
1021 </updatecheck> | |
1022 </app> | |
1023 </response> | |
1024 */ | |
1025 UpdateResponse::Result::Manifest::Package package; | |
1026 package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; | |
1027 | |
1028 UpdateResponse::Result result; | |
1029 result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; | |
1030 result.crx_urls.push_back(GURL("http://localhost/download/")); | |
1031 result.manifest.version = "1.0"; | |
1032 result.manifest.browser_min_version = "11.0.1.0"; | |
1033 result.manifest.packages.push_back(package); | |
1034 | |
1035 UpdateResponse::Results results; | |
1036 results.list.push_back(result); | |
1037 | |
1038 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1039 FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); | |
1040 return true; | |
1041 } | |
1042 }; | |
1043 | |
1044 class FakeCrxDownloader : public CrxDownloader { | |
1045 public: | |
1046 static scoped_ptr<CrxDownloader> Create( | |
1047 bool is_background_download, | |
1048 net::URLRequestContextGetter* context_getter, | |
1049 const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner, | |
1050 const scoped_refptr<base::SingleThreadTaskRunner>& | |
1051 background_task_runner) { | |
1052 return scoped_ptr<CrxDownloader>(new FakeCrxDownloader()); | |
1053 } | |
1054 | |
1055 private: | |
1056 FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {} | |
1057 ~FakeCrxDownloader() override {} | |
1058 | |
1059 void DoStartDownload(const GURL& url) override { | |
1060 DownloadMetrics download_metrics; | |
1061 download_metrics.url = url; | |
1062 download_metrics.downloader = DownloadMetrics::kNone; | |
1063 download_metrics.error = 0; | |
1064 download_metrics.downloaded_bytes = 1843; | |
1065 download_metrics.total_bytes = 1843; | |
1066 download_metrics.download_time_ms = 1000; | |
1067 | |
1068 FilePath path; | |
1069 EXPECT_TRUE(MakeTestFile( | |
1070 TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); | |
1071 | |
1072 Result result; | |
1073 result.error = 0; | |
1074 result.response = path; | |
1075 result.downloaded_bytes = 1843; | |
1076 result.total_bytes = 1843; | |
1077 | |
1078 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1079 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, | |
1080 base::Unretained(this), result)); | |
1081 | |
1082 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1083 FROM_HERE, | |
1084 base::Bind(&FakeCrxDownloader::OnDownloadComplete, | |
1085 base::Unretained(this), true, result, download_metrics)); | |
1086 } | |
1087 }; | |
1088 | |
1089 class FakePingManager : public FakePingManagerImpl { | |
1090 public: | |
1091 explicit FakePingManager(const Configurator& config) | |
1092 : FakePingManagerImpl(config) {} | |
1093 ~FakePingManager() override { | |
1094 const auto& ping_items = items(); | |
1095 EXPECT_EQ(1U, ping_items.size()); | |
1096 EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); | |
1097 EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); | |
1098 EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); | |
1099 EXPECT_EQ(3, ping_items[0].error_category); // kInstallError. | |
1100 EXPECT_EQ(9, ping_items[0].error_code); // kInstallerError. | |
1101 } | |
1102 }; | |
1103 | |
1104 scoped_ptr<PingManager> ping_manager(new FakePingManager(*config_)); | |
1105 scoped_ptr<UpdateClient> update_client(new UpdateClientImpl( | |
1106 config_, ping_manager.Pass(), &FakeUpdateChecker::Create, | |
1107 &FakeCrxDownloader::Create)); | |
1108 | |
1109 MockObserver observer; | |
1110 { | |
1111 InSequence seq; | |
1112 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
1113 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
1114 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, | |
1115 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
1116 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
1117 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
1118 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, | |
1119 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
1120 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, | |
1121 "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); | |
1122 } | |
1123 | |
1124 update_client->AddObserver(&observer); | |
1125 | |
1126 std::vector<std::string> ids; | |
1127 ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); | |
1128 | |
1129 update_client->Update( | |
1130 ids, base::Bind(&DataCallbackFake::Callback), | |
1131 base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); | |
1132 | |
1133 RunThreads(); | |
1134 | |
1135 update_client->RemoveObserver(&observer); | |
1136 } | |
1137 | |
1138 // Tests the fallback from differential to full update scenario for one CRX. | |
1139 TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) { | |
1140 class DataCallbackFake { | |
1141 public: | |
1142 static void Callback(const std::vector<std::string>& ids, | |
1143 std::vector<CrxComponent>* components) { | |
1144 static int num_calls = 0; | |
1145 | |
1146 // Must use the same stateful installer object. | |
1147 static scoped_refptr<CrxInstaller> installer( | |
1148 new VersionedTestInstaller()); | |
1149 | |
1150 ++num_calls; | |
1151 | |
1152 CrxComponent crx; | |
1153 crx.name = "test_ihfo"; | |
1154 crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); | |
1155 crx.installer = installer; | |
1156 if (num_calls == 1) { | |
1157 crx.version = Version("0.8"); | |
1158 } else if (num_calls == 2) { | |
1159 crx.version = Version("1.0"); | |
1160 } else { | |
1161 NOTREACHED(); | |
1162 } | |
1163 | |
1164 components->push_back(crx); | |
1165 } | |
1166 }; | |
1167 | |
1168 class CompletionCallbackFake { | |
1169 public: | |
1170 static void Callback(const base::Closure& quit_closure, int error) { | |
1171 EXPECT_EQ(0, error); | |
1172 quit_closure.Run(); | |
1173 } | |
1174 }; | |
1175 | |
1176 class FakeUpdateChecker : public UpdateChecker { | |
1177 public: | |
1178 static scoped_ptr<UpdateChecker> Create(const Configurator& config) { | |
1179 return scoped_ptr<UpdateChecker>(new FakeUpdateChecker()); | |
1180 } | |
1181 | |
1182 bool CheckForUpdates( | |
1183 const std::vector<CrxUpdateItem*>& items_to_check, | |
1184 const std::string& additional_attributes, | |
1185 const UpdateCheckCallback& update_check_callback) override { | |
1186 static int num_call = 0; | |
1187 ++num_call; | |
1188 | |
1189 UpdateResponse::Results results; | |
1190 | |
1191 if (num_call == 1) { | |
1192 /* | |
1193 Fake the following response: | |
1194 <?xml version='1.0' encoding='UTF-8'?> | |
1195 <response protocol='3.0'> | |
1196 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> | |
1197 <updatecheck status='ok'> | |
1198 <urls> | |
1199 <url codebase='http://localhost/download/'/> | |
1200 </urls> | |
1201 <manifest version='1.0' prodversionmin='11.0.1.0'> | |
1202 <packages> | |
1203 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'/> | |
1204 </packages> | |
1205 </manifest> | |
1206 </updatecheck> | |
1207 </app> | |
1208 </response> | |
1209 */ | |
1210 UpdateResponse::Result::Manifest::Package package; | |
1211 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; | |
1212 package.fingerprint = "1"; | |
1213 UpdateResponse::Result result; | |
1214 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; | |
1215 result.crx_urls.push_back(GURL("http://localhost/download/")); | |
1216 result.manifest.version = "1.0"; | |
1217 result.manifest.browser_min_version = "11.0.1.0"; | |
1218 result.manifest.packages.push_back(package); | |
1219 results.list.push_back(result); | |
1220 } else if (num_call == 2) { | |
1221 /* | |
1222 Fake the following response: | |
1223 <?xml version='1.0' encoding='UTF-8'?> | |
1224 <response protocol='3.0'> | |
1225 <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'> | |
1226 <updatecheck status='ok'> | |
1227 <urls> | |
1228 <url codebase='http://localhost/download/'/> | |
1229 <url codebasediff='http://localhost/download/'/> | |
1230 </urls> | |
1231 <manifest version='2.0' prodversionmin='11.0.1.0'> | |
1232 <packages> | |
1233 <package name='ihfokbkgjpifnbbojhneepfflplebdkc_2.crx' | |
1234 namediff='ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx' | |
1235 fp='22'/> | |
1236 </packages> | |
1237 </manifest> | |
1238 </updatecheck> | |
1239 </app> | |
1240 </response> | |
1241 */ | |
1242 UpdateResponse::Result::Manifest::Package package; | |
1243 package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"; | |
1244 package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"; | |
1245 package.fingerprint = "22"; | |
1246 UpdateResponse::Result result; | |
1247 result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; | |
1248 result.crx_urls.push_back(GURL("http://localhost/download/")); | |
1249 result.crx_diffurls.push_back(GURL("http://localhost/download/")); | |
1250 result.manifest.version = "2.0"; | |
1251 result.manifest.browser_min_version = "11.0.1.0"; | |
1252 result.manifest.packages.push_back(package); | |
1253 results.list.push_back(result); | |
1254 } else { | |
1255 NOTREACHED(); | |
1256 } | |
1257 | |
1258 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1259 FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); | |
1260 return true; | |
1261 } | |
1262 }; | |
1263 | |
1264 class FakeCrxDownloader : public CrxDownloader { | |
1265 public: | |
1266 static scoped_ptr<CrxDownloader> Create( | |
1267 bool is_background_download, | |
1268 net::URLRequestContextGetter* context_getter, | |
1269 const scoped_refptr<base::SequencedTaskRunner>& url_fetcher_task_runner, | |
1270 const scoped_refptr<base::SingleThreadTaskRunner>& | |
1271 background_task_runner) { | |
1272 return scoped_ptr<CrxDownloader>(new FakeCrxDownloader()); | |
1273 } | |
1274 | |
1275 private: | |
1276 FakeCrxDownloader() : CrxDownloader(scoped_ptr<CrxDownloader>().Pass()) {} | |
1277 ~FakeCrxDownloader() override {} | |
1278 | |
1279 void DoStartDownload(const GURL& url) override { | |
1280 DownloadMetrics download_metrics; | |
1281 FilePath path; | |
1282 Result result; | |
1283 if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { | |
1284 download_metrics.url = url; | |
1285 download_metrics.downloader = DownloadMetrics::kNone; | |
1286 download_metrics.error = 0; | |
1287 download_metrics.downloaded_bytes = 53638; | |
1288 download_metrics.total_bytes = 53638; | |
1289 download_metrics.download_time_ms = 2000; | |
1290 | |
1291 EXPECT_TRUE(MakeTestFile( | |
1292 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); | |
1293 | |
1294 result.error = 0; | |
1295 result.response = path; | |
1296 result.downloaded_bytes = 53638; | |
1297 result.total_bytes = 53638; | |
1298 } else if (url.path() == | |
1299 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") { | |
1300 // A download error is injected on this execution path. | |
1301 download_metrics.url = url; | |
1302 download_metrics.downloader = DownloadMetrics::kNone; | |
1303 download_metrics.error = -1; | |
1304 download_metrics.downloaded_bytes = 0; | |
1305 download_metrics.total_bytes = 2105; | |
1306 download_metrics.download_time_ms = 1000; | |
1307 | |
1308 EXPECT_TRUE(MakeTestFile( | |
1309 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path)); | |
1310 | |
1311 result.error = -1; | |
1312 result.response = path; | |
1313 result.downloaded_bytes = 0; | |
1314 result.total_bytes = 2105; | |
1315 } else if (url.path() == | |
1316 "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") { | |
1317 download_metrics.url = url; | |
1318 download_metrics.downloader = DownloadMetrics::kNone; | |
1319 download_metrics.error = 0; | |
1320 download_metrics.downloaded_bytes = 53855; | |
1321 download_metrics.total_bytes = 53855; | |
1322 download_metrics.download_time_ms = 1000; | |
1323 | |
1324 EXPECT_TRUE(MakeTestFile( | |
1325 TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path)); | |
1326 | |
1327 result.error = 0; | |
1328 result.response = path; | |
1329 result.downloaded_bytes = 53855; | |
1330 result.total_bytes = 53855; | |
1331 } | |
1332 | |
1333 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1334 FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, | |
1335 base::Unretained(this), result)); | |
1336 | |
1337 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
1338 FROM_HERE, | |
1339 base::Bind(&FakeCrxDownloader::OnDownloadComplete, | |
1340 base::Unretained(this), true, result, download_metrics)); | |
1341 } | |
1342 }; | |
1343 | |
1344 class FakePingManager : public FakePingManagerImpl { | |
1345 public: | |
1346 explicit FakePingManager(const Configurator& config) | |
1347 : FakePingManagerImpl(config) {} | |
1348 ~FakePingManager() override { | |
1349 const auto& ping_items = items(); | |
1350 EXPECT_EQ(2U, ping_items.size()); | |
1351 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id); | |
1352 EXPECT_TRUE(base::Version("0.8").Equals(ping_items[0].previous_version)); | |
1353 EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); | |
1354 EXPECT_EQ(0, ping_items[0].error_category); | |
1355 EXPECT_EQ(0, ping_items[0].error_code); | |
1356 EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); | |
1357 EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].previous_version)); | |
1358 EXPECT_TRUE(base::Version("2.0").Equals(ping_items[1].next_version)); | |
1359 EXPECT_TRUE(ping_items[1].diff_update_failed); | |
1360 EXPECT_EQ(1, ping_items[1].diff_error_category); // kNetworkError. | |
1361 EXPECT_EQ(-1, ping_items[1].diff_error_code); | |
1362 } | |
1363 }; | |
1364 | |
1365 scoped_ptr<FakePingManager> ping_manager(new FakePingManager(*config_)); | |
1366 scoped_ptr<UpdateClient> update_client(new UpdateClientImpl( | |
1367 config_, ping_manager.Pass(), &FakeUpdateChecker::Create, | |
1368 &FakeCrxDownloader::Create)); | |
1369 | |
1370 MockObserver observer; | |
1371 { | |
1372 InSequence seq; | |
1373 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
1374 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1375 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, | |
1376 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1377 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
1378 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1379 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, | |
1380 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1381 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, | |
1382 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1383 | |
1384 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, | |
1385 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1386 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, | |
1387 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1388 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
1389 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1390 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, | |
1391 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1392 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, | |
1393 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1394 EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, | |
1395 "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); | |
1396 } | |
1397 | |
1398 update_client->AddObserver(&observer); | |
1399 | |
1400 std::vector<std::string> ids; | |
1401 ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); | |
1402 | |
1403 { | |
1404 base::RunLoop runloop; | |
1405 update_client->Update( | |
1406 ids, base::Bind(&DataCallbackFake::Callback), | |
1407 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); | |
1408 runloop.Run(); | |
1409 } | |
1410 | |
1411 { | |
1412 base::RunLoop runloop; | |
1413 update_client->Update( | |
1414 ids, base::Bind(&DataCallbackFake::Callback), | |
1415 base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); | |
1416 runloop.Run(); | |
1417 } | |
1418 | |
1419 update_client->RemoveObserver(&observer); | |
1420 } | |
1421 | |
1422 } // namespace update_client | |
OLD | NEW |