1/*
2 * Copyright (C) 2012 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
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "modules/indexeddb/IDBRequest.h"
28
29#include "bindings/core/v8/ScriptState.h"
30#include "bindings/core/v8/V8Binding.h"
31#include "core/dom/DOMError.h"
32#include "core/dom/ExecutionContext.h"
33#include "core/testing/NullExecutionContext.h"
34#include "modules/indexeddb/IDBDatabaseCallbacks.h"
35#include "modules/indexeddb/IDBKey.h"
36#include "modules/indexeddb/IDBKeyRange.h"
37#include "modules/indexeddb/IDBOpenDBRequest.h"
38#include "platform/SharedBuffer.h"
39#include "public/platform/WebBlobInfo.h"
40#include "public/platform/WebIDBDatabase.h"
41#include "wtf/OwnPtr.h"
42#include "wtf/PassOwnPtr.h"
43#include "wtf/PassRefPtr.h"
44#include "wtf/Vector.h"
45#include "wtf/dtoa/utils.h"
46#include <gtest/gtest.h>
47#include <v8.h>
48
49namespace blink {
50namespace {
51
52class IDBRequestTest : public testing::Test {
53public:
54    IDBRequestTest()
55        : m_scope(v8::Isolate::GetCurrent())
56        , m_executionContext(adoptRefWillBeNoop(new NullExecutionContext()))
57    {
58        m_scope.scriptState()->setExecutionContext(m_executionContext.get());
59    }
60
61    ~IDBRequestTest()
62    {
63        m_scope.scriptState()->setExecutionContext(0);
64    }
65
66    v8::Isolate* isolate() const { return m_scope.isolate(); }
67    ScriptState* scriptState() const { return m_scope.scriptState(); }
68    ExecutionContext* executionContext() const { return m_scope.scriptState()->executionContext(); }
69
70private:
71    V8TestingScope m_scope;
72    RefPtrWillBePersistent<ExecutionContext> m_executionContext;
73};
74
75TEST_F(IDBRequestTest, EventsAfterStopping)
76{
77    IDBTransaction* transaction = 0;
78    IDBRequest* request = IDBRequest::create(scriptState(), IDBAny::createUndefined(), transaction);
79    EXPECT_EQ(request->readyState(), "pending");
80    executionContext()->stopActiveDOMObjects();
81
82    // Ensure none of the following raise assertions in stopped state:
83    request->onError(DOMError::create(AbortError, "Description goes here."));
84    request->onSuccess(Vector<String>());
85    request->onSuccess(nullptr, IDBKey::createInvalid(), IDBKey::createInvalid(), nullptr, adoptPtr(new Vector<WebBlobInfo>()));
86    request->onSuccess(IDBKey::createInvalid());
87    request->onSuccess(PassRefPtr<SharedBuffer>(nullptr), adoptPtr(new Vector<WebBlobInfo>()));
88    request->onSuccess(PassRefPtr<SharedBuffer>(nullptr), adoptPtr(new Vector<WebBlobInfo>()), IDBKey::createInvalid(), IDBKeyPath());
89    request->onSuccess(static_cast<int64_t>(0));
90    request->onSuccess();
91    request->onSuccess(IDBKey::createInvalid(), IDBKey::createInvalid(), nullptr, adoptPtr(new Vector<WebBlobInfo>()));
92}
93
94TEST_F(IDBRequestTest, AbortErrorAfterAbort)
95{
96    IDBTransaction* transaction = 0;
97    IDBRequest* request = IDBRequest::create(scriptState(), IDBAny::createUndefined(), transaction);
98    EXPECT_EQ(request->readyState(), "pending");
99
100    // Simulate the IDBTransaction having received onAbort from back end and aborting the request:
101    request->abort();
102
103    // Now simulate the back end having fired an abort error at the request to clear up any intermediaries.
104    // Ensure an assertion is not raised.
105    request->onError(DOMError::create(AbortError, "Description goes here."));
106}
107
108class MockWebIDBDatabase : public WebIDBDatabase {
109public:
110    static PassOwnPtr<MockWebIDBDatabase> create()
111    {
112        return adoptPtr(new MockWebIDBDatabase());
113    }
114    virtual ~MockWebIDBDatabase()
115    {
116        EXPECT_TRUE(m_closeCalled);
117    }
118
119    virtual void close() OVERRIDE
120    {
121        m_closeCalled = true;
122    }
123    virtual void abort(long long transactionId) OVERRIDE { }
124
125private:
126    MockWebIDBDatabase()
127        : m_closeCalled(false)
128    {
129    }
130
131    bool m_closeCalled;
132};
133
134TEST_F(IDBRequestTest, ConnectionsAfterStopping)
135{
136    const int64_t transactionId = 1234;
137    const int64_t version = 1;
138    const int64_t oldVersion = 0;
139    const IDBDatabaseMetadata metadata;
140    Persistent<IDBDatabaseCallbacks> callbacks = IDBDatabaseCallbacks::create();
141
142    {
143        OwnPtr<MockWebIDBDatabase> backend = MockWebIDBDatabase::create();
144        IDBOpenDBRequest* request = IDBOpenDBRequest::create(scriptState(), callbacks, transactionId, version);
145        EXPECT_EQ(request->readyState(), "pending");
146
147        executionContext()->stopActiveDOMObjects();
148        request->onUpgradeNeeded(oldVersion, backend.release(), metadata, WebIDBDataLossNone, String());
149    }
150
151    {
152        OwnPtr<MockWebIDBDatabase> backend = MockWebIDBDatabase::create();
153        IDBOpenDBRequest* request = IDBOpenDBRequest::create(scriptState(), callbacks, transactionId, version);
154        EXPECT_EQ(request->readyState(), "pending");
155
156        executionContext()->stopActiveDOMObjects();
157        request->onSuccess(backend.release(), metadata);
158    }
159}
160
161} // namespace
162} // namespace blink
163