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 |