Index: content/browser/indexed_db/indexed_db_backing_store_unittest.cc |
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc |
index 396189e51955a6c5797e269eab41a35ab77809d8..f3442690d486f4892c8bbf1730e65d6045b3cc3d 100644 |
--- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc |
+++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc |
@@ -4,68 +4,477 @@ |
#include "content/browser/indexed_db/indexed_db_backing_store.h" |
+#include "base/callback.h" |
+#include "base/file_util.h" |
+#include "base/files/scoped_temp_dir.h" |
#include "base/logging.h" |
#include "base/strings/string16.h" |
#include "base/strings/utf_string_conversions.h" |
+#include "base/task_runner.h" |
+#include "base/test/test_simple_task_runner.h" |
+#include "content/browser/indexed_db/indexed_db_context_impl.h" |
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
+#include "content/browser/indexed_db/indexed_db_value.h" |
+#include "net/url_request/url_request_test_util.h" |
#include "testing/gtest/include/gtest/gtest.h" |
#include "third_party/WebKit/public/platform/WebIDBTypes.h" |
+#include "webkit/browser/blob/blob_data_handle.h" |
+#include "webkit/browser/quota/mock_special_storage_policy.h" |
+#include "webkit/browser/quota/special_storage_policy.h" |
namespace content { |
namespace { |
+class Comparator : public LevelDBComparator { |
+ public: |
+ virtual int Compare(const base::StringPiece& a, |
+ const base::StringPiece& b) const OVERRIDE { |
+ return content::Compare(a, b, false /*index_keys*/); |
+ } |
+ virtual const char* Name() const OVERRIDE { return "idb_cmp1"; } |
+}; |
+ |
+class DefaultLevelDBFactory : public LevelDBFactory { |
+ public: |
+ virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, |
+ const LevelDBComparator* comparator, |
+ scoped_ptr<LevelDBDatabase>* db, |
+ bool* is_disk_full) OVERRIDE { |
+ return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); |
+ } |
+ virtual bool DestroyLevelDB(const base::FilePath& file_name) OVERRIDE { |
+ return LevelDBDatabase::Destroy(file_name); |
+ } |
+}; |
+ |
+class TestableIndexedDBBackingStore : public IndexedDBBackingStore { |
+public: |
+ static scoped_refptr<TestableIndexedDBBackingStore> Open( |
+ IndexedDBFactory* indexed_db_factory, |
+ const GURL& origin_url, |
+ const base::FilePath& path_base, |
+ net::URLRequestContext* request_context, |
+ LevelDBFactory* leveldb_factory, |
+ base::TaskRunner* task_runner) { |
+ DCHECK(!path_base.empty()); |
+ |
+ scoped_ptr<LevelDBComparator> comparator(new Comparator()); |
+ |
+ if (!file_util::CreateDirectory(path_base)) |
+ return scoped_refptr<TestableIndexedDBBackingStore>(); |
+ |
+ const base::FilePath file_path = path_base.Append("test_db_path"); |
+ const base::FilePath blob_path = path_base.Append("test_blob_path"); |
+ |
+ scoped_ptr<LevelDBDatabase> db; |
+ bool is_disk_full = false; |
+ leveldb::Status status = leveldb_factory->OpenLevelDB( |
+ file_path, comparator.get(), &db, &is_disk_full); |
+ |
+ if (!db || !status.ok()) |
+ return scoped_refptr<TestableIndexedDBBackingStore>(); |
+ |
+ scoped_refptr<TestableIndexedDBBackingStore> backing_store( |
+ new TestableIndexedDBBackingStore(indexed_db_factory, origin_url, |
+ blob_path, request_context, db.Pass(), comparator.Pass(), |
+ task_runner)); |
+ |
+ if (!backing_store->SetUpMetadata()) |
+ return scoped_refptr<TestableIndexedDBBackingStore>(); |
+ |
+ return backing_store; |
+ } |
+ |
+ const std::vector<IndexedDBBackingStore::Transaction::WriteDescriptor>& |
+ writes() const { return writes_; } |
+ const std::vector<int64> removals() const { return removals_; } |
+ |
+protected: |
+ bool WriteBlobFile(int64 database_id, |
+ const Transaction::WriteDescriptor& descriptor, |
+ Transaction::ChainedBlobWriter* chained_blob_writer) |
+ OVERRIDE { |
+ if (KeyPrefix::IsValidDatabaseId(database_id_)) { |
+ if (database_id_ != database_id) { |
+ return false; |
+ } |
+ } else { |
+ database_id_ = database_id; |
+ } |
+ writes_.push_back(descriptor); |
+ task_runner()->PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ &Transaction::ChainedBlobWriter::ReportWriteCompletion, |
+ chained_blob_writer, true, 1)); |
+ return true; |
+ } |
+ |
+ bool RemoveBlobFile(int64 database_id, int64 key) OVERRIDE { |
+ if (database_id_ != database_id || |
+ !KeyPrefix::IsValidDatabaseId(database_id)) { |
+ return false; |
+ } |
+ removals_.push_back(key); |
+ return true; |
+ } |
+ |
+ // Timers don't play nicely with unit tests. |
+ void StartJournalCleaningTimer() OVERRIDE { |
+ CleanPrimaryJournalIgnoreReturn(); |
+ } |
+ |
+private: |
+ TestableIndexedDBBackingStore( |
+ IndexedDBFactory* indexed_db_factory, |
+ const GURL& origin_url, |
+ const base::FilePath& blob_path, |
+ net::URLRequestContext* request_context, |
+ scoped_ptr<LevelDBDatabase> db, |
+ scoped_ptr<LevelDBComparator> comparator, |
+ base::TaskRunner* task_runner) |
+ : IndexedDBBackingStore(indexed_db_factory, |
+ origin_url, |
+ blob_path, |
+ request_context, |
+ db.Pass(), |
+ comparator.Pass(), |
+ task_runner), |
+ database_id_(0) {} |
+ |
+ int64 database_id_; |
+ std::vector<Transaction::WriteDescriptor> writes_; |
+ std::vector<int64> removals_; |
+}; |
+ |
+class TestIDBFactory : public IndexedDBFactory { |
+ public: |
+ TestIDBFactory(IndexedDBContextImpl* idb_context) |
+ : IndexedDBFactory(idb_context) {} |
+ |
+ scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest( |
+ const GURL& origin, |
+ net::URLRequestContext* url_request_context, |
+ base::TaskRunner* task_runner) { |
+ blink::WebIDBDataLoss data_loss; |
+ std::string data_loss_reason; |
+ bool disk_full; |
+ scoped_refptr<IndexedDBBackingStore> backing_store = OpenBackingStore( |
+ origin, context()->data_path(), url_request_context, &data_loss, |
+ &data_loss_reason, &disk_full, task_runner); |
+ scoped_refptr<TestableIndexedDBBackingStore> testable_store = |
+ static_cast<TestableIndexedDBBackingStore*>(backing_store.get()); |
+ return testable_store; |
+ } |
+ protected: |
+ scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper( |
+ const GURL& origin_url, |
+ const base::FilePath& data_directory, |
+ net::URLRequestContext* request_context, |
+ blink::WebIDBDataLoss* data_loss, |
+ std::string* data_loss_message, |
+ bool* disk_full, |
+ base::TaskRunner* task_runner, |
+ bool first_time) { |
+ DefaultLevelDBFactory leveldb_factory; |
+ return TestableIndexedDBBackingStore::Open(this, |
+ origin_url, |
+ data_directory, |
+ request_context, |
+ &leveldb_factory, |
+ task_runner); |
+ } |
+ |
+}; |
+ |
class IndexedDBBackingStoreTest : public testing::Test { |
public: |
IndexedDBBackingStoreTest() {} |
virtual void SetUp() { |
const GURL origin("http://localhost:81"); |
- backing_store_ = IndexedDBBackingStore::OpenInMemory(origin); |
+ task_runner_ = new base::TestSimpleTaskRunner(); |
+ special_storage_policy_ = new quota::MockSpecialStoragePolicy(); |
+ special_storage_policy_->SetAllUnlimited(true); |
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
+ idb_context_ = new IndexedDBContextImpl( |
+ temp_dir_.path(), special_storage_policy_, NULL, task_runner_); |
+ idb_factory_ = new TestIDBFactory(idb_context_); |
+ backing_store_ = idb_factory_->OpenBackingStoreForTest( |
+ origin, |
+ &url_request_context_, |
+ task_runner_.get()); |
// useful keys and values during tests |
- m_value1 = "value1"; |
- m_value2 = "value2"; |
- m_value3 = "value3"; |
+ m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>()); |
+ m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>()); |
+ |
+ m_blobInfo.push_back( |
+ IndexedDBBlobInfo("uuid 3", UTF8ToUTF16("blob type"), 1)); |
+ m_blobInfo.push_back( |
+ IndexedDBBlobInfo(base::FilePath(FILE_PATH_LITERAL("path/to/file")), |
+ UTF8ToUTF16("file name"), UTF8ToUTF16("file type"))); |
+ m_value3 = IndexedDBValue("value3", m_blobInfo); |
+ |
m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber); |
m_key2 = IndexedDBKey(ASCIIToUTF16("key2")); |
m_key3 = IndexedDBKey(ASCIIToUTF16("key3")); |
+ |
+ } |
+ |
+ // This just checks the data that survive getting stored and recalled, e.g. |
+ // the file path and UUID will change and thus aren't verified. |
+ bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const { |
+ if (m_blobInfo.size() != reads.size()) |
+ return false; |
+ for (size_t i = 0; i < m_blobInfo.size(); ++i) { |
+ const IndexedDBBlobInfo& a = m_blobInfo[i]; |
+ const IndexedDBBlobInfo& b = reads[i]; |
+ if (a.is_file() != b.is_file()) |
+ return false; |
+ if (a.type() != b.type()) |
+ return false; |
+ if (a.is_file()) { |
+ if (a.file_name() != b.file_name()) |
+ return false; |
+ } else { |
+ if (a.size() != b.size()) |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ bool CheckBlobReadsMatchWrites( |
+ const std::vector<IndexedDBBlobInfo>& reads) const { |
+ if (backing_store_->writes().size() != reads.size()) |
+ return false; |
+ std::set<int64> ids; |
+ for (size_t i = 0; i < backing_store_->writes().size(); ++i) |
+ ids.insert(backing_store_->writes()[i].key()); |
+ if (ids.size() != backing_store_->writes().size()) |
+ return false; |
+ for (size_t i = 0; i < reads.size(); ++i) |
+ if (ids.count(reads[i].key()) != 1) |
+ return false; |
+ return true; |
+ } |
+ |
+ bool CheckBlobWrites() const { |
+ if (backing_store_->writes().size() != m_blobInfo.size()) |
+ return false; |
+ for (size_t i = 0; i < backing_store_->writes().size(); ++i) { |
+ const IndexedDBBackingStore::Transaction::WriteDescriptor& desc = |
+ backing_store_->writes()[i]; |
+ const IndexedDBBlobInfo& info = m_blobInfo[i]; |
+ if (desc.is_file() != info.is_file()) |
+ return false; |
+ if (desc.is_file()) { |
+ if (desc.file_path() != info.file_path()) |
+ return false; |
+ } else { |
+ if (desc.url() != GURL("blob:uuid/" + info.uuid())) |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ bool CheckBlobRemovals() const { |
+ if (backing_store_->removals().size() != backing_store_->writes().size()) |
+ return false; |
+ for (size_t i = 0; i < backing_store_->writes().size(); ++i) |
+ if (backing_store_->writes()[i].key() != backing_store_->removals()[i]) |
+ return false; |
+ return true; |
} |
protected: |
- scoped_refptr<IndexedDBBackingStore> backing_store_; |
+ base::ScopedTempDir temp_dir_; |
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
+ scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy_; |
+ scoped_refptr<IndexedDBContextImpl> idb_context_; |
+ scoped_refptr<TestIDBFactory> idb_factory_; |
+ net::TestURLRequestContext url_request_context_; |
+ |
+ scoped_refptr<TestableIndexedDBBackingStore> backing_store_; |
// Sample keys and values that are consistent. |
IndexedDBKey m_key1; |
IndexedDBKey m_key2; |
IndexedDBKey m_key3; |
- std::string m_value1; |
- std::string m_value2; |
- std::string m_value3; |
+ IndexedDBValue m_value1; |
+ IndexedDBValue m_value2; |
+ IndexedDBValue m_value3; |
+ std::vector<IndexedDBBlobInfo> m_blobInfo; |
private: |
DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest); |
}; |
+class TestCallback : public IndexedDBBackingStore::BlobWriteCallback { |
+ public: |
+ TestCallback() |
+ : called(false), |
+ succeeded(false) { |
+ } |
+ virtual ~TestCallback() { |
+ } |
+ virtual void didSucceed() { |
+ called = true; |
+ succeeded = true; |
+ } |
+ virtual void didFail() { |
+ called = true; |
+ succeeded = false; |
+ } |
+ bool called; |
+ bool succeeded; |
+}; |
+ |
+ |
TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) { |
{ |
IndexedDBBackingStore::Transaction transaction1(backing_store_); |
transaction1.Begin(); |
+ ScopedVector<webkit_blob::BlobDataHandle> handles; |
IndexedDBBackingStore::RecordIdentifier record; |
bool ok = backing_store_->PutRecord( |
- &transaction1, 1, 1, m_key1, m_value1, &record); |
+ &transaction1, 1, 1, m_key1, m_value1, &handles, &record); |
EXPECT_TRUE(ok); |
- transaction1.Commit(); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ EXPECT_TRUE(transaction1.CommitPhaseOne(callback)); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction1.CommitPhaseTwo()); |
} |
{ |
IndexedDBBackingStore::Transaction transaction2(backing_store_); |
transaction2.Begin(); |
- std::string result_value; |
+ IndexedDBValue result_value; |
bool ok = |
backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value); |
- transaction2.Commit(); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ EXPECT_TRUE(transaction2.CommitPhaseOne(callback)); |
+ EXPECT_TRUE(ok); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction2.CommitPhaseTwo()); |
+ EXPECT_EQ(m_value1.bits, result_value.bits); |
+ } |
+} |
+ |
+TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) { |
+ { |
+ IndexedDBBackingStore::Transaction transaction1(backing_store_); |
+ transaction1.Begin(); |
+ ScopedVector<webkit_blob::BlobDataHandle> handles; |
+ IndexedDBBackingStore::RecordIdentifier record; |
+ bool ok = backing_store_->PutRecord( |
+ &transaction1, 1, 1, m_key3, m_value3, &handles, &record); |
+ EXPECT_TRUE(ok); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ EXPECT_TRUE(transaction1.CommitPhaseOne(callback)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_TRUE(CheckBlobWrites()); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction1.CommitPhaseTwo()); |
+ } |
+ |
+ { |
+ IndexedDBBackingStore::Transaction transaction2(backing_store_); |
+ transaction2.Begin(); |
+ IndexedDBValue result_value; |
+ bool ok = |
+ backing_store_->GetRecord(&transaction2, 1, 1, m_key3, &result_value); |
+ EXPECT_TRUE(ok); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ EXPECT_TRUE(transaction2.CommitPhaseOne(callback)); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction2.CommitPhaseTwo()); |
+ EXPECT_EQ(m_value3.bits, result_value.bits); |
+ EXPECT_TRUE(CheckBlobInfoMatches(result_value.blob_info)); |
+ EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value.blob_info)); |
+ } |
+ |
+ { |
+ IndexedDBBackingStore::Transaction transaction3(backing_store_); |
+ transaction3.Begin(); |
+ IndexedDBValue result_value; |
+ bool ok = backing_store_->DeleteRange( |
+ &transaction3, 1, 1, IndexedDBKeyRange(m_key3)); |
+ EXPECT_TRUE(ok); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ EXPECT_TRUE(transaction3.CommitPhaseOne(callback)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction3.CommitPhaseTwo()); |
+ EXPECT_TRUE(CheckBlobRemovals()); |
+ } |
+} |
+ |
+TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) { |
+ { |
+ IndexedDBBackingStore::Transaction transaction1(backing_store_); |
+ transaction1.Begin(); |
+ ScopedVector<webkit_blob::BlobDataHandle> handles; |
+ IndexedDBBackingStore::RecordIdentifier record; |
+ bool ok = backing_store_->PutRecord( |
+ &transaction1, 1, 1, m_key3, m_value3, &handles, &record); |
+ EXPECT_TRUE(ok); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ EXPECT_TRUE(transaction1.CommitPhaseOne(callback)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_TRUE(CheckBlobWrites()); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction1.CommitPhaseTwo()); |
+ } |
+ |
+ IndexedDBValue read_result_value; |
+ { |
+ IndexedDBBackingStore::Transaction transaction2(backing_store_); |
+ transaction2.Begin(); |
+ bool ok = backing_store_->GetRecord( |
+ &transaction2, 1, 1, m_key3, &read_result_value); |
+ EXPECT_TRUE(ok); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ EXPECT_TRUE(transaction2.CommitPhaseOne(callback)); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction2.CommitPhaseTwo()); |
+ EXPECT_EQ(m_value3.bits, read_result_value.bits); |
+ EXPECT_TRUE(CheckBlobInfoMatches(read_result_value.blob_info)); |
+ EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value.blob_info)); |
+ for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) { |
+ read_result_value.blob_info[i].mark_used_callback().Run(); |
+ } |
+ } |
+ |
+ { |
+ IndexedDBBackingStore::Transaction transaction3(backing_store_); |
+ transaction3.Begin(); |
+ bool ok = backing_store_->DeleteRange( |
+ &transaction3, 1, 1, IndexedDBKeyRange(m_key3)); |
EXPECT_TRUE(ok); |
- EXPECT_EQ(m_value1, result_value); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ EXPECT_TRUE(transaction3.CommitPhaseOne(callback)); |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction3.CommitPhaseTwo()); |
+ EXPECT_EQ(0U, backing_store_->removals().size()); |
+ for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) { |
+ read_result_value.blob_info[i].release_callback().Run( |
+ read_result_value.blob_info[i].file_path()); |
+ } |
+ task_runner_->RunUntilIdle(); |
+ EXPECT_NE(0U, backing_store_->removals().size()); |
+ EXPECT_TRUE(CheckBlobRemovals()); |
} |
} |
@@ -85,12 +494,14 @@ TEST_F(IndexedDBBackingStoreTest, HighIds) { |
{ |
IndexedDBBackingStore::Transaction transaction1(backing_store_); |
transaction1.Begin(); |
+ ScopedVector<webkit_blob::BlobDataHandle> handles; |
IndexedDBBackingStore::RecordIdentifier record; |
bool ok = backing_store_->PutRecord(&transaction1, |
high_database_id, |
high_object_store_id, |
m_key1, |
m_value1, |
+ &handles, |
&record); |
EXPECT_TRUE(ok); |
@@ -110,21 +521,25 @@ TEST_F(IndexedDBBackingStoreTest, HighIds) { |
record); |
EXPECT_TRUE(ok); |
- ok = transaction1.Commit(); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ ok = transaction1.CommitPhaseOne(callback); |
EXPECT_TRUE(ok); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction1.CommitPhaseTwo()); |
} |
{ |
IndexedDBBackingStore::Transaction transaction2(backing_store_); |
transaction2.Begin(); |
- std::string result_value; |
+ IndexedDBValue result_value; |
bool ok = backing_store_->GetRecord(&transaction2, |
high_database_id, |
high_object_store_id, |
m_key1, |
&result_value); |
EXPECT_TRUE(ok); |
- EXPECT_EQ(m_value1, result_value); |
+ EXPECT_EQ(m_value1.bits, result_value.bits); |
scoped_ptr<IndexedDBKey> new_primary_key; |
ok = backing_store_->GetPrimaryKeyViaIndex(&transaction2, |
@@ -144,8 +559,12 @@ TEST_F(IndexedDBBackingStoreTest, HighIds) { |
EXPECT_TRUE(ok); |
EXPECT_TRUE(new_primary_key->IsEqual(m_key1)); |
- ok = transaction2.Commit(); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ ok = transaction2.CommitPhaseOne(callback); |
EXPECT_TRUE(ok); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction2.CommitPhaseTwo()); |
} |
} |
@@ -157,31 +576,34 @@ TEST_F(IndexedDBBackingStoreTest, InvalidIds) { |
const int64 index_id = kMinimumIndexId; |
const int64 invalid_low_index_id = 19; // index_ids must be > kMinimumIndexId |
- std::string result_value; |
+ IndexedDBValue result_value; |
IndexedDBBackingStore::Transaction transaction1(backing_store_); |
transaction1.Begin(); |
+ ScopedVector<webkit_blob::BlobDataHandle> handles; |
IndexedDBBackingStore::RecordIdentifier record; |
bool ok = backing_store_->PutRecord(&transaction1, |
database_id, |
KeyPrefix::kInvalidId, |
m_key1, |
m_value1, |
+ &handles, |
&record); |
EXPECT_FALSE(ok); |
ok = backing_store_->PutRecord( |
- &transaction1, database_id, 0, m_key1, m_value1, &record); |
+ &transaction1, database_id, 0, m_key1, m_value1, &handles, &record); |
EXPECT_FALSE(ok); |
ok = backing_store_->PutRecord(&transaction1, |
KeyPrefix::kInvalidId, |
object_store_id, |
m_key1, |
m_value1, |
+ &handles, |
&record); |
EXPECT_FALSE(ok); |
ok = backing_store_->PutRecord( |
- &transaction1, 0, object_store_id, m_key1, m_value1, &record); |
+ &transaction1, 0, object_store_id, m_key1, m_value1, &handles, &record); |
EXPECT_FALSE(ok); |
ok = backing_store_->GetRecord( |
@@ -280,8 +702,12 @@ TEST_F(IndexedDBBackingStoreTest, CreateDatabase) { |
multi_entry); |
EXPECT_TRUE(ok); |
- ok = transaction.Commit(); |
+ scoped_refptr<TestCallback> callback(new TestCallback()); |
+ ok = transaction.CommitPhaseOne(callback); |
EXPECT_TRUE(ok); |
+ EXPECT_TRUE(callback->called); |
+ EXPECT_TRUE(callback->succeeded); |
+ EXPECT_TRUE(transaction.CommitPhaseTwo()); |
} |
{ |