1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "modules/indexeddb/IDBTransaction.h" 33 34 #include "core/dom/DOMError.h" 35 #include "core/dom/Document.h" 36 #include "modules/indexeddb/IDBDatabase.h" 37 #include "modules/indexeddb/IDBDatabaseCallbacks.h" 38 #include "modules/indexeddb/IDBPendingTransactionMonitor.h" 39 40 #include <gtest/gtest.h> 41 42 using namespace WebCore; 43 44 namespace { 45 46 class IDBTransactionTest : public testing::Test { 47 public: 48 IDBTransactionTest() 49 : m_handleScope(v8::Isolate::GetCurrent()) 50 , m_scope(v8::Context::New(v8::Isolate::GetCurrent())) 51 , m_document(Document::create()) 52 { 53 } 54 55 ScriptExecutionContext* scriptExecutionContext() 56 { 57 return m_document.get(); 58 } 59 60 private: 61 v8::HandleScope m_handleScope; 62 v8::Context::Scope m_scope; 63 RefPtr<Document> m_document; 64 }; 65 66 class FakeIDBDatabaseBackendProxy : public IDBDatabaseBackendInterface { 67 public: 68 static PassRefPtr<FakeIDBDatabaseBackendProxy> create() { return adoptRef(new FakeIDBDatabaseBackendProxy()); } 69 70 virtual void createObjectStore(int64_t transactionId, int64_t objectStoreId, const String& name, const IDBKeyPath&, bool autoIncrement) OVERRIDE { } 71 virtual void deleteObjectStore(int64_t transactionId, int64_t objectStoreId) OVERRIDE { } 72 virtual void createTransaction(int64_t transactionId, PassRefPtr<IDBDatabaseCallbacks>, const Vector<int64_t>& objectStoreIds, unsigned short mode) OVERRIDE { } 73 virtual void close(PassRefPtr<IDBDatabaseCallbacks>) OVERRIDE { } 74 75 virtual void commit(int64_t transactionId) OVERRIDE { } 76 virtual void abort(int64_t transactionId) OVERRIDE { } 77 78 virtual void createIndex(int64_t transactionId, int64_t objectStoreId, int64_t indexId, const String& name, const IDBKeyPath&, bool unique, bool multiEntry) OVERRIDE { } 79 virtual void deleteIndex(int64_t transactionId, int64_t objectStoreId, int64_t indexId) OVERRIDE { } 80 81 virtual void get(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange>, bool keyOnly, PassRefPtr<IDBCallbacks>) OVERRIDE { } 82 virtual void put(int64_t transactionId, int64_t objectStoreId, PassRefPtr<SharedBuffer> value, PassRefPtr<IDBKey>, PutMode, PassRefPtr<IDBCallbacks>, const Vector<int64_t>& indexIds, const Vector<IndexKeys>&) OVERRIDE { } 83 virtual void setIndexKeys(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKey>, const Vector<int64_t>& indexIds, const Vector<IndexKeys>&) OVERRIDE { } 84 virtual void setIndexesReady(int64_t transactionId, int64_t objectStoreId, const Vector<int64_t>& indexIds) OVERRIDE { } 85 virtual void openCursor(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange>, IndexedDB::CursorDirection, bool keyOnly, TaskType, PassRefPtr<IDBCallbacks>) OVERRIDE { } 86 virtual void count(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange>, PassRefPtr<IDBCallbacks>) OVERRIDE { } 87 virtual void deleteRange(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKeyRange>, PassRefPtr<IDBCallbacks>) OVERRIDE { } 88 virtual void clear(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBCallbacks>) OVERRIDE { } 89 90 private: 91 FakeIDBDatabaseBackendProxy() { } 92 }; 93 94 class FakeIDBDatabaseCallbacks : public IDBDatabaseCallbacks { 95 public: 96 static PassRefPtr<FakeIDBDatabaseCallbacks> create() { return adoptRef(new FakeIDBDatabaseCallbacks()); } 97 virtual void onVersionChange(int64_t oldVersion, int64_t newVersion) OVERRIDE { } 98 virtual void onForcedClose() OVERRIDE { } 99 virtual void onAbort(int64_t transactionId, PassRefPtr<DOMError> error) OVERRIDE { } 100 virtual void onComplete(int64_t transactionId) OVERRIDE { } 101 private: 102 FakeIDBDatabaseCallbacks() { } 103 }; 104 105 TEST_F(IDBTransactionTest, EnsureLifetime) 106 { 107 RefPtr<FakeIDBDatabaseBackendProxy> proxy = FakeIDBDatabaseBackendProxy::create(); 108 RefPtr<FakeIDBDatabaseCallbacks> connection = FakeIDBDatabaseCallbacks::create(); 109 RefPtr<IDBDatabase> db = IDBDatabase::create(scriptExecutionContext(), proxy, connection); 110 111 const int64_t transactionId = 1234; 112 const Vector<String> transactionScope; 113 RefPtr<IDBTransaction> transaction = IDBTransaction::create(scriptExecutionContext(), transactionId, transactionScope, IndexedDB::TransactionReadOnly, db.get()); 114 115 // Local reference, IDBDatabase's reference and IDBPendingTransactionMonitor's reference: 116 EXPECT_EQ(3, transaction->refCount()); 117 118 RefPtr<IDBRequest> request = IDBRequest::create(scriptExecutionContext(), IDBAny::createInvalid(), transaction.get()); 119 IDBPendingTransactionMonitor::deactivateNewTransactions(); 120 121 // Local reference, IDBDatabase's reference, and the IDBRequest's reference 122 EXPECT_EQ(3, transaction->refCount()); 123 124 // This will generate an abort() call to the back end which is dropped by the fake proxy, 125 // so an explicit onAbort call is made. 126 scriptExecutionContext()->stopActiveDOMObjects(); 127 transaction->onAbort(DOMError::create(AbortError, "Aborted")); 128 129 EXPECT_EQ(1, transaction->refCount()); 130 } 131 132 TEST_F(IDBTransactionTest, TransactionFinish) 133 { 134 RefPtr<FakeIDBDatabaseBackendProxy> proxy = FakeIDBDatabaseBackendProxy::create(); 135 RefPtr<FakeIDBDatabaseCallbacks> connection = FakeIDBDatabaseCallbacks::create(); 136 RefPtr<IDBDatabase> db = IDBDatabase::create(scriptExecutionContext(), proxy, connection); 137 138 const int64_t transactionId = 1234; 139 const Vector<String> transactionScope; 140 RefPtr<IDBTransaction> transaction = IDBTransaction::create(scriptExecutionContext(), transactionId, transactionScope, IndexedDB::TransactionReadOnly, db.get()); 141 142 // Local reference, IDBDatabase's reference and IDBPendingTransactionMonitor's reference: 143 EXPECT_EQ(3, transaction->refCount()); 144 145 IDBPendingTransactionMonitor::deactivateNewTransactions(); 146 147 // Local reference, IDBDatabase's reference 148 EXPECT_EQ(2, transaction->refCount()); 149 150 IDBTransaction* transactionPtr = transaction.get(); 151 transaction.clear(); 152 153 // IDBDatabase's reference 154 EXPECT_EQ(1, transactionPtr->refCount()); 155 156 // Stop the context, so events don't get queued (which would keep the transaction alive). 157 scriptExecutionContext()->stopActiveDOMObjects(); 158 159 // Fire an abort to make sure this doesn't free the transaction during use. The test 160 // will not fail if it is, but ASAN would notice the error. 161 db->onAbort(transactionId, DOMError::create(AbortError, "Aborted")); 162 } 163 164 } // namespace 165