Diff
Modified: trunk/LayoutTests/ChangeLog (122781 => 122782)
--- trunk/LayoutTests/ChangeLog 2012-07-17 00:31:09 UTC (rev 122781)
+++ trunk/LayoutTests/ChangeLog 2012-07-17 00:31:41 UTC (rev 122782)
@@ -1,3 +1,36 @@
+2012-07-16 Joshua Bell <[email protected]>
+
+ IndexedDB: Implement spec updates to IDBTransaction.error
+ https://bugs.webkit.org/show_bug.cgi?id=91409
+
+ Reviewed by Tony Chang.
+
+ Update transaction-abort test to accomodate refinements in the spec around
+ IDBTransaction.error and add a dedicated test to exercise all spec behavior
+ for the property.
+
+ * storage/indexeddb/resources/transaction-abort.js:
+ (startTest):
+ (firstAdd):
+ (secondAdd):
+ (transactionAborted):
+ * storage/indexeddb/resources/transaction-error.js: Added.
+ (test.request.onsuccess.request.onsuccess.request.onsuccess):
+ (test.request.onsuccess.request.onsuccess):
+ (test.request.onsuccess):
+ (test):
+ (startTest.trans.onabort):
+ (startTest):
+ (testErrorFromRequest.request.onerror):
+ (testErrorFromRequest.trans.onabort):
+ (testErrorFromRequest):
+ (testErrorFromException.request.onerror):
+ (testErrorFromException.trans.onabort):
+ (testErrorFromException):
+ * storage/indexeddb/transaction-abort-expected.txt:
+ * storage/indexeddb/transaction-error-expected.txt: Added.
+ * storage/indexeddb/transaction-error.html: Added.
+
2012-07-16 W. James MacLean <[email protected]>
[chromium] Unreviewed gardening. Layout Test plugins/embed-attributes-style.html is failing
Modified: trunk/LayoutTests/storage/indexeddb/resources/transaction-abort.js (122781 => 122782)
--- trunk/LayoutTests/storage/indexeddb/resources/transaction-abort.js 2012-07-17 00:31:09 UTC (rev 122781)
+++ trunk/LayoutTests/storage/indexeddb/resources/transaction-abort.js 2012-07-17 00:31:41 UTC (rev 122782)
@@ -49,6 +49,7 @@
request._onsuccess_ = unexpectedSuccessCallback;
request = evalAndLog("store.add({x: 'value3', y: 'zzz3'}, 'key3')");
request._onerror_ = secondAdd;
+ request._onsuccess_ = unexpectedSuccessCallback;
trans.abort();
firstError = false;
@@ -60,10 +61,7 @@
{
shouldBe("event.target.errorCode", "DOMException.ABORT_ERR");
shouldBe("event.target.error.name", "'AbortError'");
- firstDOMError = event.target.error;
- // FIXME: Ambiguous spec. See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=17236
- evalAndExpectException("trans.error", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
-
+ shouldBeNull("trans.error");
shouldBeFalse("firstError");
shouldBeFalse("secondError");
shouldBeFalse("abortFired");
@@ -76,8 +74,7 @@
{
shouldBe("event.target.errorCode", "DOMException.ABORT_ERR");
shouldBe("event.target.error.name", "'AbortError'");
- // FIXME: Ambiguous spec. See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=17236
- evalAndExpectException("trans.error", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'");
+ shouldBeNull("trans.error");
shouldBeTrue("firstError");
shouldBeFalse("secondError");
shouldBeFalse("abortFired");
@@ -89,11 +86,11 @@
shouldBeTrue("firstError");
shouldBeTrue("secondError");
shouldBeFalse("abortFired");
- shouldBe("trans.error", "firstDOMError");
+ shouldBeNull("trans.error");
abortFired = true;
evalAndExpectException("store.add({x: 'value5', y: 'zzz5'}, 'key5')", "IDBDatabaseException.TRANSACTION_INACTIVE_ERR", "'TransactionInactiveError'");
finishJSTest();
}
-test();
\ No newline at end of file
+test();
Added: trunk/LayoutTests/storage/indexeddb/resources/transaction-error.js (0 => 122782)
--- trunk/LayoutTests/storage/indexeddb/resources/transaction-error.js (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/resources/transaction-error.js 2012-07-17 00:31:41 UTC (rev 122782)
@@ -0,0 +1,138 @@
+if (this.importScripts) {
+ importScripts('../../../fast/js/resources/js-test-pre.js');
+ importScripts('shared.js');
+}
+
+description("Test IDBTransaction.error cases.");
+
+function test()
+{
+ removeVendorPrefixes();
+
+ evalAndLog("dbname = self.location.pathname");
+ request = evalAndLog("indexedDB.deleteDatabase(dbname)");
+ request._onblocked_ = unexpectedBlockedCallback;
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = function() {
+ request = evalAndLog("indexedDB.open(dbname)");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = function() {
+ evalAndLog("db = request.result");
+ request = evalAndLog("db.setVersion('1')");
+ request._onblocked_ = unexpectedBlockedCallback;
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = function() {
+ evalAndLog("trans = event.target.result");
+ trans._onabort_ = unexpectedAbortCallback;
+ evalAndLog("store = db.createObjectStore('storeName')");
+ request = evalAndLog("store.add('value', 'key')");
+ request._onerror_ = unexpectedErrorCallback;
+ trans._oncomplete_ = startTest;
+ };
+ };
+ };
+}
+
+function startTest()
+{
+ debug("");
+ evalAndLog("trans = db.transaction('storeName')");
+
+ debug("");
+ debug("IDBTransaction.error should be null if transaction is not finished:");
+ shouldBeNull("trans.error");
+
+ debug("");
+ debug("If IDBTransaction.abort() is explicitly called, IDBTransaction.error should be null:");
+ evalAndLog("trans.abort()");
+ trans._oncomplete_ = unexpectedCompleteCallback;
+ trans._onabort_ = function() {
+ shouldBeNull("trans.error");
+ testErrorFromRequest();
+ };
+}
+
+function testErrorFromRequest()
+{
+ debug("");
+ debug("If the transaction is aborted due to a request error that is not prevented, IDBTransaction.error should match:");
+ evalAndLog("trans = db.transaction('storeName', 'readwrite')");
+ evalAndLog("request = trans.objectStore('storeName').add('value2', 'key')");
+ request._onsuccess_ = unexpectedSuccessCallback;
+ request._onerror_ = function() {
+ shouldBe("request.errorCode", "IDBDatabaseException.CONSTRAINT_ERR");
+ shouldBe("request.error.name", "'ConstraintError'");
+ evalAndLog("request_error = request.error");
+ };
+ trans._oncomplete_ = unexpectedCompleteCallback;
+ trans._onabort_ = function() {
+ debug("Transaction received abort event.");
+ shouldBeNonNull("trans.error");
+ shouldBe("trans.error", "request_error");
+ testErrorFromException();
+ };
+}
+
+function testErrorFromException()
+{
+ debug("");
+ debug("If the transaction is aborted due to an exception thrown from event callback, IDBTransaction.error should be AbortError:");
+ evalAndLog("trans = db.transaction('storeName', 'readwrite')");
+ evalAndLog("request = trans.objectStore('storeName').add('value2', 'key')");
+ request._onsuccess_ = unexpectedSuccessCallback;
+ request._onerror_ = function() {
+ shouldBe("request.errorCode", "IDBDatabaseException.CONSTRAINT_ERR");
+ shouldBe("request.error.name", "'ConstraintError'");
+ debug("Throwing exception...");
+
+ // Ensure the test harness error handler is not invoked.
+ self.originalWindowOnError = self.onerror;
+ self._onerror_ = null;
+
+ throw new Error("This should *NOT* be caught!");
+ };
+ trans._oncomplete_ = unexpectedCompleteCallback;
+ trans._onabort_ = function() {
+ debug("Transaction received abort event.");
+
+ // Restore test harness error handler.
+ self._onerror_ = self.originalWindowOnError;
+
+ shouldBeNonNull("trans.error");
+ shouldBe("trans.error.name", "'AbortError'");
+ testErrorFromCommit();
+ };
+}
+
+function testErrorFromCommit()
+{
+ debug("");
+ debug("If the transaction is aborted due to an error during commit, IDBTransaction.error should reflect that error:");
+ evalAndLog("trans = db.transaction('storeName', 'readwrite')");
+ evalAndLog("request = trans.objectStore('storeName').add({id: 1}, 'record1')");
+ request._onerror_ = unexpectedErrorCallback;
+ evalAndLog("request = trans.objectStore('storeName').add({id: 1}, 'record2')");
+ request._onerror_ = unexpectedErrorCallback;
+ trans._onabort_ = unexpectedAbortCallback;
+ trans._oncomplete_ = function() {
+ evalAndLog("request = db.setVersion('2')");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onblocked_ = unexpectedBlockedCallback;
+ request._onsuccess_ = function() {
+ evalAndLog("trans = request.result");
+ debug("This should fail due to the unique constraint:");
+ evalAndLog("trans.objectStore('storeName').createIndex('indexName', 'id', {unique: true})");
+ trans._oncomplete_ = unexpectedCompleteCallback;
+ trans._onabort_ = function() {
+ debug("Transaction received abort event.");
+ shouldBeNonNull("trans.error");
+ // FIXME: Test for a specific error here, when supported.
+ shouldNotBe("trans.error.name", "'AbortError'");
+ debug("");
+ finishJSTest();
+ };
+ };
+ };
+}
+
+test();
Modified: trunk/LayoutTests/storage/indexeddb/transaction-abort-expected.txt (122781 => 122782)
--- trunk/LayoutTests/storage/indexeddb/transaction-abort-expected.txt 2012-07-17 00:31:09 UTC (rev 122781)
+++ trunk/LayoutTests/storage/indexeddb/transaction-abort-expected.txt 2012-07-17 00:31:41 UTC (rev 122782)
@@ -23,10 +23,7 @@
store.add({x: 'value3', y: 'zzz3'}, 'key3')
PASS event.target.errorCode is DOMException.ABORT_ERR
PASS event.target.error.name is 'AbortError'
-Expecting exception from trans.error
-PASS Exception was thrown.
-PASS code is DOMException.INVALID_STATE_ERR
-PASS ename is 'InvalidStateError'
+PASS trans.error is null
PASS firstError is false
PASS secondError is false
PASS abortFired is false
@@ -36,17 +33,14 @@
PASS ename is 'TransactionInactiveError'
PASS event.target.errorCode is DOMException.ABORT_ERR
PASS event.target.error.name is 'AbortError'
-Expecting exception from trans.error
-PASS Exception was thrown.
-PASS code is DOMException.INVALID_STATE_ERR
-PASS ename is 'InvalidStateError'
+PASS trans.error is null
PASS firstError is true
PASS secondError is false
PASS abortFired is false
PASS firstError is true
PASS secondError is true
PASS abortFired is false
-PASS trans.error is firstDOMError
+PASS trans.error is null
Expecting exception from store.add({x: 'value5', y: 'zzz5'}, 'key5')
PASS Exception was thrown.
PASS code is IDBDatabaseException.TRANSACTION_INACTIVE_ERR
Added: trunk/LayoutTests/storage/indexeddb/transaction-error-expected.txt (0 => 122782)
--- trunk/LayoutTests/storage/indexeddb/transaction-error-expected.txt (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/transaction-error-expected.txt 2012-07-17 00:31:41 UTC (rev 122782)
@@ -0,0 +1,62 @@
+CONSOLE MESSAGE: line 92: Uncaught Error: This should *NOT* be caught!
+Test IDBTransaction.error cases.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB;
+
+dbname = self.location.pathname
+indexedDB.deleteDatabase(dbname)
+indexedDB.open(dbname)
+db = request.result
+db.setVersion('1')
+trans = event.target.result
+store = db.createObjectStore('storeName')
+store.add('value', 'key')
+
+trans = db.transaction('storeName')
+
+IDBTransaction.error should be null if transaction is not finished:
+PASS trans.error is null
+
+If IDBTransaction.abort() is explicitly called, IDBTransaction.error should be null:
+trans.abort()
+PASS trans.error is null
+
+If the transaction is aborted due to a request error that is not prevented, IDBTransaction.error should match:
+trans = db.transaction('storeName', 'readwrite')
+request = trans.objectStore('storeName').add('value2', 'key')
+PASS request.errorCode is IDBDatabaseException.CONSTRAINT_ERR
+PASS request.error.name is 'ConstraintError'
+request_error = request.error
+Transaction received abort event.
+PASS trans.error is non-null.
+PASS trans.error is request_error
+
+If the transaction is aborted due to an exception thrown from event callback, IDBTransaction.error should be AbortError:
+trans = db.transaction('storeName', 'readwrite')
+request = trans.objectStore('storeName').add('value2', 'key')
+PASS request.errorCode is IDBDatabaseException.CONSTRAINT_ERR
+PASS request.error.name is 'ConstraintError'
+Throwing exception...
+Transaction received abort event.
+PASS trans.error is non-null.
+PASS trans.error.name is 'AbortError'
+
+If the transaction is aborted due to an error during commit, IDBTransaction.error should reflect that error:
+trans = db.transaction('storeName', 'readwrite')
+request = trans.objectStore('storeName').add({id: 1}, 'record1')
+request = trans.objectStore('storeName').add({id: 1}, 'record2')
+request = db.setVersion('2')
+trans = request.result
+This should fail due to the unique constraint:
+trans.objectStore('storeName').createIndex('indexName', 'id', {unique: true})
+Transaction received abort event.
+PASS trans.error is non-null.
+PASS trans.error.name is not 'AbortError'
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/storage/indexeddb/transaction-error.html (0 => 122782)
--- trunk/LayoutTests/storage/indexeddb/transaction-error.html (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/transaction-error.html 2012-07-17 00:31:41 UTC (rev 122782)
@@ -0,0 +1,10 @@
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (122781 => 122782)
--- trunk/Source/WebCore/ChangeLog 2012-07-17 00:31:09 UTC (rev 122781)
+++ trunk/Source/WebCore/ChangeLog 2012-07-17 00:31:41 UTC (rev 122782)
@@ -1,3 +1,34 @@
+2012-07-16 Joshua Bell <[email protected]>
+
+ IndexedDB: Implement spec updates to IDBTransaction.error
+ https://bugs.webkit.org/show_bug.cgi?id=91409
+
+ Reviewed by Tony Chang.
+
+ The Indexed DB spec was updated to resolve some edge cases around the
+ IDBTransaction.error attribute. It was agreed that accessing error should
+ never throw, error should be null if the transaction is not finished or
+ abort() was explicitly called, an appropriate error should be returned if
+ a commit failed, and a generic AbortError should be used if a request
+ callback throws. These cases are now handled per spec, except that a reason
+ is not provided for the commit failure (it's always UnknownError).
+
+ Test: storage/indexeddb/transaction-error.html
+ storage/indexeddb/transaction-abort.html
+
+ * Modules/indexeddb/IDBRequest.cpp:
+ (WebCore::IDBRequest::dispatchEvent): Refactor some nested if() blocks; don't
+ re-abort the transaction if dispatching in response to an abort.
+ (WebCore::IDBRequest::uncaughtExceptionInEventHandler): Abort transaction
+ only if not already aborting, and set it's error to AbortError.
+ * Modules/indexeddb/IDBTransaction.cpp:
+ (WebCore::IDBTransaction::onAbort): Set error if abort triggered by back end.
+ * Modules/indexeddb/IDBTransaction.h:
+ (WebCore::IDBTransaction::db): Move impl to header file.
+ (WebCore::IDBTransaction::error): Move impl to header file, simplify.
+ (IDBTransaction):
+ * Modules/indexeddb/IDBTransaction.idl: The error attribute no longer throws.
+
2012-07-16 Alec Flett <[email protected]>
IndexedDB: Introduce putWithIndexKeys and calculate them in the renderer
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp (122781 => 122782)
--- trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp 2012-07-17 00:31:09 UTC (rev 122781)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBRequest.cpp 2012-07-17 00:31:41 UTC (rev 122782)
@@ -439,25 +439,28 @@
if (cursorToNotify)
cursorToNotify->postSuccessHandlerCallback();
- if (m_transaction && event->type() != eventNames().blockedEvent) {
- // If an error event and the default wasn't prevented...
- if (dontPreventDefault && event->type() == eventNames().errorEvent) {
+ if (m_transaction) {
+ if (event->type() == eventNames().errorEvent && dontPreventDefault && !m_requestAborted) {
m_transaction->setError(m_error);
m_transaction->abort();
}
- m_transaction->backend()->didCompleteTaskEvents();
+
+ if (event->type() != eventNames().blockedEvent)
+ m_transaction->backend()->didCompleteTaskEvents();
+
+ if (m_readyState == DONE)
+ m_transaction->unregisterRequest(this);
}
- if (m_transaction && m_readyState == DONE)
- m_transaction->unregisterRequest(this);
-
return dontPreventDefault;
}
void IDBRequest::uncaughtExceptionInEventHandler()
{
- if (m_transaction)
- m_transaction->backend()->abort();
+ if (m_transaction && !m_requestAborted) {
+ m_transaction->setError(DOMError::create(IDBDatabaseException::getErrorName(IDBDatabaseException::IDB_ABORT_ERR)));
+ m_transaction->abort();
+ }
}
void IDBRequest::enqueueEvent(PassRefPtr<Event> event)
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp (122781 => 122782)
--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp 2012-07-17 00:31:09 UTC (rev 122781)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.cpp 2012-07-17 00:31:41 UTC (rev 122782)
@@ -122,20 +122,6 @@
return mode;
}
-IDBDatabase* IDBTransaction::db() const
-{
- return m_database.get();
-}
-
-PassRefPtr<DOMError> IDBTransaction::error(ExceptionCode& ec) const
-{
- if (m_state != Finished) {
- ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
- return 0;
- }
- return m_error;
-}
-
void IDBTransaction::setError(PassRefPtr<DOMError> error)
{
ASSERT(m_state != Finished);
@@ -276,6 +262,9 @@
ASSERT(m_state != Finished);
if (m_state != Finishing) {
+ // FIXME: Propagate true cause from back end (e.g. QuotaError, UnknownError, etc.)
+ setError(DOMError::create(IDBDatabaseException::getErrorName(IDBDatabaseException::UNKNOWN_ERR)));
+
// Abort was not triggered by front-end, so outstanding requests must
// be aborted now.
while (!m_requestList.isEmpty()) {
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h (122781 => 122782)
--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h 2012-07-17 00:31:09 UTC (rev 122781)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.h 2012-07-17 00:31:41 UTC (rev 122782)
@@ -75,10 +75,8 @@
// Implement the IDBTransaction IDL
const String& mode() const;
- IDBDatabase* db() const;
- PassRefPtr<DOMError> error(ExceptionCode&) const;
- void setError(PassRefPtr<DOMError>);
-
+ IDBDatabase* db() const { return m_database.get(); }
+ PassRefPtr<DOMError> error() const { return m_error; }
PassRefPtr<IDBObjectStore> objectStore(const String& name, ExceptionCode&);
void abort();
@@ -96,6 +94,7 @@
void objectStoreCreated(const String&, PassRefPtr<IDBObjectStore>);
void objectStoreDeleted(const String&);
void setActive(bool);
+ void setError(PassRefPtr<DOMError>);
DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
DEFINE_ATTRIBUTE_EVENT_LISTENER(complete);
Modified: trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.idl (122781 => 122782)
--- trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.idl 2012-07-17 00:31:09 UTC (rev 122781)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBTransaction.idl 2012-07-17 00:31:41 UTC (rev 122782)
@@ -39,13 +39,13 @@
// Properties
readonly attribute DOMString mode;
readonly attribute IDBDatabase db;
- readonly attribute DOMError error
- getter raises (IDBDatabaseException);
+ readonly attribute DOMError error;
// Methods
IDBObjectStore objectStore (in DOMString name)
raises (IDBDatabaseException);
void abort ();
+
// Events
attribute EventListener onabort;
attribute EventListener oncomplete;