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 "chrome/browser/extensions/updater/local_extension_cache.h" 6 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/test/sequenced_worker_pool_owner.h" 13 #include "base/values.h" 14 #include "chrome/common/extensions/extension_constants.h" 15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/test/test_browser_thread_bundle.h" 17 #include "content/public/test/test_utils.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace { 21 22 const char kTestExtensionId1[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 23 const char kTestExtensionId2[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; 24 const char kTestExtensionId3[] = "cccccccccccccccccccccccccccccccc"; 25 26 } // namespace 27 28 namespace extensions { 29 30 class LocalExtensionCacheTest : public testing::Test { 31 public: 32 LocalExtensionCacheTest() {} 33 virtual ~LocalExtensionCacheTest() {} 34 35 scoped_refptr<base::SequencedTaskRunner> background_task_runner() { 36 return background_task_runner_; 37 } 38 39 // testing::Test overrides: 40 virtual void SetUp() OVERRIDE { 41 pool_owner_.reset( 42 new base::SequencedWorkerPoolOwner(3, "Background Pool")); 43 background_task_runner_ = pool_owner_->pool()->GetSequencedTaskRunner( 44 pool_owner_->pool()->GetNamedSequenceToken("background")); 45 } 46 47 virtual void TearDown() OVERRIDE { 48 pool_owner_->pool()->Shutdown(); 49 base::RunLoop().RunUntilIdle(); 50 } 51 52 base::FilePath CreateCacheDir(bool initialized) { 53 EXPECT_TRUE(cache_dir_.CreateUniqueTempDir()); 54 if (initialized) 55 CreateFlagFile(cache_dir_.path()); 56 return cache_dir_.path(); 57 } 58 59 base::FilePath CreateTempDir() { 60 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); 61 return temp_dir_.path(); 62 } 63 64 void CreateFlagFile(const base::FilePath& dir) { 65 CreateFile(dir.Append( 66 extensions::LocalExtensionCache::kCacheReadyFlagFileName), 67 0, base::Time::Now()); 68 } 69 70 void CreateExtensionFile(const base::FilePath& dir, 71 const std::string& id, 72 const std::string& version, 73 size_t size, 74 const base::Time& timestamp) { 75 CreateFile(GetExtensionFileName(dir, id, version), size, timestamp); 76 } 77 78 void CreateFile(const base::FilePath& file, 79 size_t size, 80 const base::Time& timestamp) { 81 std::string data(size, 0); 82 EXPECT_EQ(base::WriteFile(file, data.data(), data.size()), int(size)); 83 EXPECT_TRUE(base::TouchFile(file, timestamp, timestamp)); 84 } 85 86 base::FilePath GetExtensionFileName(const base::FilePath& dir, 87 const std::string& id, 88 const std::string& version) { 89 return dir.Append(id + "-" + version + ".crx"); 90 } 91 92 void WaitForCompletion() { 93 // In the worst case you need to repeat this up to 3 times to make sure that 94 // all pending tasks we sent from UI thread to task runner and back to UI. 95 for (int i = 0; i < 3; i++) { 96 // Wait for background task completion that sends replay to UI thread. 97 pool_owner_->pool()->FlushForTesting(); 98 // Wait for UI thread task completion. 99 base::RunLoop().RunUntilIdle(); 100 } 101 } 102 103 private: 104 content::TestBrowserThreadBundle thread_bundle_; 105 106 scoped_ptr<base::SequencedWorkerPoolOwner> pool_owner_; 107 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; 108 109 base::ScopedTempDir cache_dir_; 110 base::ScopedTempDir temp_dir_; 111 112 DISALLOW_COPY_AND_ASSIGN(LocalExtensionCacheTest); 113 }; 114 115 static void SimpleCallback(bool* ptr) { 116 *ptr = true; 117 } 118 119 TEST_F(LocalExtensionCacheTest, Basic) { 120 base::FilePath cache_dir(CreateCacheDir(false)); 121 122 LocalExtensionCache cache(cache_dir, 123 1000, 124 base::TimeDelta::FromDays(30), 125 background_task_runner()); 126 cache.SetCacheStatusPollingDelayForTests(base::TimeDelta()); 127 128 bool initialized = false; 129 cache.Init(true, base::Bind(&SimpleCallback, &initialized)); 130 131 WaitForCompletion(); 132 EXPECT_FALSE(initialized); 133 134 CreateExtensionFile(cache_dir, kTestExtensionId1, "1.0", 100, 135 base::Time::Now() - base::TimeDelta::FromDays(1)); 136 CreateExtensionFile(cache_dir, kTestExtensionId1, "0.1", 100, 137 base::Time::Now() - base::TimeDelta::FromDays(10)); 138 CreateExtensionFile(cache_dir, kTestExtensionId2, "2.0", 100, 139 base::Time::Now() - base::TimeDelta::FromDays(40)); 140 CreateExtensionFile(cache_dir, kTestExtensionId3, "3.0", 900, 141 base::Time::Now() - base::TimeDelta::FromDays(41)); 142 143 CreateFlagFile(cache_dir); 144 145 WaitForCompletion(); 146 ASSERT_TRUE(initialized); 147 148 // Older version should be removed on cache initialization. 149 EXPECT_FALSE(base::PathExists( 150 GetExtensionFileName(cache_dir, kTestExtensionId1, "0.1"))); 151 152 // All extensions should be there because cleanup happens on shutdown to 153 // support use case when device was not used to more than 30 days and cache 154 // shouldn't be cleaned before someone will have a chance to use it. 155 EXPECT_TRUE(cache.GetExtension(kTestExtensionId1, NULL, NULL)); 156 EXPECT_TRUE(cache.GetExtension(kTestExtensionId2, NULL, NULL)); 157 EXPECT_TRUE(cache.GetExtension(kTestExtensionId3, NULL, NULL)); 158 159 bool did_shutdown = false; 160 cache.Shutdown(base::Bind(&SimpleCallback, &did_shutdown)); 161 WaitForCompletion(); 162 ASSERT_TRUE(did_shutdown); 163 164 EXPECT_TRUE(base::PathExists( 165 GetExtensionFileName(cache_dir, kTestExtensionId1, "1.0"))); 166 EXPECT_FALSE(base::PathExists( 167 GetExtensionFileName(cache_dir, kTestExtensionId2, "2.0"))); 168 EXPECT_FALSE(base::PathExists( 169 GetExtensionFileName(cache_dir, kTestExtensionId3, "3.0"))); 170 } 171 172 } // namespace extensions 173