IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / browser / dom_storage / dom_storage_context_impl_unittest.cc
blob7e33b7363d4689bb6a644ed1c315d5b93c715bf3
1 // Copyright 2013 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.
5 #include "base/bind.h"
6 #include "base/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "base/time/time.h"
13 #include "content/browser/dom_storage/dom_storage_area.h"
14 #include "content/browser/dom_storage/dom_storage_context_impl.h"
15 #include "content/browser/dom_storage/dom_storage_namespace.h"
16 #include "content/browser/dom_storage/dom_storage_task_runner.h"
17 #include "content/public/browser/local_storage_usage_info.h"
18 #include "content/public/browser/session_storage_namespace.h"
19 #include "content/public/browser/session_storage_usage_info.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "webkit/browser/quota/mock_special_storage_policy.h"
23 using base::ASCIIToUTF16;
25 namespace content {
27 class DOMStorageContextImplTest : public testing::Test {
28 public:
29 DOMStorageContextImplTest()
30 : kOrigin(GURL("http://dom_storage/")),
31 kKey(ASCIIToUTF16("key")),
32 kValue(ASCIIToUTF16("value")),
33 kDontIncludeFileInfo(false),
34 kDoIncludeFileInfo(true) {
37 const GURL kOrigin;
38 const base::string16 kKey;
39 const base::string16 kValue;
40 const bool kDontIncludeFileInfo;
41 const bool kDoIncludeFileInfo;
43 virtual void SetUp() {
44 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
45 storage_policy_ = new quota::MockSpecialStoragePolicy;
46 task_runner_ =
47 new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get());
48 context_ = new DOMStorageContextImpl(temp_dir_.path(),
49 base::FilePath(),
50 storage_policy_.get(),
51 task_runner_.get());
54 virtual void TearDown() {
55 base::MessageLoop::current()->RunUntilIdle();
58 void VerifySingleOriginRemains(const GURL& origin) {
59 // Use a new instance to examine the contexts of temp_dir_.
60 scoped_refptr<DOMStorageContextImpl> context =
61 new DOMStorageContextImpl(temp_dir_.path(), base::FilePath(),
62 NULL, NULL);
63 std::vector<LocalStorageUsageInfo> infos;
64 context->GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
65 ASSERT_EQ(1u, infos.size());
66 EXPECT_EQ(origin, infos[0].origin);
69 protected:
70 base::MessageLoop message_loop_;
71 base::ScopedTempDir temp_dir_;
72 scoped_refptr<quota::MockSpecialStoragePolicy> storage_policy_;
73 scoped_refptr<MockDOMStorageTaskRunner> task_runner_;
74 scoped_refptr<DOMStorageContextImpl> context_;
75 DISALLOW_COPY_AND_ASSIGN(DOMStorageContextImplTest);
78 TEST_F(DOMStorageContextImplTest, Basics) {
79 // This test doesn't do much, checks that the constructor
80 // initializes members properly and that invoking methods
81 // on a newly created object w/o any data on disk do no harm.
82 EXPECT_EQ(temp_dir_.path(), context_->localstorage_directory());
83 EXPECT_EQ(base::FilePath(), context_->sessionstorage_directory());
84 EXPECT_EQ(storage_policy_.get(), context_->special_storage_policy_.get());
85 context_->PurgeMemory();
86 context_->DeleteLocalStorage(GURL("http://chromium.org/"));
87 const int kFirstSessionStorageNamespaceId = 1;
88 EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId));
89 EXPECT_FALSE(context_->GetStorageNamespace(kFirstSessionStorageNamespaceId));
90 EXPECT_EQ(kFirstSessionStorageNamespaceId, context_->AllocateSessionId());
91 std::vector<LocalStorageUsageInfo> infos;
92 context_->GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
93 EXPECT_TRUE(infos.empty());
94 context_->Shutdown();
97 TEST_F(DOMStorageContextImplTest, UsageInfo) {
98 // Should be empty initially
99 std::vector<LocalStorageUsageInfo> infos;
100 context_->GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
101 EXPECT_TRUE(infos.empty());
102 context_->GetLocalStorageUsage(&infos, kDoIncludeFileInfo);
103 EXPECT_TRUE(infos.empty());
105 // Put some data into local storage and shutdown the context
106 // to ensure data is written to disk.
107 base::NullableString16 old_value;
108 EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)->
109 OpenStorageArea(kOrigin)->SetItem(kKey, kValue, &old_value));
110 context_->Shutdown();
111 context_ = NULL;
112 base::MessageLoop::current()->RunUntilIdle();
114 // Create a new context that points to the same directory, see that
115 // it knows about the origin that we stored data for.
116 context_ = new DOMStorageContextImpl(temp_dir_.path(), base::FilePath(),
117 NULL, NULL);
118 context_->GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
119 EXPECT_EQ(1u, infos.size());
120 EXPECT_EQ(kOrigin, infos[0].origin);
121 EXPECT_EQ(0u, infos[0].data_size);
122 EXPECT_EQ(base::Time(), infos[0].last_modified);
123 infos.clear();
124 context_->GetLocalStorageUsage(&infos, kDoIncludeFileInfo);
125 EXPECT_EQ(1u, infos.size());
126 EXPECT_EQ(kOrigin, infos[0].origin);
127 EXPECT_NE(0u, infos[0].data_size);
128 EXPECT_NE(base::Time(), infos[0].last_modified);
131 TEST_F(DOMStorageContextImplTest, SessionOnly) {
132 const GURL kSessionOnlyOrigin("http://www.sessiononly.com/");
133 storage_policy_->AddSessionOnly(kSessionOnlyOrigin);
135 // Store data for a normal and a session-only origin and then
136 // invoke Shutdown() which should delete data for session-only
137 // origins.
138 base::NullableString16 old_value;
139 EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)->
140 OpenStorageArea(kOrigin)->SetItem(kKey, kValue, &old_value));
141 EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)->
142 OpenStorageArea(kSessionOnlyOrigin)->SetItem(kKey, kValue, &old_value));
143 context_->Shutdown();
144 context_ = NULL;
145 base::MessageLoop::current()->RunUntilIdle();
147 // Verify that the session-only origin data is gone.
148 VerifySingleOriginRemains(kOrigin);
151 TEST_F(DOMStorageContextImplTest, SetForceKeepSessionState) {
152 const GURL kSessionOnlyOrigin("http://www.sessiononly.com/");
153 storage_policy_->AddSessionOnly(kSessionOnlyOrigin);
155 // Store data for a session-only origin, setup to save session data, then
156 // shutdown.
157 base::NullableString16 old_value;
158 EXPECT_TRUE(context_->GetStorageNamespace(kLocalStorageNamespaceId)->
159 OpenStorageArea(kSessionOnlyOrigin)->SetItem(kKey, kValue, &old_value));
160 context_->SetForceKeepSessionState(); // Should override clear behavior.
161 context_->Shutdown();
162 context_ = NULL;
163 base::MessageLoop::current()->RunUntilIdle();
165 VerifySingleOriginRemains(kSessionOnlyOrigin);
168 TEST_F(DOMStorageContextImplTest, PersistentIds) {
169 const int kFirstSessionStorageNamespaceId = 1;
170 const std::string kPersistentId = "persistent";
171 context_->CreateSessionNamespace(kFirstSessionStorageNamespaceId,
172 kPersistentId);
173 DOMStorageNamespace* dom_namespace =
174 context_->GetStorageNamespace(kFirstSessionStorageNamespaceId);
175 ASSERT_TRUE(dom_namespace);
176 EXPECT_EQ(kPersistentId, dom_namespace->persistent_namespace_id());
177 // Verify that the areas inherit the persistent ID.
178 DOMStorageArea* area = dom_namespace->OpenStorageArea(kOrigin);
179 EXPECT_EQ(kPersistentId, area->persistent_namespace_id_);
181 // Verify that the persistent IDs are handled correctly when cloning.
182 const int kClonedSessionStorageNamespaceId = 2;
183 const std::string kClonedPersistentId = "cloned";
184 context_->CloneSessionNamespace(kFirstSessionStorageNamespaceId,
185 kClonedSessionStorageNamespaceId,
186 kClonedPersistentId);
187 DOMStorageNamespace* cloned_dom_namespace =
188 context_->GetStorageNamespace(kClonedSessionStorageNamespaceId);
189 ASSERT_TRUE(dom_namespace);
190 EXPECT_EQ(kClonedPersistentId,
191 cloned_dom_namespace->persistent_namespace_id());
192 // Verify that the areas inherit the persistent ID.
193 DOMStorageArea* cloned_area = cloned_dom_namespace->OpenStorageArea(kOrigin);
194 EXPECT_EQ(kClonedPersistentId, cloned_area->persistent_namespace_id_);
197 TEST_F(DOMStorageContextImplTest, DeleteSessionStorage) {
198 // Create a DOMStorageContextImpl which will save sessionStorage on disk.
199 context_ = new DOMStorageContextImpl(temp_dir_.path(),
200 temp_dir_.path(),
201 storage_policy_.get(),
202 task_runner_.get());
203 context_->SetSaveSessionStorageOnDisk();
204 ASSERT_EQ(temp_dir_.path(), context_->sessionstorage_directory());
206 // Write data.
207 const int kSessionStorageNamespaceId = 1;
208 const std::string kPersistentId = "persistent";
209 context_->CreateSessionNamespace(kSessionStorageNamespaceId,
210 kPersistentId);
211 DOMStorageNamespace* dom_namespace =
212 context_->GetStorageNamespace(kSessionStorageNamespaceId);
213 DOMStorageArea* area = dom_namespace->OpenStorageArea(kOrigin);
214 const base::string16 kKey(ASCIIToUTF16("foo"));
215 const base::string16 kValue(ASCIIToUTF16("bar"));
216 base::NullableString16 old_nullable_value;
217 area->SetItem(kKey, kValue, &old_nullable_value);
218 dom_namespace->CloseStorageArea(area);
220 // Destroy and recreate the DOMStorageContextImpl.
221 context_->Shutdown();
222 context_ = NULL;
223 base::MessageLoop::current()->RunUntilIdle();
224 context_ = new DOMStorageContextImpl(
225 temp_dir_.path(), temp_dir_.path(),
226 storage_policy_.get(), task_runner_.get());
227 context_->SetSaveSessionStorageOnDisk();
229 // Read the data back.
230 context_->CreateSessionNamespace(kSessionStorageNamespaceId,
231 kPersistentId);
232 dom_namespace = context_->GetStorageNamespace(kSessionStorageNamespaceId);
233 area = dom_namespace->OpenStorageArea(kOrigin);
234 base::NullableString16 read_value;
235 read_value = area->GetItem(kKey);
236 EXPECT_EQ(kValue, read_value.string());
237 dom_namespace->CloseStorageArea(area);
239 SessionStorageUsageInfo info;
240 info.origin = kOrigin;
241 info.persistent_namespace_id = kPersistentId;
242 context_->DeleteSessionStorage(info);
244 // Destroy and recreate again.
245 context_->Shutdown();
246 context_ = NULL;
247 base::MessageLoop::current()->RunUntilIdle();
248 context_ = new DOMStorageContextImpl(
249 temp_dir_.path(), temp_dir_.path(),
250 storage_policy_.get(), task_runner_.get());
251 context_->SetSaveSessionStorageOnDisk();
253 // Now there should be no data.
254 context_->CreateSessionNamespace(kSessionStorageNamespaceId,
255 kPersistentId);
256 dom_namespace = context_->GetStorageNamespace(kSessionStorageNamespaceId);
257 area = dom_namespace->OpenStorageArea(kOrigin);
258 read_value = area->GetItem(kKey);
259 EXPECT_TRUE(read_value.is_null());
260 dom_namespace->CloseStorageArea(area);
261 context_->Shutdown();
262 context_ = NULL;
263 base::MessageLoop::current()->RunUntilIdle();
266 TEST_F(DOMStorageContextImplTest, SessionStorageAlias) {
267 const int kFirstSessionStorageNamespaceId = 1;
268 const std::string kPersistentId = "persistent";
269 context_->CreateSessionNamespace(kFirstSessionStorageNamespaceId,
270 kPersistentId);
271 DOMStorageNamespace* dom_namespace1 =
272 context_->GetStorageNamespace(kFirstSessionStorageNamespaceId);
273 ASSERT_TRUE(dom_namespace1);
274 DOMStorageArea* area1 = dom_namespace1->OpenStorageArea(kOrigin);
275 base::NullableString16 old_value;
276 area1->SetItem(kKey, kValue, &old_value);
277 EXPECT_TRUE(old_value.is_null());
278 base::NullableString16 read_value = area1->GetItem(kKey);
279 EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue);
281 // Create an alias.
282 const int kAliasSessionStorageNamespaceId = 2;
283 context_->CreateAliasSessionNamespace(kFirstSessionStorageNamespaceId,
284 kAliasSessionStorageNamespaceId,
285 kPersistentId);
286 DOMStorageNamespace* dom_namespace2 =
287 context_->GetStorageNamespace(kAliasSessionStorageNamespaceId);
288 ASSERT_TRUE(dom_namespace2);
289 ASSERT_TRUE(dom_namespace2->alias_master_namespace() == dom_namespace1);
291 // Verify that read values are identical.
292 DOMStorageArea* area2 = dom_namespace2->OpenStorageArea(kOrigin);
293 read_value = area2->GetItem(kKey);
294 EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue);
296 // Verify that writes are reflected in both namespaces.
297 const base::string16 kValue2(ASCIIToUTF16("value2"));
298 area2->SetItem(kKey, kValue2, &old_value);
299 read_value = area1->GetItem(kKey);
300 EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue2);
301 dom_namespace1->CloseStorageArea(area1);
302 dom_namespace2->CloseStorageArea(area2);
304 // When creating an alias of an alias, ensure that the master relationship
305 // is collapsed.
306 const int kAlias2SessionStorageNamespaceId = 3;
307 context_->CreateAliasSessionNamespace(kAliasSessionStorageNamespaceId,
308 kAlias2SessionStorageNamespaceId,
309 kPersistentId);
310 DOMStorageNamespace* dom_namespace3 =
311 context_->GetStorageNamespace(kAlias2SessionStorageNamespaceId);
312 ASSERT_TRUE(dom_namespace3);
313 ASSERT_TRUE(dom_namespace3->alias_master_namespace() == dom_namespace1);
316 TEST_F(DOMStorageContextImplTest, SessionStorageMerge) {
317 // Create a target namespace that we will merge into.
318 const int kTargetSessionStorageNamespaceId = 1;
319 const std::string kTargetPersistentId = "persistent";
320 context_->CreateSessionNamespace(kTargetSessionStorageNamespaceId,
321 kTargetPersistentId);
322 DOMStorageNamespace* target_ns =
323 context_->GetStorageNamespace(kTargetSessionStorageNamespaceId);
324 ASSERT_TRUE(target_ns);
325 DOMStorageArea* target_ns_area = target_ns->OpenStorageArea(kOrigin);
326 base::NullableString16 old_value;
327 const base::string16 kKey2(ASCIIToUTF16("key2"));
328 const base::string16 kKey2Value(ASCIIToUTF16("key2value"));
329 target_ns_area->SetItem(kKey, kValue, &old_value);
330 target_ns_area->SetItem(kKey2, kKey2Value, &old_value);
332 // Create a source namespace & its alias.
333 const int kSourceSessionStorageNamespaceId = 2;
334 const int kAliasSessionStorageNamespaceId = 3;
335 const std::string kSourcePersistentId = "persistent_source";
336 context_->CreateSessionNamespace(kSourceSessionStorageNamespaceId,
337 kSourcePersistentId);
338 context_->CreateAliasSessionNamespace(kSourceSessionStorageNamespaceId,
339 kAliasSessionStorageNamespaceId,
340 kSourcePersistentId);
341 DOMStorageNamespace* alias_ns =
342 context_->GetStorageNamespace(kAliasSessionStorageNamespaceId);
343 ASSERT_TRUE(alias_ns);
345 // Create a transaction log that can't be merged.
346 const int kPid1 = 10;
347 ASSERT_FALSE(alias_ns->IsLoggingRenderer(kPid1));
348 alias_ns->AddTransactionLogProcessId(kPid1);
349 ASSERT_TRUE(alias_ns->IsLoggingRenderer(kPid1));
350 const base::string16 kValue2(ASCIIToUTF16("value2"));
351 DOMStorageNamespace::TransactionRecord txn;
352 txn.origin = kOrigin;
353 txn.key = kKey;
354 txn.value = base::NullableString16(kValue2, false);
355 txn.transaction_type = DOMStorageNamespace::TRANSACTION_READ;
356 alias_ns->AddTransaction(kPid1, txn);
357 ASSERT_TRUE(alias_ns->Merge(false, kPid1, target_ns, NULL) ==
358 SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE);
360 // Create a transaction log that can be merged.
361 const int kPid2 = 20;
362 alias_ns->AddTransactionLogProcessId(kPid2);
363 txn.transaction_type = DOMStorageNamespace::TRANSACTION_WRITE;
364 alias_ns->AddTransaction(kPid2, txn);
365 ASSERT_TRUE(alias_ns->Merge(true, kPid2, target_ns, NULL) ==
366 SessionStorageNamespace::MERGE_RESULT_MERGEABLE);
368 // Verify that the merge was successful.
369 ASSERT_TRUE(alias_ns->alias_master_namespace() == target_ns);
370 base::NullableString16 read_value = target_ns_area->GetItem(kKey);
371 EXPECT_TRUE(!read_value.is_null() && read_value.string() == kValue2);
372 DOMStorageArea* alias_ns_area = alias_ns->OpenStorageArea(kOrigin);
373 read_value = alias_ns_area->GetItem(kKey2);
374 EXPECT_TRUE(!read_value.is_null() && read_value.string() == kKey2Value);
377 } // namespace content