OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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_backing_store.h" | 5 #include "content/browser/indexed_db/indexed_db_backing_store.h" |
6 | 6 |
7 #include "base/callback.h" | |
8 #include "base/file_util.h" | |
9 #include "base/files/scoped_temp_dir.h" | |
7 #include "base/logging.h" | 10 #include "base/logging.h" |
8 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
9 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
13 #include "base/task_runner.h" | |
14 #include "base/test/test_simple_task_runner.h" | |
15 #include "content/browser/indexed_db/indexed_db_context_impl.h" | |
10 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" | 16 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
11 #include "content/browser/indexed_db/indexed_db_value.h" | 17 #include "content/browser/indexed_db/indexed_db_value.h" |
18 #include "content/public/test/mock_special_storage_policy.h" | |
19 #include "net/url_request/url_request_test_util.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
13 #include "third_party/WebKit/public/platform/WebIDBTypes.h" | 21 #include "third_party/WebKit/public/platform/WebIDBTypes.h" |
22 #include "webkit/browser/blob/blob_data_handle.h" | |
23 #include "webkit/browser/quota/special_storage_policy.h" | |
14 | 24 |
15 using base::ASCIIToUTF16; | 25 using base::ASCIIToUTF16; |
16 | 26 |
17 namespace content { | 27 namespace content { |
18 | 28 |
19 namespace { | 29 namespace { |
20 | 30 |
31 class Comparator : public LevelDBComparator { | |
32 public: | |
33 virtual int Compare(const base::StringPiece& a, | |
34 const base::StringPiece& b) const OVERRIDE { | |
35 return content::Compare(a, b, false /*index_keys*/); | |
36 } | |
37 virtual const char* Name() const OVERRIDE { return "idb_cmp1"; } | |
38 }; | |
39 | |
40 class DefaultLevelDBFactory : public LevelDBFactory { | |
41 public: | |
42 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, | |
43 const LevelDBComparator* comparator, | |
44 scoped_ptr<LevelDBDatabase>* db, | |
45 bool* is_disk_full) OVERRIDE { | |
46 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); | |
47 } | |
48 virtual leveldb::Status DestroyLevelDB( | |
49 const base::FilePath& file_name) OVERRIDE { | |
50 return LevelDBDatabase::Destroy(file_name); | |
51 } | |
52 }; | |
53 | |
54 class TestableIndexedDBBackingStore : public IndexedDBBackingStore { | |
55 public: | |
56 static scoped_refptr<TestableIndexedDBBackingStore> Open( | |
57 IndexedDBFactory* indexed_db_factory, | |
58 const GURL& origin_url, | |
59 const base::FilePath& path_base, | |
60 net::URLRequestContext* request_context, | |
61 LevelDBFactory* leveldb_factory, | |
62 base::TaskRunner* task_runner) { | |
63 DCHECK(!path_base.empty()); | |
64 | |
65 scoped_ptr<LevelDBComparator> comparator(new Comparator()); | |
66 | |
67 if (!base::CreateDirectory(path_base)) | |
68 return scoped_refptr<TestableIndexedDBBackingStore>(); | |
69 | |
70 const base::FilePath file_path = path_base.AppendASCII("test_db_path"); | |
71 const base::FilePath blob_path = path_base.AppendASCII("test_blob_path"); | |
72 | |
73 scoped_ptr<LevelDBDatabase> db; | |
74 bool is_disk_full = false; | |
75 leveldb::Status status = leveldb_factory->OpenLevelDB( | |
76 file_path, comparator.get(), &db, &is_disk_full); | |
77 | |
78 if (!db || !status.ok()) | |
79 return scoped_refptr<TestableIndexedDBBackingStore>(); | |
80 | |
81 scoped_refptr<TestableIndexedDBBackingStore> backing_store( | |
82 new TestableIndexedDBBackingStore(indexed_db_factory, | |
83 origin_url, | |
84 blob_path, | |
85 request_context, | |
86 db.Pass(), | |
87 comparator.Pass(), | |
88 task_runner)); | |
89 | |
90 if (!backing_store->SetUpMetadata()) | |
91 return scoped_refptr<TestableIndexedDBBackingStore>(); | |
92 | |
93 return backing_store; | |
94 } | |
95 | |
96 const std::vector<IndexedDBBackingStore::Transaction::WriteDescriptor>& | |
97 writes() const { | |
98 return writes_; | |
99 } | |
100 void ClearWrites() { writes_.clear(); } | |
101 const std::vector<int64>& removals() const { return removals_; } | |
102 void ClearRemovals() { removals_.clear(); } | |
103 | |
104 protected: | |
105 virtual ~TestableIndexedDBBackingStore() {} | |
106 | |
107 virtual bool WriteBlobFile( | |
108 int64 database_id, | |
109 const Transaction::WriteDescriptor& descriptor, | |
110 Transaction::ChainedBlobWriter* chained_blob_writer) OVERRIDE { | |
111 if (KeyPrefix::IsValidDatabaseId(database_id_)) { | |
112 if (database_id_ != database_id) { | |
113 return false; | |
114 } | |
115 } else { | |
116 database_id_ = database_id; | |
117 } | |
118 writes_.push_back(descriptor); | |
119 task_runner()->PostTask( | |
120 FROM_HERE, | |
121 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion, | |
122 chained_blob_writer, | |
123 true, | |
124 1)); | |
125 return true; | |
126 } | |
127 | |
128 virtual bool RemoveBlobFile(int64 database_id, int64 key) OVERRIDE { | |
129 if (database_id_ != database_id || | |
130 !KeyPrefix::IsValidDatabaseId(database_id)) { | |
131 return false; | |
132 } | |
133 removals_.push_back(key); | |
134 return true; | |
135 } | |
136 | |
137 // Timers don't play nicely with unit tests. | |
138 virtual void StartJournalCleaningTimer() OVERRIDE { | |
139 CleanPrimaryJournalIgnoreReturn(); | |
140 } | |
141 | |
142 private: | |
143 TestableIndexedDBBackingStore(IndexedDBFactory* indexed_db_factory, | |
144 const GURL& origin_url, | |
145 const base::FilePath& blob_path, | |
146 net::URLRequestContext* request_context, | |
147 scoped_ptr<LevelDBDatabase> db, | |
148 scoped_ptr<LevelDBComparator> comparator, | |
149 base::TaskRunner* task_runner) | |
150 : IndexedDBBackingStore(indexed_db_factory, | |
151 origin_url, | |
152 blob_path, | |
153 request_context, | |
154 db.Pass(), | |
155 comparator.Pass(), | |
156 task_runner), | |
157 database_id_(0) {} | |
158 | |
159 int64 database_id_; | |
160 std::vector<Transaction::WriteDescriptor> writes_; | |
161 std::vector<int64> removals_; | |
162 }; | |
163 | |
164 class TestIDBFactory : public IndexedDBFactory { | |
165 public: | |
166 TestIDBFactory(IndexedDBContextImpl* idb_context) | |
167 : IndexedDBFactory(idb_context) {} | |
168 | |
169 scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest( | |
170 const GURL& origin, | |
171 net::URLRequestContext* url_request_context) { | |
172 blink::WebIDBDataLoss data_loss; | |
173 std::string data_loss_reason; | |
174 bool disk_full; | |
175 scoped_refptr<IndexedDBBackingStore> backing_store = | |
176 OpenBackingStore(origin, | |
177 context()->data_path(), | |
178 url_request_context, | |
179 &data_loss, | |
180 &data_loss_reason, | |
181 &disk_full); | |
182 scoped_refptr<TestableIndexedDBBackingStore> testable_store = | |
183 static_cast<TestableIndexedDBBackingStore*>(backing_store.get()); | |
184 return testable_store; | |
185 } | |
186 | |
187 protected: | |
188 virtual ~TestIDBFactory() {} | |
189 | |
190 virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper( | |
191 const GURL& origin_url, | |
192 const base::FilePath& data_directory, | |
193 net::URLRequestContext* request_context, | |
194 blink::WebIDBDataLoss* data_loss, | |
195 std::string* data_loss_message, | |
196 bool* disk_full, | |
197 bool first_time) OVERRIDE { | |
198 DefaultLevelDBFactory leveldb_factory; | |
199 return TestableIndexedDBBackingStore::Open(this, | |
200 origin_url, | |
201 data_directory, | |
202 request_context, | |
203 &leveldb_factory, | |
204 context()->TaskRunner()); | |
205 } | |
206 }; | |
207 | |
21 class IndexedDBBackingStoreTest : public testing::Test { | 208 class IndexedDBBackingStoreTest : public testing::Test { |
22 public: | 209 public: |
23 IndexedDBBackingStoreTest() {} | 210 IndexedDBBackingStoreTest() {} |
24 virtual void SetUp() { | 211 virtual void SetUp() { |
25 const GURL origin("http://localhost:81"); | 212 const GURL origin("http://localhost:81"); |
213 task_runner_ = new base::TestSimpleTaskRunner(); | |
214 special_storage_policy_ = new MockSpecialStoragePolicy(); | |
215 special_storage_policy_->SetAllUnlimited(true); | |
216 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
217 idb_context_ = new IndexedDBContextImpl( | |
218 temp_dir_.path(), special_storage_policy_, NULL, task_runner_); | |
219 idb_factory_ = new TestIDBFactory(idb_context_); | |
26 backing_store_ = | 220 backing_store_ = |
27 IndexedDBBackingStore::OpenInMemory(origin, NULL /* task_runner */); | 221 idb_factory_->OpenBackingStoreForTest(origin, &url_request_context_); |
28 | 222 |
29 // useful keys and values during tests | 223 // useful keys and values during tests |
30 m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>()); | 224 m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>()); |
31 m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>()); | 225 m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>()); |
32 | 226 |
227 m_blob_info.push_back( | |
228 IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1)); | |
229 m_blob_info.push_back( | |
230 IndexedDBBlobInfo("uuid 4", | |
231 base::FilePath(FILE_PATH_LITERAL("path/to/file")), | |
232 base::UTF8ToUTF16("file name"), | |
233 base::UTF8ToUTF16("file type"))); | |
234 m_value3 = IndexedDBValue("value3", m_blob_info); | |
235 | |
33 m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber); | 236 m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber); |
34 m_key2 = IndexedDBKey(ASCIIToUTF16("key2")); | 237 m_key2 = IndexedDBKey(ASCIIToUTF16("key2")); |
238 m_key3 = IndexedDBKey(ASCIIToUTF16("key3")); | |
239 } | |
240 | |
241 // This just checks the data that survive getting stored and recalled, e.g. | |
242 // the file path and UUID will change and thus aren't verified. | |
243 bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const { | |
244 if (m_blob_info.size() != reads.size()) | |
245 return false; | |
246 for (size_t i = 0; i < m_blob_info.size(); ++i) { | |
247 const IndexedDBBlobInfo& a = m_blob_info[i]; | |
248 const IndexedDBBlobInfo& b = reads[i]; | |
249 if (a.is_file() != b.is_file()) | |
jsbell
2014/05/28 21:29:15
Maybe add IndexedDBBlobInfo::Compare ?
ericu
2014/05/28 22:50:42
It's not clear to me that there's a general-purpos
jsbell
2014/05/28 23:35:18
I'm fine with leaving this inline, since some fiel
| |
250 return false; | |
251 if (a.type() != b.type()) | |
252 return false; | |
253 if (a.is_file()) { | |
254 if (a.file_name() != b.file_name()) | |
cmumford
2014/05/28 20:34:54
Do you also need to check last_modified?
ericu
2014/05/28 22:50:42
That can change too, for files, since we may not k
| |
255 return false; | |
256 } else { | |
257 if (a.size() != b.size()) | |
258 return false; | |
259 } | |
260 } | |
261 return true; | |
262 } | |
263 | |
264 bool CheckBlobReadsMatchWrites( | |
265 const std::vector<IndexedDBBlobInfo>& reads) const { | |
266 if (backing_store_->writes().size() != reads.size()) | |
267 return false; | |
268 std::set<int64> ids; | |
269 for (size_t i = 0; i < backing_store_->writes().size(); ++i) | |
270 ids.insert(backing_store_->writes()[i].key()); | |
271 if (ids.size() != backing_store_->writes().size()) | |
272 return false; | |
273 for (size_t i = 0; i < reads.size(); ++i) { | |
274 if (ids.count(reads[i].key()) != 1) | |
275 return false; | |
276 } | |
277 return true; | |
278 } | |
279 | |
280 bool CheckBlobWrites() const { | |
281 if (backing_store_->writes().size() != m_blob_info.size()) | |
282 return false; | |
283 for (size_t i = 0; i < backing_store_->writes().size(); ++i) { | |
284 const IndexedDBBackingStore::Transaction::WriteDescriptor& desc = | |
285 backing_store_->writes()[i]; | |
286 const IndexedDBBlobInfo& info = m_blob_info[i]; | |
287 if (desc.is_file() != info.is_file()) | |
288 return false; | |
289 if (desc.is_file()) { | |
290 if (desc.file_path() != info.file_path()) | |
291 return false; | |
292 } else { | |
293 if (desc.url() != GURL("blob:uuid/" + info.uuid())) | |
294 return false; | |
295 } | |
296 } | |
297 return true; | |
298 } | |
299 | |
300 bool CheckBlobRemovals() const { | |
301 if (backing_store_->removals().size() != backing_store_->writes().size()) | |
302 return false; | |
303 for (size_t i = 0; i < backing_store_->writes().size(); ++i) | |
jsbell
2014/05/28 21:29:15
Nit: Needs {}
ericu
2014/05/28 22:50:42
Done.
| |
304 if (backing_store_->writes()[i].key() != backing_store_->removals()[i]) | |
305 return false; | |
306 return true; | |
35 } | 307 } |
36 | 308 |
37 protected: | 309 protected: |
38 scoped_refptr<IndexedDBBackingStore> backing_store_; | 310 base::ScopedTempDir temp_dir_; |
311 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; | |
312 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_; | |
313 scoped_refptr<IndexedDBContextImpl> idb_context_; | |
314 scoped_refptr<TestIDBFactory> idb_factory_; | |
315 net::TestURLRequestContext url_request_context_; | |
316 | |
317 scoped_refptr<TestableIndexedDBBackingStore> backing_store_; | |
39 | 318 |
40 // Sample keys and values that are consistent. | 319 // Sample keys and values that are consistent. |
41 IndexedDBKey m_key1; | 320 IndexedDBKey m_key1; |
42 IndexedDBKey m_key2; | 321 IndexedDBKey m_key2; |
322 IndexedDBKey m_key3; | |
43 IndexedDBValue m_value1; | 323 IndexedDBValue m_value1; |
44 IndexedDBValue m_value2; | 324 IndexedDBValue m_value2; |
325 IndexedDBValue m_value3; | |
326 std::vector<IndexedDBBlobInfo> m_blob_info; | |
45 | 327 |
46 private: | 328 private: |
47 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest); | 329 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest); |
48 }; | 330 }; |
49 | 331 |
332 class TestCallback : public IndexedDBBackingStore::BlobWriteCallback { | |
333 public: | |
334 TestCallback() : called(false), succeeded(false) {} | |
335 virtual void Run(bool succeeded_in) OVERRIDE { | |
336 called = true; | |
337 succeeded = succeeded_in; | |
338 } | |
339 bool called; | |
340 bool succeeded; | |
341 | |
342 protected: | |
343 virtual ~TestCallback() {} | |
344 }; | |
345 | |
50 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) { | 346 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) { |
51 { | 347 { |
52 IndexedDBBackingStore::Transaction transaction1(backing_store_); | 348 IndexedDBBackingStore::Transaction transaction1(backing_store_); |
53 transaction1.Begin(); | 349 transaction1.Begin(); |
54 ScopedVector<webkit_blob::BlobDataHandle> handles; | 350 ScopedVector<webkit_blob::BlobDataHandle> handles; |
55 IndexedDBBackingStore::RecordIdentifier record; | 351 IndexedDBBackingStore::RecordIdentifier record; |
56 leveldb::Status s = backing_store_->PutRecord( | 352 leveldb::Status s = backing_store_->PutRecord( |
57 &transaction1, 1, 1, m_key1, m_value1, &handles, &record); | 353 &transaction1, 1, 1, m_key1, m_value1, &handles, &record); |
58 EXPECT_TRUE(s.ok()); | 354 EXPECT_TRUE(s.ok()); |
59 transaction1.Commit(); | 355 scoped_refptr<TestCallback> callback(new TestCallback()); |
356 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); | |
357 EXPECT_TRUE(callback->called); | |
358 EXPECT_TRUE(callback->succeeded); | |
359 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); | |
60 } | 360 } |
61 | 361 |
62 { | 362 { |
63 IndexedDBBackingStore::Transaction transaction2(backing_store_); | 363 IndexedDBBackingStore::Transaction transaction2(backing_store_); |
64 transaction2.Begin(); | 364 transaction2.Begin(); |
65 IndexedDBValue result_value; | 365 IndexedDBValue result_value; |
66 leveldb::Status s = | 366 EXPECT_TRUE( |
67 backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value); | 367 backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value) |
68 transaction2.Commit(); | 368 .ok()); |
69 EXPECT_TRUE(s.ok()); | 369 scoped_refptr<TestCallback> callback(new TestCallback()); |
370 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); | |
371 EXPECT_TRUE(callback->called); | |
372 EXPECT_TRUE(callback->succeeded); | |
373 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); | |
70 EXPECT_EQ(m_value1.bits, result_value.bits); | 374 EXPECT_EQ(m_value1.bits, result_value.bits); |
71 } | 375 } |
72 } | 376 } |
73 | 377 |
378 TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) { | |
379 { | |
380 IndexedDBBackingStore::Transaction transaction1(backing_store_); | |
381 transaction1.Begin(); | |
382 ScopedVector<webkit_blob::BlobDataHandle> handles; | |
383 IndexedDBBackingStore::RecordIdentifier record; | |
384 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
385 1, | |
386 1, | |
387 m_key3, | |
388 m_value3, | |
389 &handles, | |
390 &record).ok()); | |
391 scoped_refptr<TestCallback> callback(new TestCallback()); | |
392 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); | |
393 task_runner_->RunUntilIdle(); | |
394 EXPECT_TRUE(CheckBlobWrites()); | |
395 EXPECT_TRUE(callback->called); | |
396 EXPECT_TRUE(callback->succeeded); | |
397 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); | |
398 } | |
399 | |
400 { | |
401 IndexedDBBackingStore::Transaction transaction2(backing_store_); | |
402 transaction2.Begin(); | |
403 IndexedDBValue result_value; | |
404 EXPECT_TRUE( | |
405 backing_store_->GetRecord(&transaction2, 1, 1, m_key3, &result_value) | |
406 .ok()); | |
407 scoped_refptr<TestCallback> callback(new TestCallback()); | |
408 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); | |
409 EXPECT_TRUE(callback->called); | |
410 EXPECT_TRUE(callback->succeeded); | |
411 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); | |
412 EXPECT_EQ(m_value3.bits, result_value.bits); | |
413 EXPECT_TRUE(CheckBlobInfoMatches(result_value.blob_info)); | |
414 EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value.blob_info)); | |
415 } | |
416 | |
417 { | |
418 IndexedDBBackingStore::Transaction transaction3(backing_store_); | |
419 transaction3.Begin(); | |
420 IndexedDBValue result_value; | |
421 EXPECT_TRUE(backing_store_->DeleteRange(&transaction3, | |
422 1, | |
423 1, | |
424 IndexedDBKeyRange(m_key3)).ok()); | |
425 scoped_refptr<TestCallback> callback(new TestCallback()); | |
426 EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok()); | |
427 task_runner_->RunUntilIdle(); | |
428 EXPECT_TRUE(callback->called); | |
429 EXPECT_TRUE(callback->succeeded); | |
430 EXPECT_TRUE(transaction3.CommitPhaseTwo().ok()); | |
431 EXPECT_TRUE(CheckBlobRemovals()); | |
432 } | |
433 } | |
434 | |
435 TEST_F(IndexedDBBackingStoreTest, DeleteRange) { | |
436 IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0")); | |
437 IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1")); | |
438 IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2")); | |
439 IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3")); | |
440 IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1); | |
441 IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1); | |
442 IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1); | |
443 IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1); | |
444 IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key1, key2, false, false), | |
445 IndexedDBKeyRange(key1, key2, false, false), | |
446 IndexedDBKeyRange(key0, key2, true, false), | |
447 IndexedDBKeyRange(key1, key3, false, true), | |
448 IndexedDBKeyRange(key0, key3, true, true)}; | |
449 | |
450 for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) { | |
451 backing_store_->ClearWrites(); | |
452 backing_store_->ClearRemovals(); | |
453 | |
454 { | |
455 std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2, | |
456 blob_info3; | |
457 blob_info0.push_back(blob0); | |
458 blob_info1.push_back(blob1); | |
459 blob_info2.push_back(blob2); | |
460 blob_info3.push_back(blob3); | |
461 IndexedDBValue value0 = IndexedDBValue("value0", blob_info0); | |
462 IndexedDBValue value1 = IndexedDBValue("value1", blob_info1); | |
463 IndexedDBValue value2 = IndexedDBValue("value2", blob_info2); | |
464 IndexedDBValue value3 = IndexedDBValue("value3", blob_info3); | |
465 IndexedDBBackingStore::Transaction transaction1(backing_store_); | |
466 transaction1.Begin(); | |
467 ScopedVector<webkit_blob::BlobDataHandle> handles; | |
468 IndexedDBBackingStore::RecordIdentifier record; | |
469 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
470 1, | |
471 i + 1, | |
472 key0, | |
473 value0, | |
474 &handles, | |
475 &record).ok()); | |
476 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
477 1, | |
478 i + 1, | |
479 key1, | |
480 value1, | |
481 &handles, | |
482 &record).ok()); | |
483 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
484 1, | |
485 i + 1, | |
486 key2, | |
487 value2, | |
488 &handles, | |
489 &record).ok()); | |
490 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
491 1, | |
492 i + 1, | |
493 key3, | |
494 value3, | |
495 &handles, | |
496 &record).ok()); | |
497 scoped_refptr<TestCallback> callback(new TestCallback()); | |
498 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); | |
499 task_runner_->RunUntilIdle(); | |
500 EXPECT_TRUE(callback->called); | |
501 EXPECT_TRUE(callback->succeeded); | |
502 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); | |
503 } | |
504 | |
505 { | |
506 IndexedDBBackingStore::Transaction transaction2(backing_store_); | |
507 transaction2.Begin(); | |
508 IndexedDBValue result_value; | |
509 EXPECT_TRUE( | |
510 backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok()); | |
511 scoped_refptr<TestCallback> callback(new TestCallback()); | |
512 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); | |
513 task_runner_->RunUntilIdle(); | |
514 EXPECT_TRUE(callback->called); | |
515 EXPECT_TRUE(callback->succeeded); | |
516 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); | |
517 EXPECT_EQ(2UL, backing_store_->removals().size()); | |
518 EXPECT_EQ(backing_store_->writes()[1].key(), | |
519 backing_store_->removals()[0]); | |
520 EXPECT_EQ(backing_store_->writes()[2].key(), | |
521 backing_store_->removals()[1]); | |
522 } | |
523 } | |
524 } | |
525 | |
526 TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) { | |
527 IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0")); | |
528 IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1")); | |
529 IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2")); | |
530 IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3")); | |
531 IndexedDBKey key4 = IndexedDBKey(ASCIIToUTF16("key4")); | |
532 IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1); | |
533 IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1); | |
534 IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1); | |
535 IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1); | |
536 IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key3, key4, true, false), | |
537 IndexedDBKeyRange(key2, key1, false, false), | |
538 IndexedDBKeyRange(key2, key1, true, true)}; | |
539 | |
540 for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) { | |
cmumford
2014/05/28 20:34:54
Nit: Why not just use "arraysize(ranges)"?
ericu
2014/05/28 22:50:42
Done. Thanks; I'd forgotten we had that.
| |
541 backing_store_->ClearWrites(); | |
542 backing_store_->ClearRemovals(); | |
543 | |
544 { | |
545 std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2, | |
546 blob_info3; | |
547 blob_info0.push_back(blob0); | |
548 blob_info1.push_back(blob1); | |
549 blob_info2.push_back(blob2); | |
550 blob_info3.push_back(blob3); | |
551 IndexedDBValue value0 = IndexedDBValue("value0", blob_info0); | |
552 IndexedDBValue value1 = IndexedDBValue("value1", blob_info1); | |
553 IndexedDBValue value2 = IndexedDBValue("value2", blob_info2); | |
554 IndexedDBValue value3 = IndexedDBValue("value3", blob_info3); | |
555 IndexedDBBackingStore::Transaction transaction1(backing_store_); | |
556 transaction1.Begin(); | |
557 ScopedVector<webkit_blob::BlobDataHandle> handles; | |
558 IndexedDBBackingStore::RecordIdentifier record; | |
559 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
560 1, | |
561 i + 1, | |
562 key0, | |
563 value0, | |
564 &handles, | |
565 &record).ok()); | |
566 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
567 1, | |
568 i + 1, | |
569 key1, | |
570 value1, | |
571 &handles, | |
572 &record).ok()); | |
573 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
574 1, | |
575 i + 1, | |
576 key2, | |
577 value2, | |
578 &handles, | |
579 &record).ok()); | |
580 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
581 1, | |
582 i + 1, | |
583 key3, | |
584 value3, | |
585 &handles, | |
586 &record).ok()); | |
587 scoped_refptr<TestCallback> callback(new TestCallback()); | |
588 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); | |
589 task_runner_->RunUntilIdle(); | |
590 EXPECT_TRUE(callback->called); | |
591 EXPECT_TRUE(callback->succeeded); | |
592 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); | |
593 } | |
594 | |
595 { | |
596 IndexedDBBackingStore::Transaction transaction2(backing_store_); | |
597 transaction2.Begin(); | |
598 IndexedDBValue result_value; | |
599 EXPECT_TRUE( | |
600 backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok()); | |
601 scoped_refptr<TestCallback> callback(new TestCallback()); | |
602 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); | |
603 task_runner_->RunUntilIdle(); | |
604 EXPECT_TRUE(callback->called); | |
605 EXPECT_TRUE(callback->succeeded); | |
606 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); | |
607 EXPECT_EQ(0UL, backing_store_->removals().size()); | |
608 } | |
609 } | |
610 } | |
611 | |
612 TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) { | |
613 { | |
614 IndexedDBBackingStore::Transaction transaction1(backing_store_); | |
615 transaction1.Begin(); | |
616 ScopedVector<webkit_blob::BlobDataHandle> handles; | |
617 IndexedDBBackingStore::RecordIdentifier record; | |
618 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, | |
619 1, | |
620 1, | |
621 m_key3, | |
622 m_value3, | |
623 &handles, | |
624 &record).ok()); | |
625 scoped_refptr<TestCallback> callback(new TestCallback()); | |
626 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); | |
627 task_runner_->RunUntilIdle(); | |
628 EXPECT_TRUE(CheckBlobWrites()); | |
629 EXPECT_TRUE(callback->called); | |
630 EXPECT_TRUE(callback->succeeded); | |
631 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); | |
632 } | |
633 | |
634 IndexedDBValue read_result_value; | |
635 { | |
636 IndexedDBBackingStore::Transaction transaction2(backing_store_); | |
637 transaction2.Begin(); | |
638 EXPECT_TRUE( | |
639 backing_store_->GetRecord( | |
640 &transaction2, 1, 1, m_key3, &read_result_value) | |
641 .ok()); | |
642 scoped_refptr<TestCallback> callback(new TestCallback()); | |
643 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); | |
644 EXPECT_TRUE(callback->called); | |
645 EXPECT_TRUE(callback->succeeded); | |
646 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); | |
647 EXPECT_EQ(m_value3.bits, read_result_value.bits); | |
648 EXPECT_TRUE(CheckBlobInfoMatches(read_result_value.blob_info)); | |
649 EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value.blob_info)); | |
650 for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) { | |
651 read_result_value.blob_info[i].mark_used_callback().Run(); | |
652 } | |
653 } | |
654 | |
655 { | |
656 IndexedDBBackingStore::Transaction transaction3(backing_store_); | |
657 transaction3.Begin(); | |
658 EXPECT_TRUE(backing_store_->DeleteRange(&transaction3, | |
659 1, | |
660 1, | |
661 IndexedDBKeyRange(m_key3)).ok()); | |
662 scoped_refptr<TestCallback> callback(new TestCallback()); | |
663 EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok()); | |
664 task_runner_->RunUntilIdle(); | |
665 EXPECT_TRUE(callback->called); | |
666 EXPECT_TRUE(callback->succeeded); | |
667 EXPECT_TRUE(transaction3.CommitPhaseTwo().ok()); | |
668 EXPECT_EQ(0U, backing_store_->removals().size()); | |
669 for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) { | |
670 read_result_value.blob_info[i].release_callback().Run( | |
671 read_result_value.blob_info[i].file_path()); | |
672 } | |
673 task_runner_->RunUntilIdle(); | |
674 EXPECT_NE(0U, backing_store_->removals().size()); | |
675 EXPECT_TRUE(CheckBlobRemovals()); | |
676 } | |
677 } | |
678 | |
74 // Make sure that using very high ( more than 32 bit ) values for database_id | 679 // Make sure that using very high ( more than 32 bit ) values for database_id |
75 // and object_store_id still work. | 680 // and object_store_id still work. |
76 TEST_F(IndexedDBBackingStoreTest, HighIds) { | 681 TEST_F(IndexedDBBackingStoreTest, HighIds) { |
77 const int64 high_database_id = 1ULL << 35; | 682 const int64 high_database_id = 1ULL << 35; |
78 const int64 high_object_store_id = 1ULL << 39; | 683 const int64 high_object_store_id = 1ULL << 39; |
79 // index_ids are capped at 32 bits for storage purposes. | 684 // index_ids are capped at 32 bits for storage purposes. |
80 const int64 high_index_id = 1ULL << 29; | 685 const int64 high_index_id = 1ULL << 29; |
81 | 686 |
82 const int64 invalid_high_index_id = 1ULL << 37; | 687 const int64 invalid_high_index_id = 1ULL << 37; |
83 | 688 |
(...skipping 23 matching lines...) Expand all Loading... | |
107 EXPECT_FALSE(s.ok()); | 712 EXPECT_FALSE(s.ok()); |
108 | 713 |
109 s = backing_store_->PutIndexDataForRecord(&transaction1, | 714 s = backing_store_->PutIndexDataForRecord(&transaction1, |
110 high_database_id, | 715 high_database_id, |
111 high_object_store_id, | 716 high_object_store_id, |
112 high_index_id, | 717 high_index_id, |
113 index_key, | 718 index_key, |
114 record); | 719 record); |
115 EXPECT_TRUE(s.ok()); | 720 EXPECT_TRUE(s.ok()); |
116 | 721 |
117 s = transaction1.Commit(); | 722 scoped_refptr<TestCallback> callback(new TestCallback()); |
723 s = transaction1.CommitPhaseOne(callback); | |
724 EXPECT_TRUE(s.ok()); | |
725 EXPECT_TRUE(callback->called); | |
726 EXPECT_TRUE(callback->succeeded); | |
727 s = transaction1.CommitPhaseTwo(); | |
118 EXPECT_TRUE(s.ok()); | 728 EXPECT_TRUE(s.ok()); |
119 } | 729 } |
120 | 730 |
121 { | 731 { |
122 IndexedDBBackingStore::Transaction transaction2(backing_store_); | 732 IndexedDBBackingStore::Transaction transaction2(backing_store_); |
123 transaction2.Begin(); | 733 transaction2.Begin(); |
124 IndexedDBValue result_value; | 734 IndexedDBValue result_value; |
125 leveldb::Status s = backing_store_->GetRecord(&transaction2, | 735 leveldb::Status s = backing_store_->GetRecord(&transaction2, |
126 high_database_id, | 736 high_database_id, |
127 high_object_store_id, | 737 high_object_store_id, |
(...skipping 13 matching lines...) Expand all Loading... | |
141 | 751 |
142 s = backing_store_->GetPrimaryKeyViaIndex(&transaction2, | 752 s = backing_store_->GetPrimaryKeyViaIndex(&transaction2, |
143 high_database_id, | 753 high_database_id, |
144 high_object_store_id, | 754 high_object_store_id, |
145 high_index_id, | 755 high_index_id, |
146 index_key, | 756 index_key, |
147 &new_primary_key); | 757 &new_primary_key); |
148 EXPECT_TRUE(s.ok()); | 758 EXPECT_TRUE(s.ok()); |
149 EXPECT_TRUE(new_primary_key->Equals(m_key1)); | 759 EXPECT_TRUE(new_primary_key->Equals(m_key1)); |
150 | 760 |
151 s = transaction2.Commit(); | 761 scoped_refptr<TestCallback> callback(new TestCallback()); |
762 s = transaction2.CommitPhaseOne(callback); | |
763 EXPECT_TRUE(s.ok()); | |
764 EXPECT_TRUE(callback->called); | |
765 EXPECT_TRUE(callback->succeeded); | |
766 s = transaction2.CommitPhaseTwo(); | |
152 EXPECT_TRUE(s.ok()); | 767 EXPECT_TRUE(s.ok()); |
153 } | 768 } |
154 } | 769 } |
155 | 770 |
156 // Make sure that other invalid ids do not crash. | 771 // Make sure that other invalid ids do not crash. |
157 TEST_F(IndexedDBBackingStoreTest, InvalidIds) { | 772 TEST_F(IndexedDBBackingStoreTest, InvalidIds) { |
158 // valid ids for use when testing invalid ids | 773 // valid ids for use when testing invalid ids |
159 const int64 database_id = 1; | 774 const int64 database_id = 1; |
160 const int64 object_store_id = 1; | 775 const int64 object_store_id = 1; |
161 const int64 index_id = kMinimumIndexId; | 776 const int64 index_id = kMinimumIndexId; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
280 s = backing_store_->CreateIndex(&transaction, | 895 s = backing_store_->CreateIndex(&transaction, |
281 database_id, | 896 database_id, |
282 object_store_id, | 897 object_store_id, |
283 index_id, | 898 index_id, |
284 index_name, | 899 index_name, |
285 index_key_path, | 900 index_key_path, |
286 unique, | 901 unique, |
287 multi_entry); | 902 multi_entry); |
288 EXPECT_TRUE(s.ok()); | 903 EXPECT_TRUE(s.ok()); |
289 | 904 |
290 s = transaction.Commit(); | 905 scoped_refptr<TestCallback> callback(new TestCallback()); |
906 s = transaction.CommitPhaseOne(callback); | |
907 EXPECT_TRUE(s.ok()); | |
908 EXPECT_TRUE(callback->called); | |
909 EXPECT_TRUE(callback->succeeded); | |
910 s = transaction.CommitPhaseTwo(); | |
291 EXPECT_TRUE(s.ok()); | 911 EXPECT_TRUE(s.ok()); |
292 } | 912 } |
293 | 913 |
294 { | 914 { |
295 IndexedDBDatabaseMetadata database; | 915 IndexedDBDatabaseMetadata database; |
296 bool found; | 916 bool found; |
297 leveldb::Status s = backing_store_->GetIDBDatabaseMetaData( | 917 leveldb::Status s = backing_store_->GetIDBDatabaseMetaData( |
298 database_name, &database, &found); | 918 database_name, &database, &found); |
299 EXPECT_TRUE(s.ok()); | 919 EXPECT_TRUE(s.ok()); |
300 EXPECT_TRUE(found); | 920 EXPECT_TRUE(found); |
(...skipping 18 matching lines...) Expand all Loading... | |
319 EXPECT_EQ(index_name, index.name); | 939 EXPECT_EQ(index_name, index.name); |
320 EXPECT_EQ(index_key_path, index.key_path); | 940 EXPECT_EQ(index_key_path, index.key_path); |
321 EXPECT_EQ(unique, index.unique); | 941 EXPECT_EQ(unique, index.unique); |
322 EXPECT_EQ(multi_entry, index.multi_entry); | 942 EXPECT_EQ(multi_entry, index.multi_entry); |
323 } | 943 } |
324 } | 944 } |
325 | 945 |
326 } // namespace | 946 } // namespace |
327 | 947 |
328 } // namespace content | 948 } // namespace content |
OLD | NEW |