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.
7 #include "base/callback_forward.h"
8 #include "base/threading/sequenced_worker_pool.h"
9 #include "chrome/browser/extensions/app_data_migrator.h"
10 #include "chrome/browser/extensions/extension_special_storage_policy.h"
11 #include "chrome/test/base/testing_profile.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/indexed_db_context.h"
14 #include "content/public/browser/storage_partition.h"
15 #include "content/public/test/mock_blob_url_request_context.h"
16 #include "content/public/test/test_browser_thread_bundle.h"
17 #include "extensions/browser/extension_registry.h"
18 #include "extensions/common/extension.h"
19 #include "extensions/common/extension_builder.h"
20 #include "extensions/common/manifest.h"
21 #include "storage/browser/fileapi/file_system_context.h"
22 #include "storage/browser/fileapi/file_system_operation_runner.h"
23 #include "storage/browser/fileapi/file_system_url.h"
24 #include "testing/gtest/include/gtest/gtest.h"
27 scoped_ptr
<TestingProfile
> GetTestingProfile() {
28 TestingProfile::Builder profile_builder
;
29 return profile_builder
.Build();
33 namespace extensions
{
35 class AppDataMigratorTest
: public testing::Test
{
38 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
) {}
40 void SetUp() override
{
41 profile_
= GetTestingProfile();
42 registry_
= ExtensionRegistry::Get(profile_
.get());
43 migrator_
= scoped_ptr
<AppDataMigrator
>(
44 new AppDataMigrator(profile_
.get(), registry_
));
47 content::BrowserContext::GetDefaultStoragePartition(profile_
.get());
49 idb_context_
= default_partition_
->GetIndexedDBContext();
50 idb_context_
->SetTaskRunnerForTesting(
51 base::MessageLoop::current()->task_runner().get());
53 default_fs_context_
= default_partition_
->GetFileSystemContext();
55 url_request_context_
= scoped_ptr
<content::MockBlobURLRequestContext
>(
56 new content::MockBlobURLRequestContext(default_fs_context_
));
59 void TearDown() override
{}
62 content::TestBrowserThreadBundle thread_bundle_
;
63 scoped_ptr
<TestingProfile
> profile_
;
64 scoped_ptr
<AppDataMigrator
> migrator_
;
65 content::StoragePartition
* default_partition_
;
66 ExtensionRegistry
* registry_
;
67 storage::FileSystemContext
* default_fs_context_
;
68 content::IndexedDBContext
* idb_context_
;
69 scoped_ptr
<content::MockBlobURLRequestContext
> url_request_context_
;
72 scoped_refptr
<const Extension
> GetTestExtension(bool platform_app
) {
73 scoped_refptr
<const Extension
> app
;
75 app
= ExtensionBuilder()
78 .Set("name", "test app")
80 .Set("app", DictionaryBuilder().Set(
82 DictionaryBuilder().Set(
83 "scripts", ListBuilder().Append(
86 ListBuilder().Append("unlimitedStorage")))
89 app
= ExtensionBuilder()
90 .SetManifest(DictionaryBuilder()
91 .Set("name", "test app")
93 .Set("app", DictionaryBuilder().Set(
95 DictionaryBuilder().Set(
96 "local_path", "index.html")))
98 ListBuilder().Append("unlimitedStorage")))
104 void MigrationCallback() {
107 void DidWrite(base::File::Error status
, int64 bytes
, bool complete
) {
108 base::MessageLoop::current()->Quit();
111 void DidCreate(base::File::Error status
) {
114 void DidOpenFileSystem(const GURL
& root
,
115 const std::string
& name
,
116 base::File::Error result
) {
119 void OpenFileSystems(storage::FileSystemContext
* fs_context
,
120 GURL extension_url
) {
121 fs_context
->OpenFileSystem(extension_url
, storage::kFileSystemTypeTemporary
,
122 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT
,
123 base::Bind(&DidOpenFileSystem
));
125 fs_context
->OpenFileSystem(extension_url
, storage::kFileSystemTypePersistent
,
126 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT
,
127 base::Bind(&DidOpenFileSystem
));
128 base::MessageLoop::current()->RunUntilIdle();
131 void GenerateTestFiles(content::MockBlobURLRequestContext
* url_request_context
,
132 const Extension
* ext
,
133 storage::FileSystemContext
* fs_context
,
135 profile
->GetExtensionSpecialStoragePolicy()->GrantRightsForExtension(ext
,
138 base::FilePath
path(FILE_PATH_LITERAL("test.txt"));
140 extensions::Extension::GetBaseURLFromExtensionId(ext
->id());
142 OpenFileSystems(fs_context
, extension_url
);
144 storage::FileSystemURL fs_temp_url
= fs_context
->CreateCrackedFileSystemURL(
145 extension_url
, storage::kFileSystemTypeTemporary
, path
);
147 storage::FileSystemURL fs_persistent_url
=
148 fs_context
->CreateCrackedFileSystemURL(
149 extension_url
, storage::kFileSystemTypePersistent
, path
);
151 content::ScopedTextBlob
blob1(*url_request_context
, "blob-id:success1",
154 fs_context
->operation_runner()->CreateFile(fs_temp_url
, false,
155 base::Bind(&DidCreate
));
157 fs_context
->operation_runner()->CreateFile(fs_persistent_url
, false,
158 base::Bind(&DidCreate
));
159 base::MessageLoop::current()->RunUntilIdle();
161 fs_context
->operation_runner()->Write(url_request_context
, fs_temp_url
,
162 blob1
.GetBlobDataHandle(), 0,
163 base::Bind(&DidWrite
));
164 base::MessageLoop::current()->Run();
165 fs_context
->operation_runner()->Write(url_request_context
, fs_persistent_url
,
166 blob1
.GetBlobDataHandle(), 0,
167 base::Bind(&DidWrite
));
168 base::MessageLoop::current()->Run();
171 void VerifyFileContents(base::File file
,
172 const base::Closure
& on_close_callback
) {
173 ASSERT_EQ(14, file
.GetLength());
174 scoped_ptr
<char[]> buffer(new char[15]);
176 file
.Read(0, buffer
.get(), 14);
177 buffer
.get()[14] = 0;
179 std::string expected
= "Hello, world!\n";
180 std::string actual
= buffer
.get();
181 EXPECT_EQ(expected
, actual
);
184 if (!on_close_callback
.is_null())
185 on_close_callback
.Run();
186 base::MessageLoop::current()->Quit();
189 void VerifyTestFilesMigrated(content::StoragePartition
* new_partition
,
190 const Extension
* new_ext
) {
192 extensions::Extension::GetBaseURLFromExtensionId(new_ext
->id());
193 storage::FileSystemContext
* new_fs_context
=
194 new_partition
->GetFileSystemContext();
196 OpenFileSystems(new_fs_context
, extension_url
);
198 base::FilePath
path(FILE_PATH_LITERAL("test.txt"));
200 storage::FileSystemURL fs_temp_url
=
201 new_fs_context
->CreateCrackedFileSystemURL(
202 extension_url
, storage::kFileSystemTypeTemporary
, path
);
203 storage::FileSystemURL fs_persistent_url
=
204 new_fs_context
->CreateCrackedFileSystemURL(
205 extension_url
, storage::kFileSystemTypePersistent
, path
);
207 new_fs_context
->operation_runner()->OpenFile(
208 fs_temp_url
, base::File::FLAG_READ
| base::File::FLAG_OPEN
,
209 base::Bind(&VerifyFileContents
));
210 base::MessageLoop::current()->Run();
211 new_fs_context
->operation_runner()->OpenFile(
212 fs_persistent_url
, base::File::FLAG_READ
| base::File::FLAG_OPEN
,
213 base::Bind(&VerifyFileContents
));
214 base::MessageLoop::current()->Run();
217 TEST_F(AppDataMigratorTest
, ShouldMigrate
) {
218 scoped_refptr
<const Extension
> old_ext
= GetTestExtension(false);
219 scoped_refptr
<const Extension
> new_ext
= GetTestExtension(true);
221 EXPECT_TRUE(AppDataMigrator::NeedsMigration(old_ext
.get(), new_ext
.get()));
224 TEST_F(AppDataMigratorTest
, ShouldNotMigratePlatformApp
) {
225 scoped_refptr
<const Extension
> old_ext
= GetTestExtension(true);
226 scoped_refptr
<const Extension
> new_ext
= GetTestExtension(true);
228 EXPECT_FALSE(AppDataMigrator::NeedsMigration(old_ext
.get(), new_ext
.get()));
231 TEST_F(AppDataMigratorTest
, ShouldNotMigrateLegacyApp
) {
232 scoped_refptr
<const Extension
> old_ext
= GetTestExtension(false);
233 scoped_refptr
<const Extension
> new_ext
= GetTestExtension(false);
235 EXPECT_FALSE(AppDataMigrator::NeedsMigration(old_ext
.get(), new_ext
.get()));
238 TEST_F(AppDataMigratorTest
, NoOpMigration
) {
239 scoped_refptr
<const Extension
> old_ext
= GetTestExtension(false);
240 scoped_refptr
<const Extension
> new_ext
= GetTestExtension(true);
242 // Nothing to migrate. Basically this should just not cause an error
243 migrator_
->DoMigrationAndReply(old_ext
.get(), new_ext
.get(),
244 base::Bind(&MigrationCallback
));
247 TEST_F(AppDataMigratorTest
, FileSystemMigration
) {
248 scoped_refptr
<const Extension
> old_ext
= GetTestExtension(false);
249 scoped_refptr
<const Extension
> new_ext
= GetTestExtension(true);
251 GenerateTestFiles(url_request_context_
.get(), old_ext
.get(),
252 default_fs_context_
, profile_
.get());
254 migrator_
->DoMigrationAndReply(old_ext
.get(), new_ext
.get(),
255 base::Bind(&MigrationCallback
));
257 base::MessageLoop::current()->RunUntilIdle();
259 registry_
->AddEnabled(new_ext
);
261 extensions::Extension::GetBaseURLFromExtensionId(new_ext
->id());
263 content::StoragePartition
* new_partition
=
264 content::BrowserContext::GetStoragePartitionForSite(profile_
.get(),
267 ASSERT_NE(new_partition
->GetPath(), default_partition_
->GetPath());
269 VerifyTestFilesMigrated(new_partition
, new_ext
.get());
272 } // namespace extensions