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.
6 #include "base/files/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/thread_task_runner_handle.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_usage_info.h"
19 #include "content/public/test/mock_special_storage_policy.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using base::ASCIIToUTF16
;
26 class DOMStorageContextImplTest
: public testing::Test
{
28 DOMStorageContextImplTest()
29 : kOrigin(GURL("http://dom_storage/")),
30 kKey(ASCIIToUTF16("key")),
31 kValue(ASCIIToUTF16("value")),
32 kDontIncludeFileInfo(false),
33 kDoIncludeFileInfo(true) {
37 const base::string16 kKey
;
38 const base::string16 kValue
;
39 const bool kDontIncludeFileInfo
;
40 const bool kDoIncludeFileInfo
;
42 void SetUp() override
{
43 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
44 storage_policy_
= new MockSpecialStoragePolicy
;
46 new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get());
47 context_
= new DOMStorageContextImpl(temp_dir_
.path(),
49 storage_policy_
.get(),
53 void TearDown() override
{ base::MessageLoop::current()->RunUntilIdle(); }
55 void VerifySingleOriginRemains(const GURL
& origin
) {
56 // Use a new instance to examine the contexts of temp_dir_.
57 scoped_refptr
<DOMStorageContextImpl
> context
=
58 new DOMStorageContextImpl(temp_dir_
.path(), base::FilePath(),
60 std::vector
<LocalStorageUsageInfo
> infos
;
61 context
->GetLocalStorageUsage(&infos
, kDontIncludeFileInfo
);
62 ASSERT_EQ(1u, infos
.size());
63 EXPECT_EQ(origin
, infos
[0].origin
);
66 int session_id_offset() { return context_
->session_id_offset_
; }
69 base::MessageLoop message_loop_
;
70 base::ScopedTempDir temp_dir_
;
71 scoped_refptr
<MockSpecialStoragePolicy
> storage_policy_
;
72 scoped_refptr
<MockDOMStorageTaskRunner
> task_runner_
;
73 scoped_refptr
<DOMStorageContextImpl
> context_
;
74 DISALLOW_COPY_AND_ASSIGN(DOMStorageContextImplTest
);
77 TEST_F(DOMStorageContextImplTest
, Basics
) {
78 // This test doesn't do much, checks that the constructor
79 // initializes members properly and that invoking methods
80 // on a newly created object w/o any data on disk do no harm.
81 EXPECT_EQ(temp_dir_
.path(), context_
->localstorage_directory());
82 EXPECT_EQ(base::FilePath(), context_
->sessionstorage_directory());
83 EXPECT_EQ(storage_policy_
.get(), context_
->special_storage_policy_
.get());
84 context_
->DeleteLocalStorage(GURL("http://chromium.org/"));
85 const int kFirstSessionStorageNamespaceId
= 1 + session_id_offset();
86 EXPECT_TRUE(context_
->GetStorageNamespace(kLocalStorageNamespaceId
));
87 EXPECT_FALSE(context_
->GetStorageNamespace(kFirstSessionStorageNamespaceId
));
88 EXPECT_EQ(kFirstSessionStorageNamespaceId
, context_
->AllocateSessionId());
89 std::vector
<LocalStorageUsageInfo
> infos
;
90 context_
->GetLocalStorageUsage(&infos
, kDontIncludeFileInfo
);
91 EXPECT_TRUE(infos
.empty());
95 TEST_F(DOMStorageContextImplTest
, UsageInfo
) {
96 // Should be empty initially
97 std::vector
<LocalStorageUsageInfo
> infos
;
98 context_
->GetLocalStorageUsage(&infos
, kDontIncludeFileInfo
);
99 EXPECT_TRUE(infos
.empty());
100 context_
->GetLocalStorageUsage(&infos
, kDoIncludeFileInfo
);
101 EXPECT_TRUE(infos
.empty());
103 // Put some data into local storage and shutdown the context
104 // to ensure data is written to disk.
105 base::NullableString16 old_value
;
106 EXPECT_TRUE(context_
->GetStorageNamespace(kLocalStorageNamespaceId
)->
107 OpenStorageArea(kOrigin
)->SetItem(kKey
, kValue
, &old_value
));
108 context_
->Shutdown();
110 base::MessageLoop::current()->RunUntilIdle();
112 // Create a new context that points to the same directory, see that
113 // it knows about the origin that we stored data for.
114 context_
= new DOMStorageContextImpl(temp_dir_
.path(), base::FilePath(),
116 context_
->GetLocalStorageUsage(&infos
, kDontIncludeFileInfo
);
117 EXPECT_EQ(1u, infos
.size());
118 EXPECT_EQ(kOrigin
, infos
[0].origin
);
119 EXPECT_EQ(0u, infos
[0].data_size
);
120 EXPECT_EQ(base::Time(), infos
[0].last_modified
);
122 context_
->GetLocalStorageUsage(&infos
, kDoIncludeFileInfo
);
123 EXPECT_EQ(1u, infos
.size());
124 EXPECT_EQ(kOrigin
, infos
[0].origin
);
125 EXPECT_NE(0u, infos
[0].data_size
);
126 EXPECT_NE(base::Time(), infos
[0].last_modified
);
129 TEST_F(DOMStorageContextImplTest
, SessionOnly
) {
130 const GURL
kSessionOnlyOrigin("http://www.sessiononly.com/");
131 storage_policy_
->AddSessionOnly(kSessionOnlyOrigin
);
133 // Store data for a normal and a session-only origin and then
134 // invoke Shutdown() which should delete data for session-only
136 base::NullableString16 old_value
;
137 EXPECT_TRUE(context_
->GetStorageNamespace(kLocalStorageNamespaceId
)->
138 OpenStorageArea(kOrigin
)->SetItem(kKey
, kValue
, &old_value
));
139 EXPECT_TRUE(context_
->GetStorageNamespace(kLocalStorageNamespaceId
)->
140 OpenStorageArea(kSessionOnlyOrigin
)->SetItem(kKey
, kValue
, &old_value
));
141 context_
->Shutdown();
143 base::MessageLoop::current()->RunUntilIdle();
145 // Verify that the session-only origin data is gone.
146 VerifySingleOriginRemains(kOrigin
);
149 TEST_F(DOMStorageContextImplTest
, SetForceKeepSessionState
) {
150 const GURL
kSessionOnlyOrigin("http://www.sessiononly.com/");
151 storage_policy_
->AddSessionOnly(kSessionOnlyOrigin
);
153 // Store data for a session-only origin, setup to save session data, then
155 base::NullableString16 old_value
;
156 EXPECT_TRUE(context_
->GetStorageNamespace(kLocalStorageNamespaceId
)->
157 OpenStorageArea(kSessionOnlyOrigin
)->SetItem(kKey
, kValue
, &old_value
));
158 context_
->SetForceKeepSessionState(); // Should override clear behavior.
159 context_
->Shutdown();
161 base::MessageLoop::current()->RunUntilIdle();
163 VerifySingleOriginRemains(kSessionOnlyOrigin
);
166 TEST_F(DOMStorageContextImplTest
, PersistentIds
) {
167 const int kFirstSessionStorageNamespaceId
= 1 + session_id_offset();
168 const std::string kPersistentId
= "persistent";
169 context_
->CreateSessionNamespace(kFirstSessionStorageNamespaceId
,
171 DOMStorageNamespace
* dom_namespace
=
172 context_
->GetStorageNamespace(kFirstSessionStorageNamespaceId
);
173 ASSERT_TRUE(dom_namespace
);
174 EXPECT_EQ(kPersistentId
, dom_namespace
->persistent_namespace_id());
175 // Verify that the areas inherit the persistent ID.
176 DOMStorageArea
* area
= dom_namespace
->OpenStorageArea(kOrigin
);
177 EXPECT_EQ(kPersistentId
, area
->persistent_namespace_id_
);
179 // Verify that the persistent IDs are handled correctly when cloning.
180 const int kClonedSessionStorageNamespaceId
= 2 + session_id_offset();
181 const std::string kClonedPersistentId
= "cloned";
182 context_
->CloneSessionNamespace(kFirstSessionStorageNamespaceId
,
183 kClonedSessionStorageNamespaceId
,
184 kClonedPersistentId
);
185 DOMStorageNamespace
* cloned_dom_namespace
=
186 context_
->GetStorageNamespace(kClonedSessionStorageNamespaceId
);
187 ASSERT_TRUE(dom_namespace
);
188 EXPECT_EQ(kClonedPersistentId
,
189 cloned_dom_namespace
->persistent_namespace_id());
190 // Verify that the areas inherit the persistent ID.
191 DOMStorageArea
* cloned_area
= cloned_dom_namespace
->OpenStorageArea(kOrigin
);
192 EXPECT_EQ(kClonedPersistentId
, cloned_area
->persistent_namespace_id_
);
195 TEST_F(DOMStorageContextImplTest
, DeleteSessionStorage
) {
196 // Create a DOMStorageContextImpl which will save sessionStorage on disk.
197 context_
= new DOMStorageContextImpl(temp_dir_
.path(),
199 storage_policy_
.get(),
201 context_
->SetSaveSessionStorageOnDisk();
202 ASSERT_EQ(temp_dir_
.path(), context_
->sessionstorage_directory());
205 const int kSessionStorageNamespaceId
= 1 + session_id_offset();
206 const std::string kPersistentId
= "persistent";
207 context_
->CreateSessionNamespace(kSessionStorageNamespaceId
,
209 DOMStorageNamespace
* dom_namespace
=
210 context_
->GetStorageNamespace(kSessionStorageNamespaceId
);
211 DOMStorageArea
* area
= dom_namespace
->OpenStorageArea(kOrigin
);
212 const base::string16
kKey(ASCIIToUTF16("foo"));
213 const base::string16
kValue(ASCIIToUTF16("bar"));
214 base::NullableString16 old_nullable_value
;
215 area
->SetItem(kKey
, kValue
, &old_nullable_value
);
216 dom_namespace
->CloseStorageArea(area
);
218 // Destroy and recreate the DOMStorageContextImpl.
219 context_
->Shutdown();
221 base::MessageLoop::current()->RunUntilIdle();
222 context_
= new DOMStorageContextImpl(
223 temp_dir_
.path(), temp_dir_
.path(),
224 storage_policy_
.get(), task_runner_
.get());
225 context_
->SetSaveSessionStorageOnDisk();
227 // Read the data back.
228 context_
->CreateSessionNamespace(kSessionStorageNamespaceId
,
230 dom_namespace
= context_
->GetStorageNamespace(kSessionStorageNamespaceId
);
231 area
= dom_namespace
->OpenStorageArea(kOrigin
);
232 base::NullableString16 read_value
;
233 read_value
= area
->GetItem(kKey
);
234 EXPECT_EQ(kValue
, read_value
.string());
235 dom_namespace
->CloseStorageArea(area
);
237 SessionStorageUsageInfo info
;
238 info
.origin
= kOrigin
;
239 info
.persistent_namespace_id
= kPersistentId
;
240 context_
->DeleteSessionStorage(info
);
242 // Destroy and recreate again.
243 context_
->Shutdown();
245 base::MessageLoop::current()->RunUntilIdle();
246 context_
= new DOMStorageContextImpl(
247 temp_dir_
.path(), temp_dir_
.path(),
248 storage_policy_
.get(), task_runner_
.get());
249 context_
->SetSaveSessionStorageOnDisk();
251 // Now there should be no data.
252 context_
->CreateSessionNamespace(kSessionStorageNamespaceId
,
254 dom_namespace
= context_
->GetStorageNamespace(kSessionStorageNamespaceId
);
255 area
= dom_namespace
->OpenStorageArea(kOrigin
);
256 read_value
= area
->GetItem(kKey
);
257 EXPECT_TRUE(read_value
.is_null());
258 dom_namespace
->CloseStorageArea(area
);
259 context_
->Shutdown();
261 base::MessageLoop::current()->RunUntilIdle();
264 } // namespace content