Title: [131466] trunk/LayoutTests
Revision
131466
Author
[email protected]
Date
2012-10-16 09:52:26 -0700 (Tue, 16 Oct 2012)

Log Message

IndexedDB: setTimeout in layout tests causes flakiness in multiprocess ports
https://bugs.webkit.org/show_bug.cgi?id=98949

Reviewed by Tony Chang.

In multiprocess ports with asynchronous IPC, events and timers may race causing script
callbacks to execute in different orders.

Eliminate the uses of setTimeout() where the intent is to have code delayed but may
race with a pending event.

* fast/js/resources/js-test-pre.js:
(evalAndLog) Added quiet flag.
* storage/indexeddb/deletedatabase-blocked-expected.txt:
* storage/indexeddb/deletedatabase-delayed-by-open-and-versionchange-expected.txt:
* storage/indexeddb/deletedatabase-delayed-by-versionchange-expected.txt:
* storage/indexeddb/intversion-close-between-events-expected.txt:
* storage/indexeddb/resources/deletedatabase-blocked.js: Remove setTimeout.
(test.request.onsuccess.openOnSuccess.h.onversionchange):
(test.request.onsuccess.openOnSuccess.request.onblocked):
* storage/indexeddb/resources/deletedatabase-delayed-by-open-and-versionchange.js: Remove setTimeout.
(test.request.onsuccess.openOnSuccess.h.onversionchange):
(test.request.onsuccess.openOnSuccess.request.onblocked):
* storage/indexeddb/resources/deletedatabase-delayed-by-versionchange.js: Remove setTimeout.
(test.request.onsuccess.openOnSuccess.h.onversionchange):
(test.request.onsuccess.openOnSuccess.request.onsuccess.h2OpenOnSuccess.request.onblocked):
* storage/indexeddb/resources/intversion-close-between-events.js: Test was intended to call db.close()
between "complete" and "success" but in single process ports this is not possible, and in multi-process
ports is not reliable. To make the test not flaky and watch out for regressions in this edge case, it
is changed to have minimal logging.
(deleteSuccess):
(upgradeNeeded.transaction.oncomplete):
(upgradeNeeded):
(closeDB):
(openSuccess):
(checkFinished):
* storage/indexeddb/resources/intversion-close-in-oncomplete.js: Log on error rather than timing out.
(deleteSuccess):
* storage/indexeddb/resources/setversion-blocked.js: Removed setTimeout.
(test.request.onsuccess.h1OpenOnSuccess.request.onsuccess.h2OpenOnSuccess.h2.onversionchange):
(test.request.onsuccess.h1OpenOnSuccess.request.onsuccess.h2OpenOnSuccess.request.onblocked):
* storage/indexeddb/resources/shared.js:
(evalAndExpectException) Added quiet flag.
* storage/indexeddb/setversion-blocked-expected.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (131465 => 131466)


