| Index: extensions/browser/api/lock_screen_data/data_item_unittest.cc
|
| diff --git a/extensions/browser/api/lock_screen_data/data_item_unittest.cc b/extensions/browser/api/lock_screen_data/data_item_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e785c03d49593e64927927e237806e6ce8a03cb8
|
| --- /dev/null
|
| +++ b/extensions/browser/api/lock_screen_data/data_item_unittest.cc
|
| @@ -0,0 +1,582 @@
|
| +// 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/data_item.h"
|
| +
|
| +#include <memory>
|
| +#include <utility>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/callback.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/files/file_util.h"
|
| +#include "base/files/scoped_temp_dir.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/task_scheduler/post_task.h"
|
| +#include "base/test/scoped_task_environment.h"
|
| +#include "base/values.h"
|
| +#include "crypto/symmetric_key.h"
|
| +#include "extensions/browser/api/lock_screen_data/operation_result.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace extensions {
|
| +namespace lock_screen_data {
|
| +
|
| +namespace {
|
| +
|
| +void WriteCallback(const base::Closure& callback,
|
| + OperationResult* result_out,
|
| + OperationResult result) {
|
| + *result_out = result;
|
| + callback.Run();
|
| +}
|
| +
|
| +void DeleteCallback(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 NotCalled(const std::string& message) {
|
| + ADD_FAILURE() << "Not expected to be called: " << message;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class DataItemTest : public testing::Test {
|
| + public:
|
| + DataItemTest() = default;
|
| + ~DataItemTest() override = default;
|
| +
|
| + void SetUp() override {
|
| + task_runner_ =
|
| + base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()});
|
| + ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
|
| + }
|
| +
|
| + std::string GenerateKey(const std::string& password) {
|
| + std::unique_ptr<crypto::SymmetricKey> key =
|
| + crypto::SymmetricKey::DeriveKeyFromPassword(
|
| + crypto::SymmetricKey::AES, password, "salt", 1000, 256);
|
| + if (!key) {
|
| + ADD_FAILURE() << "Failed to create symmetric key";
|
| + return std::string();
|
| + }
|
| +
|
| + return key->key();
|
| + }
|
| +
|
| + void DrainTaskRunner() {
|
| + base::RunLoop run_loop;
|
| + task_runner()->PostTaskAndReply(FROM_HERE, base::Bind(&base::DoNothing),
|
| + run_loop.QuitClosure());
|
| + run_loop.Run();
|
| + }
|
| +
|
| + const base::FilePath& test_dir() const { return test_dir_.GetPath(); }
|
| +
|
| + scoped_refptr<base::SequencedTaskRunner> task_runner() {
|
| + return task_runner_;
|
| + }
|
| +
|
| + private:
|
| + base::ScopedTempDir test_dir_;
|
| +
|
| + base::test::ScopedTaskEnvironment scoped_task_environment_;
|
| + scoped_refptr<base::SequencedTaskRunner> task_runner_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DataItemTest);
|
| +};
|
| +
|
| +TEST_F(DataItemTest, ValueConversion) {
|
| + DataItem item("data_id");
|
| +
|
| + std::unique_ptr<base::DictionaryValue> value = item.ToValue();
|
| + ASSERT_TRUE(value);
|
| +
|
| + {
|
| + DataItem converted("data_id");
|
| + EXPECT_TRUE(converted.InitFromValue(*value));
|
| +
|
| + EXPECT_EQ("data_id", converted.id());
|
| + EXPECT_TRUE(converted.backing_file().empty());
|
| + }
|
| +
|
| + item.set_backing_file(test_dir().AppendASCII("test_file"));
|
| +
|
| + value = item.ToValue();
|
| + {
|
| + DataItem converted("data_id");
|
| + EXPECT_TRUE(converted.InitFromValue(*value));
|
| +
|
| + EXPECT_EQ("data_id", converted.id());
|
| + EXPECT_EQ(test_dir().AppendASCII("test_file"), converted.backing_file());
|
| + }
|
| +
|
| + {
|
| + DataItem converted("different_id");
|
| + EXPECT_FALSE(converted.InitFromValue(*value));
|
| +
|
| + EXPECT_EQ("different_id", converted.id());
|
| + EXPECT_TRUE(converted.backing_file().empty());
|
| + }
|
| +}
|
| +
|
| +TEST_F(DataItemTest, WriteLocation) {
|
| + DataItem item("data_id");
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
|
| +
|
| + item.set_backing_file(test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback, run_loop.QuitClosure(),
|
| + &write_result)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, write_result);
|
| +
|
| + EXPECT_TRUE(
|
| + base::PathExists(test_dir().AppendASCII("app").AppendASCII("test_file")));
|
| +
|
| + OperationResult delete_result = OperationResult::kFailed;
|
| + {
|
| + base::RunLoop run_loop;
|
| + item.Delete(
|
| + task_runner(),
|
| + base::Bind(&DeleteCallback, run_loop.QuitClosure(), &delete_result));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, delete_result);
|
| + EXPECT_FALSE(
|
| + base::PathExists(test_dir().AppendASCII("app").AppendASCII("test_file")));
|
| +}
|
| +
|
| +TEST_F(DataItemTest, ReadWrite) {
|
| + DataItem item("data_id");
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
|
| +
|
| + EXPECT_EQ(
|
| + OperationResult::kNoBackingFile,
|
| + item.Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback,
|
| + base::Bind(&NotCalled,
|
| + "Writing item with no backing file"),
|
| + &write_result)));
|
| +
|
| + item.set_backing_file(test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback, run_loop.QuitClosure(),
|
| + &write_result)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, write_result);
|
| +
|
| + OperationResult read_result = OperationResult::kFailed;
|
| + std::unique_ptr<std::vector<char>> read_content;
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Read(key, task_runner(),
|
| + base::Bind(&ReadCallback, run_loop.QuitClosure(),
|
| + &read_result, &read_content)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + ASSERT_EQ(OperationResult::kSuccess, read_result);
|
| + ASSERT_TRUE(read_content);
|
| + EXPECT_EQ(content, *read_content);
|
| +
|
| + std::string different_key = GenerateKey("key_2");
|
| + ASSERT_FALSE(different_key.empty());
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Read(different_key, task_runner(),
|
| + base::Bind(&ReadCallback, run_loop.QuitClosure(),
|
| + &read_result, &read_content)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + ASSERT_EQ(OperationResult::kWrongKey, read_result);
|
| + ASSERT_TRUE(read_content);
|
| + EXPECT_TRUE(read_content->empty());
|
| +}
|
| +
|
| +TEST_F(DataItemTest, ReadFromNonexistentSource) {
|
| + DataItem item("data_id");
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult read_result = OperationResult::kFailed;
|
| + std::unique_ptr<std::vector<char>> read_content;
|
| +
|
| + EXPECT_EQ(
|
| + OperationResult::kNoBackingFile,
|
| + item.Read(key, task_runner(),
|
| + base::Bind(
|
| + &ReadCallback,
|
| + base::Bind(&NotCalled, "Reading item with no backing file"),
|
| + &read_result, &read_content)));
|
| +
|
| + item.set_backing_file(test_dir().AppendASCII("nonexistent"));
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Read(key, task_runner(),
|
| + base::Bind(&ReadCallback, run_loop.QuitClosure(),
|
| + &read_result, &read_content)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kNotFound, read_result);
|
| + ASSERT_TRUE(read_content);
|
| + EXPECT_TRUE(read_content->empty());
|
| +}
|
| +
|
| +TEST_F(DataItemTest, ReadOldFile) {
|
| + std::unique_ptr<DataItem> writer = base::MakeUnique<DataItem>("data_id");
|
| + writer->set_backing_file(
|
| + test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + writer->Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback, run_loop.QuitClosure(),
|
| + &write_result)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + writer.reset();
|
| +
|
| + OperationResult read_result = OperationResult::kFailed;
|
| + std::unique_ptr<std::vector<char>> read_content;
|
| +
|
| + std::unique_ptr<DataItem> reader = base::MakeUnique<DataItem>("data_id");
|
| + reader->set_backing_file(
|
| + test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + reader->Read(key, task_runner(),
|
| + base::Bind(&ReadCallback, run_loop.QuitClosure(),
|
| + &read_result, &read_content)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, read_result);
|
| + ASSERT_TRUE(read_content);
|
| + EXPECT_EQ(content, *read_content);
|
| +}
|
| +
|
| +TEST_F(DataItemTest, RepeatedWrite) {
|
| + DataItem item("data_id");
|
| + item.set_backing_file(test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> first_write = {'f', 'i', 'l', 'e', '_', '1'};
|
| + std::vector<char> second_write = {'f', 'i', 'l', 'e', '_', '2'};
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(
|
| + OperationResult::kPending,
|
| + item.Write(first_write, key, task_runner(),
|
| + base::Bind(&WriteCallback, base::Bind(&base::DoNothing),
|
| + &write_result)));
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Write(second_write, key, task_runner(),
|
| + base::Bind(&WriteCallback, run_loop.QuitClosure(),
|
| + &write_result)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + DataItem reader("data_id");
|
| + reader.set_backing_file(
|
| + test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| + OperationResult read_result = OperationResult::kFailed;
|
| + std::unique_ptr<std::vector<char>> read_content;
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + reader.Read(key, task_runner(),
|
| + base::Bind(&ReadCallback, run_loop.QuitClosure(),
|
| + &read_result, &read_content)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, read_result);
|
| + ASSERT_TRUE(read_content);
|
| + EXPECT_EQ(second_write, *read_content);
|
| +}
|
| +
|
| +TEST_F(DataItemTest, DeleteWithNoBackingFile) {
|
| + DataItem item("data_id");
|
| +
|
| + OperationResult delete_result = OperationResult::kFailed;
|
| + EXPECT_EQ(OperationResult::kNoBackingFile,
|
| + item.Delete(task_runner(),
|
| + base::Bind(&DeleteCallback,
|
| + base::Bind(&NotCalled,
|
| + "Delete with no backing file"),
|
| + &delete_result)));
|
| +
|
| + DrainTaskRunner();
|
| +}
|
| +
|
| +TEST_F(DataItemTest, ReadDeletedItem) {
|
| + DataItem item("data_id");
|
| + item.set_backing_file(test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback, run_loop.QuitClosure(),
|
| + &write_result)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, write_result);
|
| +
|
| + OperationResult delete_result = OperationResult::kFailed;
|
| + {
|
| + base::RunLoop run_loop;
|
| + item.Delete(
|
| + task_runner(),
|
| + base::Bind(&DeleteCallback, run_loop.QuitClosure(), &delete_result));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, delete_result);
|
| +
|
| + OperationResult read_result = OperationResult::kFailed;
|
| + std::unique_ptr<std::vector<char>> read_content;
|
| + EXPECT_EQ(
|
| + OperationResult::kNoBackingFile,
|
| + item.Read(key, task_runner(),
|
| + base::Bind(&ReadCallback,
|
| + base::Bind(&NotCalled, "Read deleted item callback"),
|
| + &read_result, &read_content)));
|
| +
|
| + DrainTaskRunner();
|
| +}
|
| +
|
| +TEST_F(DataItemTest, WriteDeletedItem) {
|
| + DataItem item("data_id");
|
| + item.set_backing_file(test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback, run_loop.QuitClosure(),
|
| + &write_result)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, write_result);
|
| +
|
| + OperationResult delete_result = OperationResult::kFailed;
|
| + {
|
| + base::RunLoop run_loop;
|
| + item.Delete(
|
| + task_runner(),
|
| + base::Bind(&DeleteCallback, run_loop.QuitClosure(), &delete_result));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, delete_result);
|
| +
|
| + EXPECT_EQ(OperationResult::kNoBackingFile,
|
| + item.Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback,
|
| + base::Bind(&NotCalled,
|
| + "Write deleted item callback"),
|
| + &write_result)));
|
| +
|
| + DrainTaskRunner();
|
| +}
|
| +
|
| +TEST_F(DataItemTest, WriteWithInvalidKey) {
|
| + DataItem item("data_id");
|
| + item.set_backing_file(test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback, run_loop.QuitClosure(),
|
| + &write_result)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, write_result);
|
| +
|
| + OperationResult read_result = OperationResult::kFailed;
|
| + std::unique_ptr<std::vector<char>> read_content;
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Read("invalid", task_runner(),
|
| + base::Bind(&ReadCallback, run_loop.QuitClosure(),
|
| + &read_result, &read_content)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kInvalidKey, read_result);
|
| +}
|
| +
|
| +TEST_F(DataItemTest, ReadWithInvalidKey) {
|
| + DataItem item("data_id");
|
| + item.set_backing_file(test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + item.Write(content, "invalid", task_runner(),
|
| + base::Bind(&WriteCallback, run_loop.QuitClosure(),
|
| + &write_result)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kInvalidKey, write_result);
|
| +}
|
| +
|
| +TEST_F(DataItemTest, ResetBeforeCallback) {
|
| + std::unique_ptr<DataItem> writer = base::MakeUnique<DataItem>("data_id");
|
| + writer->set_backing_file(
|
| + test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + std::string key = GenerateKey("key_1");
|
| + ASSERT_FALSE(key.empty());
|
| +
|
| + OperationResult write_result = OperationResult::kFailed;
|
| + std::vector<char> content = {'f', 'i', 'l', 'e', '_', '1'};
|
| +
|
| + ASSERT_EQ(
|
| + OperationResult::kPending,
|
| + writer->Write(content, key, task_runner(),
|
| + base::Bind(&WriteCallback,
|
| + base::Bind(&NotCalled, "Reset writer callback"),
|
| + &write_result)));
|
| + writer.reset();
|
| +
|
| + std::unique_ptr<DataItem> reader = base::MakeUnique<DataItem>("data_id");
|
| + reader->set_backing_file(
|
| + test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| + OperationResult read_result = OperationResult::kFailed;
|
| + std::unique_ptr<std::vector<char>> read_content;
|
| +
|
| + {
|
| + base::RunLoop run_loop;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + reader->Read(key, task_runner(),
|
| + base::Bind(&ReadCallback, run_loop.QuitClosure(),
|
| + &read_result, &read_content)));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + EXPECT_EQ(OperationResult::kSuccess, read_result);
|
| + ASSERT_TRUE(read_content);
|
| + EXPECT_EQ(content, *read_content);
|
| +
|
| + ASSERT_EQ(
|
| + OperationResult::kPending,
|
| + reader->Read(key, task_runner(),
|
| + base::Bind(&ReadCallback,
|
| + base::Bind(&NotCalled, "Reset reader calblack"),
|
| + &read_result, &read_content)));
|
| + reader.reset();
|
| +
|
| + std::unique_ptr<DataItem> deleter = base::MakeUnique<DataItem>("data_id");
|
| + deleter->set_backing_file(
|
| + test_dir().AppendASCII("app").AppendASCII("test_file"));
|
| +
|
| + OperationResult delete_result = OperationResult::kFailed;
|
| + ASSERT_EQ(OperationResult::kPending,
|
| + deleter->Delete(
|
| + task_runner(),
|
| + base::Bind(&DeleteCallback,
|
| + base::Bind(&NotCalled, "Reset delete callback"),
|
| + &delete_result)));
|
| + deleter.reset();
|
| +
|
| + DrainTaskRunner();
|
| +
|
| + EXPECT_FALSE(
|
| + base::PathExists(test_dir().AppendASCII("app").AppendASCII("test_file")));
|
| +}
|
| +
|
| +} // namespace lock_screen_data
|
| +} // namespace extensions
|
|
|