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/public/browser/storage_partition.h" 13 #include "content/public/common/url_constants.h" 14 #include "content/public/test/test_browser_context.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "webkit/browser/quota/mock_special_storage_policy.h" 17 #include "webkit/browser/quota/quota_manager.h" 18 #include "webkit/browser/quota/special_storage_policy.h" 19 #include "webkit/common/database/database_identifier.h" 20 21 namespace content { 22 23 class IndexedDBTest : public testing::Test { 24 public: 25 const GURL kNormalOrigin; 26 const GURL kSessionOnlyOrigin; 27 28 IndexedDBTest() 29 : kNormalOrigin("http://normal/"), 30 kSessionOnlyOrigin("http://session-only/"), 31 message_loop_(base::MessageLoop::TYPE_IO), 32 task_runner_(new base::TestSimpleTaskRunner), 33 special_storage_policy_(new quota::MockSpecialStoragePolicy), 34 file_thread_(BrowserThread::FILE_USER_BLOCKING, &message_loop_), 35 io_thread_(BrowserThread::IO, &message_loop_) { 36 special_storage_policy_->AddSessionOnly(kSessionOnlyOrigin); 37 } 38 39 protected: 40 void FlushIndexedDBTaskRunner() { task_runner_->RunUntilIdle(); } 41 42 base::MessageLoop message_loop_; 43 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; 44 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy_; 45 46 private: 47 BrowserThreadImpl file_thread_; 48 BrowserThreadImpl io_thread_; 49 }; 50 51 TEST_F(IndexedDBTest, ClearSessionOnlyDatabases) { 52 base::ScopedTempDir temp_dir; 53 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 54 55 base::FilePath normal_path; 56 base::FilePath session_only_path; 57 58 // Create the scope which will ensure we run the destructor of the context 59 // which should trigger the clean up. 60 { 61 scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl( 62 temp_dir.path(), special_storage_policy_, NULL, task_runner_); 63 64 normal_path = idb_context->GetFilePathForTesting( 65 webkit_database::GetIdentifierFromOrigin(kNormalOrigin)); 66 session_only_path = idb_context->GetFilePathForTesting( 67 webkit_database::GetIdentifierFromOrigin(kSessionOnlyOrigin)); 68 ASSERT_TRUE(file_util::CreateDirectory(normal_path)); 69 ASSERT_TRUE(file_util::CreateDirectory(session_only_path)); 70 FlushIndexedDBTaskRunner(); 71 message_loop_.RunUntilIdle(); 72 } 73 74 FlushIndexedDBTaskRunner(); 75 message_loop_.RunUntilIdle(); 76 77 EXPECT_TRUE(base::DirectoryExists(normal_path)); 78 EXPECT_FALSE(base::DirectoryExists(session_only_path)); 79 } 80 81 TEST_F(IndexedDBTest, SetForceKeepSessionState) { 82 base::ScopedTempDir temp_dir; 83 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 84 85 base::FilePath normal_path; 86 base::FilePath session_only_path; 87 88 // Create the scope which will ensure we run the destructor of the context. 89 { 90 // Create some indexedDB paths. 91 // With the levelDB backend, these are directories. 92 scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl( 93 temp_dir.path(), special_storage_policy_, NULL, task_runner_); 94 95 // Save session state. This should bypass the destruction-time deletion. 96 idb_context->SetForceKeepSessionState(); 97 98 normal_path = idb_context->GetFilePathForTesting( 99 webkit_database::GetIdentifierFromOrigin(kNormalOrigin)); 100 session_only_path = idb_context->GetFilePathForTesting( 101 webkit_database::GetIdentifierFromOrigin(kSessionOnlyOrigin)); 102 ASSERT_TRUE(file_util::CreateDirectory(normal_path)); 103 ASSERT_TRUE(file_util::CreateDirectory(session_only_path)); 104 message_loop_.RunUntilIdle(); 105 } 106 107 // Make sure we wait until the destructor has run. 108 message_loop_.RunUntilIdle(); 109 110 // No data was cleared because of SetForceKeepSessionState. 111 EXPECT_TRUE(base::DirectoryExists(normal_path)); 112 EXPECT_TRUE(base::DirectoryExists(session_only_path)); 113 } 114 115 class MockConnection : public IndexedDBConnection { 116 public: 117 explicit MockConnection(bool expect_force_close) 118 : IndexedDBConnection(NULL, NULL), 119 expect_force_close_(expect_force_close), 120 force_close_called_(false) {} 121 122 virtual ~MockConnection() { 123 EXPECT_TRUE(force_close_called_ == expect_force_close_); 124 } 125 126 virtual void ForceClose() OVERRIDE { 127 ASSERT_TRUE(expect_force_close_); 128 force_close_called_ = true; 129 } 130 131 private: 132 bool expect_force_close_; 133 bool force_close_called_; 134 }; 135 136 TEST_F(IndexedDBTest, ForceCloseOpenDatabasesOnDelete) { 137 base::ScopedTempDir temp_dir; 138 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 139 140 base::FilePath test_path; 141 142 // Create the scope which will ensure we run the destructor of the context. 143 { 144 TestBrowserContext browser_context; 145 146 const GURL kTestOrigin("http://test/"); 147 148 scoped_refptr<IndexedDBContextImpl> idb_context = new IndexedDBContextImpl( 149 temp_dir.path(), special_storage_policy_, NULL, task_runner_); 150 151 test_path = idb_context->GetFilePathForTesting( 152 webkit_database::GetIdentifierFromOrigin(kTestOrigin)); 153 ASSERT_TRUE(file_util::CreateDirectory(test_path)); 154 155 const bool kExpectForceClose = true; 156 157 MockConnection connection1(kExpectForceClose); 158 idb_context->TaskRunner()->PostTask( 159 FROM_HERE, 160 base::Bind(&IndexedDBContextImpl::ConnectionOpened, 161 idb_context, 162 kTestOrigin, 163 &connection1)); 164 165 MockConnection connection2(!kExpectForceClose); 166 idb_context->TaskRunner()->PostTask( 167 FROM_HERE, 168 base::Bind(&IndexedDBContextImpl::ConnectionOpened, 169 idb_context, 170 kTestOrigin, 171 &connection2)); 172 idb_context->TaskRunner()->PostTask( 173 FROM_HERE, 174 base::Bind(&IndexedDBContextImpl::ConnectionClosed, 175 idb_context, 176 kTestOrigin, 177 &connection2)); 178 179 idb_context->TaskRunner()->PostTask( 180 FROM_HERE, 181 base::Bind( 182 &IndexedDBContextImpl::DeleteForOrigin, idb_context, kTestOrigin)); 183 FlushIndexedDBTaskRunner(); 184 message_loop_.RunUntilIdle(); 185 } 186 187 // Make sure we wait until the destructor has run. 188 message_loop_.RunUntilIdle(); 189 190 EXPECT_FALSE(base::DirectoryExists(test_path)); 191 } 192 193 } // namespace content 194