Index: content/browser/dom_storage/local_storage_context_mojo_unittest.cc |
diff --git a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc |
index aa5be074a138cb1f73b0697c08cb0a73e285756c..33db77ce8fceb280e24febebc21bf7434626e73f 100644 |
--- a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc |
+++ b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc |
@@ -13,6 +13,7 @@ |
#include "content/public/browser/local_storage_usage_info.h" |
#include "content/public/test/test_browser_thread_bundle.h" |
#include "content/test/mock_leveldb_database.h" |
+#include "mojo/public/cpp/bindings/associated_binding.h" |
#include "mojo/public/cpp/bindings/binding.h" |
#include "mojo/public/cpp/bindings/binding_set.h" |
#include "services/file/file_service.h" |
@@ -51,6 +52,56 @@ void GetCallback(const base::Closure& callback, |
callback.Run(); |
} |
+class TestLevelDBObserver : public mojom::LevelDBObserver { |
+ public: |
+ struct Observation { |
+ enum { kAdd, kChange, kDelete, kDeleteAll } type; |
+ std::string key; |
+ std::string old_value; |
+ std::string new_value; |
+ std::string source; |
+ }; |
+ |
+ TestLevelDBObserver() : binding_(this) {} |
+ |
+ mojom::LevelDBObserverAssociatedPtrInfo Bind( |
+ mojo::AssociatedGroup* associated_group) { |
+ mojom::LevelDBObserverAssociatedPtrInfo ptr_info; |
+ binding_.Bind(&ptr_info, associated_group); |
+ return ptr_info; |
+ } |
+ |
+ const std::vector<Observation>& observations() { return observations_; } |
+ |
+ private: |
+ void KeyAdded(const std::vector<uint8_t>& key, |
+ const std::vector<uint8_t>& value, |
+ const std::string& source) override { |
+ observations_.push_back({Observation::kAdd, Uint8VectorToStdString(key), "", |
+ Uint8VectorToStdString(value), source}); |
+ } |
+ void KeyChanged(const std::vector<uint8_t>& key, |
+ const std::vector<uint8_t>& new_value, |
+ const std::vector<uint8_t>& old_value, |
+ const std::string& source) override { |
+ observations_.push_back({Observation::kChange, Uint8VectorToStdString(key), |
+ Uint8VectorToStdString(old_value), |
+ Uint8VectorToStdString(new_value), source}); |
+ } |
+ void KeyDeleted(const std::vector<uint8_t>& key, |
+ const std::vector<uint8_t>& old_value, |
+ const std::string& source) override { |
+ observations_.push_back({Observation::kDelete, Uint8VectorToStdString(key), |
+ Uint8VectorToStdString(old_value), "", source}); |
+ } |
+ void AllDeleted(const std::string& source) override { |
+ observations_.push_back({Observation::kDeleteAll, "", "", "", source}); |
+ } |
+ |
+ std::vector<Observation> observations_; |
+ mojo::AssociatedBinding<mojom::LevelDBObserver> binding_; |
+}; |
+ |
} // namespace |
class LocalStorageContextMojoTest : public testing::Test { |
@@ -300,6 +351,183 @@ TEST_F(LocalStorageContextMojoTest, MetaDataClearedOnDeleteAll) { |
} |
} |
+TEST_F(LocalStorageContextMojoTest, DeleteStorage) { |
+ set_mock_data("VERSION", "1"); |
+ set_mock_data(std::string("_http://foobar.com") + '\x00' + "key", "value"); |
+ |
+ context()->DeleteStorage(url::Origin(GURL("http://foobar.com"))); |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_EQ(1u, mock_data().size()); |
+} |
+ |
+TEST_F(LocalStorageContextMojoTest, DeleteStorageWithoutConnection) { |
+ url::Origin origin1(GURL("http://foobar.com")); |
+ url::Origin origin2(GURL("http://example.com")); |
+ auto key = StdStringToUint8Vector("key"); |
+ auto value = StdStringToUint8Vector("value"); |
+ |
+ mojom::LevelDBWrapperPtr wrapper; |
+ context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ |
+ context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ |
+ // Make sure all data gets committed to disk. |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_FALSE(mock_data().empty()); |
+ |
+ context()->DeleteStorage(origin1); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Data from origin2 should exist, including meta-data, but nothing should |
+ // exist for origin1. |
+ EXPECT_EQ(3u, mock_data().size()); |
+ for (const auto& it : mock_data()) { |
+ if (Uint8VectorToStdString(it.first) == "VERSION") |
+ continue; |
+ EXPECT_EQ(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin1.Serialize())); |
+ EXPECT_NE(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin2.Serialize())); |
+ } |
+} |
+ |
+TEST_F(LocalStorageContextMojoTest, DeleteStorageNotifiesWrapper) { |
+ url::Origin origin1(GURL("http://foobar.com")); |
+ url::Origin origin2(GURL("http://example.com")); |
+ auto key = StdStringToUint8Vector("key"); |
+ auto value = StdStringToUint8Vector("value"); |
+ |
+ mojom::LevelDBWrapperPtr wrapper; |
+ context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ |
+ context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ |
+ // Make sure all data gets committed to disk. |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_FALSE(mock_data().empty()); |
+ |
+ TestLevelDBObserver observer; |
+ context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
+ wrapper->AddObserver(observer.Bind(wrapper.associated_group())); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ context()->DeleteStorage(origin1); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ ASSERT_EQ(1u, observer.observations().size()); |
+ EXPECT_EQ(TestLevelDBObserver::Observation::kDeleteAll, |
+ observer.observations()[0].type); |
+ |
+ // Data from origin2 should exist, including meta-data, but nothing should |
+ // exist for origin1. |
+ EXPECT_EQ(3u, mock_data().size()); |
+ for (const auto& it : mock_data()) { |
+ if (Uint8VectorToStdString(it.first) == "VERSION") |
+ continue; |
+ EXPECT_EQ(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin1.Serialize())); |
+ EXPECT_NE(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin2.Serialize())); |
+ } |
+} |
+ |
+TEST_F(LocalStorageContextMojoTest, DeleteStorageWithPendingWrites) { |
+ url::Origin origin1(GURL("http://foobar.com")); |
+ url::Origin origin2(GURL("http://example.com")); |
+ auto key = StdStringToUint8Vector("key"); |
+ auto value = StdStringToUint8Vector("value"); |
+ |
+ mojom::LevelDBWrapperPtr wrapper; |
+ context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ |
+ context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ |
+ // Make sure all data gets committed to disk. |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_FALSE(mock_data().empty()); |
+ |
+ TestLevelDBObserver observer; |
+ context()->OpenLocalStorage(origin1, MakeRequest(&wrapper)); |
+ wrapper->AddObserver(observer.Bind(wrapper.associated_group())); |
+ wrapper->Put(StdStringToUint8Vector("key2"), value, "source", |
+ base::Bind(&NoOpSuccess)); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ context()->DeleteStorage(origin1); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ ASSERT_EQ(2u, observer.observations().size()); |
+ EXPECT_EQ(TestLevelDBObserver::Observation::kAdd, |
+ observer.observations()[0].type); |
+ EXPECT_EQ(TestLevelDBObserver::Observation::kDeleteAll, |
+ observer.observations()[1].type); |
+ |
+ // Data from origin2 should exist, including meta-data, but nothing should |
+ // exist for origin1. |
+ EXPECT_EQ(3u, mock_data().size()); |
+ for (const auto& it : mock_data()) { |
+ if (Uint8VectorToStdString(it.first) == "VERSION") |
+ continue; |
+ EXPECT_EQ(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin1.Serialize())); |
+ EXPECT_NE(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin2.Serialize())); |
+ } |
+} |
+ |
+TEST_F(LocalStorageContextMojoTest, DeleteStorageForPhysicalOrigin) { |
+ url::Origin origin1a(GURL("http://foobar.com")); |
+ url::Origin origin1b(GURL("http-so://suborigin.foobar.com")); |
+ url::Origin origin2(GURL("https://foobar.com")); |
+ auto key = StdStringToUint8Vector("key"); |
+ auto value = StdStringToUint8Vector("value"); |
+ |
+ mojom::LevelDBWrapperPtr wrapper; |
+ context()->OpenLocalStorage(origin1a, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ context()->OpenLocalStorage(origin1b, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ |
+ context()->OpenLocalStorage(origin2, MakeRequest(&wrapper)); |
+ wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess)); |
+ wrapper.reset(); |
+ |
+ // Make sure all data gets committed to disk. |
+ base::RunLoop().RunUntilIdle(); |
+ EXPECT_FALSE(mock_data().empty()); |
+ |
+ context()->DeleteStorageForPhysicalOrigin(origin1b); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Data from origin2 should exist, including meta-data, but nothing should |
+ // exist for origin1. |
+ EXPECT_EQ(3u, mock_data().size()); |
+ for (const auto& it : mock_data()) { |
+ if (Uint8VectorToStdString(it.first) == "VERSION") |
+ continue; |
+ EXPECT_EQ(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin1a.Serialize())); |
+ EXPECT_EQ(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin1b.Serialize())); |
+ EXPECT_NE(std::string::npos, |
+ Uint8VectorToStdString(it.first).find(origin2.Serialize())); |
+ } |
+} |
+ |
namespace { |
class ServiceTestClient : public service_manager::test::ServiceTestClient, |