Rename GetIconID to GetIconId
[chromium-blink-merge.git] / chrome / browser / extensions / updater / local_extension_cache_unittest.cc
blob3fe8a2b0df09c4a3ee59589f564a9c7da4b6c5d4
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.
5 #include "chrome/browser/extensions/updater/local_extension_cache.h"
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/test/sequenced_worker_pool_owner.h"
15 #include "base/values.h"
16 #include "chrome/common/extensions/extension_constants.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/test/test_browser_thread_bundle.h"
19 #include "content/public/test/test_utils.h"
20 #include "crypto/secure_hash.h"
21 #include "crypto/sha2.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 namespace {
26 const char kTestExtensionId1[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
27 const char kTestExtensionId2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
28 const char kTestExtensionId3[] = "cccccccccccccccccccccccccccccccc";
30 } // namespace
32 namespace extensions {
34 class LocalExtensionCacheTest : public testing::Test {
35 public:
36 LocalExtensionCacheTest() {}
37 ~LocalExtensionCacheTest() override {}
39 scoped_refptr<base::SequencedTaskRunner> background_task_runner() {
40 return background_task_runner_;
43 // testing::Test overrides:
44 void SetUp() override {
45 pool_owner_.reset(
46 new base::SequencedWorkerPoolOwner(3, "Background Pool"));
47 background_task_runner_ = pool_owner_->pool()->GetSequencedTaskRunner(
48 pool_owner_->pool()->GetNamedSequenceToken("background"));
51 void TearDown() override {
52 pool_owner_->pool()->Shutdown();
53 base::RunLoop().RunUntilIdle();
56 base::FilePath CreateCacheDir(bool initialized) {
57 EXPECT_TRUE(cache_dir_.CreateUniqueTempDir());
58 if (initialized)
59 CreateFlagFile(cache_dir_.path());
60 return cache_dir_.path();
63 base::FilePath CreateTempDir() {
64 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
65 return temp_dir_.path();
68 void CreateFlagFile(const base::FilePath& dir) {
69 CreateFile(dir.Append(
70 extensions::LocalExtensionCache::kCacheReadyFlagFileName),
71 0, base::Time::Now());
74 void CreateExtensionFile(const base::FilePath& dir,
75 const std::string& id,
76 const std::string& version,
77 size_t size,
78 const base::Time& timestamp,
79 base::FilePath* filename) {
80 const base::FilePath file = GetExtensionFileName(dir, id, version, "");
81 if (filename)
82 *filename = file;
83 CreateFile(file, size, timestamp);
86 void CreateFile(const base::FilePath& file,
87 size_t size,
88 const base::Time& timestamp) {
89 std::string data(size, 0);
90 EXPECT_EQ(base::WriteFile(file, data.data(), data.size()), int(size));
91 EXPECT_TRUE(base::TouchFile(file, timestamp, timestamp));
94 std::string CreateSignedExtensionFile(const base::FilePath& dir,
95 const std::string& id,
96 const std::string& version,
97 size_t size,
98 const base::Time& timestamp,
99 base::FilePath* filename) {
100 std::string data(size, 0);
102 crypto::SecureHash* hash =
103 crypto::SecureHash::Create(crypto::SecureHash::SHA256);
104 hash->Update(data.c_str(), size);
105 uint8 output[crypto::kSHA256Length];
106 hash->Finish(output, sizeof(output));
107 const std::string hex_hash =
108 base::ToLowerASCII(base::HexEncode(output, sizeof(output)));
109 delete hash;
111 const base::FilePath file =
112 GetExtensionFileName(dir, id, version, hex_hash);
113 if (filename)
114 *filename = file;
115 EXPECT_EQ(base::WriteFile(file, data.data(), data.size()), int(size));
116 EXPECT_TRUE(base::TouchFile(file, timestamp, timestamp));
118 return hex_hash;
121 base::FilePath GetExtensionFileName(const base::FilePath& dir,
122 const std::string& id,
123 const std::string& version,
124 const std::string& hash) {
125 return dir.Append(
126 extensions::LocalExtensionCache::ExtensionFileName(id, version, hash));
129 void WaitForCompletion() {
130 // In the worst case you need to repeat this up to 3 times to make sure that
131 // all pending tasks we sent from UI thread to task runner and back to UI.
132 for (int i = 0; i < 3; i++) {
133 // Wait for background task completion that sends replay to UI thread.
134 pool_owner_->pool()->FlushForTesting();
135 // Wait for UI thread task completion.
136 base::RunLoop().RunUntilIdle();
140 private:
141 content::TestBrowserThreadBundle thread_bundle_;
143 scoped_ptr<base::SequencedWorkerPoolOwner> pool_owner_;
144 scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
146 base::ScopedTempDir cache_dir_;
147 base::ScopedTempDir temp_dir_;
149 DISALLOW_COPY_AND_ASSIGN(LocalExtensionCacheTest);
152 static void SimpleCallback(bool* ptr) {
153 *ptr = true;
156 TEST_F(LocalExtensionCacheTest, Basic) {
157 base::FilePath cache_dir(CreateCacheDir(false));
159 LocalExtensionCache cache(cache_dir,
160 1000,
161 base::TimeDelta::FromDays(30),
162 background_task_runner());
163 cache.SetCacheStatusPollingDelayForTests(base::TimeDelta());
165 bool initialized = false;
166 cache.Init(true, base::Bind(&SimpleCallback, &initialized));
168 WaitForCompletion();
169 EXPECT_FALSE(initialized);
171 base::FilePath file10, file01, file20, file30;
172 CreateExtensionFile(cache_dir, kTestExtensionId1, "1.0", 100,
173 base::Time::Now() - base::TimeDelta::FromDays(1),
174 &file10);
175 CreateExtensionFile(cache_dir, kTestExtensionId1, "0.1", 100,
176 base::Time::Now() - base::TimeDelta::FromDays(10),
177 &file01);
178 CreateExtensionFile(cache_dir, kTestExtensionId2, "2.0", 100,
179 base::Time::Now() - base::TimeDelta::FromDays(40),
180 &file20);
181 CreateExtensionFile(cache_dir, kTestExtensionId3, "3.0", 900,
182 base::Time::Now() - base::TimeDelta::FromDays(41),
183 &file30);
185 CreateFlagFile(cache_dir);
187 WaitForCompletion();
188 ASSERT_TRUE(initialized);
190 // Older version should be removed on cache initialization.
191 EXPECT_FALSE(base::PathExists(file01));
193 // All extensions should be there because cleanup happens on shutdown to
194 // support use case when device was not used to more than 30 days and cache
195 // shouldn't be cleaned before someone will have a chance to use it.
196 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, "", NULL, NULL));
197 EXPECT_TRUE(cache.GetExtension(kTestExtensionId2, "", NULL, NULL));
198 EXPECT_TRUE(cache.GetExtension(kTestExtensionId3, "", NULL, NULL));
200 bool did_shutdown = false;
201 cache.Shutdown(base::Bind(&SimpleCallback, &did_shutdown));
202 WaitForCompletion();
203 ASSERT_TRUE(did_shutdown);
205 EXPECT_TRUE(base::PathExists(file10));
206 EXPECT_FALSE(base::PathExists(file20));
207 EXPECT_FALSE(base::PathExists(file30));
210 TEST_F(LocalExtensionCacheTest, KeepHashed) {
211 base::FilePath cache_dir(CreateCacheDir(false));
213 LocalExtensionCache cache(cache_dir, 1000, base::TimeDelta::FromDays(30),
214 background_task_runner());
215 cache.SetCacheStatusPollingDelayForTests(base::TimeDelta());
217 bool initialized = false;
218 cache.Init(true, base::Bind(&SimpleCallback, &initialized));
220 WaitForCompletion();
221 EXPECT_FALSE(initialized);
223 // Add three identical extensions with different hash sums
224 const base::Time time = base::Time::Now() - base::TimeDelta::FromDays(1);
225 base::FilePath file, file1, file2;
226 CreateExtensionFile(cache_dir, kTestExtensionId1, "1.0", 100, time, &file);
227 const std::string hash1 = CreateSignedExtensionFile(
228 cache_dir, kTestExtensionId1, "1.0", 100, time, &file1);
229 const std::string hash2 = CreateSignedExtensionFile(
230 cache_dir, kTestExtensionId1, "1.0", 123, time, &file2);
232 CreateFlagFile(cache_dir);
234 WaitForCompletion();
235 ASSERT_TRUE(initialized);
237 // Unhashed version should be removed on cache initialization.
238 EXPECT_FALSE(base::PathExists(file));
239 // Both hashed versions should stay
240 EXPECT_TRUE(base::PathExists(file1));
241 EXPECT_TRUE(base::PathExists(file2));
243 // We should be able to lookup all three extension queries
244 std::string version;
245 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, "", NULL, &version));
246 EXPECT_EQ(version, "1.0");
247 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash1, NULL, NULL));
248 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash2, NULL, NULL));
251 TEST_F(LocalExtensionCacheTest, KeepLatest) {
252 base::FilePath cache_dir(CreateCacheDir(false));
254 LocalExtensionCache cache(cache_dir, 1000, base::TimeDelta::FromDays(30),
255 background_task_runner());
256 cache.SetCacheStatusPollingDelayForTests(base::TimeDelta());
258 bool initialized = false;
259 cache.Init(true, base::Bind(&SimpleCallback, &initialized));
261 WaitForCompletion();
262 EXPECT_FALSE(initialized);
264 // All extension files are hashed, but have different versions
265 const base::Time time = base::Time::Now() - base::TimeDelta::FromDays(1);
266 base::FilePath file1, file21, file22;
267 const std::string hash1 = CreateSignedExtensionFile(
268 cache_dir, kTestExtensionId1, "1.0", 100, time, &file1);
269 const std::string hash21 = CreateSignedExtensionFile(
270 cache_dir, kTestExtensionId1, "2.0", 101, time, &file21);
271 const std::string hash22 = CreateSignedExtensionFile(
272 cache_dir, kTestExtensionId1, "2.0", 123, time, &file22);
274 CreateFlagFile(cache_dir);
276 WaitForCompletion();
277 ASSERT_TRUE(initialized);
279 // Older version should be removed
280 EXPECT_FALSE(base::PathExists(file1));
281 // Both newer hashed versions should stay
282 EXPECT_TRUE(base::PathExists(file21));
283 EXPECT_TRUE(base::PathExists(file22));
285 // We should be able to lookup only the latest version queries
286 EXPECT_FALSE(cache.GetExtension(kTestExtensionId1, hash1, NULL, NULL));
287 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash21, NULL, NULL));
288 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash22, NULL, NULL));
291 TEST_F(LocalExtensionCacheTest, Complex) {
292 base::FilePath cache_dir(CreateCacheDir(false));
294 LocalExtensionCache cache(cache_dir, 1000, base::TimeDelta::FromDays(30),
295 background_task_runner());
296 cache.SetCacheStatusPollingDelayForTests(base::TimeDelta());
298 bool initialized = false;
299 cache.Init(true, base::Bind(&SimpleCallback, &initialized));
301 WaitForCompletion();
302 EXPECT_FALSE(initialized);
304 // Like in KeepHashed test, but with two different versions
305 const base::Time time = base::Time::Now() - base::TimeDelta::FromDays(1);
306 base::FilePath file1, file11, file12, file2, file21, file22;
307 CreateExtensionFile(cache_dir, kTestExtensionId1, "1.0", 100, time, &file1);
308 const std::string hash11 = CreateSignedExtensionFile(
309 cache_dir, kTestExtensionId1, "1.0", 101, time, &file11);
310 const std::string hash12 = CreateSignedExtensionFile(
311 cache_dir, kTestExtensionId1, "1.0", 102, time, &file12);
312 CreateExtensionFile(cache_dir, kTestExtensionId1, "2.0", 103, time, &file2);
313 const std::string hash21 = CreateSignedExtensionFile(
314 cache_dir, kTestExtensionId1, "2.0", 104, time, &file21);
315 const std::string hash22 = CreateSignedExtensionFile(
316 cache_dir, kTestExtensionId1, "2.0", 105, time, &file22);
318 CreateFlagFile(cache_dir);
320 WaitForCompletion();
321 ASSERT_TRUE(initialized);
323 // Older and unhashed versions should be removed
324 EXPECT_FALSE(base::PathExists(file1));
325 EXPECT_FALSE(base::PathExists(file11));
326 EXPECT_FALSE(base::PathExists(file12));
327 EXPECT_FALSE(base::PathExists(file2));
328 // Newest hashed versions should stay
329 EXPECT_TRUE(base::PathExists(file21));
330 EXPECT_TRUE(base::PathExists(file22));
332 // We should be able to lookup only the latest version queries, both with and
333 // without hash
334 std::string version;
335 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, "", NULL, &version));
336 EXPECT_EQ(version, "2.0");
337 EXPECT_FALSE(cache.GetExtension(kTestExtensionId1, hash11, NULL, NULL));
338 EXPECT_FALSE(cache.GetExtension(kTestExtensionId1, hash12, NULL, NULL));
339 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash21, NULL, NULL));
340 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash22, NULL, NULL));
343 static void OnPutExtension(scoped_ptr<base::RunLoop>* run_loop,
344 const base::FilePath& file_path,
345 bool file_ownership_passed) {
346 ASSERT_TRUE(*run_loop);
347 (*run_loop)->Quit();
350 static void PutExtensionAndWait(LocalExtensionCache& cache,
351 const std::string& id,
352 const std::string& expected_hash,
353 const base::FilePath& path,
354 const std::string& version) {
355 scoped_ptr<base::RunLoop> run_loop;
356 run_loop.reset(new base::RunLoop);
357 cache.PutExtension(id, expected_hash, path, version,
358 base::Bind(&OnPutExtension, &run_loop));
359 run_loop->Run();
362 TEST_F(LocalExtensionCacheTest, PutExtensionCases) {
363 base::FilePath cache_dir(CreateCacheDir(false));
365 LocalExtensionCache cache(cache_dir, 1000, base::TimeDelta::FromDays(30),
366 background_task_runner());
367 cache.SetCacheStatusPollingDelayForTests(base::TimeDelta());
369 bool initialized = false;
370 cache.Init(true, base::Bind(&SimpleCallback, &initialized));
372 WaitForCompletion();
373 EXPECT_FALSE(initialized);
375 // Initialize cache with several different files
376 const base::Time time = base::Time::Now() - base::TimeDelta::FromDays(1);
377 base::FilePath file11, file12, file2, file3;
378 const std::string hash11 = CreateSignedExtensionFile(
379 cache_dir, kTestExtensionId1, "1.0", 101, time, &file11);
380 const std::string hash12 = CreateSignedExtensionFile(
381 cache_dir, kTestExtensionId1, "1.0", 102, time, &file12);
382 CreateSignedExtensionFile(cache_dir, kTestExtensionId2, "0.2", 200, time,
383 &file2);
384 CreateExtensionFile(cache_dir, kTestExtensionId3, "0.3", 300, time, &file3);
386 CreateFlagFile(cache_dir);
388 WaitForCompletion();
389 ASSERT_TRUE(initialized);
391 // Create and initialize installation source directory.
392 base::ScopedTempDir temp_dir;
393 EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
394 const base::FilePath temp_path = temp_dir.path();
395 std::string version;
397 // Right now we have two files for the first extension
398 EXPECT_TRUE(base::PathExists(file11));
399 EXPECT_TRUE(base::PathExists(file12));
400 EXPECT_TRUE(base::PathExists(file2));
401 EXPECT_TRUE(base::PathExists(file3));
403 // 1. Cache contains an older version
404 base::FilePath temp1;
405 CreateExtensionFile(temp_path, kTestExtensionId1, "3.0", 110, time, &temp1);
406 PutExtensionAndWait(cache, kTestExtensionId1, "", temp1, "3.0");
407 // New file added
408 const base::FilePath unhashed =
409 GetExtensionFileName(cache_dir, kTestExtensionId1, "3.0", "");
410 EXPECT_TRUE(base::PathExists(unhashed));
411 // Old files removed from cache (kept in the directory though)
412 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash11, NULL, &version));
413 EXPECT_EQ(version, "3.0");
414 EXPECT_TRUE(base::DeleteFile(temp1, false));
416 // 2. Cache contains a newer version
417 base::FilePath temp2;
418 CreateExtensionFile(temp_path, kTestExtensionId1, "2.0", 120, time, &temp2);
419 PutExtensionAndWait(cache, kTestExtensionId1, "", temp2, "2.0");
420 // New file skipped
421 EXPECT_FALSE(base::PathExists(
422 GetExtensionFileName(cache_dir, kTestExtensionId1, "2.0", "")));
423 // Old file kept
424 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, "", NULL, &version));
425 EXPECT_EQ(version, "3.0");
426 EXPECT_TRUE(base::DeleteFile(temp2, false));
428 // 3. Cache contains the same version without hash, our file is unhashed
429 base::FilePath temp3;
430 CreateExtensionFile(temp_path, kTestExtensionId1, "3.0", 130, time, &temp3);
431 PutExtensionAndWait(cache, kTestExtensionId1, "", temp3, "3.0");
432 // New file skipped, old file kept
433 EXPECT_EQ(base::File(unhashed, base::File::FLAG_READ | base::File::FLAG_OPEN)
434 .GetLength(),
435 110);
436 EXPECT_TRUE(base::DeleteFile(temp3, false));
438 // 4. Cache contains the same version without hash, our file is hashed
439 base::FilePath temp4;
440 const std::string hash3 = CreateSignedExtensionFile(
441 temp_path, kTestExtensionId1, "3.0", 140, time, &temp4);
442 PutExtensionAndWait(cache, kTestExtensionId1, hash3, temp4, "3.0");
443 // New file added
444 const base::FilePath hashed =
445 GetExtensionFileName(cache_dir, kTestExtensionId1, "3.0", hash3);
446 EXPECT_TRUE(base::PathExists(hashed));
447 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash3, NULL, NULL));
448 // Old file removed (queries return hashed version)
449 base::FilePath unhashed_path;
450 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, "", &unhashed_path, NULL));
451 EXPECT_EQ(unhashed_path, hashed);
452 EXPECT_TRUE(base::DeleteFile(temp4, false));
453 EXPECT_TRUE(base::DeleteFile(unhashed, false));
455 // 5. Cache contains the same version with hash, our file is unhashed
456 base::FilePath temp5;
457 CreateExtensionFile(temp_path, kTestExtensionId1, "3.0", 150, time, &temp5);
458 PutExtensionAndWait(cache, kTestExtensionId1, "", temp5, "3.0");
459 // New file skipped
460 EXPECT_FALSE(base::PathExists(unhashed));
461 // Old file kept
462 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash3, NULL, NULL));
463 EXPECT_TRUE(base::DeleteFile(temp5, false));
465 // 6. Cache contains the same version with hash, our file has the "same" hash
466 base::FilePath temp6;
467 CreateExtensionFile(temp_path, kTestExtensionId1, "3.0", 160, time, &temp6);
468 PutExtensionAndWait(cache, kTestExtensionId1, hash3, temp6, "3.0");
469 // New file skipped, old file kept
470 EXPECT_EQ(base::File(hashed, base::File::FLAG_READ | base::File::FLAG_OPEN)
471 .GetLength(),
472 140);
473 EXPECT_TRUE(base::DeleteFile(temp6, false));
475 // 7. Cache contains the same version with hash, our file is different
476 base::FilePath temp7;
477 const std::string hash4 = CreateSignedExtensionFile(
478 temp_path, kTestExtensionId1, "3.0", 170, time, &temp7);
479 PutExtensionAndWait(cache, kTestExtensionId1, hash4, temp7, "3.0");
480 // New file addded
481 const base::FilePath hashed2 =
482 GetExtensionFileName(cache_dir, kTestExtensionId1, "3.0", hash4);
483 EXPECT_TRUE(base::PathExists(hashed2));
484 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash4, NULL, NULL));
485 // Old file kept
486 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, hash3, NULL, NULL));
487 EXPECT_TRUE(base::DeleteFile(temp7, false));
490 } // namespace extensions