blob: a42299b99cdb96c6ea2436fd164bffb982726d52 [file] [log] [blame]
// Copyright 2017 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 "extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl.h"
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "crypto/symmetric_key.h"
#include "extensions/browser/api/lock_screen_data/data_item.h"
#include "extensions/browser/api/lock_screen_data/operation_result.h"
#include "extensions/browser/api/storage/backend_task_runner.h"
#include "extensions/browser/api/storage/local_value_store_cache.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/test_extensions_browser_client.h"
#include "extensions/browser/value_store/test_value_store_factory.h"
#include "extensions/browser/value_store/testing_value_store.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/value_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
namespace lock_screen_data {
namespace {
constexpr char kFirstExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
constexpr char kSecondExtensionId[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
constexpr char kThirdExtensionId[] = "cccccccccccccccccccccccccccccccc";
void ExpectNotRun(const std::string& message) {
ADD_FAILURE() << "Unexpectedly run: " << message;
}
void WriteCallback(const base::Closure& callback,
OperationResult* result_out,
OperationResult result) {
*result_out = result;
callback.Run();
}
void ReadCallback(const base::Closure& callback,
OperationResult* result_out,
std::unique_ptr<std::vector<char>>* content_out,
OperationResult result,
std::unique_ptr<std::vector<char>> content) {
*result_out = result;
*content_out = std::move(content);
callback.Run();
}
void GetRegisteredItemsCallback(
const base::Closure& callback,
OperationResult* result_out,
std::unique_ptr<base::DictionaryValue>* value_out,
OperationResult result,
std::unique_ptr<base::DictionaryValue> value) {
*result_out = result;
*value_out = std::move(value);
callback.Run();
}
} // namespace
class LockScreenValueStoreMigratorImplTest : public testing::Test {
public:
LockScreenValueStoreMigratorImplTest() = default;
~LockScreenValueStoreMigratorImplTest() override = default;
void SetUp() override {
task_runner_ = GetBackendTaskRunner();
context_ = std::make_unique<content::TestBrowserContext>();
extensions_browser_client_ =
std::make_unique<TestExtensionsBrowserClient>(context_.get());
BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(
context_.get());
ExtensionsBrowserClient::Set(extensions_browser_client_.get());
source_value_store_factory_ = base::MakeRefCounted<TestValueStoreFactory>();
source_value_store_cache_ =
std::make_unique<LocalValueStoreCache>(source_value_store_factory_);
target_value_store_factory_ = base::MakeRefCounted<TestValueStoreFactory>();
target_value_store_cache_ =
std::make_unique<LocalValueStoreCache>(target_value_store_factory_);
migrator_crypto_key_ = GenerateKey("password");
migrator_ = std::make_unique<LockScreenValueStoreMigratorImpl>(
context_.get(), source_value_store_cache_.get(),
target_value_store_cache_.get(), task_runner_.get(),
migrator_crypto_key_);
}
void TearDown() override {
TearDownValueStoreCache();
BrowserContextDependencyManager::GetInstance()
->DestroyBrowserContextServices(context_.get());
ExtensionsBrowserClient::Set(nullptr);
extensions_browser_client_.reset();
context_.reset();
}
protected:
struct TestItemData {
std::string id;
ExtensionId extension_id;
std::string crypto_key;
std::vector<char> content;
};
enum class StorageType { SOURCE, TARGET };
void RunMigrator(const std::set<ExtensionId>& extensions_to_migrate) {
migrator_->Run(
extensions_to_migrate,
base::Bind(&LockScreenValueStoreMigratorImplTest::OnExtensionMigrated,
base::Unretained(this)));
}
std::string GenerateKey(const std::string& password) {
std::unique_ptr<crypto::SymmetricKey> key =
crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
crypto::SymmetricKey::AES, password, "salt", 1000, 256);
if (!key) {
ADD_FAILURE() << "Failed to create symmetric key";
return std::string();
}
return key->key();
}
bool InitializeStorage(StorageType storage_type,
const std::vector<TestItemData>& items) {
ValueStoreCache* storage = storage_type == StorageType::SOURCE
? source_value_store_cache_.get()
: target_value_store_cache_.get();
for (const auto& item : items) {
auto data_item = std::make_unique<DataItem>(
item.id, item.extension_id, context_.get(), storage,
task_runner_.get(), item.crypto_key);
if (RegisterDataItem(data_item.get()) != OperationResult::kSuccess) {
ADD_FAILURE() << "Register " << item.id;
return false;
}
if (WriteToDataItem(data_item.get(), item.content) !=
OperationResult::kSuccess) {
ADD_FAILURE() << "Write " << item.id;
return false;
}
}
return true;
}
std::vector<std::vector<char>> GetItemContent(
StorageType storage_type,
std::vector<std::string> item_ids,
const ExtensionId& extension_id,
const std::string& crypto_key) {
ValueStoreCache* storage = storage_type == StorageType::SOURCE
? source_value_store_cache_.get()
: target_value_store_cache_.get();
std::vector<std::vector<char>> items;
for (const auto& item_id : item_ids) {
auto data_item =
std::make_unique<DataItem>(item_id, extension_id, context_.get(),
storage, task_runner_.get(), crypto_key);
std::unique_ptr<std::vector<char>> data;
OperationResult read_result = ReadDataItem(data_item.get(), &data);
if (read_result == OperationResult::kSuccess) {
items.emplace_back();
items.back().swap(*data);
} else {
ADD_FAILURE() << "Reading " << item_id << " failed "
<< static_cast<int>(read_result);
}
}
return items;
}
OperationResult RegisterDataItem(DataItem* item) {
base::RunLoop run_loop;
OperationResult result = OperationResult::kFailed;
item->Register(base::Bind(&WriteCallback, run_loop.QuitClosure(), &result));
run_loop.Run();
return result;
}
OperationResult WriteToDataItem(DataItem* item,
const std::vector<char>& content) {
base::RunLoop run_loop;
OperationResult result = OperationResult::kFailed;
item->Write(content,
base::Bind(&WriteCallback, run_loop.QuitClosure(), &result));
run_loop.Run();
return result;
}
OperationResult ReadDataItem(DataItem* item,
std::unique_ptr<std::vector<char>>* data) {
OperationResult result = OperationResult::kFailed;
std::unique_ptr<std::vector<char>> read_content;
base::RunLoop run_loop;
item->Read(base::Bind(&ReadCallback, run_loop.QuitClosure(), &result,
&read_content));
run_loop.Run();
if (data)
*data = std::move(read_content);
return result;
}
std::set<std::string> GetRegisteredItemIds(StorageType storage_type,
const ExtensionId& extension_id) {
ValueStoreCache* storage = storage_type == StorageType::SOURCE
? source_value_store_cache_.get()
: target_value_store_cache_.get();
OperationResult result = OperationResult::kFailed;
std::unique_ptr<base::DictionaryValue> items_value;
base::RunLoop run_loop;
DataItem::GetRegisteredValuesForExtension(
context_.get(), storage, task_runner_.get(), extension_id,
base::Bind(&GetRegisteredItemsCallback, run_loop.QuitClosure(), &result,
&items_value));
run_loop.Run();
if (result != OperationResult::kSuccess) {
ADD_FAILURE() << "Getting registered items failed";
return std::set<std::string>();
}
std::set<std::string> items;
for (base::DictionaryValue::Iterator iter(*items_value); !iter.IsAtEnd();
iter.Advance()) {
items.insert(iter.key());
}
return items;
}
scoped_refptr<const Extension> AddTestExtension(
const ExtensionId& extension_id) {
DictionaryBuilder app_builder;
app_builder.Set("background",
DictionaryBuilder()
.Set("scripts", ListBuilder().Append("script").Build())
.Build());
ListBuilder app_handlers_builder;
app_handlers_builder.Append(DictionaryBuilder()
.Set("action", "new_note")
.Set("enabled_on_lock_screen", true)
.Build());
scoped_refptr<const Extension> extension =
ExtensionBuilder()
.SetID(extension_id)
.SetManifest(
DictionaryBuilder()
.Set("name", "Test app")
.Set("version", "1.0")
.Set("manifest_version", 2)
.Set("app", app_builder.Build())
.Set("action_handlers", app_handlers_builder.Build())
.Set("permissions",
ListBuilder().Append("lockScreen").Build())
.Build())
.Build();
ExtensionRegistry::Get(context_.get())->AddEnabled(extension);
return extension;
}
const std::string& migrator_crypto_key() const {
return migrator_crypto_key_;
}
LockScreenValueStoreMigratorImpl* migrator() { return migrator_.get(); }
const std::vector<ExtensionId>& migrated_extension_ids() const {
return migrated_extension_ids_;
}
void DeleteMigrator() { migrator_.reset(); }
void RunTaskRunnerTasks() {
base::RunLoop run_loop;
task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
run_loop.QuitClosure());
run_loop.Run();
}
void WaitMigrationDone(const ExtensionId& extension_id) {
extension_waiters_[extension_id].Run();
}
void SetReturnCodeForValueStoreOperations(StorageType storage_type,
const ExtensionId& extension_id,
ValueStore::StatusCode code) {
task_runner_->PostTask(
FROM_HERE,
base::Bind(
&LockScreenValueStoreMigratorImplTest::SetValueStoreReturnCodeImpl,
base::Unretained(this), storage_type, extension_id, code));
}
private:
void TearDownValueStoreCache() {
base::RunLoop run_loop;
task_runner_->PostTaskAndReply(
FROM_HERE,
base::Bind(
&LockScreenValueStoreMigratorImplTest::ReleaseValueStoreCaches,
base::Unretained(this)),
run_loop.QuitClosure());
run_loop.Run();
}
void ReleaseValueStoreCaches() {
source_value_store_cache_.reset();
target_value_store_cache_.reset();
}
void SetValueStoreReturnCodeImpl(StorageType storage_type,
const ExtensionId& extension_id,
ValueStore::StatusCode code) {
TestValueStoreFactory* factory = storage_type == StorageType::SOURCE
? source_value_store_factory_.get()
: target_value_store_factory_.get();
TestingValueStore* store =
static_cast<TestingValueStore*>(factory->GetExisting(extension_id));
ASSERT_TRUE(store);
store->set_status_code(code);
}
void OnExtensionMigrated(const ExtensionId& extension_id) {
migrated_extension_ids_.push_back(extension_id);
extension_waiters_[extension_id].Quit();
}
content::TestBrowserThreadBundle thread_bundle_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::unique_ptr<content::TestBrowserContext> context_;
std::unique_ptr<TestExtensionsBrowserClient> extensions_browser_client_;
scoped_refptr<TestValueStoreFactory> source_value_store_factory_;
std::unique_ptr<ValueStoreCache> source_value_store_cache_;
scoped_refptr<TestValueStoreFactory> target_value_store_factory_;
std::unique_ptr<ValueStoreCache> target_value_store_cache_;
std::string migrator_crypto_key_;
std::vector<ExtensionId> migrated_extension_ids_;
std::unique_ptr<LockScreenValueStoreMigratorImpl> migrator_;
std::map<ExtensionId, base::RunLoop> extension_waiters_;
DISALLOW_COPY_AND_ASSIGN(LockScreenValueStoreMigratorImplTest);
};
TEST_F(LockScreenValueStoreMigratorImplTest, Basic) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
std::string other_key = GenerateKey("other");
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'c', 'd'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'e', 'f', 'g'}},
{"item_4", app_1->id(), other_key, {'h', 'i'}}}));
RunMigrator({app_1->id()});
WaitMigrationDone(app_1->id());
// Verify items beloning to app_1 and encrypted with the same key have been
// moved to the new storage.
EXPECT_EQ(std::set<std::string>({"item_1", "item_2"}),
GetRegisteredItemIds(StorageType::TARGET, app_1->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}, {'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_1", "item_2"},
app_1->id(), migrator_crypto_key()));
// Items belonging to app_2 should not be moved.
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app_2->id()).empty());
// Original storage should not contain migrated items anymore.
EXPECT_EQ(std::set<std::string>({"item_4"}),
GetRegisteredItemIds(StorageType::SOURCE, app_1->id()));
EXPECT_EQ(
std::vector<std::vector<char>>({{'h', 'i'}}),
GetItemContent(StorageType::SOURCE, {"item_4"}, app_1->id(), other_key));
// Original storage should still contain items belonging to app_2.
EXPECT_EQ(std::set<std::string>({"item_3"}),
GetRegisteredItemIds(StorageType::SOURCE, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'e', 'f', 'g'}}),
GetItemContent(StorageType::SOURCE, {"item_3"}, app_2->id(),
migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest, MigratingMultipleApps) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
auto app_3 = AddTestExtension(kThirdExtensionId);
std::string other_key = GenerateKey("other");
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'c', 'd'}},
{"item_3", app_1->id(), other_key, {'e', 'f'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'g', 'h', 'i'}},
{"item_5", app_3->id(), migrator_crypto_key(), {'j'}},
{"item_6", app_3->id(), other_key, {'k', 'l', 'm'}}}));
RunMigrator({app_1->id(), app_2->id()});
WaitMigrationDone(app_1->id());
WaitMigrationDone(app_2->id());
// Verify items beloning to app_1 and encrypted with the same key have been
// moved to the new storage.
EXPECT_EQ(std::set<std::string>({"item_1", "item_2"}),
GetRegisteredItemIds(StorageType::TARGET, app_1->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}, {'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_1", "item_2"},
app_1->id(), migrator_crypto_key()));
// Verify items beloning to app_2 and encrypted with the same key have been
// moved to the new storage.
EXPECT_EQ(std::set<std::string>({"item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'g', 'h', 'i'}}),
GetItemContent(StorageType::TARGET, {"item_4"}, app_2->id(),
migrator_crypto_key()));
// Items belonging to app_3 should not be moved.
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app_3->id()).empty());
// Original storage should not contain migrated items anymore.
EXPECT_EQ(std::set<std::string>({"item_3"}),
GetRegisteredItemIds(StorageType::SOURCE, app_1->id()));
EXPECT_EQ(
std::vector<std::vector<char>>({{'e', 'f'}}),
GetItemContent(StorageType::SOURCE, {"item_3"}, app_1->id(), other_key));
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
// Original storage should still contain all items belonging to app_3.
EXPECT_EQ(std::set<std::string>({"item_5", "item_6"}),
GetRegisteredItemIds(StorageType::SOURCE, app_3->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'j'}}),
GetItemContent(StorageType::SOURCE, {"item_5"}, app_3->id(),
migrator_crypto_key()));
EXPECT_EQ(
std::vector<std::vector<char>>({{'k', 'l', 'm'}}),
GetItemContent(StorageType::SOURCE, {"item_6"}, app_3->id(), other_key));
}
// Tests that any item in the target storage is overriden with the contents of
// the item with the same id in the source storage (this situation might arrise
// if previous migration attempt was cancelled before the item was written to
// target, but after its registration in target storage).
TEST_F(LockScreenValueStoreMigratorImplTest, ItemIdExistsInTheTarget) {
auto app = AddTestExtension(kFirstExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app->id(), migrator_crypto_key(), {'c', 'd'}}}));
ASSERT_TRUE(
InitializeStorage(StorageType::TARGET,
{{"item_1", app->id(), migrator_crypto_key(), {0}}}));
RunMigrator({app->id()});
WaitMigrationDone(app->id());
EXPECT_EQ(std::set<std::string>({"item_1", "item_2"}),
GetRegisteredItemIds(StorageType::TARGET, app->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}, {'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_1", "item_2"}, app->id(),
migrator_crypto_key()));
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app->id()).empty());
}
// Tests storage state at the moment the item is registered in the target.
TEST_F(LockScreenValueStoreMigratorImplTest,
StepByStepMigrationRegisterInTarget) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'e'}}}));
RunMigrator({app_1->id()});
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_2->id()));
EXPECT_TRUE(migrated_extension_ids().empty());
// Run task runner - first set of operation should retrieve set of
// registered items in the source, with no changs to the storage.
RunTaskRunnerTasks();
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_2->id()));
EXPECT_TRUE(migrated_extension_ids().empty());
// Run task runner - second set of operation should retrieve the first
// item source, there should be no visible changes to the storage,
RunTaskRunnerTasks();
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_2->id()));
EXPECT_TRUE(migrated_extension_ids().empty());
// Reset the migrator instance to stop migration (so the running migration
// tasks do not interfere with the torage state) - note that at this will not
// cancel in progress tasks on the storage.
DeleteMigrator();
// Run task runner - third set of operation should register the item in the
// target storage.
RunTaskRunnerTasks();
EXPECT_TRUE(migrated_extension_ids().empty());
EXPECT_EQ(std::set<std::string>({"item_1"}),
GetRegisteredItemIds(StorageType::SOURCE, app_1->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}}),
GetItemContent(StorageType::SOURCE, {"item_1"}, app_1->id(),
migrator_crypto_key()));
EXPECT_EQ(std::set<std::string>({"item_1"}),
GetRegisteredItemIds(StorageType::TARGET, app_1->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{}}),
GetItemContent(StorageType::TARGET, {"item_1"}, app_1->id(),
migrator_crypto_key()));
}
// Tests storage state at the moment the target item content is written.
TEST_F(LockScreenValueStoreMigratorImplTest,
StepByStepMigrationWriteTargetContents) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'e'}}}));
RunMigrator({app_1->id()});
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_2->id()));
EXPECT_TRUE(migrated_extension_ids().empty());
// Get registered items in source.
RunTaskRunnerTasks();
// Read migrated item contents in source.
RunTaskRunnerTasks();
// Register migrated item in the target.
RunTaskRunnerTasks();
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_2->id()));
EXPECT_TRUE(migrated_extension_ids().empty());
// Reset the migrator instance to stop migration (so the running migration
// tasks do not interfere with the torage state) - note that at this will not
// cancel in progress tasks on the storage.
DeleteMigrator();
// Run task runner - fourth set of operations should copy the item content
// from the source to the target storage.
RunTaskRunnerTasks();
EXPECT_TRUE(migrated_extension_ids().empty());
EXPECT_EQ(std::set<std::string>({"item_1"}),
GetRegisteredItemIds(StorageType::SOURCE, app_1->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}}),
GetItemContent(StorageType::SOURCE, {"item_1"}, app_1->id(),
migrator_crypto_key()));
EXPECT_EQ(std::set<std::string>({"item_1"}),
GetRegisteredItemIds(StorageType::TARGET, app_1->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}}),
GetItemContent(StorageType::TARGET, {"item_1"}, app_1->id(),
migrator_crypto_key()));
}
// Tests storage state after the final step of an item migration - deletion
// from source storage.
TEST_F(LockScreenValueStoreMigratorImplTest,
StepByStepMigrationDeleteSourceItem) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'e'}}}));
RunMigrator({app_1->id()});
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_2->id()));
EXPECT_TRUE(migrated_extension_ids().empty());
// Get registered items in source.
RunTaskRunnerTasks();
// Read migrated item contents in source.
RunTaskRunnerTasks();
// Register migrated item in the target.
RunTaskRunnerTasks();
// Copy item data to target.
RunTaskRunnerTasks();
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_2->id()));
EXPECT_TRUE(migrated_extension_ids().empty());
// Run task runner - fifth set of operations should delete the item from the
// source storage. Given that there are no items to migrate left, migrator
// should report extension data as migrated.
RunTaskRunnerTasks();
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_2->id()));
EXPECT_EQ(std::vector<ExtensionId>({app_1->id()}), migrated_extension_ids());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_1"}),
GetRegisteredItemIds(StorageType::TARGET, app_1->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}}),
GetItemContent(StorageType::TARGET, {"item_1"}, app_1->id(),
migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest,
MigratorDeletedWhenGettingItemsFromSource) {
auto app = AddTestExtension(kFirstExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app->id(), migrator_crypto_key(), {'a', 'b', 'c'}}}));
RunMigrator({app->id()});
DeleteMigrator();
// Get registered items in source.
RunTaskRunnerTasks();
EXPECT_TRUE(migrated_extension_ids().empty());
EXPECT_EQ(std::set<std::string>({"item_1"}),
GetRegisteredItemIds(StorageType::SOURCE, app->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}}),
GetItemContent(StorageType::SOURCE, {"item_1"}, app->id(),
migrator_crypto_key()));
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app->id()).empty());
}
TEST_F(LockScreenValueStoreMigratorImplTest,
MigratorDeletedWhenReadingItemsFromSource) {
auto app = AddTestExtension(kFirstExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app->id(), migrator_crypto_key(), {'a', 'b', 'c'}}}));
RunMigrator({app->id()});
// Get registered items in source.
RunTaskRunnerTasks();
DeleteMigrator();
// Get registered items in source.
RunTaskRunnerTasks();
EXPECT_TRUE(migrated_extension_ids().empty());
EXPECT_EQ(std::set<std::string>({"item_1"}),
GetRegisteredItemIds(StorageType::SOURCE, app->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}}),
GetItemContent(StorageType::SOURCE, {"item_1"}, app->id(),
migrator_crypto_key()));
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app->id()).empty());
}
TEST_F(LockScreenValueStoreMigratorImplTest,
MigratorDeletedWhenDeletingItemsFromSource) {
auto app = AddTestExtension(kFirstExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app->id(), migrator_crypto_key(), {'a', 'b', 'c'}}}));
RunMigrator({app->id()});
// Get registered items in source.
RunTaskRunnerTasks();
// Read migrated item contents in source.
RunTaskRunnerTasks();
// Register migrated item in the target.
RunTaskRunnerTasks();
// Copy item data to target.
RunTaskRunnerTasks();
DeleteMigrator();
// Delete items from source.
RunTaskRunnerTasks();
// While the extension data has been moved at this point, the migrator was
// deleted before it could send out notification about migration completion
// to observers.
EXPECT_TRUE(migrated_extension_ids().empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_1"}),
GetRegisteredItemIds(StorageType::TARGET, app->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c'}}),
GetItemContent(StorageType::TARGET, {"item_1"}, app->id(),
migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest,
ClearExtensionDataDuringGetRegisteredItemsFromSource) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app_1->id(), app_2->id()});
// Clear data for app 1.
base::RunLoop run_loop;
migrator()->ClearDataForExtension(app_1->id(), run_loop.QuitClosure());
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_2->id()));
run_loop.Run();
// Verify there are no registered items left.
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app_1->id()).empty());
// Finish migration for app 2, and verify that it's not affected by clearing
// of app 1 data.
WaitMigrationDone(app_2->id());
EXPECT_EQ(std::vector<ExtensionId>({app_2->id()}), migrated_extension_ids());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest,
ClearExtensionDataDuringReadItemFromSource) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app_1->id(), app_2->id()});
// Get registered items in source.
RunTaskRunnerTasks();
// Clear data for app 1.
base::RunLoop run_loop;
migrator()->ClearDataForExtension(app_1->id(), run_loop.QuitClosure());
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_2->id()));
run_loop.Run();
// Verify there are no registered items left.
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app_1->id()).empty());
// Finish migration for app 2, and verify that it's not affected by clearing
// of app 1 data.
WaitMigrationDone(app_2->id());
EXPECT_EQ(std::vector<ExtensionId>({app_2->id()}), migrated_extension_ids());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest,
ClearExtensionDataDuringRegisterItemInTarget) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app_1->id(), app_2->id()});
// Get registered items in source.
RunTaskRunnerTasks();
// Read migrated item contents in source.
RunTaskRunnerTasks();
// Clear data for app 1.
base::RunLoop run_loop;
migrator()->ClearDataForExtension(app_1->id(), run_loop.QuitClosure());
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_2->id()));
run_loop.Run();
// Verify there are no registered items left.
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app_1->id()).empty());
// Finish migration for app 2, and verify that it's not affected by clearing
// of app 1 data.
WaitMigrationDone(app_2->id());
EXPECT_EQ(std::vector<ExtensionId>({app_2->id()}), migrated_extension_ids());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest,
ClearExtensionDataDuringWriteItemInTarget) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app_1->id(), app_2->id()});
// Get registered items in source.
RunTaskRunnerTasks();
// Read migrated item contents in source.
RunTaskRunnerTasks();
// Register migrated item in the target.
RunTaskRunnerTasks();
// Clear data for app 1.
base::RunLoop run_loop;
migrator()->ClearDataForExtension(app_1->id(), run_loop.QuitClosure());
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_2->id()));
run_loop.Run();
// Verify there are no registered items left.
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app_1->id()).empty());
// Finish migration for app 2, and verify that it's not affected by clearing
// of app 1 data.
WaitMigrationDone(app_2->id());
EXPECT_EQ(std::vector<ExtensionId>({app_2->id()}), migrated_extension_ids());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest,
ClearExtensionDataDuringDeleteItemFromSource) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app_1->id(), app_2->id()});
// Get registered items in source.
RunTaskRunnerTasks();
// Read migrated item contents in source.
RunTaskRunnerTasks();
// Register migrated item in the target.
RunTaskRunnerTasks();
// Copy item data to target.
RunTaskRunnerTasks();
// Clear data for app 1.
base::RunLoop run_loop;
migrator()->ClearDataForExtension(app_1->id(), run_loop.QuitClosure());
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app_1->id()));
EXPECT_TRUE(migrator()->IsMigratingExtensionData(app_2->id()));
run_loop.Run();
// Verify there are no registered items left.
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app_1->id()).empty());
// Finish migration for app 2, and verify that it's not affected by clearing
// of app 1 data.
WaitMigrationDone(app_2->id());
EXPECT_EQ(std::vector<ExtensionId>({app_2->id()}), migrated_extension_ids());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest,
MigratorDeletedWhileClearingDataFromTargetStorage) {
auto app = AddTestExtension(kFirstExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app->id(), migrator_crypto_key(), {'d', 'e'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app->id()});
// Get registered items in source.
RunTaskRunnerTasks();
// Read migrated item contents in source.
RunTaskRunnerTasks();
// Register migrated item in the target.
RunTaskRunnerTasks();
// Clear data for app 1.
migrator()->ClearDataForExtension(
app->id(), base::Bind(&ExpectNotRun, "clear data callback"));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app->id()));
DeleteMigrator();
// Run any tasks left over on the task runner.
RunTaskRunnerTasks();
EXPECT_TRUE(migrated_extension_ids().empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app->id()).empty());
}
TEST_F(LockScreenValueStoreMigratorImplTest,
MigratorDeletedWhileClearingDataFromSourceStorage) {
auto app = AddTestExtension(kFirstExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app->id(), migrator_crypto_key(), {'d', 'e'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app->id()});
// Get registered items in source.
RunTaskRunnerTasks();
// Read migrated item contents in source.
RunTaskRunnerTasks();
// Register migrated item in the target.
RunTaskRunnerTasks();
// Clear data for app 1.
migrator()->ClearDataForExtension(
app->id(), base::Bind(&ExpectNotRun, "clear data callback"));
EXPECT_FALSE(migrator()->IsMigratingExtensionData(app->id()));
// This should clear the target storage.
RunTaskRunnerTasks();
DeleteMigrator();
// Run any tasks left over on the task runner.
RunTaskRunnerTasks();
EXPECT_TRUE(migrated_extension_ids().empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app->id()).empty());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::TARGET, app->id()).empty());
}
TEST_F(LockScreenValueStoreMigratorImplTest, FailToGetItemsFromSource) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
SetReturnCodeForValueStoreOperations(StorageType::SOURCE, app_1->id(),
ValueStore::OTHER_ERROR);
RunMigrator({app_1->id(), app_2->id()});
WaitMigrationDone(app_1->id());
WaitMigrationDone(app_2->id());
EXPECT_EQ(std::set<std::string>({"item_0"}),
GetRegisteredItemIds(StorageType::TARGET, app_1->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'a', 'b', 'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_0"}, app_1->id(),
migrator_crypto_key()));
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest, FailToReadItemFromSource) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app_1->id(), app_2->id()});
// Make read for the first app_1 item fail.
SetReturnCodeForValueStoreOperations(StorageType::SOURCE, app_1->id(),
ValueStore::OTHER_ERROR);
// Run tasks that get registered items.
RunTaskRunnerTasks();
// Make read for the rest of app_1 items succeed.
SetReturnCodeForValueStoreOperations(StorageType::SOURCE, app_1->id(),
ValueStore::OK);
// Run tasks that read item contents.
RunTaskRunnerTasks();
WaitMigrationDone(app_1->id());
WaitMigrationDone(app_2->id());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
std::set<std::string> items =
GetRegisteredItemIds(StorageType::TARGET, app_1->id());
EXPECT_EQ(2u, items.size());
if (items.count("item_1")) {
EXPECT_EQ(
std::vector<std::vector<char>>({{'a', 'b', 'c'}, {'a', 'b', 'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_1", "item_0"}, app_1->id(),
migrator_crypto_key()));
} else if (items.count("item_2")) {
EXPECT_EQ(
std::vector<std::vector<char>>({{'d', 'e'}, {'a', 'b', 'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_2", "item_0"}, app_1->id(),
migrator_crypto_key()));
} else {
ADD_FAILURE() << "Neither of items migrated";
}
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest, FailToRegisterItemInTarget) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app_1->id(), app_2->id()});
// Run tasks that get registered items.
RunTaskRunnerTasks();
// Make registration for the first app_1 item fail.
SetReturnCodeForValueStoreOperations(StorageType::TARGET, app_1->id(),
ValueStore::OTHER_ERROR);
// Run tasks that read registered items.
RunTaskRunnerTasks();
// Make read for the rest of app_1 items succeed.
SetReturnCodeForValueStoreOperations(StorageType::TARGET, app_1->id(),
ValueStore::OK);
WaitMigrationDone(app_1->id());
WaitMigrationDone(app_2->id());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
std::set<std::string> items =
GetRegisteredItemIds(StorageType::TARGET, app_1->id());
EXPECT_EQ(2u, items.size());
if (items.count("item_1")) {
EXPECT_EQ(
std::vector<std::vector<char>>({{'a', 'b', 'c'}, {'a', 'b', 'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_1", "item_0"}, app_1->id(),
migrator_crypto_key()));
} else if (items.count("item_2")) {
EXPECT_EQ(
std::vector<std::vector<char>>({{'d', 'e'}, {'a', 'b', 'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_2", "item_0"}, app_1->id(),
migrator_crypto_key()));
} else {
ADD_FAILURE() << "Neither of items migrated";
}
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
TEST_F(LockScreenValueStoreMigratorImplTest, FailToWriteItemContentsToTarget) {
auto app_1 = AddTestExtension(kFirstExtensionId);
auto app_2 = AddTestExtension(kSecondExtensionId);
ASSERT_TRUE(InitializeStorage(
StorageType::SOURCE,
{{"item_1", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c'}},
{"item_2", app_1->id(), migrator_crypto_key(), {'d', 'e'}},
{"item_3", app_2->id(), migrator_crypto_key(), {'f', 'g'}},
{"item_4", app_2->id(), migrator_crypto_key(), {'h'}}}));
ASSERT_TRUE(InitializeStorage(
StorageType::TARGET,
{{"item_0", app_1->id(), migrator_crypto_key(), {'a', 'b', 'c', 'd'}}}));
RunMigrator({app_1->id(), app_2->id()});
// Run tasks that get registered items.
RunTaskRunnerTasks();
// Run tasks that read registered items.
RunTaskRunnerTasks();
// Make write for the first app_1 item fail.
SetReturnCodeForValueStoreOperations(StorageType::TARGET, app_1->id(),
ValueStore::OTHER_ERROR);
// Run tasks that register new items in target.
RunTaskRunnerTasks();
// Make read for the rest of app_1 items succeed.
SetReturnCodeForValueStoreOperations(StorageType::TARGET, app_1->id(),
ValueStore::OK);
WaitMigrationDone(app_1->id());
WaitMigrationDone(app_2->id());
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_1->id()).empty());
std::set<std::string> items =
GetRegisteredItemIds(StorageType::TARGET, app_1->id());
EXPECT_EQ(2u, items.size());
if (items.count("item_1")) {
EXPECT_EQ(
std::vector<std::vector<char>>({{'a', 'b', 'c'}, {'a', 'b', 'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_1", "item_0"}, app_1->id(),
migrator_crypto_key()));
} else if (items.count("item_2")) {
EXPECT_EQ(
std::vector<std::vector<char>>({{'d', 'e'}, {'a', 'b', 'c', 'd'}}),
GetItemContent(StorageType::TARGET, {"item_2", "item_0"}, app_1->id(),
migrator_crypto_key()));
} else {
ADD_FAILURE() << "Neither of items migrated";
}
EXPECT_TRUE(GetRegisteredItemIds(StorageType::SOURCE, app_2->id()).empty());
EXPECT_EQ(std::set<std::string>({"item_3", "item_4"}),
GetRegisteredItemIds(StorageType::TARGET, app_2->id()));
EXPECT_EQ(std::vector<std::vector<char>>({{'f', 'g'}, {'h'}}),
GetItemContent(StorageType::TARGET, {"item_3", "item_4"},
app_2->id(), migrator_crypto_key()));
}
} // namespace lock_screen_data
} // namespace extensions