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.
5 #include "base/file_util.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/test/test_simple_task_runner.h"
8 #include "base/threading/thread.h"
9 #include "content/browser/browser_thread_impl.h"
10 #include "content/browser/indexed_db/indexed_db_connection.h"
11 #include "content/browser/indexed_db/indexed_db_context_impl.h"
12 #include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
13 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
14 #include "content/public/browser/storage_partition.h"
15 #include "content/public/common/url_constants.h"
16 #include "content/public/test/test_browser_context.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "webkit/browser/quota/mock_special_storage_policy.h"
19 #include "webkit/browser/quota/quota_manager.h"
20 #include "webkit/browser/quota/special_storage_policy.h"
21 #include "webkit/common/database/database_identifier.h"
25 class IndexedDBTest
: public testing::Test
{
27 const GURL kNormalOrigin
;
28 const GURL kSessionOnlyOrigin
;
31 : kNormalOrigin("http://normal/"),
32 kSessionOnlyOrigin("http://session-only/"),
33 task_runner_(new base::TestSimpleTaskRunner
),
34 special_storage_policy_(new quota::MockSpecialStoragePolicy
),
35 file_thread_(BrowserThread::FILE_USER_BLOCKING
, &message_loop_
),
36 io_thread_(BrowserThread::IO
, &message_loop_
) {
37 special_storage_policy_
->AddSessionOnly(kSessionOnlyOrigin
);
41 void FlushIndexedDBTaskRunner() { task_runner_
->RunUntilIdle(); }
43 base::MessageLoopForIO message_loop_
;
44 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
45 scoped_refptr
<quota::MockSpecialStoragePolicy
> special_storage_policy_
;
48 BrowserThreadImpl file_thread_
;
49 BrowserThreadImpl io_thread_
;
51 DISALLOW_COPY_AND_ASSIGN(IndexedDBTest
);
54 TEST_F(IndexedDBTest
, ClearSessionOnlyDatabases
) {
55 base::ScopedTempDir temp_dir
;
56 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
58 base::FilePath normal_path
;
59 base::FilePath session_only_path
;
61 // Create the scope which will ensure we run the destructor of the context
62 // which should trigger the clean up.
64 scoped_refptr
<IndexedDBContextImpl
> idb_context
= new IndexedDBContextImpl(
65 temp_dir
.path(), special_storage_policy_
, NULL
, task_runner_
);
67 normal_path
= idb_context
->GetFilePathForTesting(
68 webkit_database::GetIdentifierFromOrigin(kNormalOrigin
));
69 session_only_path
= idb_context
->GetFilePathForTesting(
70 webkit_database::GetIdentifierFromOrigin(kSessionOnlyOrigin
));
71 ASSERT_TRUE(base::CreateDirectory(normal_path
));
72 ASSERT_TRUE(base::CreateDirectory(session_only_path
));
73 FlushIndexedDBTaskRunner();
74 message_loop_
.RunUntilIdle();
77 FlushIndexedDBTaskRunner();
78 message_loop_
.RunUntilIdle();
80 EXPECT_TRUE(base::DirectoryExists(normal_path
));
81 EXPECT_FALSE(base::DirectoryExists(session_only_path
));
84 TEST_F(IndexedDBTest
, SetForceKeepSessionState
) {
85 base::ScopedTempDir temp_dir
;
86 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
88 base::FilePath normal_path
;
89 base::FilePath session_only_path
;
91 // Create the scope which will ensure we run the destructor of the context.
93 // Create some indexedDB paths.
94 // With the levelDB backend, these are directories.
95 scoped_refptr
<IndexedDBContextImpl
> idb_context
= new IndexedDBContextImpl(
96 temp_dir
.path(), special_storage_policy_
, NULL
, task_runner_
);
98 // Save session state. This should bypass the destruction-time deletion.
99 idb_context
->SetForceKeepSessionState();
101 normal_path
= idb_context
->GetFilePathForTesting(
102 webkit_database::GetIdentifierFromOrigin(kNormalOrigin
));
103 session_only_path
= idb_context
->GetFilePathForTesting(
104 webkit_database::GetIdentifierFromOrigin(kSessionOnlyOrigin
));
105 ASSERT_TRUE(base::CreateDirectory(normal_path
));
106 ASSERT_TRUE(base::CreateDirectory(session_only_path
));
107 message_loop_
.RunUntilIdle();
110 // Make sure we wait until the destructor has run.
111 message_loop_
.RunUntilIdle();
113 // No data was cleared because of SetForceKeepSessionState.
114 EXPECT_TRUE(base::DirectoryExists(normal_path
));
115 EXPECT_TRUE(base::DirectoryExists(session_only_path
));
118 class ForceCloseDBCallbacks
: public IndexedDBCallbacks
{
120 ForceCloseDBCallbacks(scoped_refptr
<IndexedDBContextImpl
> idb_context
,
121 const GURL
& origin_url
)
122 : IndexedDBCallbacks(NULL
, 0, 0),
123 idb_context_(idb_context
),
124 origin_url_(origin_url
) {}
126 virtual void OnSuccess() OVERRIDE
{}
127 virtual void OnSuccess(const std::vector
<base::string16
>&) OVERRIDE
{}
128 virtual void OnSuccess(scoped_ptr
<IndexedDBConnection
> connection
,
129 const IndexedDBDatabaseMetadata
& metadata
) OVERRIDE
{
130 connection_
= connection
.Pass();
131 idb_context_
->ConnectionOpened(origin_url_
, connection_
.get());
134 IndexedDBConnection
* connection() { return connection_
.get(); }
137 virtual ~ForceCloseDBCallbacks() {}
140 scoped_refptr
<IndexedDBContextImpl
> idb_context_
;
142 scoped_ptr
<IndexedDBConnection
> connection_
;
143 DISALLOW_COPY_AND_ASSIGN(ForceCloseDBCallbacks
);
146 TEST_F(IndexedDBTest
, ForceCloseOpenDatabasesOnDelete
) {
147 base::ScopedTempDir temp_dir
;
148 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
150 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> open_db_callbacks(
151 new MockIndexedDBDatabaseCallbacks());
152 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> closed_db_callbacks(
153 new MockIndexedDBDatabaseCallbacks());
155 base::FilePath test_path
;
157 // Create the scope which will ensure we run the destructor of the context.
159 TestBrowserContext browser_context
;
161 const GURL
kTestOrigin("http://test/");
163 scoped_refptr
<IndexedDBContextImpl
> idb_context
= new IndexedDBContextImpl(
164 temp_dir
.path(), special_storage_policy_
, NULL
, task_runner_
);
166 scoped_refptr
<ForceCloseDBCallbacks
> open_callbacks
=
167 new ForceCloseDBCallbacks(idb_context
, kTestOrigin
);
169 scoped_refptr
<ForceCloseDBCallbacks
> closed_callbacks
=
170 new ForceCloseDBCallbacks(idb_context
, kTestOrigin
);
172 IndexedDBFactory
* factory
= idb_context
->GetIDBFactory();
174 test_path
= idb_context
->GetFilePathForTesting(
175 webkit_database::GetIdentifierFromOrigin(kTestOrigin
));
177 IndexedDBPendingConnection
open_connection(open_callbacks
,
179 0 /* child_process_id */,
180 0 /* host_transaction_id */,
182 factory
->Open(base::ASCIIToUTF16("opendb"),
185 idb_context
->data_path());
186 IndexedDBPendingConnection
closed_connection(closed_callbacks
,
188 0 /* child_process_id */,
189 0 /* host_transaction_id */,
191 factory
->Open(base::ASCIIToUTF16("closeddb"),
194 idb_context
->data_path());
196 closed_callbacks
->connection()->Close();
198 idb_context
->TaskRunner()->PostTask(
201 &IndexedDBContextImpl::DeleteForOrigin
, idb_context
, kTestOrigin
));
202 FlushIndexedDBTaskRunner();
203 message_loop_
.RunUntilIdle();
206 // Make sure we wait until the destructor has run.
207 message_loop_
.RunUntilIdle();
209 EXPECT_TRUE(open_db_callbacks
->forced_close_called());
210 EXPECT_FALSE(closed_db_callbacks
->forced_close_called());
211 EXPECT_FALSE(base::DirectoryExists(test_path
));
214 TEST_F(IndexedDBTest
, DeleteFailsIfDirectoryLocked
) {
215 base::ScopedTempDir temp_dir
;
216 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
217 const GURL
kTestOrigin("http://test/");
219 scoped_refptr
<IndexedDBContextImpl
> idb_context
= new IndexedDBContextImpl(
220 temp_dir
.path(), special_storage_policy_
, NULL
, task_runner_
);
222 base::FilePath test_path
= idb_context
->GetFilePathForTesting(
223 webkit_database::GetIdentifierFromOrigin(kTestOrigin
));
224 ASSERT_TRUE(base::CreateDirectory(test_path
));
226 scoped_ptr
<LevelDBLock
> lock
=
227 LevelDBDatabase::LockForTesting(test_path
);
230 idb_context
->TaskRunner()->PostTask(
233 &IndexedDBContextImpl::DeleteForOrigin
, idb_context
, kTestOrigin
));
234 FlushIndexedDBTaskRunner();
236 EXPECT_TRUE(base::DirectoryExists(test_path
));
239 TEST_F(IndexedDBTest
, ForceCloseOpenDatabasesOnCommitFailure
) {
240 const GURL
kTestOrigin("http://test/");
242 base::ScopedTempDir temp_dir
;
243 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
245 scoped_refptr
<IndexedDBContextImpl
> context
= new IndexedDBContextImpl(
246 temp_dir
.path(), special_storage_policy_
, NULL
, task_runner_
);
248 scoped_refptr
<IndexedDBFactory
> factory
= context
->GetIDBFactory();
250 scoped_refptr
<MockIndexedDBCallbacks
> callbacks(new MockIndexedDBCallbacks());
251 scoped_refptr
<MockIndexedDBDatabaseCallbacks
> db_callbacks(
252 new MockIndexedDBDatabaseCallbacks());
253 const int64 transaction_id
= 1;
254 IndexedDBPendingConnection
connection(
257 0 /* child_process_id */,
259 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
);
261 base::ASCIIToUTF16("db"), connection
, kTestOrigin
, temp_dir
.path());
263 EXPECT_TRUE(callbacks
->connection());
265 // ConnectionOpened() is usually called by the dispatcher.
266 context
->ConnectionOpened(kTestOrigin
, callbacks
->connection());
268 EXPECT_TRUE(factory
->IsBackingStoreOpen(kTestOrigin
));
270 // Simulate the write failure.
271 callbacks
->connection()->database()->TransactionCommitFailed();
273 EXPECT_TRUE(db_callbacks
->forced_close_called());
274 EXPECT_FALSE(factory
->IsBackingStoreOpen(kTestOrigin
));
277 } // namespace content