OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 15 matching lines...) Expand all Loading... |
26 #include "modules/indexeddb/IDBRequest.h" | 26 #include "modules/indexeddb/IDBRequest.h" |
27 | 27 |
28 #include <memory> | 28 #include <memory> |
29 | 29 |
30 #include "bindings/core/v8/V8BindingForCore.h" | 30 #include "bindings/core/v8/V8BindingForCore.h" |
31 #include "bindings/core/v8/V8BindingForTesting.h" | 31 #include "bindings/core/v8/V8BindingForTesting.h" |
32 #include "core/dom/DOMException.h" | 32 #include "core/dom/DOMException.h" |
33 #include "core/dom/ExceptionCode.h" | 33 #include "core/dom/ExceptionCode.h" |
34 #include "core/dom/ExecutionContext.h" | 34 #include "core/dom/ExecutionContext.h" |
35 #include "core/testing/NullExecutionContext.h" | 35 #include "core/testing/NullExecutionContext.h" |
| 36 #include "modules/indexeddb/IDBDatabase.h" |
36 #include "modules/indexeddb/IDBDatabaseCallbacks.h" | 37 #include "modules/indexeddb/IDBDatabaseCallbacks.h" |
37 #include "modules/indexeddb/IDBKey.h" | 38 #include "modules/indexeddb/IDBKey.h" |
38 #include "modules/indexeddb/IDBOpenDBRequest.h" | 39 #include "modules/indexeddb/IDBOpenDBRequest.h" |
| 40 #include "modules/indexeddb/IDBTransaction.h" |
39 #include "modules/indexeddb/IDBValue.h" | 41 #include "modules/indexeddb/IDBValue.h" |
| 42 #include "modules/indexeddb/IDBValueWrapping.h" |
40 #include "modules/indexeddb/MockWebIDBDatabase.h" | 43 #include "modules/indexeddb/MockWebIDBDatabase.h" |
41 #include "platform/SharedBuffer.h" | 44 #include "platform/SharedBuffer.h" |
42 #include "platform/bindings/ScriptState.h" | 45 #include "platform/bindings/ScriptState.h" |
43 #include "platform/wtf/PassRefPtr.h" | 46 #include "platform/wtf/PassRefPtr.h" |
44 #include "platform/wtf/Vector.h" | 47 #include "platform/wtf/Vector.h" |
45 #include "platform/wtf/dtoa/utils.h" | 48 #include "platform/wtf/dtoa/utils.h" |
| 49 #include "public/platform/Platform.h" |
| 50 #include "public/platform/WebURLLoaderMockFactory.h" |
| 51 #include "public/platform/WebURLResponse.h" |
46 #include "public/platform/modules/indexeddb/WebIDBCallbacks.h" | 52 #include "public/platform/modules/indexeddb/WebIDBCallbacks.h" |
47 #include "testing/gtest/include/gtest/gtest.h" | 53 #include "testing/gtest/include/gtest/gtest.h" |
48 #include "v8/include/v8.h" | 54 #include "v8/include/v8.h" |
49 | 55 |
50 namespace blink { | 56 namespace blink { |
51 namespace { | 57 namespace { |
52 | 58 |
53 TEST(IDBRequestTest, EventsAfterStopping) { | 59 class IDBRequestTest : public ::testing::Test { |
| 60 protected: |
| 61 void SetUp() override { |
| 62 url_loader_mock_factory_ = Platform::Current()->GetURLLoaderMockFactory(); |
| 63 WebURLResponse response; |
| 64 response.SetURL(KURL(KURL(), "blob:")); |
| 65 url_loader_mock_factory_->RegisterURLProtocol(WebString("blob"), response, |
| 66 ""); |
| 67 } |
| 68 |
| 69 void TearDown() override { |
| 70 url_loader_mock_factory_->UnregisterAllURLsAndClearMemoryCache(); |
| 71 } |
| 72 |
| 73 void BuildTransaction(V8TestingScope& scope, |
| 74 std::unique_ptr<MockWebIDBDatabase> backend) { |
| 75 db_ = |
| 76 IDBDatabase::Create(scope.GetExecutionContext(), std::move(backend), |
| 77 IDBDatabaseCallbacks::Create(), scope.GetIsolate()); |
| 78 |
| 79 HashSet<String> transaction_scope = {"store"}; |
| 80 transaction_ = IDBTransaction::CreateNonVersionChange( |
| 81 scope.GetScriptState(), kTransactionId, transaction_scope, |
| 82 kWebIDBTransactionModeReadOnly, db_.Get()); |
| 83 } |
| 84 |
| 85 WebURLLoaderMockFactory* url_loader_mock_factory_; |
| 86 Persistent<IDBDatabase> db_; |
| 87 Persistent<IDBTransaction> transaction_; |
| 88 |
| 89 static constexpr int64_t kTransactionId = 1234; |
| 90 }; |
| 91 |
| 92 // The created value is an array of true. If create_wrapped_value is true, the |
| 93 // IDBValue's byte array will be wrapped in a Blob, otherwise it will not be. |
| 94 RefPtr<IDBValue> CreateIDBValue(v8::Isolate* isolate, |
| 95 bool create_wrapped_value) { |
| 96 size_t element_count = create_wrapped_value ? 16 : 2; |
| 97 v8::Local<v8::Array> v8_array = v8::Array::New(isolate, element_count); |
| 98 for (size_t i = 0; i < element_count; ++i) |
| 99 v8_array->Set(i, v8::True(isolate)); |
| 100 |
| 101 NonThrowableExceptionState non_throwable_exception_state; |
| 102 IDBValueWrapper wrapper(isolate, v8_array, |
| 103 SerializedScriptValue::SerializeOptions::kSerialize, |
| 104 non_throwable_exception_state); |
| 105 wrapper.WrapIfBiggerThan(create_wrapped_value ? 0 : 1024 * element_count); |
| 106 |
| 107 std::unique_ptr<Vector<RefPtr<BlobDataHandle>>> blob_data_handles = |
| 108 WTF::MakeUnique<Vector<RefPtr<BlobDataHandle>>>(); |
| 109 wrapper.ExtractBlobDataHandles(blob_data_handles.get()); |
| 110 Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo(); |
| 111 RefPtr<SharedBuffer> wrapped_marker_buffer = wrapper.ExtractWireBytes(); |
| 112 |
| 113 RefPtr<IDBValue> idb_value = |
| 114 IDBValue::Create(wrapped_marker_buffer, std::move(blob_data_handles), |
| 115 WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos)); |
| 116 |
| 117 DCHECK_EQ(create_wrapped_value, |
| 118 IDBValueUnwrapper::IsWrapped(idb_value.Get())); |
| 119 return idb_value; |
| 120 } |
| 121 |
| 122 void EnsureIDBCallbacksDontThrow(IDBRequest* request, |
| 123 ExceptionState& exception_state) { |
| 124 ASSERT_TRUE(request->transaction()); |
| 125 |
| 126 request->HandleResponse( |
| 127 DOMException::Create(kAbortError, "Description goes here.")); |
| 128 request->HandleResponse(nullptr, IDBKey::CreateInvalid(), |
| 129 IDBKey::CreateInvalid(), IDBValue::Create()); |
| 130 request->HandleResponse(IDBKey::CreateInvalid()); |
| 131 request->HandleResponse(IDBValue::Create()); |
| 132 request->HandleResponse(static_cast<int64_t>(0)); |
| 133 request->HandleResponse(); |
| 134 request->HandleResponse(IDBKey::CreateInvalid(), IDBKey::CreateInvalid(), |
| 135 IDBValue::Create()); |
| 136 request->EnqueueResponse(Vector<String>()); |
| 137 |
| 138 EXPECT_TRUE(!exception_state.HadException()); |
| 139 } |
| 140 |
| 141 TEST_F(IDBRequestTest, EventsAfterEarlyDeathStop) { |
| 142 V8TestingScope scope; |
| 143 std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create(); |
| 144 EXPECT_CALL(*backend, Close()).Times(1); |
| 145 BuildTransaction(scope, std::move(backend)); |
| 146 |
| 147 ASSERT_TRUE(!scope.GetExceptionState().HadException()); |
| 148 ASSERT_TRUE(transaction_); |
| 149 |
| 150 IDBRequest* request = IDBRequest::Create( |
| 151 scope.GetScriptState(), IDBAny::CreateUndefined(), transaction_.Get()); |
| 152 EXPECT_EQ(request->readyState(), "pending"); |
| 153 ASSERT_TRUE(!scope.GetExceptionState().HadException()); |
| 154 ASSERT_TRUE(request->transaction()); |
| 155 scope.GetExecutionContext()->NotifyContextDestroyed(); |
| 156 |
| 157 EnsureIDBCallbacksDontThrow(request, scope.GetExceptionState()); |
| 158 } |
| 159 |
| 160 TEST_F(IDBRequestTest, EventsAfterDoneStop) { |
| 161 V8TestingScope scope; |
| 162 std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create(); |
| 163 EXPECT_CALL(*backend, Close()).Times(1); |
| 164 BuildTransaction(scope, std::move(backend)); |
| 165 |
| 166 ASSERT_TRUE(!scope.GetExceptionState().HadException()); |
| 167 ASSERT_TRUE(transaction_); |
| 168 |
| 169 IDBRequest* request = IDBRequest::Create( |
| 170 scope.GetScriptState(), IDBAny::CreateUndefined(), transaction_.Get()); |
| 171 ASSERT_TRUE(!scope.GetExceptionState().HadException()); |
| 172 ASSERT_TRUE(request->transaction()); |
| 173 request->HandleResponse(CreateIDBValue(scope.GetIsolate(), false)); |
| 174 scope.GetExecutionContext()->NotifyContextDestroyed(); |
| 175 |
| 176 EnsureIDBCallbacksDontThrow(request, scope.GetExceptionState()); |
| 177 } |
| 178 |
| 179 TEST_F(IDBRequestTest, EventsAfterEarlyDeathStopWithQueuedResult) { |
| 180 V8TestingScope scope; |
| 181 std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create(); |
| 182 EXPECT_CALL(*backend, Close()).Times(1); |
| 183 BuildTransaction(scope, std::move(backend)); |
| 184 |
| 185 ASSERT_TRUE(!scope.GetExceptionState().HadException()); |
| 186 ASSERT_TRUE(transaction_); |
| 187 |
| 188 IDBRequest* request = IDBRequest::Create( |
| 189 scope.GetScriptState(), IDBAny::CreateUndefined(), transaction_.Get()); |
| 190 EXPECT_EQ(request->readyState(), "pending"); |
| 191 ASSERT_TRUE(!scope.GetExceptionState().HadException()); |
| 192 ASSERT_TRUE(request->transaction()); |
| 193 request->HandleResponse(CreateIDBValue(scope.GetIsolate(), true)); |
| 194 scope.GetExecutionContext()->NotifyContextDestroyed(); |
| 195 |
| 196 EnsureIDBCallbacksDontThrow(request, scope.GetExceptionState()); |
| 197 url_loader_mock_factory_->ServeAsynchronousRequests(); |
| 198 EnsureIDBCallbacksDontThrow(request, scope.GetExceptionState()); |
| 199 } |
| 200 |
| 201 TEST_F(IDBRequestTest, EventsAfterEarlyDeathStopWithTwoQueuedResults) { |
| 202 V8TestingScope scope; |
| 203 std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create(); |
| 204 EXPECT_CALL(*backend, Close()).Times(1); |
| 205 BuildTransaction(scope, std::move(backend)); |
| 206 |
| 207 ASSERT_TRUE(!scope.GetExceptionState().HadException()); |
| 208 ASSERT_TRUE(transaction_); |
| 209 |
| 210 IDBRequest* request1 = IDBRequest::Create( |
| 211 scope.GetScriptState(), IDBAny::CreateUndefined(), transaction_.Get()); |
| 212 IDBRequest* request2 = IDBRequest::Create( |
| 213 scope.GetScriptState(), IDBAny::CreateUndefined(), transaction_.Get()); |
| 214 EXPECT_EQ(request1->readyState(), "pending"); |
| 215 EXPECT_EQ(request2->readyState(), "pending"); |
| 216 ASSERT_TRUE(!scope.GetExceptionState().HadException()); |
| 217 ASSERT_TRUE(request1->transaction()); |
| 218 ASSERT_TRUE(request2->transaction()); |
| 219 request1->HandleResponse(CreateIDBValue(scope.GetIsolate(), true)); |
| 220 request2->HandleResponse(CreateIDBValue(scope.GetIsolate(), true)); |
| 221 scope.GetExecutionContext()->NotifyContextDestroyed(); |
| 222 |
| 223 EnsureIDBCallbacksDontThrow(request1, scope.GetExceptionState()); |
| 224 EnsureIDBCallbacksDontThrow(request2, scope.GetExceptionState()); |
| 225 url_loader_mock_factory_->ServeAsynchronousRequests(); |
| 226 EnsureIDBCallbacksDontThrow(request1, scope.GetExceptionState()); |
| 227 EnsureIDBCallbacksDontThrow(request2, scope.GetExceptionState()); |
| 228 } |
| 229 |
| 230 TEST_F(IDBRequestTest, AbortErrorAfterAbort) { |
54 V8TestingScope scope; | 231 V8TestingScope scope; |
55 IDBTransaction* transaction = nullptr; | 232 IDBTransaction* transaction = nullptr; |
56 IDBRequest* request = IDBRequest::Create( | 233 IDBRequest* request = IDBRequest::Create( |
57 scope.GetScriptState(), IDBAny::CreateUndefined(), transaction); | |
58 EXPECT_EQ(request->readyState(), "pending"); | |
59 scope.GetExecutionContext()->NotifyContextDestroyed(); | |
60 | |
61 // Ensure none of the following raise assertions in stopped state: | |
62 request->EnqueueResponse( | |
63 DOMException::Create(kAbortError, "Description goes here.")); | |
64 request->EnqueueResponse(Vector<String>()); | |
65 request->EnqueueResponse(nullptr, IDBKey::CreateInvalid(), | |
66 IDBKey::CreateInvalid(), IDBValue::Create()); | |
67 request->EnqueueResponse(IDBKey::CreateInvalid()); | |
68 request->EnqueueResponse(IDBValue::Create()); | |
69 request->EnqueueResponse(static_cast<int64_t>(0)); | |
70 request->EnqueueResponse(); | |
71 request->EnqueueResponse(IDBKey::CreateInvalid(), IDBKey::CreateInvalid(), | |
72 IDBValue::Create()); | |
73 } | |
74 | |
75 TEST(IDBRequestTest, AbortErrorAfterAbort) { | |
76 V8TestingScope scope; | |
77 IDBTransaction* transaction = nullptr; | |
78 IDBRequest* request = IDBRequest::Create( | |
79 scope.GetScriptState(), IDBAny::CreateUndefined(), transaction); | 234 scope.GetScriptState(), IDBAny::CreateUndefined(), transaction); |
80 EXPECT_EQ(request->readyState(), "pending"); | 235 EXPECT_EQ(request->readyState(), "pending"); |
81 | 236 |
82 // Simulate the IDBTransaction having received OnAbort from back end and | 237 // Simulate the IDBTransaction having received OnAbort from back end and |
83 // aborting the request: | 238 // aborting the request: |
84 request->Abort(); | 239 request->Abort(); |
85 | 240 |
86 // Now simulate the back end having fired an abort error at the request to | 241 // Now simulate the back end having fired an abort error at the request to |
87 // clear up any intermediaries. Ensure an assertion is not raised. | 242 // clear up any intermediaries. Ensure an assertion is not raised. |
88 request->EnqueueResponse( | 243 request->HandleResponse( |
89 DOMException::Create(kAbortError, "Description goes here.")); | 244 DOMException::Create(kAbortError, "Description goes here.")); |
90 | 245 |
91 // Stop the request lest it be GCed and its destructor | 246 // Stop the request lest it be GCed and its destructor |
92 // finds the object in a pending state (and asserts.) | 247 // finds the object in a pending state (and asserts.) |
93 scope.GetExecutionContext()->NotifyContextDestroyed(); | 248 scope.GetExecutionContext()->NotifyContextDestroyed(); |
94 } | 249 } |
95 | 250 |
96 TEST(IDBRequestTest, ConnectionsAfterStopping) { | 251 TEST_F(IDBRequestTest, ConnectionsAfterStopping) { |
97 V8TestingScope scope; | 252 V8TestingScope scope; |
98 const int64_t kTransactionId = 1234; | 253 const int64_t kTransactionId = 1234; |
99 const int64_t kVersion = 1; | 254 const int64_t kVersion = 1; |
100 const int64_t kOldVersion = 0; | 255 const int64_t kOldVersion = 0; |
101 const WebIDBMetadata metadata; | 256 const WebIDBMetadata metadata; |
102 Persistent<IDBDatabaseCallbacks> callbacks = IDBDatabaseCallbacks::Create(); | 257 Persistent<IDBDatabaseCallbacks> callbacks = IDBDatabaseCallbacks::Create(); |
103 | 258 |
104 { | 259 { |
105 std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create(); | 260 std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create(); |
106 EXPECT_CALL(*backend, Close()).Times(1); | 261 EXPECT_CALL(*backend, Close()).Times(1); |
(...skipping 15 matching lines...) Expand all Loading... |
122 EXPECT_EQ(request->readyState(), "pending"); | 277 EXPECT_EQ(request->readyState(), "pending"); |
123 std::unique_ptr<WebIDBCallbacks> callbacks = request->CreateWebCallbacks(); | 278 std::unique_ptr<WebIDBCallbacks> callbacks = request->CreateWebCallbacks(); |
124 | 279 |
125 scope.GetExecutionContext()->NotifyContextDestroyed(); | 280 scope.GetExecutionContext()->NotifyContextDestroyed(); |
126 callbacks->OnSuccess(backend.release(), metadata); | 281 callbacks->OnSuccess(backend.release(), metadata); |
127 } | 282 } |
128 } | 283 } |
129 | 284 |
130 } // namespace | 285 } // namespace |
131 } // namespace blink | 286 } // namespace blink |
OLD | NEW |