Index: third_party/WebKit/LayoutTests/storage/indexeddb/upgrade-transaction-lifecycle-microtasks.html |
diff --git a/third_party/WebKit/LayoutTests/storage/indexeddb/upgrade-transaction-lifecycle-microtasks.html b/third_party/WebKit/LayoutTests/storage/indexeddb/upgrade-transaction-lifecycle-microtasks.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..40750c9b7db678e8a48df909953d1930a241ffc0 |
--- /dev/null |
+++ b/third_party/WebKit/LayoutTests/storage/indexeddb/upgrade-transaction-lifecycle-microtasks.html |
@@ -0,0 +1,199 @@ |
+<!doctype html> |
+<title>IndexedDB: versionchange transaction lifecycle</title> |
+<!-- These tests cannot yet be upstreamed to WPT because they rely on microtask |
+ sequencing, which was not fully specified yet. --> |
+<link rel="help" |
+ href="https://w3c.github.io/IndexedDB/#upgrade-transaction-steps"> |
+<link rel="help" |
+ href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore"> |
+<link rel="help" |
+ href="https://w3c.github.io/IndexedDB/#dom-idbdatabase-deleteobjectstore"> |
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan"> |
+<script src="../../resources/testharness.js"></script> |
+<script src="../../resources/testharnessreport.js"></script> |
+<script src="resources/support-promises.js"></script> |
+<script> |
+'use strict'; |
+ |
+promise_test(t => { |
+ let testStepPromise = null, abortPromise = null; |
+ return createDatabase(t, database => { |
+ createBooksStore(t, database); |
+ }).then(database => { |
+ database.close(); |
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
+ let abortFired = false; |
+ |
+ testStepPromise = Promise.resolve().then(() => { |
+ assert_false( |
+ abortFired, |
+ 'The abort event should fire after promises are resolved'); |
+ assert_equals( |
+ request.transaction, transaction, |
+ "The open request's transaction should be reset after onabort"); |
+ try { |
+ database.createObjectStore('books2'); |
+ } catch(e) { |
+ assert_false( |
+ e, |
+ 'createObjectStore should not throw an exception, because the ' + |
+ 'transaction is still active'); |
+ } |
+ try { |
+ database.deleteObjectStore('books'); |
+ } catch(e) { |
+ assert_false( |
+ e, |
+ 'deleteObjectStore should not throw an exception, because the ' + |
+ 'transaction is still active'); |
+ } |
+ }); |
+ abortPromise = new Promise((resolve, reject) => { |
+ transaction.addEventListener('abort', () => { |
+ abortFired = true; |
+ resolve(); |
+ }, false); |
+ transaction.objectStore('books').add(BOOKS_RECORD_DATA[0]); |
+ transaction._willBeAborted(); |
+ }); |
+ })).then(() => Promise.all([testStepPromise, abortPromise])); |
+}, 'asynchronously after a failing request is issued, before the abort event ' + |
+ 'is fired'); |
+ |
+promise_test(t => { |
+ let testStepPromise = null; |
+ return createDatabase(t, database => { |
+ createBooksStore(t, database); |
+ }).then(database => { |
+ database.close(); |
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
+ testStepPromise = new Promise((resolve, reject) => { |
+ transaction.addEventListener('abort', () => resolve(), false); |
+ transaction.objectStore('books').add(BOOKS_RECORD_DATA[0]); |
+ transaction._willBeAborted(); |
+ }).then(() => { |
+ assert_equals( |
+ request.transaction, transaction, |
+ "The open request's transaction should be reset after onabort " + |
+ 'microtasks'); |
+ assert_throws( |
+ 'InvalidStateError', |
+ () => { database.createObjectStore('books2'); }, |
+ 'createObjectStore exception should reflect that the transaction ' + |
+ 'is no longer running'); |
+ assert_throws( |
+ 'InvalidStateError', |
+ () => { database.deleteObjectStore('books'); }, |
+ 'deleteObjectStore exception should reflect that the transaction ' + |
+ 'is no longer running'); |
+ }); |
+ })).then(() => testStepPromise); |
+}, 'after the abort event is fired due to a bad request'); |
+ |
+promise_test(t => { |
+ let testStepPromise = null; |
+ return createDatabase(t, database => { |
+ createBooksStore(t, database); |
+ }).then(database => { |
+ database.close(); |
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
+ testStepPromise = new Promise((resolve, reject) => { |
+ transaction.addEventListener('abort', () => resolve(), false); |
+ transaction.abort(); |
+ }).then(() => { |
+ assert_equals( |
+ request.transaction, transaction, |
+ "The open request's transaction should be reset after onabort " + |
+ 'microtasks'); |
+ assert_throws( |
+ 'InvalidStateError', |
+ () => { database.createObjectStore('books2'); }, |
+ 'createObjectStore exception should reflect that the transaction ' + |
+ 'is no longer running'); |
+ assert_throws( |
+ 'InvalidStateError', |
+ () => { database.deleteObjectStore('books'); }, |
+ 'deleteObjectStore exception should reflect that the transaction ' + |
+ 'is no longer running'); |
+ }); |
+ })).then(() => testStepPromise); |
+}, 'after the abort event is fired due to an abort() call'); |
+ |
+promise_test(t => { |
+ let testStepPromise = null, completePromise = null; |
+ return createDatabase(t, database => { |
+ createBooksStore(t, database); |
+ }).then(database => { |
+ database.close(); |
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
+ let completeFired = false; |
+ completePromise = new Promise((resolve, reject) => { |
+ transaction.addEventListener('complete', () => { |
+ completeFired = true; |
+ resolve(); |
+ }, false); |
+ }); |
+ |
+ testStepPromise = Promise.resolve().then(() => { |
+ assert_false( |
+ completeFired, |
+ 'The complete event should fire after promises are resolved'); |
+ assert_equals( |
+ request.transaction, transaction, |
+ "The open request's transaction should be reset after oncomplete"); |
+ try { |
+ database.createObjectStore('books2'); |
+ } catch(e) { |
+ assert_false( |
+ e, |
+ 'createObjectStore should not throw an exception, because the ' + |
+ 'transaction is still active'); |
+ } |
+ |
+ try { |
+ database.deleteObjectStore('books'); |
+ } catch(e) { |
+ assert_false( |
+ e, |
+ 'deleteObjectStore should not throw an exception, because the ' + |
+ 'transaction is still active'); |
+ } |
+ }); |
+ })).then(database => { |
+ database.close(); |
+ return Promise.all([testStepPromise, completePromise]); |
+ }); |
+}, 'in a resolved promise after the transaction requests are performed'); |
+ |
+promise_test(t => { |
+ let testStepPromise = null, completePromise = null; |
+ return createDatabase(t, database => { |
+ createBooksStore(t, database); |
+ }).then(database => { |
+ database.close(); |
+ }).then(() => migrateDatabase(t, 2, (database, transaction, request) => { |
+ completePromise = new Promise((resolve, reject) => { |
+ transaction.addEventListener('complete', () => resolve(), false); |
+ }).then(() => { |
+ assert_equals( |
+ request.transaction, transaction, |
+ "The open request's transaction should be reset after oncomplete " + |
+ 'microtasks'); |
+ assert_throws( |
+ 'InvalidStateError', |
+ () => { database.createObjectStore('books2'); }, |
+ 'createObjectStore exception should reflect that the transaction ' + |
+ 'is no longer running'); |
+ assert_throws( |
+ 'InvalidStateError', |
+ () => { database.deleteObjectStore('books'); }, |
+ 'deleteObjectStore exception should reflect that the transaction ' + |
+ 'is no longer running'); |
+ }); |
+ })).then(database => { |
+ database.close(); |
+ return Promise.all([testStepPromise, completePromise]); |
+ }); |
+}, 'in a resolved promise after the complete event is fired'); |
+ |
+</script> |