1 // Copyright 2016 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.
4
5 #include "extensions/browser/value_store/leveldb_scoped_database.h"
6
7 #include <stddef.h>
8
9 #include <map>
10 #include <string>
11
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/values.h"
16 #include "content/public/test/browser_task_environment.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace {
20 const char kTestUMAClientName[] = "Test";
21 } // namespace
22
23 class LeveldbScopedDatabaseUnitTest : public testing::Test {
24 public:
LeveldbScopedDatabaseUnitTest()25 LeveldbScopedDatabaseUnitTest() {}
~LeveldbScopedDatabaseUnitTest()26 ~LeveldbScopedDatabaseUnitTest() override {}
27
28 protected:
SetUp()29 void SetUp() override {
30 ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
31 db_ =
32 new LeveldbScopedDatabase(kTestUMAClientName, database_dir_.GetPath());
33 }
34
TearDown()35 void TearDown() override {
36 db_ = nullptr;
37 base::DeleteFileRecursively(database_dir_.GetPath());
38 }
39
ReadAllValues(std::map<std::string,std::string> * values) const40 ValueStore::Status ReadAllValues(
41 std::map<std::string, std::string>* values) const {
42 values->clear();
43 leveldb::ReadOptions read_options;
44 read_options.verify_checksums = true;
45 std::unique_ptr<leveldb::Iterator> iterator;
46 ValueStore::Status status = db_->CreateIterator(read_options, &iterator);
47 if (!status.ok())
48 return status;
49 iterator->SeekToFirst();
50 while (iterator->Valid()) {
51 // The LeveldbProfileDatabase writes all values as JSON strings.
52 // This method returns the encoded strings.
53 (*values)[iterator->key().ToString()] = iterator->value().ToString();
54 iterator->Next();
55 }
56 return db_->ToValueStoreError(iterator->status());
57 }
58
59 content::BrowserTaskEnvironment task_environment_;
60 base::ScopedTempDir database_dir_;
61 scoped_refptr<LeveldbScopedDatabase> db_;
62 };
63
TEST_F(LeveldbScopedDatabaseUnitTest,TestSplitKey)64 TEST_F(LeveldbScopedDatabaseUnitTest, TestSplitKey) {
65 std::string scope;
66 std::string key;
67 EXPECT_TRUE(LeveldbScopedDatabase::SplitKey("s:k", &scope, &key));
68 EXPECT_EQ(scope, "s");
69 EXPECT_EQ(key, "k");
70 EXPECT_TRUE(LeveldbScopedDatabase::SplitKey("s:", &scope, &key));
71 EXPECT_EQ(scope, "s");
72 EXPECT_EQ(key, "");
73 EXPECT_TRUE(LeveldbScopedDatabase::SplitKey("s:k:o", &scope, &key));
74 EXPECT_EQ(scope, "s");
75 EXPECT_EQ(key, "k:o");
76 EXPECT_FALSE(LeveldbScopedDatabase::SplitKey("s-k", &scope, &key));
77 EXPECT_FALSE(LeveldbScopedDatabase::SplitKey("", &scope, &key));
78 EXPECT_FALSE(LeveldbScopedDatabase::SplitKey(":k", &scope, &key));
79 }
80
TEST_F(LeveldbScopedDatabaseUnitTest,TestCreateKey)81 TEST_F(LeveldbScopedDatabaseUnitTest, TestCreateKey) {
82 std::string scoped_key;
83
84 EXPECT_TRUE(LeveldbScopedDatabase::CreateKey("scope", "key", &scoped_key));
85 EXPECT_EQ("scope:key", scoped_key);
86 EXPECT_TRUE(LeveldbScopedDatabase::CreateKey("scope", "", &scoped_key));
87 EXPECT_EQ("scope:", scoped_key);
88 EXPECT_TRUE(LeveldbScopedDatabase::CreateKey("scope", "key:o", &scoped_key));
89 EXPECT_EQ("scope:key:o", scoped_key);
90
91 EXPECT_FALSE(LeveldbScopedDatabase::CreateKey("", "key", &scoped_key));
92 EXPECT_FALSE(
93 LeveldbScopedDatabase::CreateKey("scope:withdelim", "key", &scoped_key));
94 }
95
TEST_F(LeveldbScopedDatabaseUnitTest,TestWrite)96 TEST_F(LeveldbScopedDatabaseUnitTest, TestWrite) {
97 std::map<std::string, std::string> db_values;
98 EXPECT_TRUE(ReadAllValues(&db_values).ok());
99 EXPECT_EQ(0u, db_values.size());
100
101 base::DictionaryValue scope1_values;
102 scope1_values.SetString("s1_key1", "s1_value1");
103 scope1_values.SetString("s1_key2", "s1_value2");
104 EXPECT_FALSE(db_->Write("", scope1_values).ok());
105 EXPECT_TRUE(db_->Write("scope1", scope1_values).ok());
106
107 base::DictionaryValue scope2_values;
108 scope2_values.SetString("s2_key1", "s2_value1");
109 scope2_values.SetString("s2_key2", "s2_value2");
110 EXPECT_TRUE(db_->Write("scope2", scope2_values).ok());
111
112 // Read all values using raw leveldb. Values are JSON strings.
113 EXPECT_TRUE(ReadAllValues(&db_values).ok());
114 EXPECT_EQ(4u, db_values.size());
115 EXPECT_EQ("\"s1_value1\"", db_values["scope1:s1_key1"]);
116 EXPECT_EQ("\"s1_value2\"", db_values["scope1:s1_key2"]);
117 EXPECT_EQ("\"s2_value1\"", db_values["scope2:s2_key1"]);
118 EXPECT_EQ("\"s2_value2\"", db_values["scope2:s2_key2"]);
119
120 // Intentionally overwrite value (with a new value).
121 base::DictionaryValue changed_scope2_values;
122 changed_scope2_values.SetString("s2_key1", "s2_value1");
123 changed_scope2_values.SetString("s2_key2", "s2_value3");
124 EXPECT_TRUE(db_->Write("scope2", changed_scope2_values).ok());
125
126 EXPECT_TRUE(ReadAllValues(&db_values).ok());
127 EXPECT_EQ(4u, db_values.size());
128 EXPECT_EQ("\"s1_value1\"", db_values["scope1:s1_key1"]);
129 EXPECT_EQ("\"s1_value2\"", db_values["scope1:s1_key2"]);
130 EXPECT_EQ("\"s2_value1\"", db_values["scope2:s2_key1"]);
131 EXPECT_EQ("\"s2_value3\"", db_values["scope2:s2_key2"]);
132 }
133
TEST_F(LeveldbScopedDatabaseUnitTest,TestRead)134 TEST_F(LeveldbScopedDatabaseUnitTest, TestRead) {
135 base::DictionaryValue scope1_values;
136 scope1_values.SetString("s1_key1", "s1_value1");
137 scope1_values.SetString("s1_key2", "s1_value2");
138 EXPECT_TRUE(db_->Write("scope1", scope1_values).ok());
139
140 base::DictionaryValue scope2_values;
141 scope2_values.SetString("s2_key1", "s2_value1");
142 scope2_values.SetString("s2_key2", "s2_value2");
143 EXPECT_TRUE(db_->Write("scope2", scope2_values).ok());
144
145 // And test an empty scope.
146 EXPECT_FALSE(db_->Write("", scope2_values).ok());
147
148 base::DictionaryValue read_s1_vals;
149 EXPECT_FALSE(db_->Read("", &read_s1_vals).ok());
150 EXPECT_TRUE(db_->Read("scope1", &read_s1_vals).ok());
151 EXPECT_TRUE(scope1_values.Equals(&read_s1_vals));
152
153 base::DictionaryValue read_s2_vals;
154 EXPECT_TRUE(db_->Read("scope2", &read_s2_vals).ok());
155 EXPECT_TRUE(scope2_values.Equals(&read_s2_vals));
156 }
157
TEST_F(LeveldbScopedDatabaseUnitTest,TestEmptyValue)158 TEST_F(LeveldbScopedDatabaseUnitTest, TestEmptyValue) {
159 base::DictionaryValue values;
160 values.SetString("s1_key1", "");
161 EXPECT_TRUE(db_->Write("scope1", values).ok());
162
163 base::Optional<base::Value> value;
164 ASSERT_TRUE(db_->Read("scope1", "s1_key1", &value).ok());
165 ASSERT_TRUE(value.has_value());
166 ASSERT_TRUE(value->is_string());
167 EXPECT_EQ(value->GetString(), "");
168 }
169
TEST_F(LeveldbScopedDatabaseUnitTest,TestValueContainingDelimiter)170 TEST_F(LeveldbScopedDatabaseUnitTest, TestValueContainingDelimiter) {
171 base::DictionaryValue values;
172 values.SetString("s1_key1", "with:delimiter");
173 EXPECT_TRUE(db_->Write("scope1", values).ok());
174
175 base::Optional<base::Value> value;
176 ASSERT_TRUE(db_->Read("scope1", "s1_key1", &value).ok());
177 ASSERT_TRUE(value.has_value());
178 ASSERT_TRUE(value->is_string());
179 EXPECT_EQ(value->GetString(), "with:delimiter");
180 }
181
TEST_F(LeveldbScopedDatabaseUnitTest,TestDeleteValues)182 TEST_F(LeveldbScopedDatabaseUnitTest, TestDeleteValues) {
183 base::DictionaryValue scope1_values;
184 scope1_values.SetString("s1_key1", "s1_value1");
185 scope1_values.SetString("s1_key2", "s1_value2");
186 EXPECT_TRUE(db_->Write("scope1", scope1_values).ok());
187
188 base::DictionaryValue scope2_values;
189 scope2_values.SetString("s2_key1", "s2_value1");
190 scope2_values.SetString("s2_key2", "s2_value2");
191 EXPECT_TRUE(db_->Write("scope2", scope2_values).ok());
192
193 std::vector<std::string> keys;
194 keys.push_back("s2_key1");
195 keys.push_back("s2_key2");
196 keys.push_back("s1_key1");
197 EXPECT_TRUE(db_->DeleteValues("scope2", keys).ok());
198
199 base::DictionaryValue read_s1_vals;
200 EXPECT_TRUE(db_->Read("scope1", &read_s1_vals).ok());
201 EXPECT_TRUE(scope1_values.Equals(&read_s1_vals));
202
203 base::DictionaryValue read_s2_vals;
204 EXPECT_TRUE(db_->Read("scope2", &read_s2_vals).ok());
205 EXPECT_TRUE(read_s2_vals.empty());
206 }
207