Index: webkit/dom_storage/dom_storage_cached_area_unittest.cc |
=================================================================== |
--- webkit/dom_storage/dom_storage_cached_area_unittest.cc (revision 0) |
+++ webkit/dom_storage/dom_storage_cached_area_unittest.cc (revision 0) |
@@ -0,0 +1,349 @@ |
+// Copyright (c) 2012 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 <list> |
+ |
+#include "base/bind.h" |
+#include "base/utf_string_conversions.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "webkit/dom_storage/dom_storage_cached_area.h" |
+#include "webkit/dom_storage/dom_storage_proxy.h" |
+ |
+namespace dom_storage { |
+ |
+namespace { |
+// A mock implementation of the DomStorageProxy interface. |
+class MockProxy : public DomStorageProxy { |
+ public: |
+ MockProxy() { |
+ ResetObservations(); |
+ } |
+ |
+ // DomStorageProxy interface for use by DomStorageCachedArea. |
+ |
+ virtual void LoadArea(int connection_id, ValuesMap* values, |
+ const CompletionCallback& callback) OVERRIDE { |
+ pending_callbacks_.push_back(callback); |
+ observed_load_area_ = true; |
+ observed_connection_id_ = connection_id; |
+ *values = load_area_return_values_; |
+ } |
+ |
+ virtual void SetItem(int connection_id, const string16& key, |
+ const string16& value, const GURL& page_url, |
+ const CompletionCallback& callback) OVERRIDE { |
+ pending_callbacks_.push_back(callback); |
+ observed_set_item_ = true; |
+ observed_connection_id_ = connection_id; |
+ observed_key_ = key; |
+ observed_value_ = value; |
+ observed_page_url_ = page_url; |
+ } |
+ |
+ virtual void RemoveItem(int connection_id, const string16& key, |
+ const GURL& page_url, |
+ const CompletionCallback& callback) OVERRIDE { |
+ pending_callbacks_.push_back(callback); |
+ observed_remove_item_ = true; |
+ observed_connection_id_ = connection_id; |
+ observed_key_ = key; |
+ observed_page_url_ = page_url; |
+ } |
+ |
+ virtual void ClearArea(int connection_id, |
+ const GURL& page_url, |
+ const CompletionCallback& callback) OVERRIDE { |
+ pending_callbacks_.push_back(callback); |
+ observed_clear_area_ = true; |
+ observed_connection_id_ = connection_id; |
+ observed_page_url_ = page_url; |
+ } |
+ |
+ // Methods and members for use by test fixtures. |
+ |
+ void ResetObservations() { |
+ observed_load_area_ = false; |
+ observed_set_item_ = false; |
+ observed_remove_item_ = false; |
+ observed_clear_area_ = false; |
+ observed_connection_id_ = 0; |
+ observed_key_.clear(); |
+ observed_value_.clear(); |
+ observed_page_url_ = GURL(); |
+ } |
+ |
+ void CompleteAllPendingCallbacks() { |
+ while (!pending_callbacks_.empty()) |
+ CompleteOnePendingCallback(true); |
+ } |
+ |
+ void CompleteOnePendingCallback(bool success) { |
+ ASSERT_TRUE(!pending_callbacks_.empty()); |
+ pending_callbacks_.front().Run(success); |
+ pending_callbacks_.pop_front(); |
+ } |
+ |
+ typedef std::list<CompletionCallback> CallbackList; |
+ |
+ ValuesMap load_area_return_values_; |
+ CallbackList pending_callbacks_; |
+ bool observed_load_area_; |
+ bool observed_set_item_; |
+ bool observed_remove_item_; |
+ bool observed_clear_area_; |
+ int observed_connection_id_; |
+ string16 observed_key_; |
+ string16 observed_value_; |
+ GURL observed_page_url_; |
+ |
+ private: |
+ virtual ~MockProxy() {} |
+}; |
+} // namespace |
+ |
+class DomStorageCachedAreaTest : public testing::Test { |
+ public: |
+ DomStorageCachedAreaTest() |
+ : kNamespaceId(10), |
+ kOrigin("http://dom_storage/"), |
+ kKey(ASCIIToUTF16("key")), |
+ kValue(ASCIIToUTF16("value")), |
+ kPageUrl("http://dom_storage/page") { |
+ } |
+ |
+ const int64 kNamespaceId; |
+ const GURL kOrigin; |
+ const string16 kKey; |
+ const string16 kValue; |
+ const GURL kPageUrl; |
+ |
+ virtual void SetUp() { |
+ mock_proxy_ = new MockProxy(); |
+ } |
+ |
+ bool IsPrimed(DomStorageCachedArea* cached_area) { |
+ return cached_area->map_.get(); |
+ } |
+ |
+ bool IsIgnoringAllMutations(DomStorageCachedArea* cached_area) { |
+ return cached_area->ignore_all_mutations_; |
+ } |
+ |
+ bool IsIgnoringKeyMutations(DomStorageCachedArea* cached_area, |
+ const string16& key) { |
+ return cached_area->should_ignore_key_mutation(key); |
+ } |
+ |
+ void ResetAll(DomStorageCachedArea* cached_area) { |
+ cached_area->Reset(); |
+ mock_proxy_->ResetObservations(); |
+ mock_proxy_->pending_callbacks_.clear(); |
+ } |
+ |
+ void ResetCacheOnly(DomStorageCachedArea* cached_area) { |
+ cached_area->Reset(); |
+ } |
+ |
+ protected: |
+ scoped_refptr<MockProxy> mock_proxy_; |
+}; |
+ |
+TEST_F(DomStorageCachedAreaTest, Basics) { |
+ EXPECT_TRUE(mock_proxy_->HasOneRef()); |
+ scoped_refptr<DomStorageCachedArea> cached_area = |
+ new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_); |
+ EXPECT_EQ(kNamespaceId, cached_area->namespace_id()); |
+ EXPECT_EQ(kOrigin, cached_area->origin()); |
+ EXPECT_FALSE(mock_proxy_->HasOneRef()); |
+ cached_area->ApplyMutation(NullableString16(kKey, false), |
+ NullableString16(kValue, false)); |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+ |
+ ResetAll(cached_area); |
+ EXPECT_EQ(kNamespaceId, cached_area->namespace_id()); |
+ EXPECT_EQ(kOrigin, cached_area->origin()); |
+ |
+ const int kConnectionId = 1; |
+ EXPECT_EQ(0u, cached_area->GetLength(kConnectionId)); |
+ EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl)); |
+ EXPECT_EQ(1u, cached_area->GetLength(kConnectionId)); |
+ EXPECT_EQ(kKey, cached_area->GetKey(kConnectionId, 0).string()); |
+ EXPECT_EQ(kValue, cached_area->GetItem(kConnectionId, kKey).string()); |
+ cached_area->RemoveItem(kConnectionId, kKey, kPageUrl); |
+ EXPECT_EQ(0u, cached_area->GetLength(kConnectionId)); |
+} |
+ |
+TEST_F(DomStorageCachedAreaTest, Getters) { |
+ const int kConnectionId = 7; |
+ scoped_refptr<DomStorageCachedArea> cached_area = |
+ new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_); |
+ |
+ // GetLength, we expect to see one call to load in the proxy. |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+ EXPECT_EQ(0u, cached_area->GetLength(kConnectionId)); |
+ EXPECT_TRUE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(mock_proxy_->observed_load_area_); |
+ EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_); |
+ EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size()); |
+ EXPECT_TRUE(IsIgnoringAllMutations(cached_area)); |
+ mock_proxy_->CompleteAllPendingCallbacks(); |
+ EXPECT_FALSE(IsIgnoringAllMutations(cached_area)); |
+ |
+ // GetKey, expect the one call to load. |
+ ResetAll(cached_area); |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(cached_area->GetKey(kConnectionId, 2).is_null()); |
+ EXPECT_TRUE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(mock_proxy_->observed_load_area_); |
+ EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_); |
+ EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size()); |
+ |
+ // GetItem, ditto. |
+ ResetAll(cached_area); |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(cached_area->GetItem(kConnectionId, kKey).is_null()); |
+ EXPECT_TRUE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(mock_proxy_->observed_load_area_); |
+ EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_); |
+ EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size()); |
+} |
+ |
+TEST_F(DomStorageCachedAreaTest, Setters) { |
+ const int kConnectionId = 7; |
+ scoped_refptr<DomStorageCachedArea> cached_area = |
+ new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_); |
+ |
+ // SetItem, we expect a call to load followed by a call to set item |
+ // in the proxy. |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl)); |
+ EXPECT_TRUE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(mock_proxy_->observed_load_area_); |
+ EXPECT_TRUE(mock_proxy_->observed_set_item_); |
+ EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_); |
+ EXPECT_EQ(kPageUrl, mock_proxy_->observed_page_url_); |
+ EXPECT_EQ(kKey, mock_proxy_->observed_key_); |
+ EXPECT_EQ(kValue, mock_proxy_->observed_value_); |
+ EXPECT_EQ(2u, mock_proxy_->pending_callbacks_.size()); |
+ |
+ // Clear, we expect a just the one call to clear in the proxy since |
+ // there's no need to load the data prior to deleting it. |
+ ResetAll(cached_area); |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+ cached_area->Clear(kConnectionId, kPageUrl); |
+ EXPECT_TRUE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(mock_proxy_->observed_clear_area_); |
+ EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_); |
+ EXPECT_EQ(kPageUrl, mock_proxy_->observed_page_url_); |
+ EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size()); |
+ |
+ // RemoveItem with nothing to remove, expect just one call to load. |
+ ResetAll(cached_area); |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+ cached_area->RemoveItem(kConnectionId, kKey, kPageUrl); |
+ EXPECT_TRUE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(mock_proxy_->observed_load_area_); |
+ EXPECT_FALSE(mock_proxy_->observed_remove_item_); |
+ EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_); |
+ EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size()); |
+ |
+ // RemoveItem with something to remove, expect a call to load followed |
+ // by a call to remove. |
+ ResetAll(cached_area); |
+ mock_proxy_->load_area_return_values_[kKey] = NullableString16(kValue, false); |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+ cached_area->RemoveItem(kConnectionId, kKey, kPageUrl); |
+ EXPECT_TRUE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(mock_proxy_->observed_load_area_); |
+ EXPECT_TRUE(mock_proxy_->observed_remove_item_); |
+ EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_); |
+ EXPECT_EQ(kPageUrl, mock_proxy_->observed_page_url_); |
+ EXPECT_EQ(kKey, mock_proxy_->observed_key_); |
+ EXPECT_EQ(2u, mock_proxy_->pending_callbacks_.size()); |
+} |
+ |
+TEST_F(DomStorageCachedAreaTest, MutationsAreIgnoredUntilLoadCompletion) { |
+ const int kConnectionId = 7; |
+ scoped_refptr<DomStorageCachedArea> cached_area = |
+ new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_); |
+ EXPECT_TRUE(cached_area->GetItem(kConnectionId, kKey).is_null()); |
+ EXPECT_TRUE(IsPrimed(cached_area)); |
+ EXPECT_TRUE(IsIgnoringAllMutations(cached_area)); |
+ |
+ // Before load completion, the mutation should be ignored. |
+ cached_area->ApplyMutation(NullableString16(kKey, false), |
+ NullableString16(kValue, false)); |
+ EXPECT_TRUE(cached_area->GetItem(kConnectionId, kKey).is_null()); |
+ |
+ // Call the load completion callback. |
+ mock_proxy_->CompleteOnePendingCallback(true); |
+ EXPECT_FALSE(IsIgnoringAllMutations(cached_area)); |
+ |
+ // Verify that mutations are now applied. |
+ cached_area->ApplyMutation(NullableString16(kKey, false), |
+ NullableString16(kValue, false)); |
+ EXPECT_EQ(kValue, cached_area->GetItem(kConnectionId, kKey).string()); |
+} |
+ |
+TEST_F(DomStorageCachedAreaTest, MutationsAreIgnoredUntilClearCompletion) { |
+ const int kConnectionId = 4; |
+ scoped_refptr<DomStorageCachedArea> cached_area = |
+ new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_); |
+ cached_area->Clear(kConnectionId, kPageUrl); |
+ EXPECT_TRUE(IsIgnoringAllMutations(cached_area)); |
+ mock_proxy_->CompleteOnePendingCallback(true); |
+ EXPECT_FALSE(IsIgnoringAllMutations(cached_area)); |
+ |
+ // Verify that calling Clear twice works as expected, the first |
+ // completion callback should have been cancelled. |
+ ResetCacheOnly(cached_area); |
+ cached_area->Clear(kConnectionId, kPageUrl); |
+ EXPECT_TRUE(IsIgnoringAllMutations(cached_area)); |
+ cached_area->Clear(kConnectionId, kPageUrl); |
+ EXPECT_TRUE(IsIgnoringAllMutations(cached_area)); |
+ mock_proxy_->CompleteOnePendingCallback(true); |
+ EXPECT_TRUE(IsIgnoringAllMutations(cached_area)); |
+ mock_proxy_->CompleteOnePendingCallback(true); |
+ EXPECT_FALSE(IsIgnoringAllMutations(cached_area)); |
+} |
+ |
+TEST_F(DomStorageCachedAreaTest, KeyMutationsAreIgnoredUntilCompletion) { |
+ const int kConnectionId = 8; |
+ scoped_refptr<DomStorageCachedArea> cached_area = |
+ new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_); |
+ |
+ // SetItem |
+ EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl)); |
+ mock_proxy_->CompleteOnePendingCallback(true); // load completion |
+ EXPECT_FALSE(IsIgnoringAllMutations(cached_area)); |
+ EXPECT_TRUE(IsIgnoringKeyMutations(cached_area, kKey)); |
+ cached_area->ApplyMutation(NullableString16(kKey, false), |
+ NullableString16(true)); |
+ EXPECT_EQ(kValue, cached_area->GetItem(kConnectionId, kKey).string()); |
+ mock_proxy_->CompleteOnePendingCallback(true); // set completion |
+ EXPECT_FALSE(IsIgnoringKeyMutations(cached_area, kKey)); |
+ |
+ // RemoveItem |
+ cached_area->RemoveItem(kConnectionId, kKey, kPageUrl); |
+ EXPECT_TRUE(IsIgnoringKeyMutations(cached_area, kKey)); |
+ mock_proxy_->CompleteOnePendingCallback(true); // remove completion |
+ EXPECT_FALSE(IsIgnoringKeyMutations(cached_area, kKey)); |
+ |
+ // Multiple mutations to the same key. |
+ EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl)); |
+ cached_area->RemoveItem(kConnectionId, kKey, kPageUrl); |
+ EXPECT_TRUE(IsIgnoringKeyMutations(cached_area, kKey)); |
+ mock_proxy_->CompleteOnePendingCallback(true); // set completion |
+ EXPECT_TRUE(IsIgnoringKeyMutations(cached_area, kKey)); |
+ mock_proxy_->CompleteOnePendingCallback(true); // remove completion |
+ EXPECT_FALSE(IsIgnoringKeyMutations(cached_area, kKey)); |
+ |
+ // A failed set item operation should Reset the cache. |
+ EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl)); |
+ EXPECT_TRUE(IsIgnoringKeyMutations(cached_area, kKey)); |
+ mock_proxy_->CompleteOnePendingCallback(false); |
+ EXPECT_FALSE(IsPrimed(cached_area)); |
+} |
+ |
+} // namespace dom_storage |
Property changes on: webkit\dom_storage\dom_storage_cached_area_unittest.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |