Home | History | Annotate | Download | only in indexeddb
      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