--- trunk/LayoutTests/ChangeLog	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/ChangeLog	2012-10-16 16:52:26 UTC (rev 131466)
@@ -1,3 +1,50 @@
+2012-10-16  Joshua Bell  <[email protected]>
+
+        IndexedDB: setTimeout in layout tests causes flakiness in multiprocess ports
+        https://bugs.webkit.org/show_bug.cgi?id=98949
+
+        Reviewed by Tony Chang.
+
+        In multiprocess ports with asynchronous IPC, events and timers may race causing script
+        callbacks to execute in different orders.
+
+        Eliminate the uses of setTimeout() where the intent is to have code delayed but may
+        race with a pending event.
+
+        * fast/js/resources/js-test-pre.js:
+        (evalAndLog) Added quiet flag.
+        * storage/indexeddb/deletedatabase-blocked-expected.txt:
+        * storage/indexeddb/deletedatabase-delayed-by-open-and-versionchange-expected.txt:
+        * storage/indexeddb/deletedatabase-delayed-by-versionchange-expected.txt:
+        * storage/indexeddb/intversion-close-between-events-expected.txt:
+        * storage/indexeddb/resources/deletedatabase-blocked.js: Remove setTimeout.
+        (test.request.onsuccess.openOnSuccess.h.onversionchange):
+        (test.request.onsuccess.openOnSuccess.request.onblocked):
+        * storage/indexeddb/resources/deletedatabase-delayed-by-open-and-versionchange.js: Remove setTimeout.
+        (test.request.onsuccess.openOnSuccess.h.onversionchange):
+        (test.request.onsuccess.openOnSuccess.request.onblocked):
+        * storage/indexeddb/resources/deletedatabase-delayed-by-versionchange.js: Remove setTimeout.
+        (test.request.onsuccess.openOnSuccess.h.onversionchange):
+        (test.request.onsuccess.openOnSuccess.request.onsuccess.h2OpenOnSuccess.request.onblocked):
+        * storage/indexeddb/resources/intversion-close-between-events.js: Test was intended to call db.close()
+        between "complete" and "success" but in single process ports this is not possible, and in multi-process
+        ports is not reliable. To make the test not flaky and watch out for regressions in this edge case, it
+        is changed to have minimal logging.
+        (deleteSuccess):
+        (upgradeNeeded.transaction.oncomplete):
+        (upgradeNeeded):
+        (closeDB):
+        (openSuccess):
+        (checkFinished):
+        * storage/indexeddb/resources/intversion-close-in-oncomplete.js: Log on error rather than timing out.
+        (deleteSuccess):
+        * storage/indexeddb/resources/setversion-blocked.js: Removed setTimeout.
+        (test.request.onsuccess.h1OpenOnSuccess.request.onsuccess.h2OpenOnSuccess.h2.onversionchange):
+        (test.request.onsuccess.h1OpenOnSuccess.request.onsuccess.h2OpenOnSuccess.request.onblocked):
+        * storage/indexeddb/resources/shared.js:
+        (evalAndExpectException) Added quiet flag.
+        * storage/indexeddb/setversion-blocked-expected.txt:
+
 2012-10-16  Takashi Sakamoto  <[email protected]>
 
         [Meta] [Shadow] contenteditable attribute for distributed nodes.

Modified: trunk/LayoutTests/fast/js/resources/js-test-pre.js (131465 => 131466)


--- trunk/LayoutTests/fast/js/resources/js-test-pre.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/fast/js/resources/js-test-pre.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -145,13 +145,14 @@
     else return "" + v;
 }
 
