Bug 1523562 [wpt PR 14761] - [IndexedDB]: Explicit commit error timing handling., a=testonly

Automatic update from web-platform-tests
[IndexedDB]: Explicit commit error timing handling.

When a transaction is explicitly committed, there may yet be unhandled
errors that the browser has sent but the renderer has not yet seen. This
can cause strange behaviour (see the Github discussion link below). This
patch keeps track of the 'handled errors' in the renderer and the 'sent
errors' in the backend. The 'handled errors' number is sent when the
transaction is explicitly committed, and the browser can compare this
with the 'sent errors'. If they don't match, the transaction is aborted

GitHub Discussion: https://github.com/w3c/IndexedDB/pull/242

Bug: 911877
Change-Id: I7ea7b9e20c70528de3f363e961f87a3d8f5798d3
Reviewed-on: https://chromium-review.googlesource.com/c/1378806
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Chase Phillips <cmp@chromium.org>
Reviewed-by: Daniel Murphy <dmurph@chromium.org>
Commit-Queue: Andreas Butler <andreasbutler@google.com>
Cr-Commit-Position: refs/heads/master@{#625780}

--

wpt-commits: b0fbbb9ff451b18bf8a69fd54027bf59d21c2667
wpt-pr: 14761
This commit is contained in:
Andreas Butler 2019-01-31 19:01:00 +00:00 committed by James Graham
parent f5d2a13606
commit c79d1d2143

View File

@ -188,20 +188,17 @@ promise_test(async testCase => {
});
// Txn1 should commit before txn2, even though txn2 uses commit().
const txn1 = db.transaction(['books'], 'readwrite');
const objectStore1 = txn1.objectStore('books');
const putRequest1 = objectStore1.put({isbn:'one', title:'title1'});
txn1.objectStore('books').put({isbn: 'one', title: 'title1'});
const releaseTxnFunction = keepAlive(testCase, txn1, 'books');
const txn2 = db.transaction(['books'], 'readwrite');
const objectStore2 = txn2.objectStore('books');
const putRequest2 = objectStore2.put({isbn:'one', title:'title2'});
txn2.objectStore('books').put({isbn:'one', title:'title2'});
txn2.commit();
// Exercise the IndexedDB transaction ordering by executing one with a
// different scope.
const txn3 = db.transaction(['not_books'], 'readwrite');
const objectStore3 = txn3.objectStore('not_books');
objectStore3.put({'title': 'not_title'}, 'key');
txn3.objectStore('not_books').put({'title': 'not_title'}, 'key');
txn3.oncomplete = function() {
releaseTxnFunction();
}
@ -210,8 +207,7 @@ promise_test(async testCase => {
// Read the data back to verify that txn2 executed last.
const txn4 = db.transaction(['books'], 'readonly');
const objectStore4 = txn4.objectStore('books');
const getRequest4 = objectStore4.get('one');
const getRequest4 = txn4.objectStore('books').get('one');
await promiseForTransaction(testCase, txn4);
assert_equals(getRequest4.result.title, 'title2');
db.close();
@ -225,8 +221,7 @@ promise_test(async testCase => {
});
// Txn1 creates the book 'one' so the 'add()' below fails.
const txn1 = db.transaction(['books'], 'readwrite');
const objectStore1 = txn1.objectStore('books');
const putRequest1 = objectStore1.add({isbn:'one', title:'title1'});
txn1.objectStore('books').add({isbn:'one', title:'title1'});
txn1.commit();
await promiseForTransaction(testCase, txn1);
@ -235,15 +230,17 @@ promise_test(async testCase => {
const txn2 = db.transaction(['books'], 'readwrite');
const objectStore2 = txn2.objectStore('books');
objectStore2.put({isbn:'two', title:'title2'});
const addRequest2 = objectStore2.add({isbn:'one', title:'title2'});
const addRequest = objectStore2.add({isbn:'one', title:'title2'});
txn2.commit();
txn2.oncomplete = assert_unreached(
'Transaction with invalid "add" call should not be completed.');
txn2.oncomplete = () => { assert_unreached(
'Transaction with invalid "add" call should not be completed.'); };
var addWatcher = requestWatcher(testCase, addRequest2);
var txnWatcher = transactionWatcher(testCase, txn2);
await Promise.all([addWatcher.wait_for('error'),
txnWatcher.wait_for('error', 'abort')]);
// Wait for the transaction to complete. We have to explicitly wait for the
// error signal on the transaction because of the nature of the test tooling.
await Promise.all([
requestWatcher(testCase, addRequest).wait_for('error'),
transactionWatcher(testCase, txn2).wait_for(['error', 'abort'])
]);
// Read the data back to verify that txn2 was aborted.
const txn3 = db.transaction(['books'], 'readonly');
@ -255,3 +252,41 @@ promise_test(async testCase => {
assert_equals(getRequest2.result, 0);
db.close();
}, 'Transactions that explicitly commit and have errors should abort.');
promise_test(async testCase => {
const db = await createDatabase(testCase, db => {
createBooksStore(testCase, db);
});
const txn1 = db.transaction(['books'], 'readwrite');
txn1.objectStore('books').add({isbn: 'one', title: 'title1'});
txn1.commit();
await promiseForTransaction(testCase, txn1);
// The second add request will throw an error, but the onerror handler will
// appropriately catch the error allowing the valid put request on the
// transaction to commit.
const txn2 = db.transaction(['books'], 'readwrite');
const objectStore2 = txn2.objectStore('books');
objectStore2.put({isbn: 'two', title:'title2'});
const addRequest = objectStore2.add({isbn: 'one', title:'unreached_title'});
addRequest.onerror = (event) => {
event.preventDefault();
addRequest.transaction.commit();
};
// Wait for the transaction to complete. We have to explicitly wait for the
// error signal on the transaction because of the nature of the test tooling.
await transactionWatcher(testCase,txn2).wait_for(['error', 'complete'])
// Read the data back to verify that txn2 was committed.
const txn3 = db.transaction(['books'], 'readonly');
const objectStore3 = txn3.objectStore('books');
const getRequest1 = objectStore3.get('one');
const getRequest2 = objectStore3.get('two');
await promiseForTransaction(testCase, txn3);
assert_equals(getRequest1.result.title, 'title1');
assert_equals(getRequest2.result.title, 'title2');
db.close();
}, 'Transactions that handle all errors properly should be behave as ' +
'expected when an explicit commit is called in an onerror handler.');