michael@0: /** michael@0: * Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ michael@0: */ michael@0: "use strict"; michael@0: michael@0: var self = this; michael@0: michael@0: var testGenerator = testSteps(); michael@0: michael@0: function testSteps() michael@0: { michael@0: const dbName = self.window ? michael@0: window.location.pathname : michael@0: "test_transaction_abort_hang"; michael@0: const objStoreName = "foo"; michael@0: const transactionCount = 30; michael@0: michael@0: let completedTransactionCount = 0; michael@0: let caughtError = false; michael@0: michael@0: let abortedTransactionIndex = Math.floor(transactionCount / 2); michael@0: if (abortedTransactionIndex % 2 == 0) { michael@0: abortedTransactionIndex++; michael@0: } michael@0: michael@0: let request = indexedDB.open(dbName, 1); michael@0: request.onerror = errorHandler; michael@0: request.onupgradeneeded = grabEventAndContinueHandler; michael@0: let event = yield undefined; michael@0: michael@0: request.result.createObjectStore(objStoreName, { autoIncrement: true }); michael@0: michael@0: request.onupgradeneeded = null; michael@0: request.onsuccess = grabEventAndContinueHandler; michael@0: event = yield undefined; michael@0: michael@0: let db = event.target.result; michael@0: michael@0: for (let i = 0; i < transactionCount; i++) { michael@0: const readonly = i % 2 == 0; michael@0: const mode = readonly ? "readonly" : "readwrite"; michael@0: michael@0: let transaction = db.transaction(objStoreName, mode); michael@0: michael@0: if (i == transactionCount - 1) { michael@0: // Last one, finish the test. michael@0: transaction.oncomplete = grabEventAndContinueHandler; michael@0: } else if (i == abortedTransactionIndex - 1) { michael@0: transaction.oncomplete = function(event) { michael@0: ok(true, "Completed transaction " + ++completedTransactionCount + michael@0: " (We may hang after this!)"); michael@0: }; michael@0: } else if (i == abortedTransactionIndex) { michael@0: // Special transaction that we abort outside the normal event flow. michael@0: transaction.onerror = function(event) { michael@0: ok(true, "Aborted transaction " + ++completedTransactionCount + michael@0: " (We didn't hang!)"); michael@0: is(event.target.error.name, "AbortError", michael@0: "AbortError set as the error on the request"); michael@0: is(event.target.transaction.error, null, michael@0: "No error set on the transaction"); michael@0: ok(!caughtError, "Haven't seen the error event yet"); michael@0: caughtError = true; michael@0: event.preventDefault(); michael@0: }; michael@0: // This has to happen after the we return to the event loop but before the michael@0: // transaction starts running. michael@0: executeSoon(function() { transaction.abort(); }); michael@0: } else { michael@0: transaction.oncomplete = function(event) { michael@0: ok(true, "Completed transaction " + ++completedTransactionCount); michael@0: }; michael@0: } michael@0: michael@0: if (readonly) { michael@0: transaction.objectStore(objStoreName).get(0); michael@0: } else { michael@0: try { transaction.objectStore(objStoreName).add({}); } catch(e) { } michael@0: } michael@0: } michael@0: ok(true, "Created all transactions"); michael@0: michael@0: event = yield undefined; michael@0: michael@0: ok(true, "Completed transaction " + ++completedTransactionCount); michael@0: ok(caughtError, "Caught the error event when we aborted the transaction"); michael@0: michael@0: finishTest(); michael@0: yield undefined; michael@0: }