-function evalAndLog(_a)
+function evalAndLog(_a, _quiet)
 {
   if (typeof _a != "string")
     debug("WARN: tryAndLog() expects a string argument");
 
   // Log first in case things go horribly wrong or this causes a sync event.
-  debug(_a);
+  if (!_quiet)
+    debug(_a);
 
   var _av;
   try {
@@ -527,7 +528,6 @@
             workerPort = e.ports[0];
             workerPort._onmessage_ = function(event)
             {
-                
                 var colon = event.data.indexOf(":");
                 if (colon == -1) {
                     testFailed("Unrecognized message to shared worker: " + event.data);

Modified: trunk/LayoutTests/storage/indexeddb/deletedatabase-blocked-expected.txt (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/deletedatabase-blocked-expected.txt	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/deletedatabase-blocked-expected.txt	2012-10-16 16:52:26 UTC (rev 131466)
@@ -16,12 +16,9 @@
 onVersionChange():
 old = 1
 new = ""
-scheduling timeout to close
 
 deleteDatabaseOnBlocked():
 blockedEventFired = true
-
-timeoutCallback():
 h.close()
 
 deleteDatabaseOnSuccess():

Modified: trunk/LayoutTests/storage/indexeddb/deletedatabase-delayed-by-open-and-versionchange-expected.txt (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/deletedatabase-delayed-by-open-and-versionchange-expected.txt	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/deletedatabase-delayed-by-open-and-versionchange-expected.txt	2012-10-16 16:52:26 UTC (rev 131466)
@@ -24,11 +24,8 @@
 onVersionChange():
 old = "1"
 new = ""
-scheduling timeout to close
 
 deleteDatabaseOnBlocked():
-
-timeoutCallback():
 h.close()
 
 deleteDatabaseOnSuccess():

Modified: trunk/LayoutTests/storage/indexeddb/deletedatabase-delayed-by-versionchange-expected.txt (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/deletedatabase-delayed-by-versionchange-expected.txt	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/deletedatabase-delayed-by-versionchange-expected.txt	2012-10-16 16:52:26 UTC (rev 131466)
@@ -39,12 +39,9 @@
 onVersionChange():
 old = "1"
 new = ""
-scheduling timeout to close
 
 deleteDatabaseOnBlocked():
 deleteDatabaseBlockedEventFired = true
-
-timeoutCallback():
 h.close()
 
 deleteDatabaseOnSuccess():

Modified: trunk/LayoutTests/storage/indexeddb/intversion-close-between-events-expected.txt (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/intversion-close-between-events-expected.txt	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/intversion-close-between-events-expected.txt	2012-10-16 16:52:26 UTC (rev 131466)
@@ -7,30 +7,33 @@
 
 dbname = "intversion-close-between-events.html"
 indexedDB.deleteDatabase(dbname)
+
+deleteSuccess():
 request = indexedDB.open(dbname, 7)
 
-
 upgradeNeeded():
 db = event.target.result
 PASS event.newVersion is 7
 db.createObjectStore('objectstore')
 transaction = event.target.transaction
 
-transaction.oncomplete:
+transactionComplete():
 sawTransactionComplete = true
+
+Now try and close the database after oncomplete but before onsuccess.
+This will not happen in single process ports. In multi-process ports
+it may and is fine; but flaky crashes would indicate a regression.
+
 setTimeout(closeDB, 0)
 
-openSuccess():
-PASS didCallCloseDB is false
+checkFinished():
+Not done yet...
+
+checkFinished():
+PASS didCallCloseDB is true
 PASS sawTransactionComplete is true
-db = event.target.result
 PASS db.version is 7
 PASS db.objectStoreNames.length is 1
-db.transaction(db.objectStoreNames)
-
-closeDB():
-didCallCloseDB = true
-db.close()
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/storage/indexeddb/mozilla/resources/create-index-unique.js (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/mozilla/resources/create-index-unique.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/mozilla/resources/create-index-unique.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -38,7 +38,7 @@
 
     indexName = "1";
     indexKeyPath = "unique_value";
-    index = evalAndLog("index = objectStore.createIndex(indexName, indexKeyPath, { unique: true });", "IDBDatabaseException.CONSTRAINT_ERR");
+    index = evalAndLog("index = objectStore.createIndex(indexName, indexKeyPath, { unique: true });");
     shouldBe("index.name", "indexName");
     shouldBe("index.keyPath", "indexKeyPath");
     shouldBe("index.unique", "true");

Modified: trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-blocked.js (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-blocked.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-blocked.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -22,25 +22,14 @@
             preamble(evt);
             debug("old = " + JSON.stringify(event.target.version));
             debug("new = " + JSON.stringify(event.version));
+       };
 
-            debug("scheduling timeout to close");
-            // This setTimeout() is used to move the close call outside of the event dispatch
-            // callback. Per spec, a blocked event should only fire if connections are still
-            // open after the versionchange event dispatch is complete.
-            // FIXME: There is potential for test flakiness in the timing between when the
-            // timeout runs and when the blocked event is dispatched. Move the close call
-            // into or after the blocked event handler.
-            setTimeout(function timeoutCallback() {
-                preamble();
-                evalAndLog("h.close()");
-            }, 0);
-        };
-
         request = evalAndLog("indexedDB.deleteDatabase(dbname)");
         request._onerror_ = unexpectedErrorCallback;
         request._onblocked_ = function deleteDatabaseOnBlocked(evt) {
             preamble(evt);
             evalAndLog("blockedEventFired = true");
+            evalAndLog("h.close()");
         };
         request._onsuccess_ = function deleteDatabaseOnSuccess(evt) {
             preamble(evt);

Modified: trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-delayed-by-open-and-versionchange.js (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-delayed-by-open-and-versionchange.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-delayed-by-open-and-versionchange.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -23,18 +23,6 @@
             preamble(evt);
             debug("old = " + JSON.stringify(event.target.version));
             debug("new = " + JSON.stringify(event.version));
-
-            debug("scheduling timeout to close");
-            // This setTimeout() is used to move the close call outside of the event dispatch
-            // callback. Per spec, a blocked event should only fire if connections are still
-            // open after the versionchange event dispatch is complete.
-            // FIXME: There is potential for test flakiness in the timing between when the
-            // timeout runs and when the blocked event is dispatched. Move the close call
-            // into or after the blocked event handler.
-            setTimeout(function timeoutCallback() {
-                preamble();
-                evalAndLog("h.close()");
-            }, 0);
         };
 
         request = evalAndLog("h.setVersion(String(ver++))");
@@ -55,6 +43,8 @@
         request._onerror_ = unexpectedErrorCallback;
         request._onblocked_ = function deleteDatabaseOnBlocked(evt) {
             preamble(evt);
+
+            evalAndLog("h.close()");
         };
         request._onsuccess_ = function deleteDatabaseOnSuccess(evt) {
             preamble(evt);

Modified: trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-delayed-by-versionchange.js (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-delayed-by-versionchange.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/resources/deletedatabase-delayed-by-versionchange.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -26,18 +26,6 @@
             preamble(evt);
             debug("old = " + JSON.stringify(event.target.version));
             debug("new = " + JSON.stringify(event.version));
-
-            debug("scheduling timeout to close");
-            // This setTimeout() is used to move the close call outside of the event dispatch
-            // callback. Per spec, a blocked event should only fire if connections are still
-            // open after the versionchange event dispatch is complete.
-            // FIXME: There is potential for test flakiness in the timing between when the
-            // timeout runs and when the blocked event is dispatched. Move the close call
-            // into or after the blocked event handler.
-            setTimeout(function timeoutCallback() {
-                preamble();
-                evalAndLog("h.close()");
-            }, 0);
         };
 
         request = evalAndLog("indexedDB.open(dbname)");
@@ -93,6 +81,8 @@
             request._onblocked_ = function deleteDatabaseOnBlocked(evt) {
                 preamble(evt);
                 evalAndLog("deleteDatabaseBlockedEventFired = true");
+
+                evalAndLog("h.close()");
             };
             request._onsuccess_ = function deleteDatabaseOnSuccess(evt) {
                 preamble(evt);

Modified: trunk/LayoutTests/storage/indexeddb/resources/intversion-close-between-events.js (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/resources/intversion-close-between-events.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/resources/intversion-close-between-events.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -16,58 +16,78 @@
 }
 
 function deleteSuccess(evt) {
+    preamble(evt);
+
     evalAndLog("request = indexedDB.open(dbname, 7)");
     request._onsuccess_ = openSuccess;
     request._onupgradeneeded_ = upgradeNeeded;
     request._onblocked_ = unexpectedBlockedCallback;
-    debug("");
+    request._onerror_ = unexpectedErrorCallback;
 }
 
 var sawTransactionComplete = false;
 function upgradeNeeded(evt)
 {
-    event = evt;
-    debug("");
-    debug("upgradeNeeded():");
+    preamble(evt);
     evalAndLog("db = event.target.result");
     shouldBe("event.newVersion", "7");
     evalAndLog("db.createObjectStore('objectstore')");
 
     evalAndLog("transaction = event.target.transaction");
     transaction._onabort_ = unexpectedAbortCallback;
-    transaction._oncomplete_ = function() {
+    transaction._oncomplete_ = function transactionComplete(evt) {
+        preamble(evt);
+        evalAndLog("sawTransactionComplete = true");
+
         debug("");
-        debug("transaction.oncomplete:");
-        evalAndLog("sawTransactionComplete = true");
+        debug("Now try and close the database after oncomplete but before onsuccess.");
+        debug("This will not happen in single process ports. In multi-process ports");
+        debug("it may and is fine; but flaky crashes would indicate a regression.");
+        debug("");
+
         evalAndLog("setTimeout(closeDB, 0)");
-    }
+    };
 }
 
 var didCallCloseDB = false;
+var didGetOpenSuccess = false;
+
 function closeDB()
 {
-    debug("");
-    debug("closeDB():");
-    evalAndLog("didCallCloseDB = true");
-    evalAndLog("db.close()");
-    finishJSTest();
+    db.close();
+    didCallCloseDB = true;
+    checkFinished();
 }
 
 function openSuccess(evt)
 {
-    event = evt;
-    debug("");
-    debug("openSuccess():");
-    shouldBeFalse("didCallCloseDB");
+    didGetOpenSuccess = true;
+
+    var quiet = true;
+    if (didCallCloseDB) {
+        evalAndExpectException("db.transaction(db.objectStoreNames)", "DOMException.INVALID_STATE_ERR", "'InvalidStateError'", quiet);
+    } else {
+        evalAndLog("db.transaction(db.objectStoreNames)", quiet);
+    }
+
+    checkFinished();
+}
+
+function checkFinished()
+{
+    preamble();
+
+    if (!didCallCloseDB || !didGetOpenSuccess) {
+        debug("Not done yet...");
+        return;
+    }
+
+    shouldBeTrue("didCallCloseDB");
     shouldBeTrue("sawTransactionComplete");
-    db = evalAndLog("db = event.target.result");
     shouldBe('db.version', "7");
-    if (db.version !== 7) {
-        finishJSTest();
-        return;
-    }
     shouldBe("db.objectStoreNames.length", "1");
-    evalAndLog("db.transaction(db.objectStoreNames)");
+
+    finishJSTest();
 }
 
 test();

Modified: trunk/LayoutTests/storage/indexeddb/resources/intversion-close-in-oncomplete.js (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/resources/intversion-close-in-oncomplete.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/resources/intversion-close-in-oncomplete.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -20,6 +20,7 @@
     request._onsuccess_ = openSuccess;
     request._onupgradeneeded_ = upgradeNeeded;
     request._onblocked_ = unexpectedBlockedCallback;
+    request._onerror_ = unexpectedErrorCallback;
 }
 
 var sawTransactionComplete = false;

Modified: trunk/LayoutTests/storage/indexeddb/resources/setversion-blocked.js (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/resources/setversion-blocked.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/resources/setversion-blocked.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -32,18 +32,6 @@
                 preamble(evt);
                 debug("old = " + JSON.stringify(event.target.version));
                 debug("new = " + JSON.stringify(event.version));
-
-                debug("scheduling timeout to close h2");
-                // This setTimeout() is used to move the close call outside of the event dispatch
-                // callback. Per spec, a blocked event should only fire if connections are still
-                // open after the versionchange event dispatch is complete.
-                // FIXME: There is potential for test flakiness in the timing between when the
-                // timeout runs and when the blocked event is dispatched. Move the close call
-                // into or after the blocked event handler.
-                setTimeout(function timeoutCallback() {
-                    preamble();
-                    evalAndLog("h2.close()");
-                }, 0);
             };
 
             request = evalAndLog("h1.setVersion(String(ver++))");
@@ -51,6 +39,7 @@
             request._onblocked_ = function h1SetVersionOnBlocked(evt) {
                 preamble(evt);
                 evalAndLog("blockedEventFired = true");
+                evalAndLog("h2.close()");
             };
             request._onsuccess_ = function h1SetVersionOnSuccess(evt) {
                 preamble(evt);

Modified: trunk/LayoutTests/storage/indexeddb/resources/shared.js (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/resources/shared.js	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/resources/shared.js	2012-10-16 16:52:26 UTC (rev 131466)
@@ -82,19 +82,21 @@
     finishJSTest();
 }
 
-function evalAndExpectException(cmd, exceptionCode, exceptionName)
+function evalAndExpectException(cmd, exceptionCode, exceptionName, _quiet)
 {
-    debug("Expecting exception from " + cmd);
+    if (!_quiet)
+        debug("Expecting exception from " + cmd);
     try {
         eval(cmd);
         testFailed("No exception thrown! Should have been " + exceptionCode);
     } catch (e) {
         code = e.code;
-        testPassed("Exception was thrown.");
-        shouldBe("code", exceptionCode);
+        if (!_quiet)
+            testPassed("Exception was thrown.");
+        shouldBe("code", exceptionCode, _quiet);
         if (exceptionName) {
             ename = e.name;
-            shouldBe("ename", exceptionName);
+            shouldBe("ename", exceptionName, _quiet);
         }
     }
 }

Modified: trunk/LayoutTests/storage/indexeddb/setversion-blocked-expected.txt (131465 => 131466)


--- trunk/LayoutTests/storage/indexeddb/setversion-blocked-expected.txt	2012-10-16 16:42:02 UTC (rev 131465)
+++ trunk/LayoutTests/storage/indexeddb/setversion-blocked-expected.txt	2012-10-16 16:52:26 UTC (rev 131466)
@@ -22,12 +22,9 @@
 h2OnVersionChange():
 old = 1
 new = "1"
-scheduling timeout to close h2
 
 h1SetVersionOnBlocked():
 blockedEventFired = true
-
-timeoutCallback():
 h2.close()
 
 h1SetVersionOnSuccess():
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to