Update To 11.40.268.0
[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/files/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/indexed_db_factory_impl.h"
13 #include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
14 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
15 #include "content/public/browser/storage_partition.h"
16 #include "content/public/common/url_constants.h"
17 #include "content/public/test/mock_special_storage_policy.h"
18 #include "content/public/test/test_browser_context.h"
19 #include "storage/browser/quota/quota_manager.h"
20 #include "storage/browser/quota/special_storage_policy.h"
21 #include "storage/common/database/database_identifier.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace content {
25
26 class IndexedDBTest : public testing::Test {
27  public:
28   const GURL kNormalOrigin;
29   const GURL kSessionOnlyOrigin;
30
31   IndexedDBTest()
32       : kNormalOrigin("http://normal/"),
33         kSessionOnlyOrigin("http://session-only/"),
34         task_runner_(new base::TestSimpleTaskRunner),
35         special_storage_policy_(new 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::MessageLoopForIO message_loop_;
45   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
46   scoped_refptr<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 =
66         new IndexedDBContextImpl(temp_dir.path(),
67                                  special_storage_policy_.get(),
68                                  NULL,
69                                  task_runner_.get());
70
71     normal_path = idb_context->GetFilePathForTesting(
72         storage::GetIdentifierFromOrigin(kNormalOrigin));
73     session_only_path = idb_context->GetFilePathForTesting(
74         storage::GetIdentifierFromOrigin(kSessionOnlyOrigin));
75     ASSERT_TRUE(base::CreateDirectory(normal_path));
76     ASSERT_TRUE(base::CreateDirectory(session_only_path));
77     FlushIndexedDBTaskRunner();
78     message_loop_.RunUntilIdle();
79   }
80
81   FlushIndexedDBTaskRunner();
82   message_loop_.RunUntilIdle();
83
84   EXPECT_TRUE(base::DirectoryExists(normal_path));
85   EXPECT_FALSE(base::DirectoryExists(session_only_path));
86 }
87
88 TEST_F(IndexedDBTest, SetForceKeepSessionState) {
89   base::ScopedTempDir temp_dir;
90   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
91
92   base::FilePath normal_path;
93   base::FilePath session_only_path;
94
95   // Create the scope which will ensure we run the destructor of the context.
96   {
97     // Create some indexedDB paths.
98     // With the levelDB backend, these are directories.
99     scoped_refptr<IndexedDBContextImpl> idb_context =
100         new IndexedDBContextImpl(temp_dir.path(),
101                                  special_storage_policy_.get(),
102                                  NULL,
103                                  task_runner_.get());
104
105     // Save session state. This should bypass the destruction-time deletion.
106     idb_context->SetForceKeepSessionState();
107
108     normal_path = idb_context->GetFilePathForTesting(
109         storage::GetIdentifierFromOrigin(kNormalOrigin));
110     session_only_path = idb_context->GetFilePathForTesting(
111         storage::GetIdentifierFromOrigin(kSessionOnlyOrigin));
112     ASSERT_TRUE(base::CreateDirectory(normal_path));
113     ASSERT_TRUE(base::CreateDirectory(session_only_path));
114     message_loop_.RunUntilIdle();
115   }
116
117   // Make sure we wait until the destructor has run.
118   message_loop_.RunUntilIdle();
119
120   // No data was cleared because of SetForceKeepSessionState.
121   EXPECT_TRUE(base::DirectoryExists(normal_path));
122   EXPECT_TRUE(base::DirectoryExists(session_only_path));
123 }
124
125 class ForceCloseDBCallbacks : public IndexedDBCallbacks {
126  public:
127   ForceCloseDBCallbacks(scoped_refptr<IndexedDBContextImpl> idb_context,
128                         const GURL& origin_url)
129       : IndexedDBCallbacks(NULL, 0, 0),
130         idb_context_(idb_context),
131         origin_url_(origin_url) {}
132
133   void OnSuccess() override {}
134   void OnSuccess(const std::vector<base::string16>&) override {}
135   void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
136                  const IndexedDBDatabaseMetadata& metadata) override {
137     connection_ = connection.Pass();
138     idb_context_->ConnectionOpened(origin_url_, connection_.get());
139   }
140
141   IndexedDBConnection* connection() { return connection_.get(); }
142
143  protected:
144   ~ForceCloseDBCallbacks() override {}
145
146  private:
147   scoped_refptr<IndexedDBContextImpl> idb_context_;
148   GURL origin_url_;
149   scoped_ptr<IndexedDBConnection> connection_;
150   DISALLOW_COPY_AND_ASSIGN(ForceCloseDBCallbacks);
151 };
152
153 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
154   base::ScopedTempDir temp_dir;
155   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
156
157   scoped_refptr<MockIndexedDBDatabaseCallbacks> open_db_callbacks(
158       new MockIndexedDBDatabaseCallbacks());
159   scoped_refptr<MockIndexedDBDatabaseCallbacks> closed_db_callbacks(
160       new MockIndexedDBDatabaseCallbacks());
161
162   base::FilePath test_path;
163
164   // Create the scope which will ensure we run the destructor of the context.
165   {
166     TestBrowserContext browser_context;
167
168     const GURL kTestOrigin("http://test/");
169
170     scoped_refptr<IndexedDBContextImpl> idb_context =
171         new IndexedDBContextImpl(temp_dir.path(),
172                                  special_storage_policy_.get(),
173                                  NULL,
174                                  task_runner_.get());
175
176     scoped_refptr<ForceCloseDBCallbacks> open_callbacks =
177         new ForceCloseDBCallbacks(idb_context, kTestOrigin);
178
179     scoped_refptr<ForceCloseDBCallbacks> closed_callbacks =
180         new ForceCloseDBCallbacks(idb_context, kTestOrigin);
181
182     IndexedDBFactory* factory = idb_context->GetIDBFactory();
183
184     test_path = idb_context->GetFilePathForTesting(
185         storage::GetIdentifierFromOrigin(kTestOrigin));
186
187     IndexedDBPendingConnection open_connection(open_callbacks,
188                                                open_db_callbacks,
189                                                0 /* child_process_id */,
190                                                0 /* host_transaction_id */,
191                                                0 /* version */);
192     factory->Open(base::ASCIIToUTF16("opendb"),
193                   open_connection,
194                   NULL /* request_context */,
195                   kTestOrigin,
196                   idb_context->data_path());
197     IndexedDBPendingConnection closed_connection(closed_callbacks,
198                                                  closed_db_callbacks,
199                                                  0 /* child_process_id */,
200                                                  0 /* host_transaction_id */,
201                                                  0 /* version */);
202     factory->Open(base::ASCIIToUTF16("closeddb"),
203                   closed_connection,
204                   NULL /* request_context */,
205                   kTestOrigin,
206                   idb_context->data_path());
207
208     closed_callbacks->connection()->Close();
209
210     idb_context->TaskRunner()->PostTask(
211         FROM_HERE,
212         base::Bind(
213             &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin));
214     FlushIndexedDBTaskRunner();
215     message_loop_.RunUntilIdle();
216   }
217
218   // Make sure we wait until the destructor has run.
219   message_loop_.RunUntilIdle();
220
221   EXPECT_TRUE(open_db_callbacks->forced_close_called());
222   EXPECT_FALSE(closed_db_callbacks->forced_close_called());
223   EXPECT_FALSE(base::DirectoryExists(test_path));
224 }
225
226 TEST_F(IndexedDBTest, DeleteFailsIfDirectoryLocked) {
227   base::ScopedTempDir temp_dir;
228   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
229   const GURL kTestOrigin("http://test/");
230
231   scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
232       temp_dir.path(), special_storage_policy_.get(), NULL, task_runner_.get());
233
234   base::FilePath test_path = idb_context->GetFilePathForTesting(
235       storage::GetIdentifierFromOrigin(kTestOrigin));
236   ASSERT_TRUE(base::CreateDirectory(test_path));
237
238   scoped_ptr<LevelDBLock> lock =
239       LevelDBDatabase::LockForTesting(test_path);
240   ASSERT_TRUE(lock);
241
242   idb_context->TaskRunner()->PostTask(
243       FROM_HERE,
244       base::Bind(
245           &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin));
246   FlushIndexedDBTaskRunner();
247
248   EXPECT_TRUE(base::DirectoryExists(test_path));
249 }
250
251 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
252   const GURL kTestOrigin("http://test/");
253
254   base::ScopedTempDir temp_dir;
255   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
256
257   scoped_refptr<IndexedDBContextImpl> context = new IndexedDBContextImpl(
258       temp_dir.path(), special_storage_policy_.get(), NULL, task_runner_.get());
259
260   scoped_refptr<IndexedDBFactoryImpl> factory =
261       static_cast<IndexedDBFactoryImpl*>(context->GetIDBFactory());
262
263   scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
264   scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
265       new MockIndexedDBDatabaseCallbacks());
266   const int64 transaction_id = 1;
267   IndexedDBPendingConnection connection(
268       callbacks,
269       db_callbacks,
270       0 /* child_process_id */,
271       transaction_id,
272       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
273   factory->Open(base::ASCIIToUTF16("db"),
274                 connection,
275                 NULL /* request_context */,
276                 kTestOrigin,
277                 temp_dir.path());
278
279   EXPECT_TRUE(callbacks->connection());
280
281   // ConnectionOpened() is usually called by the dispatcher.
282   context->ConnectionOpened(kTestOrigin, callbacks->connection());
283
284   EXPECT_TRUE(factory->IsBackingStoreOpen(kTestOrigin));
285
286   // Simulate the write failure.
287   leveldb::Status status = leveldb::Status::IOError("Simulated failure");
288   callbacks->connection()->database()->TransactionCommitFailed(status);
289
290   EXPECT_TRUE(db_callbacks->forced_close_called());
291   EXPECT_FALSE(factory->IsBackingStoreOpen(kTestOrigin));
292 }
293
294 }  // namespace content