Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: content/browser/indexed_db/indexed_db_database_unittest.cc

Issue 277583002: IndexedDB: Prevent store/index deletion from racing ahead of use (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: base::Closure copies const-refs, so this is better Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/indexed_db/indexed_db_database.h" 5 #include "content/browser/indexed_db/indexed_db_database.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/run_loop.h"
9 #include "base/strings/string16.h" 10 #include "base/strings/string16.h"
10 #include "base/strings/utf_string_conversions.h" 11 #include "base/strings/utf_string_conversions.h"
11 #include "content/browser/indexed_db/indexed_db.h" 12 #include "content/browser/indexed_db/indexed_db.h"
12 #include "content/browser/indexed_db/indexed_db_backing_store.h" 13 #include "content/browser/indexed_db/indexed_db_backing_store.h"
13 #include "content/browser/indexed_db/indexed_db_callbacks.h" 14 #include "content/browser/indexed_db/indexed_db_callbacks.h"
14 #include "content/browser/indexed_db/indexed_db_connection.h" 15 #include "content/browser/indexed_db/indexed_db_connection.h"
15 #include "content/browser/indexed_db/indexed_db_cursor.h" 16 #include "content/browser/indexed_db/indexed_db_cursor.h"
16 #include "content/browser/indexed_db/indexed_db_database.h" 17 #include "content/browser/indexed_db/indexed_db_database.h"
17 #include "content/browser/indexed_db/indexed_db_factory.h" 18 #include "content/browser/indexed_db/indexed_db_factory.h"
18 #include "content/browser/indexed_db/indexed_db_fake_backing_store.h" 19 #include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
19 #include "content/browser/indexed_db/indexed_db_transaction.h" 20 #include "content/browser/indexed_db/indexed_db_transaction.h"
21 #include "content/browser/indexed_db/indexed_db_value.h"
20 #include "content/browser/indexed_db/mock_indexed_db_callbacks.h" 22 #include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
21 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h" 23 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
22 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/gtest/include/gtest/gtest.h"
23 25
24 using base::ASCIIToUTF16; 26 using base::ASCIIToUTF16;
25 27
26 namespace { 28 namespace {
27 const int FAKE_CHILD_PROCESS_ID = 0; 29 const int kFakeChildProcessId = 0;
28 } 30 }
29 31
30 namespace content { 32 namespace content {
31 33
32 TEST(IndexedDBDatabaseTest, BackingStoreRetention) { 34 TEST(IndexedDBDatabaseTest, BackingStoreRetention) {
33 scoped_refptr<IndexedDBFakeBackingStore> backing_store = 35 scoped_refptr<IndexedDBFakeBackingStore> backing_store =
34 new IndexedDBFakeBackingStore(); 36 new IndexedDBFakeBackingStore();
35 EXPECT_TRUE(backing_store->HasOneRef()); 37 EXPECT_TRUE(backing_store->HasOneRef());
36 38
37 IndexedDBFactory* factory = 0; 39 IndexedDBFactory* factory = 0;
(...skipping 26 matching lines...) Expand all
64 ASSERT_TRUE(s.ok()); 66 ASSERT_TRUE(s.ok());
65 EXPECT_FALSE(backing_store->HasOneRef()); // local and db 67 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
66 68
67 scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks()); 69 scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
68 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1( 70 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
69 new MockIndexedDBDatabaseCallbacks()); 71 new MockIndexedDBDatabaseCallbacks());
70 const int64 transaction_id1 = 1; 72 const int64 transaction_id1 = 1;
71 IndexedDBPendingConnection connection1( 73 IndexedDBPendingConnection connection1(
72 request1, 74 request1,
73 callbacks1, 75 callbacks1,
74 FAKE_CHILD_PROCESS_ID, 76 kFakeChildProcessId,
75 transaction_id1, 77 transaction_id1,
76 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION); 78 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
77 db->OpenConnection(connection1); 79 db->OpenConnection(connection1);
78 80
79 EXPECT_FALSE(backing_store->HasOneRef()); // db, connection count > 0 81 EXPECT_FALSE(backing_store->HasOneRef()); // db, connection count > 0
80 82
81 scoped_refptr<MockIndexedDBCallbacks> request2(new MockIndexedDBCallbacks()); 83 scoped_refptr<MockIndexedDBCallbacks> request2(new MockIndexedDBCallbacks());
82 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks2( 84 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks2(
83 new MockIndexedDBDatabaseCallbacks()); 85 new MockIndexedDBDatabaseCallbacks());
84 const int64 transaction_id2 = 2; 86 const int64 transaction_id2 = 2;
85 IndexedDBPendingConnection connection2( 87 IndexedDBPendingConnection connection2(
86 request2, 88 request2,
87 callbacks2, 89 callbacks2,
88 FAKE_CHILD_PROCESS_ID, 90 kFakeChildProcessId,
89 transaction_id2, 91 transaction_id2,
90 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION); 92 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
91 db->OpenConnection(connection2); 93 db->OpenConnection(connection2);
92 94
93 EXPECT_FALSE(backing_store->HasOneRef()); // local and connection 95 EXPECT_FALSE(backing_store->HasOneRef()); // local and connection
94 96
95 request1->connection()->ForceClose(); 97 request1->connection()->ForceClose();
96 EXPECT_FALSE(request1->connection()->IsConnected()); 98 EXPECT_FALSE(request1->connection()->IsConnected());
97 99
98 EXPECT_FALSE(backing_store->HasOneRef()); // local and connection 100 EXPECT_FALSE(backing_store->HasOneRef()); // local and connection
(...skipping 23 matching lines...) Expand all
122 ASSERT_TRUE(s.ok()); 124 ASSERT_TRUE(s.ok());
123 EXPECT_FALSE(backing_store->HasOneRef()); // local and db 125 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
124 126
125 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks( 127 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks(
126 new MockIndexedDBDatabaseCallbacks()); 128 new MockIndexedDBDatabaseCallbacks());
127 scoped_refptr<MockIndexedDBCallbacks> request(new MockIndexedDBCallbacks()); 129 scoped_refptr<MockIndexedDBCallbacks> request(new MockIndexedDBCallbacks());
128 const int64 upgrade_transaction_id = 3; 130 const int64 upgrade_transaction_id = 3;
129 IndexedDBPendingConnection connection( 131 IndexedDBPendingConnection connection(
130 request, 132 request,
131 callbacks, 133 callbacks,
132 FAKE_CHILD_PROCESS_ID, 134 kFakeChildProcessId,
133 upgrade_transaction_id, 135 upgrade_transaction_id,
134 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION); 136 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
135 database->OpenConnection(connection); 137 database->OpenConnection(connection);
136 EXPECT_EQ(database, request->connection()->database()); 138 EXPECT_EQ(database, request->connection()->database());
137 139
138 const int64 transaction_id = 123; 140 const int64 transaction_id = 123;
139 const std::vector<int64> scope; 141 const std::vector<int64> scope;
140 database->CreateTransaction(transaction_id, 142 database->CreateTransaction(transaction_id,
141 request->connection(), 143 request->connection(),
142 scope, 144 scope,
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 ASSERT_TRUE(s.ok()); 188 ASSERT_TRUE(s.ok());
187 EXPECT_FALSE(backing_store->HasOneRef()); // local and db 189 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
188 190
189 scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks()); 191 scoped_refptr<MockIndexedDBCallbacks> request1(new MockIndexedDBCallbacks());
190 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1( 192 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks1(
191 new MockIndexedDBDatabaseCallbacks()); 193 new MockIndexedDBDatabaseCallbacks());
192 const int64 transaction_id1 = 1; 194 const int64 transaction_id1 = 1;
193 IndexedDBPendingConnection connection( 195 IndexedDBPendingConnection connection(
194 request1, 196 request1,
195 callbacks1, 197 callbacks1,
196 FAKE_CHILD_PROCESS_ID, 198 kFakeChildProcessId,
197 transaction_id1, 199 transaction_id1,
198 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION); 200 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
199 db->OpenConnection(connection); 201 db->OpenConnection(connection);
200 202
201 EXPECT_FALSE(backing_store->HasOneRef()); // local and db 203 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
202 204
203 scoped_refptr<MockDeleteCallbacks> request2(new MockDeleteCallbacks()); 205 scoped_refptr<MockDeleteCallbacks> request2(new MockDeleteCallbacks());
204 db->DeleteDatabase(request2); 206 db->DeleteDatabase(request2);
205 207
206 EXPECT_TRUE(request2->blocked_called()); 208 EXPECT_TRUE(request2->blocked_called());
207 EXPECT_FALSE(backing_store->HasOneRef()); // local and db 209 EXPECT_FALSE(backing_store->HasOneRef()); // local and db
208 210
209 db->Close(request1->connection(), true /* forced */); 211 db->Close(request1->connection(), true /* forced */);
210 212
211 EXPECT_FALSE(db->backing_store()); 213 EXPECT_FALSE(db->backing_store());
212 EXPECT_TRUE(backing_store->HasOneRef()); // local 214 EXPECT_TRUE(backing_store->HasOneRef()); // local
213 EXPECT_TRUE(request2->success_called()); 215 EXPECT_TRUE(request2->success_called());
214 } 216 }
215 217
218 void DummyOperation(IndexedDBTransaction* transaction) {
219 }
220
221 class IndexedDBDatabaseOperationTest : public testing::Test {
222 public:
223 IndexedDBDatabaseOperationTest() : commit_success_(true) {}
224
225 virtual void SetUp() {
226 backing_store_ = new IndexedDBFakeBackingStore();
227 leveldb::Status s;
228 db_ = IndexedDBDatabase::Create(ASCIIToUTF16("db"),
229 backing_store_,
230 NULL /*factory*/,
231 IndexedDBDatabase::Identifier(),
232 &s);
233 ASSERT_TRUE(s.ok());
234
235 request_ = new MockIndexedDBCallbacks();
236 callbacks_ = new MockIndexedDBDatabaseCallbacks();
237 const int64 transaction_id = 1;
238 db_->OpenConnection(IndexedDBPendingConnection(
239 request_,
240 callbacks_,
241 kFakeChildProcessId,
242 transaction_id,
243 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION));
244 EXPECT_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
245 db_->metadata().int_version);
246
247 transaction_ = new IndexedDBTransaction(
248 transaction_id,
249 callbacks_,
250 std::set<int64>() /*scope*/,
251 indexed_db::TRANSACTION_VERSION_CHANGE,
252 db_,
253 new IndexedDBFakeBackingStore::FakeTransaction(commit_success_));
254 db_->TransactionCreated(transaction_);
255
256 // Add a dummy task which takes the place of the VersionChangeOperation
257 // which kicks off the upgrade. This ensures that the transaction has
258 // processed at least one task before the CreateObjectStore call.
259 transaction_->ScheduleTask(base::Bind(&DummyOperation));
260 }
261
262 void RunPostedTasks() { base::RunLoop().RunUntilIdle(); }
263
264 protected:
265 scoped_refptr<IndexedDBFakeBackingStore> backing_store_;
266 scoped_refptr<IndexedDBDatabase> db_;
267 scoped_refptr<MockIndexedDBCallbacks> request_;
268 scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks_;
269 scoped_refptr<IndexedDBTransaction> transaction_;
270
271 bool commit_success_;
272
273 private:
274 base::MessageLoop message_loop_;
275
276 DISALLOW_COPY_AND_ASSIGN(IndexedDBDatabaseOperationTest);
277 };
278
279 TEST_F(IndexedDBDatabaseOperationTest, CreateObjectStore) {
280 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
281 const int64 store_id = 1001;
282 db_->CreateObjectStore(transaction_->id(),
283 store_id,
284 ASCIIToUTF16("store"),
285 IndexedDBKeyPath(),
286 false /*auto_increment*/);
287 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
288 RunPostedTasks();
289 transaction_->Commit();
290 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
291 }
292
293 TEST_F(IndexedDBDatabaseOperationTest, CreateIndex) {
294 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
295 const int64 store_id = 1001;
296 db_->CreateObjectStore(transaction_->id(),
297 store_id,
298 ASCIIToUTF16("store"),
299 IndexedDBKeyPath(),
300 false /*auto_increment*/);
301 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
302 const int64 index_id = 2002;
303 db_->CreateIndex(transaction_->id(),
304 store_id,
305 index_id,
306 ASCIIToUTF16("index"),
307 IndexedDBKeyPath(),
308 false /*unique*/,
309 false /*multi_entry*/);
310 EXPECT_EQ(
311 1ULL,
312 db_->metadata().object_stores.find(store_id)->second.indexes.size());
313 RunPostedTasks();
314 transaction_->Commit();
315 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
316 EXPECT_EQ(
317 1ULL,
318 db_->metadata().object_stores.find(store_id)->second.indexes.size());
319 }
320
321 class IndexedDBDatabaseOperationAbortTest
322 : public IndexedDBDatabaseOperationTest {
323 public:
324 IndexedDBDatabaseOperationAbortTest() { commit_success_ = false; }
325 };
326
327 TEST_F(IndexedDBDatabaseOperationAbortTest, CreateObjectStore) {
328 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
329 const int64 store_id = 1001;
330 db_->CreateObjectStore(transaction_->id(),
331 store_id,
332 ASCIIToUTF16("store"),
333 IndexedDBKeyPath(),
334 false /*auto_increment*/);
335 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
336 RunPostedTasks();
337 transaction_->Commit();
338 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
339 }
340
341 TEST_F(IndexedDBDatabaseOperationAbortTest, CreateIndex) {
342 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
343 const int64 store_id = 1001;
344 db_->CreateObjectStore(transaction_->id(),
345 store_id,
346 ASCIIToUTF16("store"),
347 IndexedDBKeyPath(),
348 false /*auto_increment*/);
349 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
350 const int64 index_id = 2002;
351 db_->CreateIndex(transaction_->id(),
352 store_id,
353 index_id,
354 ASCIIToUTF16("index"),
355 IndexedDBKeyPath(),
356 false /*unique*/,
357 false /*multi_entry*/);
358 EXPECT_EQ(
359 1ULL,
360 db_->metadata().object_stores.find(store_id)->second.indexes.size());
361 RunPostedTasks();
362 transaction_->Commit();
363 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
364 }
365
366 TEST_F(IndexedDBDatabaseOperationTest, CreatePutDelete) {
367 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
368 const int64 store_id = 1001;
369
370 // Creation is synchronous.
371 db_->CreateObjectStore(transaction_->id(),
372 store_id,
373 ASCIIToUTF16("store"),
374 IndexedDBKeyPath(),
375 false /*auto_increment*/);
376 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
377
378
379 // Put is asynchronous
380 IndexedDBValue value("value1", std::vector<IndexedDBBlobInfo>());
381 ScopedVector<webkit_blob::BlobDataHandle> handles;
382 scoped_ptr<IndexedDBKey> key(new IndexedDBKey("key"));
383 std::vector<IndexedDBDatabase::IndexKeys> index_keys;
384 scoped_refptr<MockIndexedDBCallbacks> request(
385 new MockIndexedDBCallbacks(false));
386 db_->Put(transaction_->id(),
387 store_id,
388 &value,
389 &handles,
390 key.Pass(),
391 IndexedDBDatabase::ADD_ONLY,
392 request,
393 index_keys);
394
395 // Deletion is asynchronous.
396 db_->DeleteObjectStore(transaction_->id(),
397 store_id);
398 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
399
400 // This will execute the Put then Delete.
401 RunPostedTasks();
402 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
403 }
404
216 } // namespace content 405 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698