| 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 |