- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / indexed_db / indexed_db_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 "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"
22
23 namespace content {
24
25 class IndexedDBTest : public testing::Test {
26  public:
27   const GURL kNormalOrigin;
28   const GURL kSessionOnlyOrigin;
29
30   IndexedDBTest()
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);
39   }
40
41  protected:
42   void FlushIndexedDBTaskRunner() { task_runner_->RunUntilIdle(); }
43
44   base::MessageLoop message_loop_;
45   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
46   scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy_;
47
48  private:
49   BrowserThreadImpl file_thread_;
50   BrowserThreadImpl io_thread_;
51
52   DISALLOW_COPY_AND_ASSIGN(IndexedDBTest);
53 };
54
55 TEST_F(IndexedDBTest, ClearSessionOnlyDatabases) {
56   base::ScopedTempDir temp_dir;
57   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
58
59   base::FilePath normal_path;
60   base::FilePath session_only_path;
61
62   // Create the scope which will ensure we run the destructor of the context
63   // which should trigger the clean up.
64   {
65     scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
66         temp_dir.path(), special_storage_policy_, NULL, task_runner_);
67
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();
76   }
77
78   FlushIndexedDBTaskRunner();
79   message_loop_.RunUntilIdle();
80
81   EXPECT_TRUE(base::DirectoryExists(normal_path));
82   EXPECT_FALSE(base::DirectoryExists(session_only_path));
83 }
84
85 TEST_F(IndexedDBTest, SetForceKeepSessionState) {
86   base::ScopedTempDir temp_dir;
87   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
88
89   base::FilePath normal_path;
90   base::FilePath session_only_path;
91
92   // Create the scope which will ensure we run the destructor of the context.
93   {
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_);
98
99     // Save session state. This should bypass the destruction-time deletion.
100     idb_context->SetForceKeepSessionState();
101
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();
109   }
110
111   // Make sure we wait until the destructor has run.
112   message_loop_.RunUntilIdle();
113
114   // No data was cleared because of SetForceKeepSessionState.
115   EXPECT_TRUE(base::DirectoryExists(normal_path));
116   EXPECT_TRUE(base::DirectoryExists(session_only_path));
117 }
118
119 class MockConnection : public IndexedDBConnection {
120  public:
121   explicit MockConnection(bool expect_force_close)
122       : IndexedDBConnection(NULL, NULL),
123         expect_force_close_(expect_force_close),
124         force_close_called_(false) {}
125
126   virtual ~MockConnection() {
127     EXPECT_TRUE(force_close_called_ == expect_force_close_);
128   }
129
130   virtual void ForceClose() OVERRIDE {
131     ASSERT_TRUE(expect_force_close_);
132     force_close_called_ = true;
133   }
134
135   virtual bool IsConnected() OVERRIDE {
136     return !force_close_called_;
137   }
138
139  private:
140   bool expect_force_close_;
141   bool force_close_called_;
142 };
143
144 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
145   base::ScopedTempDir temp_dir;
146   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
147
148   base::FilePath test_path;
149
150   // Create the scope which will ensure we run the destructor of the context.
151   {
152     TestBrowserContext browser_context;
153
154     const GURL kTestOrigin("http://test/");
155
156     scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
157         temp_dir.path(), special_storage_policy_, NULL, task_runner_);
158
159     test_path = idb_context->GetFilePathForTesting(
160         webkit_database::GetIdentifierFromOrigin(kTestOrigin));
161     ASSERT_TRUE(file_util::CreateDirectory(test_path));
162
163     const bool kExpectForceClose = true;
164
165     MockConnection connection1(kExpectForceClose);
166     idb_context->TaskRunner()->PostTask(
167         FROM_HERE,
168         base::Bind(&IndexedDBContextImpl::ConnectionOpened,
169                    idb_context,
170                    kTestOrigin,
171                    &connection1));
172
173     MockConnection connection2(!kExpectForceClose);
174     idb_context->TaskRunner()->PostTask(
175         FROM_HERE,
176         base::Bind(&IndexedDBContextImpl::ConnectionOpened,
177                    idb_context,
178                    kTestOrigin,
179                    &connection2));
180     idb_context->TaskRunner()->PostTask(
181         FROM_HERE,
182         base::Bind(&IndexedDBContextImpl::ConnectionClosed,
183                    idb_context,
184                    kTestOrigin,
185                    &connection2));
186
187     idb_context->TaskRunner()->PostTask(
188         FROM_HERE,
189         base::Bind(
190             &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin));
191     FlushIndexedDBTaskRunner();
192     message_loop_.RunUntilIdle();
193   }
194
195   // Make sure we wait until the destructor has run.
196   message_loop_.RunUntilIdle();
197
198   EXPECT_FALSE(base::DirectoryExists(test_path));
199 }
200
201 TEST_F(IndexedDBTest, DeleteFailsIfDirectoryLocked) {
202   base::ScopedTempDir temp_dir;
203   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
204   const GURL kTestOrigin("http://test/");
205
206   scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
207       temp_dir.path(), special_storage_policy_, NULL, task_runner_);
208
209   base::FilePath test_path = idb_context->GetFilePathForTesting(
210       webkit_database::GetIdentifierFromOrigin(kTestOrigin));
211   ASSERT_TRUE(file_util::CreateDirectory(test_path));
212
213   scoped_ptr<LevelDBLock> lock =
214       LevelDBDatabase::LockForTesting(test_path);
215   ASSERT_TRUE(lock);
216
217   idb_context->TaskRunner()->PostTask(
218       FROM_HERE,
219       base::Bind(
220           &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin));
221   FlushIndexedDBTaskRunner();
222
223   EXPECT_TRUE(base::DirectoryExists(test_path));
224 }
225
226 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
227   const GURL kTestOrigin("http://test/");
228
229   base::ScopedTempDir temp_dir;
230   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
231
232   scoped_refptr<IndexedDBContextImpl> context = new IndexedDBContextImpl(
233       temp_dir.path(), special_storage_policy_, NULL, task_runner_);
234
235   scoped_refptr<IndexedDBFactory> factory = context->GetIDBFactory();
236
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,
243                 transaction_id,
244                 callbacks,
245                 db_callbacks,
246                 kTestOrigin,
247                 temp_dir.path());
248
249   EXPECT_TRUE(callbacks->connection());
250
251   // ConnectionOpened() is usually called by the dispatcher.
252   context->ConnectionOpened(kTestOrigin, callbacks->connection());
253
254   EXPECT_TRUE(factory->IsBackingStoreOpenForTesting(kTestOrigin));
255
256   // Simulate the write failure.
257   callbacks->connection()->database()->TransactionCommitFailed();
258
259   EXPECT_TRUE(db_callbacks->forced_close_called());
260   EXPECT_FALSE(factory->IsBackingStoreOpenForTesting(kTestOrigin));
261 }
262
263 }  // namespace content