• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/mock_special_storage_policy.h"
17 #include "content/public/test/test_browser_context.h"
18 #include "testing/gtest/include/gtest/gtest.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 
IndexedDBTest()30   IndexedDBTest()
31       : kNormalOrigin("http://normal/"),
32         kSessionOnlyOrigin("http://session-only/"),
33         task_runner_(new base::TestSimpleTaskRunner),
34         special_storage_policy_(new MockSpecialStoragePolicy),
35         file_thread_(BrowserThread::FILE_USER_BLOCKING, &message_loop_),
36         io_thread_(BrowserThread::IO, &message_loop_) {
37     special_storage_policy_->AddSessionOnly(kSessionOnlyOrigin);
38   }
39 
40  protected:
FlushIndexedDBTaskRunner()41   void FlushIndexedDBTaskRunner() { task_runner_->RunUntilIdle(); }
42 
43   base::MessageLoopForIO message_loop_;
44   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
45   scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
46 
47  private:
48   BrowserThreadImpl file_thread_;
49   BrowserThreadImpl io_thread_;
50 
51   DISALLOW_COPY_AND_ASSIGN(IndexedDBTest);
52 };
53 
TEST_F(IndexedDBTest,ClearSessionOnlyDatabases)54 TEST_F(IndexedDBTest, ClearSessionOnlyDatabases) {
55   base::ScopedTempDir temp_dir;
56   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
57 
58   base::FilePath normal_path;
59   base::FilePath session_only_path;
60 
61   // Create the scope which will ensure we run the destructor of the context
62   // which should trigger the clean up.
63   {
64     scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
65         temp_dir.path(), special_storage_policy_, NULL, task_runner_);
66 
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();
75   }
76 
77   FlushIndexedDBTaskRunner();
78   message_loop_.RunUntilIdle();
79 
80   EXPECT_TRUE(base::DirectoryExists(normal_path));
81   EXPECT_FALSE(base::DirectoryExists(session_only_path));
82 }
83 
TEST_F(IndexedDBTest,SetForceKeepSessionState)84 TEST_F(IndexedDBTest, SetForceKeepSessionState) {
85   base::ScopedTempDir temp_dir;
86   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
87 
88   base::FilePath normal_path;
89   base::FilePath session_only_path;
90 
91   // Create the scope which will ensure we run the destructor of the context.
92   {
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_);
97 
98     // Save session state. This should bypass the destruction-time deletion.
99     idb_context->SetForceKeepSessionState();
100 
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();
108   }
109 
110   // Make sure we wait until the destructor has run.
111   message_loop_.RunUntilIdle();
112 
113   // No data was cleared because of SetForceKeepSessionState.
114   EXPECT_TRUE(base::DirectoryExists(normal_path));
115   EXPECT_TRUE(base::DirectoryExists(session_only_path));
116 }
117 
118 class ForceCloseDBCallbacks : public IndexedDBCallbacks {
119  public:
ForceCloseDBCallbacks(scoped_refptr<IndexedDBContextImpl> idb_context,const GURL & origin_url)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) {}
125 
OnSuccess()126   virtual void OnSuccess() OVERRIDE {}
OnSuccess(const std::vector<base::string16> &)127   virtual void OnSuccess(const std::vector<base::string16>&) OVERRIDE {}
OnSuccess(scoped_ptr<IndexedDBConnection> connection,const IndexedDBDatabaseMetadata & metadata)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());
132   }
133 
connection()134   IndexedDBConnection* connection() { return connection_.get(); }
135 
136  protected:
~ForceCloseDBCallbacks()137   virtual ~ForceCloseDBCallbacks() {}
138 
139  private:
140   scoped_refptr<IndexedDBContextImpl> idb_context_;
141   GURL origin_url_;
142   scoped_ptr<IndexedDBConnection> connection_;
143   DISALLOW_COPY_AND_ASSIGN(ForceCloseDBCallbacks);
144 };
145 
TEST_F(IndexedDBTest,ForceCloseOpenDatabasesOnDelete)146 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) {
147   base::ScopedTempDir temp_dir;
148   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
149 
150   scoped_refptr<MockIndexedDBDatabaseCallbacks> open_db_callbacks(
151       new MockIndexedDBDatabaseCallbacks());
152   scoped_refptr<MockIndexedDBDatabaseCallbacks> closed_db_callbacks(
153       new MockIndexedDBDatabaseCallbacks());
154 
155   base::FilePath test_path;
156 
157   // Create the scope which will ensure we run the destructor of the context.
158   {
159     TestBrowserContext browser_context;
160 
161     const GURL kTestOrigin("http://test/");
162 
163     scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
164         temp_dir.path(), special_storage_policy_, NULL, task_runner_);
165 
166     scoped_refptr<ForceCloseDBCallbacks> open_callbacks =
167         new ForceCloseDBCallbacks(idb_context, kTestOrigin);
168 
169     scoped_refptr<ForceCloseDBCallbacks> closed_callbacks =
170         new ForceCloseDBCallbacks(idb_context, kTestOrigin);
171 
172     IndexedDBFactory* factory = idb_context->GetIDBFactory();
173 
174     test_path = idb_context->GetFilePathForTesting(
175         webkit_database::GetIdentifierFromOrigin(kTestOrigin));
176 
177     IndexedDBPendingConnection open_connection(open_callbacks,
178                                                open_db_callbacks,
179                                                0 /* child_process_id */,
180                                                0 /* host_transaction_id */,
181                                                0 /* version */);
182     factory->Open(base::ASCIIToUTF16("opendb"),
183                   open_connection,
184                   NULL /* request_context */,
185                   kTestOrigin,
186                   idb_context->data_path());
187     IndexedDBPendingConnection closed_connection(closed_callbacks,
188                                                  closed_db_callbacks,
189                                                  0 /* child_process_id */,
190                                                  0 /* host_transaction_id */,
191                                                  0 /* version */);
192     factory->Open(base::ASCIIToUTF16("closeddb"),
193                   closed_connection,
194                   NULL /* request_context */,
195                   kTestOrigin,
196                   idb_context->data_path());
197 
198     closed_callbacks->connection()->Close();
199 
200     idb_context->TaskRunner()->PostTask(
201         FROM_HERE,
202         base::Bind(
203             &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin));
204     FlushIndexedDBTaskRunner();
205     message_loop_.RunUntilIdle();
206   }
207 
208   // Make sure we wait until the destructor has run.
209   message_loop_.RunUntilIdle();
210 
211   EXPECT_TRUE(open_db_callbacks->forced_close_called());
212   EXPECT_FALSE(closed_db_callbacks->forced_close_called());
213   EXPECT_FALSE(base::DirectoryExists(test_path));
214 }
215 
TEST_F(IndexedDBTest,DeleteFailsIfDirectoryLocked)216 TEST_F(IndexedDBTest, DeleteFailsIfDirectoryLocked) {
217   base::ScopedTempDir temp_dir;
218   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
219   const GURL kTestOrigin("http://test/");
220 
221   scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl(
222       temp_dir.path(), special_storage_policy_, NULL, task_runner_);
223 
224   base::FilePath test_path = idb_context->GetFilePathForTesting(
225       webkit_database::GetIdentifierFromOrigin(kTestOrigin));
226   ASSERT_TRUE(base::CreateDirectory(test_path));
227 
228   scoped_ptr<LevelDBLock> lock =
229       LevelDBDatabase::LockForTesting(test_path);
230   ASSERT_TRUE(lock);
231 
232   idb_context->TaskRunner()->PostTask(
233       FROM_HERE,
234       base::Bind(
235           &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin));
236   FlushIndexedDBTaskRunner();
237 
238   EXPECT_TRUE(base::DirectoryExists(test_path));
239 }
240 
TEST_F(IndexedDBTest,ForceCloseOpenDatabasesOnCommitFailure)241 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnCommitFailure) {
242   const GURL kTestOrigin("http://test/");
243 
244   base::ScopedTempDir temp_dir;
245   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
246 
247   scoped_refptr<IndexedDBContextImpl> context = new IndexedDBContextImpl(
248       temp_dir.path(), special_storage_policy_, NULL, task_runner_);
249 
250   scoped_refptr<IndexedDBFactory> factory = context->GetIDBFactory();
251 
252   scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
253   scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
254       new MockIndexedDBDatabaseCallbacks());
255   const int64 transaction_id = 1;
256   IndexedDBPendingConnection connection(
257       callbacks,
258       db_callbacks,
259       0 /* child_process_id */,
260       transaction_id,
261       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
262   factory->Open(base::ASCIIToUTF16("db"),
263                 connection,
264                 NULL /* request_context */,
265                 kTestOrigin,
266                 temp_dir.path());
267 
268   EXPECT_TRUE(callbacks->connection());
269 
270   // ConnectionOpened() is usually called by the dispatcher.
271   context->ConnectionOpened(kTestOrigin, callbacks->connection());
272 
273   EXPECT_TRUE(factory->IsBackingStoreOpen(kTestOrigin));
274 
275   // Simulate the write failure.
276   callbacks->connection()->database()->TransactionCommitFailed();
277 
278   EXPECT_TRUE(db_callbacks->forced_close_called());
279   EXPECT_FALSE(factory->IsBackingStoreOpen(kTestOrigin));
280 }
281 
282 }  // namespace content
283