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 message_loop_(base::MessageLoop::TYPE_IO),
34 task_runner_(new base::TestSimpleTaskRunner),
35 special_storage_policy_(new quota::MockSpecialStoragePolicy),
36 file_thread_(BrowserThread::FILE_USER_BLOCKING, &message_loop_),
37 io_thread_(BrowserThread::IO, &message_loop_) {
38 special_storage_policy_->AddSessionOnly(kSessionOnlyOrigin);
42 void FlushIndexedDBTaskRunner() { task_runner_->RunUntilIdle(); }
44 base::MessageLoop message_loop_;
45 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
46 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy_;
49 BrowserThreadImpl file_thread_;
50 BrowserThreadImpl io_thread_;
52 DISALLOW_COPY_AND_ASSIGN(IndexedDBTest);
55 TEST_F(IndexedDBTest, ClearSessionOnlyDatabases) {
56 base::ScopedTempDir temp_dir;
57 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
59 base::FilePath normal_path;
60 base::FilePath session_only_path;
62 // Create the scope which will ensure we run the destructor of the context
63 // which should trigger the clean up.
65 scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
66 temp_dir.path(), special_storage_policy_, NULL, task_runner_);
68 normal_path = idb_context->GetFilePathForTesting(
69 webkit_database::GetIdentifierFromOrigin(kNormalOrigin));
70 session_only_path = idb_context->GetFilePathForTesting(
71 webkit_database::GetIdentifierFromOrigin(kSessionOnlyOrigin));
72 ASSERT_TRUE(file_util::CreateDirectory(normal_path));
73 ASSERT_TRUE(file_util::CreateDirectory(session_only_path));
74 FlushIndexedDBTaskRunner();
75 message_loop_.RunUntilIdle();
78 FlushIndexedDBTaskRunner();
79 message_loop_.RunUntilIdle();
81 EXPECT_TRUE(base::DirectoryExists(normal_path));
82 EXPECT_FALSE(base::DirectoryExists(session_only_path));
85 TEST_F(IndexedDBTest, SetForceKeepSessionState) {
86 base::ScopedTempDir temp_dir;
87 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
89 base::FilePath normal_path;
90 base::FilePath session_only_path;
92 // Create the scope which will ensure we run the destructor of the context.
94 // Create some indexedDB paths.
95 // With the levelDB backend, these are directories.
96 scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
97 temp_dir.path(), special_storage_policy_, NULL, task_runner_);
99 // Save session state. This should bypass the destruction-time deletion.
100 idb_context->SetForceKeepSessionState();
102 normal_path = idb_context->GetFilePathForTesting(
103 webkit_database::GetIdentifierFromOrigin(kNormalOrigin));
104 session_only_path = idb_context->GetFilePathForTesting(
105 webkit_database::GetIdentifierFromOrigin(kSessionOnlyOrigin));
106 ASSERT_TRUE(file_util::CreateDirectory(normal_path));
107 ASSERT_TRUE(file_util::CreateDirectory(session_only_path));
108 message_loop_.RunUntilIdle();
111 // Make sure we wait until the destructor has run.
112 message_loop_.RunUntilIdle();
114 // No data was cleared because of SetForceKeepSessionState.
115 EXPECT_TRUE(base::DirectoryExists(normal_path));
116 EXPECT_TRUE(base::DirectoryExists(session_only_path));
119 class MockConnection : public IndexedDBConnection {
121 explicit MockConnection(bool expect_force_close)
122 : IndexedDBConnection(NULL, NULL),
123 expect_force_close_(expect_force_close),
124 force_close_called_(false) {}
126 virtual ~MockConnection() {
127 EXPECT_TRUE(force_close_called_ == expect_force_close_);
130 virtual void ForceClose() OVERRIDE {
131 ASSERT_TRUE(expect_force_close_);
132 force_close_called_ = true;
135 virtual bool IsConnected() OVERRIDE {
136 return !force_close_called_;
140 bool expect_force_close_;
141 bool force_close_called_;
144 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
145 base::ScopedTempDir temp_dir;
146 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
148 base::FilePath test_path;
150 // Create the scope which will ensure we run the destructor of the context.
152 TestBrowserContext browser_context;
154 const GURL kTestOrigin("http://test/");
156 scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
157 temp_dir.path(), special_storage_policy_, NULL, task_runner_);
159 test_path = idb_context->GetFilePathForTesting(
160 webkit_database::GetIdentifierFromOrigin(kTestOrigin));
161 ASSERT_TRUE(file_util::CreateDirectory(test_path));
163 const bool kExpectForceClose = true;
165 MockConnection connection1(kExpectForceClose);
166 idb_context->TaskRunner()->PostTask(
168 base::Bind(&IndexedDBContextImpl::ConnectionOpened,
173 MockConnection connection2(!kExpectForceClose);
174 idb_context->TaskRunner()->PostTask(
176 base::Bind(&IndexedDBContextImpl::ConnectionOpened,
180 idb_context->TaskRunner()->PostTask(
182 base::Bind(&IndexedDBContextImpl::ConnectionClosed,
187 idb_context->TaskRunner()->PostTask(
190 &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin));
191 FlushIndexedDBTaskRunner();
192 message_loop_.RunUntilIdle();
195 // Make sure we wait until the destructor has run.
196 message_loop_.RunUntilIdle();
198 EXPECT_FALSE(base::DirectoryExists(test_path));
201 TEST_F(IndexedDBTest, DeleteFailsIfDirectoryLocked) {
202 base::ScopedTempDir temp_dir;
203 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
204 const GURL kTestOrigin("http://test/");
206 scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
207 temp_dir.path(), special_storage_policy_, NULL, task_runner_);
209 base::FilePath test_path = idb_context->GetFilePathForTesting(
210 webkit_database::GetIdentifierFromOrigin(kTestOrigin));
211 ASSERT_TRUE(file_util::CreateDirectory(test_path));
213 scoped_ptr<LevelDBLock> lock =
214 LevelDBDatabase::LockForTesting(test_path);
217 idb_context->TaskRunner()->PostTask(
220 &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin));
221 FlushIndexedDBTaskRunner();
223 EXPECT_TRUE(base::DirectoryExists(test_path));
226 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
227 const GURL kTestOrigin("http://test/");
229 base::ScopedTempDir temp_dir;
230 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
232 scoped_refptr<IndexedDBContextImpl> context = new IndexedDBContextImpl(
233 temp_dir.path(), special_storage_policy_, NULL, task_runner_);
235 scoped_refptr<IndexedDBFactory> factory = context->GetIDBFactory();
237 scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
238 scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
239 new MockIndexedDBDatabaseCallbacks());
240 const int64 transaction_id = 1;
241 factory->Open(ASCIIToUTF16("db"),
242 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION,
249 EXPECT_TRUE(callbacks->connection());
251 // ConnectionOpened() is usually called by the dispatcher.
252 context->ConnectionOpened(kTestOrigin, callbacks->connection());
254 EXPECT_TRUE(factory->IsBackingStoreOpenForTesting(kTestOrigin));
256 // Simulate the write failure.
257 callbacks->connection()->database()->TransactionCommitFailed();
259 EXPECT_TRUE(db_callbacks->forced_close_called());
260 EXPECT_FALSE(factory->IsBackingStoreOpenForTesting(kTestOrigin));
263 } // namespace content