1 // Copyright 2014 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 <set> 6 7 #include "base/test/test_simple_task_runner.h" 8 #include "content/browser/indexed_db/indexed_db_active_blob_registry.h" 9 #include "content/browser/indexed_db/indexed_db_backing_store.h" 10 #include "content/browser/indexed_db/indexed_db_fake_backing_store.h" 11 #include "content/browser/indexed_db/mock_indexed_db_factory.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 namespace content { 15 16 namespace { 17 18 class RegistryTestMockFactory : public MockIndexedDBFactory { 19 public: 20 RegistryTestMockFactory() : duplicate_calls_(false) {} 21 22 virtual void ReportOutstandingBlobs(const GURL& origin_url, 23 bool blobs_outstanding) OVERRIDE { 24 if (blobs_outstanding) { 25 if (origins_.count(origin_url)) { 26 duplicate_calls_ = true; 27 } else { 28 origins_.insert(origin_url); 29 } 30 } else { 31 if (!origins_.count(origin_url)) { 32 duplicate_calls_ = true; 33 } else { 34 origins_.erase(origin_url); 35 } 36 } 37 } 38 39 bool CheckNoOriginsInUse() const { 40 return !duplicate_calls_ && !origins_.size(); 41 } 42 43 bool CheckSingleOriginInUse(const GURL& origin) const { 44 return !duplicate_calls_ && origins_.size() == 1 && origins_.count(origin); 45 } 46 47 private: 48 virtual ~RegistryTestMockFactory() {} 49 50 std::set<GURL> origins_; 51 bool duplicate_calls_; 52 53 DISALLOW_COPY_AND_ASSIGN(RegistryTestMockFactory); 54 }; 55 56 class MockIDBBackingStore : public IndexedDBFakeBackingStore { 57 public: 58 typedef std::pair<int64, int64> KeyPair; 59 typedef std::set<KeyPair> KeyPairSet; 60 61 MockIDBBackingStore(IndexedDBFactory* factory, 62 base::SequencedTaskRunner* task_runner) 63 : IndexedDBFakeBackingStore(factory, task_runner), 64 duplicate_calls_(false) {} 65 66 virtual void ReportBlobUnused(int64 database_id, int64 blob_key) OVERRIDE { 67 unused_blobs_.insert(std::make_pair(database_id, blob_key)); 68 } 69 70 bool CheckUnusedBlobsEmpty() const { 71 return !duplicate_calls_ && !unused_blobs_.size(); 72 } 73 bool CheckSingleUnusedBlob(int64 database_id, int64 blob_key) const { 74 return !duplicate_calls_ && unused_blobs_.size() == 1 && 75 unused_blobs_.count(std::make_pair(database_id, blob_key)); 76 } 77 78 const KeyPairSet& unused_blobs() const { return unused_blobs_; } 79 80 protected: 81 virtual ~MockIDBBackingStore() {} 82 83 private: 84 KeyPairSet unused_blobs_; 85 bool duplicate_calls_; 86 87 DISALLOW_COPY_AND_ASSIGN(MockIDBBackingStore); 88 }; 89 90 // Base class for our test fixtures. 91 class IndexedDBActiveBlobRegistryTest : public testing::Test { 92 public: 93 typedef storage::ShareableFileReference::FinalReleaseCallback 94 ReleaseCallback; 95 96 static const int64 kDatabaseId0 = 7; 97 static const int64 kDatabaseId1 = 12; 98 static const int64 kBlobKey0 = 77; 99 static const int64 kBlobKey1 = 14; 100 101 IndexedDBActiveBlobRegistryTest() 102 : task_runner_(new base::TestSimpleTaskRunner), 103 factory_(new RegistryTestMockFactory), 104 backing_store_( 105 new MockIDBBackingStore(factory_.get(), task_runner_.get())), 106 registry_(new IndexedDBActiveBlobRegistry(backing_store_.get())) {} 107 108 void RunUntilIdle() { task_runner_->RunUntilIdle(); } 109 RegistryTestMockFactory* factory() const { return factory_.get(); } 110 MockIDBBackingStore* backing_store() const { return backing_store_.get(); } 111 IndexedDBActiveBlobRegistry* registry() const { return registry_.get(); } 112 113 private: 114 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; 115 scoped_refptr<RegistryTestMockFactory> factory_; 116 scoped_refptr<MockIDBBackingStore> backing_store_; 117 scoped_ptr<IndexedDBActiveBlobRegistry> registry_; 118 119 DISALLOW_COPY_AND_ASSIGN(IndexedDBActiveBlobRegistryTest); 120 }; 121 122 TEST_F(IndexedDBActiveBlobRegistryTest, DeleteUnused) { 123 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 124 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 125 126 EXPECT_FALSE(registry()->MarkDeletedCheckIfUsed(kDatabaseId0, kBlobKey0)); 127 RunUntilIdle(); 128 129 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 130 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 131 } 132 133 TEST_F(IndexedDBActiveBlobRegistryTest, SimpleUse) { 134 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 135 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 136 137 base::Closure add_ref = 138 registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey0); 139 ReleaseCallback release = 140 registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey0); 141 add_ref.Run(); 142 RunUntilIdle(); 143 144 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 145 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 146 147 release.Run(base::FilePath()); 148 RunUntilIdle(); 149 150 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 151 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 152 } 153 154 TEST_F(IndexedDBActiveBlobRegistryTest, DeleteWhileInUse) { 155 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 156 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 157 158 base::Closure add_ref = 159 registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey0); 160 ReleaseCallback release = 161 registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey0); 162 163 add_ref.Run(); 164 RunUntilIdle(); 165 166 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 167 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 168 169 EXPECT_TRUE(registry()->MarkDeletedCheckIfUsed(kDatabaseId0, kBlobKey0)); 170 RunUntilIdle(); 171 172 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 173 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 174 175 release.Run(base::FilePath()); 176 RunUntilIdle(); 177 178 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 179 EXPECT_TRUE(backing_store()->CheckSingleUnusedBlob(kDatabaseId0, kBlobKey0)); 180 } 181 182 TEST_F(IndexedDBActiveBlobRegistryTest, MultipleBlobs) { 183 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 184 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 185 186 base::Closure add_ref_00 = 187 registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey0); 188 ReleaseCallback release_00 = 189 registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey0); 190 base::Closure add_ref_01 = 191 registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey1); 192 ReleaseCallback release_01 = 193 registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey1); 194 base::Closure add_ref_10 = 195 registry()->GetAddBlobRefCallback(kDatabaseId1, kBlobKey0); 196 ReleaseCallback release_10 = 197 registry()->GetFinalReleaseCallback(kDatabaseId1, kBlobKey0); 198 base::Closure add_ref_11 = 199 registry()->GetAddBlobRefCallback(kDatabaseId1, kBlobKey1); 200 ReleaseCallback release_11 = 201 registry()->GetFinalReleaseCallback(kDatabaseId1, kBlobKey1); 202 203 add_ref_00.Run(); 204 add_ref_01.Run(); 205 RunUntilIdle(); 206 207 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 208 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 209 210 release_00.Run(base::FilePath()); 211 add_ref_10.Run(); 212 add_ref_11.Run(); 213 RunUntilIdle(); 214 215 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 216 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 217 218 EXPECT_TRUE(registry()->MarkDeletedCheckIfUsed(kDatabaseId0, kBlobKey1)); 219 RunUntilIdle(); 220 221 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 222 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 223 224 release_01.Run(base::FilePath()); 225 release_11.Run(base::FilePath()); 226 RunUntilIdle(); 227 228 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 229 EXPECT_TRUE(backing_store()->CheckSingleUnusedBlob(kDatabaseId0, kBlobKey1)); 230 231 release_10.Run(base::FilePath()); 232 RunUntilIdle(); 233 234 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 235 EXPECT_TRUE(backing_store()->CheckSingleUnusedBlob(kDatabaseId0, kBlobKey1)); 236 } 237 238 TEST_F(IndexedDBActiveBlobRegistryTest, ForceShutdown) { 239 EXPECT_TRUE(factory()->CheckNoOriginsInUse()); 240 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 241 242 base::Closure add_ref_0 = 243 registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey0); 244 ReleaseCallback release_0 = 245 registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey0); 246 base::Closure add_ref_1 = 247 registry()->GetAddBlobRefCallback(kDatabaseId0, kBlobKey1); 248 ReleaseCallback release_1 = 249 registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobKey1); 250 251 add_ref_0.Run(); 252 RunUntilIdle(); 253 254 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 255 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 256 257 registry()->ForceShutdown(); 258 259 add_ref_1.Run(); 260 RunUntilIdle(); 261 262 // Nothing changes. 263 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 264 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 265 266 release_0.Run(base::FilePath()); 267 release_1.Run(base::FilePath()); 268 RunUntilIdle(); 269 270 // Nothing changes. 271 EXPECT_TRUE(factory()->CheckSingleOriginInUse(backing_store()->origin_url())); 272 EXPECT_TRUE(backing_store()->CheckUnusedBlobsEmpty()); 273 } 274 275 } // namespace 276 277 } // namespace content 278