Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / renderer / dom_storage / dom_storage_cached_area_unittest.cc
1 // Copyright (c) 2012 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 "content/renderer/dom_storage/dom_storage_cached_area.h"
6
7 #include <list>
8
9 #include "base/bind.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/renderer/dom_storage/dom_storage_proxy.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace content {
15
16 namespace {
17 // A mock implementation of the DOMStorageProxy interface.
18 class MockProxy : public DOMStorageProxy {
19  public:
20   MockProxy() {
21     ResetObservations();
22   }
23
24   // DOMStorageProxy interface for use by DOMStorageCachedArea.
25
26   void LoadArea(int connection_id,
27                 DOMStorageValuesMap* values,
28                 bool* send_log_get_messages,
29                 const CompletionCallback& callback) override {
30     pending_callbacks_.push_back(callback);
31     observed_load_area_ = true;
32     observed_connection_id_ = connection_id;
33     *values = load_area_return_values_;
34     *send_log_get_messages = false;
35   }
36
37   void SetItem(int connection_id,
38                const base::string16& key,
39                const base::string16& value,
40                const GURL& page_url,
41                const CompletionCallback& callback) override {
42     pending_callbacks_.push_back(callback);
43     observed_set_item_ = true;
44     observed_connection_id_ = connection_id;
45     observed_key_ = key;
46     observed_value_ = value;
47     observed_page_url_ = page_url;
48   }
49
50   void LogGetItem(int connection_id,
51                   const base::string16& key,
52                   const base::NullableString16& value) override {}
53
54   void RemoveItem(int connection_id,
55                   const base::string16& key,
56                   const GURL& page_url,
57                   const CompletionCallback& callback) override {
58     pending_callbacks_.push_back(callback);
59     observed_remove_item_ = true;
60     observed_connection_id_ = connection_id;
61     observed_key_ = key;
62     observed_page_url_ = page_url;
63   }
64
65   void ClearArea(int connection_id,
66                  const GURL& page_url,
67                  const CompletionCallback& callback) override {
68     pending_callbacks_.push_back(callback);
69     observed_clear_area_ = true;
70     observed_connection_id_ = connection_id;
71     observed_page_url_ = page_url;
72   }
73
74   // Methods and members for use by test fixtures.
75
76   void ResetObservations() {
77     observed_load_area_ = false;
78     observed_set_item_ = false;
79     observed_remove_item_ = false;
80     observed_clear_area_ = false;
81     observed_connection_id_ = 0;
82     observed_key_.clear();
83     observed_value_.clear();
84     observed_page_url_ = GURL();
85   }
86
87   void CompleteAllPendingCallbacks() {
88     while (!pending_callbacks_.empty())
89       CompleteOnePendingCallback(true);
90   }
91
92   void CompleteOnePendingCallback(bool success) {
93     ASSERT_TRUE(!pending_callbacks_.empty());
94     pending_callbacks_.front().Run(success);
95     pending_callbacks_.pop_front();
96   }
97
98   typedef std::list<CompletionCallback> CallbackList;
99
100   DOMStorageValuesMap load_area_return_values_;
101   CallbackList pending_callbacks_;
102   bool observed_load_area_;
103   bool observed_set_item_;
104   bool observed_remove_item_;
105   bool observed_clear_area_;
106   int observed_connection_id_;
107   base::string16 observed_key_;
108   base::string16 observed_value_;
109   GURL observed_page_url_;
110
111  private:
112   ~MockProxy() override {}
113 };
114
115 }  // namespace
116
117 class DOMStorageCachedAreaTest : public testing::Test {
118  public:
119   DOMStorageCachedAreaTest()
120     : kNamespaceId(10),
121       kOrigin("http://dom_storage/"),
122       kKey(base::ASCIIToUTF16("key")),
123       kValue(base::ASCIIToUTF16("value")),
124       kPageUrl("http://dom_storage/page") {
125   }
126
127   const int64 kNamespaceId;
128   const GURL kOrigin;
129   const base::string16 kKey;
130   const base::string16 kValue;
131   const GURL kPageUrl;
132
133   void SetUp() override { mock_proxy_ = new MockProxy(); }
134
135   bool IsPrimed(DOMStorageCachedArea* cached_area) {
136     return cached_area->map_.get();
137   }
138
139   bool IsIgnoringAllMutations(DOMStorageCachedArea* cached_area) {
140     return cached_area->ignore_all_mutations_;
141   }
142
143   bool IsIgnoringKeyMutations(DOMStorageCachedArea* cached_area,
144                               const base::string16& key) {
145     return cached_area->should_ignore_key_mutation(key);
146   }
147
148   void ResetAll(DOMStorageCachedArea* cached_area) {
149     cached_area->Reset();
150     mock_proxy_->ResetObservations();
151     mock_proxy_->pending_callbacks_.clear();
152   }
153
154   void ResetCacheOnly(DOMStorageCachedArea* cached_area) {
155     cached_area->Reset();
156   }
157
158  protected:
159   scoped_refptr<MockProxy> mock_proxy_;
160 };
161
162 TEST_F(DOMStorageCachedAreaTest, Basics) {
163   EXPECT_TRUE(mock_proxy_->HasOneRef());
164   scoped_refptr<DOMStorageCachedArea> cached_area =
165       new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
166   EXPECT_EQ(kNamespaceId, cached_area->namespace_id());
167   EXPECT_EQ(kOrigin, cached_area->origin());
168   EXPECT_FALSE(mock_proxy_->HasOneRef());
169   cached_area->ApplyMutation(base::NullableString16(kKey, false),
170                              base::NullableString16(kValue, false));
171   EXPECT_FALSE(IsPrimed(cached_area.get()));
172
173   ResetAll(cached_area.get());
174   EXPECT_EQ(kNamespaceId, cached_area->namespace_id());
175   EXPECT_EQ(kOrigin, cached_area->origin());
176
177   const int kConnectionId = 1;
178   EXPECT_EQ(0u, cached_area->GetLength(kConnectionId));
179   EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl));
180   EXPECT_EQ(1u, cached_area->GetLength(kConnectionId));
181   EXPECT_EQ(kKey, cached_area->GetKey(kConnectionId, 0).string());
182   EXPECT_EQ(kValue, cached_area->GetItem(kConnectionId, kKey).string());
183   cached_area->RemoveItem(kConnectionId, kKey, kPageUrl);
184   EXPECT_EQ(0u, cached_area->GetLength(kConnectionId));
185 }
186
187 TEST_F(DOMStorageCachedAreaTest, Getters) {
188   const int kConnectionId = 7;
189   scoped_refptr<DOMStorageCachedArea> cached_area =
190       new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
191
192   // GetLength, we expect to see one call to load in the proxy.
193   EXPECT_FALSE(IsPrimed(cached_area.get()));
194   EXPECT_EQ(0u, cached_area->GetLength(kConnectionId));
195   EXPECT_TRUE(IsPrimed(cached_area.get()));
196   EXPECT_TRUE(mock_proxy_->observed_load_area_);
197   EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_);
198   EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size());
199   EXPECT_TRUE(IsIgnoringAllMutations(cached_area.get()));
200   mock_proxy_->CompleteAllPendingCallbacks();
201   EXPECT_FALSE(IsIgnoringAllMutations(cached_area.get()));
202
203   // GetKey, expect the one call to load.
204   ResetAll(cached_area.get());
205   EXPECT_FALSE(IsPrimed(cached_area.get()));
206   EXPECT_TRUE(cached_area->GetKey(kConnectionId, 2).is_null());
207   EXPECT_TRUE(IsPrimed(cached_area.get()));
208   EXPECT_TRUE(mock_proxy_->observed_load_area_);
209   EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_);
210   EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size());
211
212   // GetItem, ditto.
213   ResetAll(cached_area.get());
214   EXPECT_FALSE(IsPrimed(cached_area.get()));
215   EXPECT_TRUE(cached_area->GetItem(kConnectionId, kKey).is_null());
216   EXPECT_TRUE(IsPrimed(cached_area.get()));
217   EXPECT_TRUE(mock_proxy_->observed_load_area_);
218   EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_);
219   EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size());
220 }
221
222 TEST_F(DOMStorageCachedAreaTest, Setters) {
223   const int kConnectionId = 7;
224   scoped_refptr<DOMStorageCachedArea> cached_area =
225       new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
226
227   // SetItem, we expect a call to load followed by a call to set item
228   // in the proxy.
229   EXPECT_FALSE(IsPrimed(cached_area.get()));
230   EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl));
231   EXPECT_TRUE(IsPrimed(cached_area.get()));
232   EXPECT_TRUE(mock_proxy_->observed_load_area_);
233   EXPECT_TRUE(mock_proxy_->observed_set_item_);
234   EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_);
235   EXPECT_EQ(kPageUrl, mock_proxy_->observed_page_url_);
236   EXPECT_EQ(kKey, mock_proxy_->observed_key_);
237   EXPECT_EQ(kValue, mock_proxy_->observed_value_);
238   EXPECT_EQ(2u, mock_proxy_->pending_callbacks_.size());
239
240   // Clear, we expect a just the one call to clear in the proxy since
241   // there's no need to load the data prior to deleting it.
242   ResetAll(cached_area.get());
243   EXPECT_FALSE(IsPrimed(cached_area.get()));
244   cached_area->Clear(kConnectionId, kPageUrl);
245   EXPECT_TRUE(IsPrimed(cached_area.get()));
246   EXPECT_TRUE(mock_proxy_->observed_clear_area_);
247   EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_);
248   EXPECT_EQ(kPageUrl, mock_proxy_->observed_page_url_);
249   EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size());
250
251   // RemoveItem with nothing to remove, expect just one call to load.
252   ResetAll(cached_area.get());
253   EXPECT_FALSE(IsPrimed(cached_area.get()));
254   cached_area->RemoveItem(kConnectionId, kKey, kPageUrl);
255   EXPECT_TRUE(IsPrimed(cached_area.get()));
256   EXPECT_TRUE(mock_proxy_->observed_load_area_);
257   EXPECT_FALSE(mock_proxy_->observed_remove_item_);
258   EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_);
259   EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size());
260
261   // RemoveItem with something to remove, expect a call to load followed
262   // by a call to remove.
263   ResetAll(cached_area.get());
264   mock_proxy_->load_area_return_values_[kKey] =
265       base::NullableString16(kValue, false);
266   EXPECT_FALSE(IsPrimed(cached_area.get()));
267   cached_area->RemoveItem(kConnectionId, kKey, kPageUrl);
268   EXPECT_TRUE(IsPrimed(cached_area.get()));
269   EXPECT_TRUE(mock_proxy_->observed_load_area_);
270   EXPECT_TRUE(mock_proxy_->observed_remove_item_);
271   EXPECT_EQ(kConnectionId, mock_proxy_->observed_connection_id_);
272   EXPECT_EQ(kPageUrl, mock_proxy_->observed_page_url_);
273   EXPECT_EQ(kKey, mock_proxy_->observed_key_);
274   EXPECT_EQ(2u, mock_proxy_->pending_callbacks_.size());
275 }
276
277 TEST_F(DOMStorageCachedAreaTest, MutationsAreIgnoredUntilLoadCompletion) {
278   const int kConnectionId = 7;
279   scoped_refptr<DOMStorageCachedArea> cached_area =
280       new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
281   EXPECT_TRUE(cached_area->GetItem(kConnectionId, kKey).is_null());
282   EXPECT_TRUE(IsPrimed(cached_area.get()));
283   EXPECT_TRUE(IsIgnoringAllMutations(cached_area.get()));
284
285   // Before load completion, the mutation should be ignored.
286   cached_area->ApplyMutation(base::NullableString16(kKey, false),
287                              base::NullableString16(kValue, false));
288   EXPECT_TRUE(cached_area->GetItem(kConnectionId, kKey).is_null());
289
290   // Call the load completion callback.
291   mock_proxy_->CompleteOnePendingCallback(true);
292   EXPECT_FALSE(IsIgnoringAllMutations(cached_area.get()));
293
294   // Verify that mutations are now applied.
295   cached_area->ApplyMutation(base::NullableString16(kKey, false),
296                              base::NullableString16(kValue, false));
297   EXPECT_EQ(kValue, cached_area->GetItem(kConnectionId, kKey).string());
298 }
299
300 TEST_F(DOMStorageCachedAreaTest, MutationsAreIgnoredUntilClearCompletion) {
301   const int kConnectionId = 4;
302   scoped_refptr<DOMStorageCachedArea> cached_area =
303       new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
304   cached_area->Clear(kConnectionId, kPageUrl);
305   EXPECT_TRUE(IsIgnoringAllMutations(cached_area.get()));
306   mock_proxy_->CompleteOnePendingCallback(true);
307   EXPECT_FALSE(IsIgnoringAllMutations(cached_area.get()));
308
309   // Verify that calling Clear twice works as expected, the first
310   // completion callback should have been cancelled.
311   ResetCacheOnly(cached_area.get());
312   cached_area->Clear(kConnectionId, kPageUrl);
313   EXPECT_TRUE(IsIgnoringAllMutations(cached_area.get()));
314   cached_area->Clear(kConnectionId, kPageUrl);
315   EXPECT_TRUE(IsIgnoringAllMutations(cached_area.get()));
316   mock_proxy_->CompleteOnePendingCallback(true);
317   EXPECT_TRUE(IsIgnoringAllMutations(cached_area.get()));
318   mock_proxy_->CompleteOnePendingCallback(true);
319   EXPECT_FALSE(IsIgnoringAllMutations(cached_area.get()));
320 }
321
322 TEST_F(DOMStorageCachedAreaTest, KeyMutationsAreIgnoredUntilCompletion) {
323   const int kConnectionId = 8;
324   scoped_refptr<DOMStorageCachedArea> cached_area =
325       new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
326
327   // SetItem
328   EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl));
329   mock_proxy_->CompleteOnePendingCallback(true);  // load completion
330   EXPECT_FALSE(IsIgnoringAllMutations(cached_area.get()));
331   EXPECT_TRUE(IsIgnoringKeyMutations(cached_area.get(), kKey));
332   cached_area->ApplyMutation(base::NullableString16(kKey, false),
333                              base::NullableString16());
334   EXPECT_EQ(kValue, cached_area->GetItem(kConnectionId, kKey).string());
335   mock_proxy_->CompleteOnePendingCallback(true);  // set completion
336   EXPECT_FALSE(IsIgnoringKeyMutations(cached_area.get(), kKey));
337
338   // RemoveItem
339   cached_area->RemoveItem(kConnectionId, kKey, kPageUrl);
340   EXPECT_TRUE(IsIgnoringKeyMutations(cached_area.get(), kKey));
341   mock_proxy_->CompleteOnePendingCallback(true);  // remove completion
342   EXPECT_FALSE(IsIgnoringKeyMutations(cached_area.get(), kKey));
343
344   // Multiple mutations to the same key.
345   EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl));
346   cached_area->RemoveItem(kConnectionId, kKey, kPageUrl);
347   EXPECT_TRUE(IsIgnoringKeyMutations(cached_area.get(), kKey));
348   mock_proxy_->CompleteOnePendingCallback(true);  // set completion
349   EXPECT_TRUE(IsIgnoringKeyMutations(cached_area.get(), kKey));
350   mock_proxy_->CompleteOnePendingCallback(true);  // remove completion
351   EXPECT_FALSE(IsIgnoringKeyMutations(cached_area.get(), kKey));
352
353   // A failed set item operation should Reset the cache.
354   EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl));
355   EXPECT_TRUE(IsIgnoringKeyMutations(cached_area.get(), kKey));
356   mock_proxy_->CompleteOnePendingCallback(false);
357   EXPECT_FALSE(IsPrimed(cached_area.get()));
358 }
359
360 }  // namespace content