OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/dom_storage/local_storage_context_mojo.h" | 5 #include "content/browser/dom_storage/local_storage_context_mojo.h" |
6 | 6 |
7 #include "base/files/file_enumerator.h" | 7 #include "base/files/file_enumerator.h" |
8 #include "base/files/scoped_temp_dir.h" | 8 #include "base/files/scoped_temp_dir.h" |
9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
10 #include "components/filesystem/public/interfaces/file_system.mojom.h" | 10 #include "components/filesystem/public/interfaces/file_system.mojom.h" |
11 #include "components/leveldb/public/cpp/util.h" | 11 #include "components/leveldb/public/cpp/util.h" |
12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 13 #include "content/public/browser/local_storage_usage_info.h" |
13 #include "content/public/test/test_browser_thread_bundle.h" | 14 #include "content/public/test/test_browser_thread_bundle.h" |
14 #include "content/test/mock_leveldb_database.h" | 15 #include "content/test/mock_leveldb_database.h" |
15 #include "mojo/public/cpp/bindings/binding.h" | 16 #include "mojo/public/cpp/bindings/binding.h" |
16 #include "mojo/public/cpp/bindings/binding_set.h" | 17 #include "mojo/public/cpp/bindings/binding_set.h" |
17 #include "services/file/file_service.h" | 18 #include "services/file/file_service.h" |
18 #include "services/file/public/interfaces/constants.mojom.h" | 19 #include "services/file/public/interfaces/constants.mojom.h" |
19 #include "services/file/user_id_map.h" | 20 #include "services/file/user_id_map.h" |
20 #include "services/service_manager/public/cpp/interface_factory.h" | 21 #include "services/service_manager/public/cpp/interface_factory.h" |
21 #include "services/service_manager/public/cpp/interface_registry.h" | 22 #include "services/service_manager/public/cpp/interface_registry.h" |
22 #include "services/service_manager/public/cpp/service_context.h" | 23 #include "services/service_manager/public/cpp/service_context.h" |
23 #include "services/service_manager/public/cpp/service_test.h" | 24 #include "services/service_manager/public/cpp/service_test.h" |
24 #include "services/service_manager/public/interfaces/service_factory.mojom.h" | 25 #include "services/service_manager/public/interfaces/service_factory.mojom.h" |
25 #include "testing/gtest/include/gtest/gtest.h" | 26 #include "testing/gtest/include/gtest/gtest.h" |
26 | 27 |
27 using leveldb::StdStringToUint8Vector; | 28 using leveldb::StdStringToUint8Vector; |
28 using leveldb::Uint8VectorToStdString; | 29 using leveldb::Uint8VectorToStdString; |
29 | 30 |
30 namespace content { | 31 namespace content { |
31 | 32 |
32 namespace { | 33 namespace { |
33 | 34 |
34 void NoOpSuccess(bool success) {} | 35 void NoOpSuccess(bool success) {} |
35 | 36 |
| 37 void GetStorageUsageCallback(const base::Closure& callback, |
| 38 std::vector<LocalStorageUsageInfo>* out_result, |
| 39 std::vector<LocalStorageUsageInfo> result) { |
| 40 *out_result = std::move(result); |
| 41 callback.Run(); |
| 42 } |
| 43 |
36 void GetCallback(const base::Closure& callback, | 44 void GetCallback(const base::Closure& callback, |
37 bool* success_out, | 45 bool* success_out, |
38 std::vector<uint8_t>* value_out, | 46 std::vector<uint8_t>* value_out, |
39 bool success, | 47 bool success, |
40 const std::vector<uint8_t>& value) { | 48 const std::vector<uint8_t>& value) { |
41 *success_out = success; | 49 *success_out = success; |
42 *value_out = value; | 50 *value_out = value; |
43 callback.Run(); | 51 callback.Run(); |
44 } | 52 } |
45 | 53 |
(...skipping 12 matching lines...) Expand all Loading... |
58 return context_.get(); | 66 return context_.get(); |
59 } | 67 } |
60 const std::map<std::vector<uint8_t>, std::vector<uint8_t>>& mock_data() { | 68 const std::map<std::vector<uint8_t>, std::vector<uint8_t>>& mock_data() { |
61 return mock_data_; | 69 return mock_data_; |
62 } | 70 } |
63 | 71 |
64 void set_mock_data(const std::string& key, const std::string& value) { | 72 void set_mock_data(const std::string& key, const std::string& value) { |
65 mock_data_[StdStringToUint8Vector(key)] = StdStringToUint8Vector(value); | 73 mock_data_[StdStringToUint8Vector(key)] = StdStringToUint8Vector(value); |
66 } | 74 } |
67 | 75 |
| 76 std::vector<LocalStorageUsageInfo> GetStorageUsageSync() { |
| 77 base::RunLoop run_loop; |
| 78 std::vector<LocalStorageUsageInfo> result; |
| 79 context()->GetStorageUsage(base::BindOnce(&GetStorageUsageCallback, |
| 80 run_loop.QuitClosure(), &result)); |
| 81 run_loop.Run(); |
| 82 return result; |
| 83 } |
| 84 |
68 private: | 85 private: |
69 TestBrowserThreadBundle thread_bundle_; | 86 TestBrowserThreadBundle thread_bundle_; |
70 std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_; | 87 std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_; |
71 MockLevelDBDatabase db_; | 88 MockLevelDBDatabase db_; |
72 mojo::Binding<leveldb::mojom::LevelDBDatabase> db_binding_; | 89 mojo::Binding<leveldb::mojom::LevelDBDatabase> db_binding_; |
73 | 90 |
74 std::unique_ptr<LocalStorageContextMojo> context_; | 91 std::unique_ptr<LocalStorageContextMojo> context_; |
75 | 92 |
76 DISALLOW_COPY_AND_ASSIGN(LocalStorageContextMojoTest); | 93 DISALLOW_COPY_AND_ASSIGN(LocalStorageContextMojoTest); |
77 }; | 94 }; |
78 | 95 |
79 TEST_F(LocalStorageContextMojoTest, Basic) { | 96 TEST_F(LocalStorageContextMojoTest, Basic) { |
80 auto key = StdStringToUint8Vector("key"); | 97 auto key = StdStringToUint8Vector("key"); |
81 auto value = StdStringToUint8Vector("value"); | 98 auto value = StdStringToUint8Vector("value"); |
82 | 99 |
83 mojom::LevelDBWrapperPtr wrapper; | 100 mojom::LevelDBWrapperPtr wrapper; |
84 context()->OpenLocalStorage(url::Origin(GURL("http://foobar.com")), | 101 context()->OpenLocalStorage(url::Origin(GURL("http://foobar.com")), |
85 MakeRequest(&wrapper)); | 102 MakeRequest(&wrapper)); |
86 wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); | 103 wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
87 wrapper.reset(); | 104 wrapper.reset(); |
88 | 105 |
89 base::RunLoop().RunUntilIdle(); | 106 base::RunLoop().RunUntilIdle(); |
90 | 107 |
91 ASSERT_EQ(2u, mock_data().size()); | 108 // Should have three rows of data, one for the version, one for the actual |
92 EXPECT_EQ(value, mock_data().rbegin()->second); | 109 // data and one for metadata. |
| 110 ASSERT_EQ(3u, mock_data().size()); |
93 } | 111 } |
94 | 112 |
95 TEST_F(LocalStorageContextMojoTest, OriginsAreIndependent) { | 113 TEST_F(LocalStorageContextMojoTest, OriginsAreIndependent) { |
96 url::Origin origin1(GURL("http://foobar.com:123")); | 114 url::Origin origin1(GURL("http://foobar.com:123")); |
97 url::Origin origin2(GURL("http://foobar.com:1234")); | 115 url::Origin origin2(GURL("http://foobar.com:1234")); |
98 auto key1 = StdStringToUint8Vector("4key"); | 116 auto key1 = StdStringToUint8Vector("4key"); |
99 auto key2 = StdStringToUint8Vector("key"); | 117 auto key2 = StdStringToUint8Vector("key"); |
100 auto value = StdStringToUint8Vector("value"); | 118 auto value = StdStringToUint8Vector("value"); |
101 | 119 |
102 mojom::LevelDBWrapperPtr wrapper; | 120 mojom::LevelDBWrapperPtr wrapper; |
103 context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); | 121 context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
104 wrapper->Put(key1, value, "source", base::Bind(&NoOpSuccess)); | 122 wrapper->Put(key1, value, "source", base::Bind(&NoOpSuccess)); |
105 wrapper.reset(); | 123 wrapper.reset(); |
106 | 124 |
107 context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); | 125 context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); |
108 wrapper->Put(key2, value, "source", base::Bind(&NoOpSuccess)); | 126 wrapper->Put(key2, value, "source", base::Bind(&NoOpSuccess)); |
109 wrapper.reset(); | 127 wrapper.reset(); |
110 | 128 |
111 base::RunLoop().RunUntilIdle(); | 129 base::RunLoop().RunUntilIdle(); |
112 ASSERT_EQ(3u, mock_data().size()); | 130 ASSERT_EQ(5u, mock_data().size()); |
113 EXPECT_EQ(value, mock_data().rbegin()->second); | |
114 } | 131 } |
115 | 132 |
116 TEST_F(LocalStorageContextMojoTest, ValidVersion) { | 133 TEST_F(LocalStorageContextMojoTest, ValidVersion) { |
117 set_mock_data("VERSION", "1"); | 134 set_mock_data("VERSION", "1"); |
118 set_mock_data(std::string("_http://foobar.com") + '\x00' + "key", "value"); | 135 set_mock_data(std::string("_http://foobar.com") + '\x00' + "key", "value"); |
119 | 136 |
120 mojom::LevelDBWrapperPtr wrapper; | 137 mojom::LevelDBWrapperPtr wrapper; |
121 context()->OpenLocalStorage(url::Origin(GURL("http://foobar.com")), | 138 context()->OpenLocalStorage(url::Origin(GURL("http://foobar.com")), |
122 MakeRequest(&wrapper)); | 139 MakeRequest(&wrapper)); |
123 | 140 |
(...skipping 23 matching lines...) Expand all Loading... |
147 StdStringToUint8Vector("key"), | 164 StdStringToUint8Vector("key"), |
148 base::Bind(&GetCallback, run_loop.QuitClosure(), &success, &result)); | 165 base::Bind(&GetCallback, run_loop.QuitClosure(), &success, &result)); |
149 run_loop.Run(); | 166 run_loop.Run(); |
150 EXPECT_FALSE(success); | 167 EXPECT_FALSE(success); |
151 } | 168 } |
152 | 169 |
153 TEST_F(LocalStorageContextMojoTest, VersionOnlyWrittenOnCommit) { | 170 TEST_F(LocalStorageContextMojoTest, VersionOnlyWrittenOnCommit) { |
154 mojom::LevelDBWrapperPtr wrapper; | 171 mojom::LevelDBWrapperPtr wrapper; |
155 context()->OpenLocalStorage(url::Origin(GURL("http://foobar.com")), | 172 context()->OpenLocalStorage(url::Origin(GURL("http://foobar.com")), |
156 MakeRequest(&wrapper)); | 173 MakeRequest(&wrapper)); |
| 174 |
157 base::RunLoop run_loop; | 175 base::RunLoop run_loop; |
158 bool success = false; | 176 bool success = false; |
159 std::vector<uint8_t> result; | 177 std::vector<uint8_t> result; |
160 wrapper->Get( | 178 wrapper->Get( |
161 StdStringToUint8Vector("key"), | 179 StdStringToUint8Vector("key"), |
162 base::Bind(&GetCallback, run_loop.QuitClosure(), &success, &result)); | 180 base::Bind(&GetCallback, run_loop.QuitClosure(), &success, &result)); |
163 run_loop.Run(); | 181 run_loop.Run(); |
164 EXPECT_FALSE(success); | 182 EXPECT_FALSE(success); |
165 wrapper.reset(); | 183 wrapper.reset(); |
166 | 184 |
167 base::RunLoop().RunUntilIdle(); | 185 base::RunLoop().RunUntilIdle(); |
168 EXPECT_TRUE(mock_data().empty()); | 186 EXPECT_TRUE(mock_data().empty()); |
169 } | 187 } |
170 | 188 |
| 189 TEST_F(LocalStorageContextMojoTest, GetStorageUsage_NoData) { |
| 190 std::vector<LocalStorageUsageInfo> info = GetStorageUsageSync(); |
| 191 EXPECT_EQ(0u, info.size()); |
| 192 } |
| 193 |
| 194 TEST_F(LocalStorageContextMojoTest, GetStorageUsage_Data) { |
| 195 url::Origin origin1(GURL("http://foobar.com")); |
| 196 url::Origin origin2(GURL("http://example.com")); |
| 197 auto key1 = StdStringToUint8Vector("key1"); |
| 198 auto key2 = StdStringToUint8Vector("key"); |
| 199 auto value = StdStringToUint8Vector("value"); |
| 200 |
| 201 base::Time before_write = base::Time::Now(); |
| 202 |
| 203 mojom::LevelDBWrapperPtr wrapper; |
| 204 context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
| 205 wrapper->Put(key1, value, "source", base::Bind(&NoOpSuccess)); |
| 206 wrapper->Put(key2, value, "source", base::Bind(&NoOpSuccess)); |
| 207 wrapper.reset(); |
| 208 |
| 209 context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); |
| 210 wrapper->Put(key2, value, "source", base::Bind(&NoOpSuccess)); |
| 211 wrapper.reset(); |
| 212 |
| 213 // GetStorageUsage only include committed data, so nothing at this point. |
| 214 std::vector<LocalStorageUsageInfo> info = GetStorageUsageSync(); |
| 215 EXPECT_EQ(0u, info.size()); |
| 216 |
| 217 // Make sure all data gets committed to disk. |
| 218 base::RunLoop().RunUntilIdle(); |
| 219 |
| 220 base::Time after_write = base::Time::Now(); |
| 221 |
| 222 info = GetStorageUsageSync(); |
| 223 ASSERT_EQ(2u, info.size()); |
| 224 if (url::Origin(info[0].origin) == origin2) |
| 225 std::swap(info[0], info[1]); |
| 226 |
| 227 EXPECT_EQ(origin1, url::Origin(info[0].origin)); |
| 228 EXPECT_EQ(origin2, url::Origin(info[1].origin)); |
| 229 EXPECT_LE(before_write, info[0].last_modified); |
| 230 EXPECT_LE(before_write, info[1].last_modified); |
| 231 EXPECT_GE(after_write, info[0].last_modified); |
| 232 EXPECT_GE(after_write, info[1].last_modified); |
| 233 EXPECT_GT(info[0].data_size, info[1].data_size); |
| 234 } |
| 235 |
| 236 TEST_F(LocalStorageContextMojoTest, MetaDataClearedOnDelete) { |
| 237 url::Origin origin1(GURL("http://foobar.com")); |
| 238 url::Origin origin2(GURL("http://example.com")); |
| 239 auto key = StdStringToUint8Vector("key"); |
| 240 auto value = StdStringToUint8Vector("value"); |
| 241 |
| 242 mojom::LevelDBWrapperPtr wrapper; |
| 243 context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
| 244 wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
| 245 wrapper.reset(); |
| 246 context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); |
| 247 wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
| 248 wrapper.reset(); |
| 249 context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
| 250 wrapper->Delete(key, "source", base::Bind(&NoOpSuccess)); |
| 251 wrapper.reset(); |
| 252 |
| 253 // Make sure all data gets committed to disk. |
| 254 base::RunLoop().RunUntilIdle(); |
| 255 |
| 256 // Data from origin2 should exist, including meta-data, but nothing should |
| 257 // exist for origin1. |
| 258 EXPECT_EQ(3u, mock_data().size()); |
| 259 for (const auto& it : mock_data()) { |
| 260 if (Uint8VectorToStdString(it.first) == "VERSION") |
| 261 continue; |
| 262 EXPECT_EQ(std::string::npos, |
| 263 Uint8VectorToStdString(it.first).find(origin1.Serialize())); |
| 264 EXPECT_NE(std::string::npos, |
| 265 Uint8VectorToStdString(it.first).find(origin2.Serialize())); |
| 266 } |
| 267 } |
| 268 |
| 269 TEST_F(LocalStorageContextMojoTest, MetaDataClearedOnDeleteAll) { |
| 270 url::Origin origin1(GURL("http://foobar.com")); |
| 271 url::Origin origin2(GURL("http://example.com")); |
| 272 auto key = StdStringToUint8Vector("key"); |
| 273 auto value = StdStringToUint8Vector("value"); |
| 274 |
| 275 mojom::LevelDBWrapperPtr wrapper; |
| 276 context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
| 277 wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
| 278 wrapper.reset(); |
| 279 context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); |
| 280 wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
| 281 wrapper.reset(); |
| 282 |
| 283 context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
| 284 wrapper->DeleteAll("source", base::Bind(&NoOpSuccess)); |
| 285 wrapper.reset(); |
| 286 |
| 287 // Make sure all data gets committed to disk. |
| 288 base::RunLoop().RunUntilIdle(); |
| 289 |
| 290 // Data from origin2 should exist, including meta-data, but nothing should |
| 291 // exist for origin1. |
| 292 EXPECT_EQ(3u, mock_data().size()); |
| 293 for (const auto& it : mock_data()) { |
| 294 if (Uint8VectorToStdString(it.first) == "VERSION") |
| 295 continue; |
| 296 EXPECT_EQ(std::string::npos, |
| 297 Uint8VectorToStdString(it.first).find(origin1.Serialize())); |
| 298 EXPECT_NE(std::string::npos, |
| 299 Uint8VectorToStdString(it.first).find(origin2.Serialize())); |
| 300 } |
| 301 } |
| 302 |
171 namespace { | 303 namespace { |
172 | 304 |
173 class ServiceTestClient : public service_manager::test::ServiceTestClient, | 305 class ServiceTestClient : public service_manager::test::ServiceTestClient, |
174 public service_manager::mojom::ServiceFactory, | 306 public service_manager::mojom::ServiceFactory, |
175 public service_manager::InterfaceFactory< | 307 public service_manager::InterfaceFactory< |
176 service_manager::mojom::ServiceFactory> { | 308 service_manager::mojom::ServiceFactory> { |
177 public: | 309 public: |
178 explicit ServiceTestClient(service_manager::test::ServiceTest* test) | 310 explicit ServiceTestClient(service_manager::test::ServiceTest* test) |
179 : service_manager::test::ServiceTestClient(test) {} | 311 : service_manager::test::ServiceTestClient(test) {} |
180 ~ServiceTestClient() override {} | 312 ~ServiceTestClient() override {} |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 // Should have created files. | 498 // Should have created files. |
367 EXPECT_EQ(test_path, FirstEntryInDir().BaseName()); | 499 EXPECT_EQ(test_path, FirstEntryInDir().BaseName()); |
368 | 500 |
369 // Should be able to re-open. | 501 // Should be able to re-open. |
370 context.reset(new LocalStorageContextMojo(connector(), test_path)); | 502 context.reset(new LocalStorageContextMojo(connector(), test_path)); |
371 EXPECT_TRUE(DoTestGet(context.get(), key, &result)); | 503 EXPECT_TRUE(DoTestGet(context.get(), key, &result)); |
372 EXPECT_EQ(value, result); | 504 EXPECT_EQ(value, result); |
373 } | 505 } |
374 | 506 |
375 } // namespace content | 507 } // namespace content |
OLD | NEW |