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