- Revision
- 106165
- Author
- jsb...@chromium.org
- Date
- 2012-01-27 16:04:52 -0800 (Fri, 27 Jan 2012)
Log Message
IndexedDB does not update r/w index cursors that are mutated during iteration
https://bugs.webkit.org/show_bug.cgi?id=59822
Added tests to verify that index cursors see updates made to an object store while
iterating, assuming the cursor and updates occur within the same transaction.
Reviewed by Tony Chang.
* storage/indexeddb/mozilla/cursor-mutation-expected.txt: Added.
* storage/indexeddb/mozilla/cursor-mutation.html: Added.
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (106164 => 106165)
--- trunk/LayoutTests/ChangeLog 2012-01-27 23:42:04 UTC (rev 106164)
+++ trunk/LayoutTests/ChangeLog 2012-01-28 00:04:52 UTC (rev 106165)
@@ -1,3 +1,16 @@
+2012-01-27 Joshua Bell <jsb...@chromium.org>
+
+ IndexedDB does not update r/w index cursors that are mutated during iteration
+ https://bugs.webkit.org/show_bug.cgi?id=59822
+
+ Added tests to verify that index cursors see updates made to an object store while
+ iterating, assuming the cursor and updates occur within the same transaction.
+
+ Reviewed by Tony Chang.
+
+ * storage/indexeddb/mozilla/cursor-mutation-expected.txt: Added.
+ * storage/indexeddb/mozilla/cursor-mutation.html: Added.
+
2012-01-27 Raymond Toy <r...@google.com>
Round time to sample frame
Added: trunk/LayoutTests/storage/indexeddb/mozilla/cursor-mutation-expected.txt (0 => 106165)
--- trunk/LayoutTests/storage/indexeddb/mozilla/cursor-mutation-expected.txt (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/mozilla/cursor-mutation-expected.txt 2012-01-28 00:04:52 UTC (rev 106165)
@@ -0,0 +1,138 @@
+Test IndexedDB's cursor mutation
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB
+PASS indexedDB == null is false
+IDBDatabaseException = window.IDBDatabaseException || window.webkitIDBDatabaseException
+PASS IDBDatabaseException == null is false
+IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction
+PASS IDBTransaction == null is false
+
+indexedDB.deleteDatabase(name)
+indexedDB.open(name)
+db = event.target.result
+db.setVersion('1')
+
+setupObjectStoreAndCreateIndex():
+trans = request.result
+objectStore = db.createObjectStore('foo', { keyPath: 'ss' })
+index = objectStore.createIndex('name', 'name', { unique: true })
+objectStoreData = [
+ { ss: '237-23-7732', name: 'Bob' },
+ { ss: '237-23-7733', name: 'Ann' },
+ { ss: '237-23-7734', name: 'Ron' },
+ { ss: '237-23-7735', name: 'Sue' },
+ { ss: '237-23-7736', name: 'Joe' },
+ { ss: '237-23-7737', name: 'Pat' }
+ ]
+objectStore.add(objectStoreData[0])
+objectStore.add(objectStoreData[1])
+objectStore.add(objectStoreData[2])
+objectStore.add(objectStoreData[3])
+objectStore.add(objectStoreData[4])
+trans._oncomplete_ = checkCursorResults
+
+setupCursor():
+count = 0
+sawAdded = false
+sawRemoved = false
+request = objectStore.openCursor()
+
+iterateCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Bob"
+sawRemoved = true
+count++
+cursor.continue()
+
+iterateCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Ann"
+count++
+cursor.continue()
+
+iterateCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Ron"
+count++
+cursor.continue()
+
+iterateCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Sue"
+count++
+cursor.continue()
+
+iterateCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Joe"
+count++
+cursor.continue()
+
+iterateCursor():
+cursor = event.target.result
+
+checkCursorResults():
+PASS count is objectStoreData.length - 1
+PASS sawAdded is false
+PASS sawRemoved is true
+
+setupMutatingCursor():
+count = 0
+sawAdded = false
+sawRemoved = false
+[objectStoreDataNameSort is an array of indexes into objectStoreData in alphabetical order by name]
+objectStoreDataNameSort = [ 1, 4, 5, 2, 3 ]
+
+trans = db.transaction('foo', IDBTransaction.READ_WRITE)
+objectStore = trans.objectStore('foo')
+request = objectStore.index('name').openCursor()
+trans._oncomplete_ = checkMutatingCursorResults
+
+iterateMutatingCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Ann"
+count++
+
+Mutating the object store:
+Removing Bob
+request = objectStore.delete(objectStoreData[0].ss)
+
+addFinalData():
+Adding Pat
+request = objectStore.add(objectStoreData[objectStoreData.length - 1])
+
+iterateMutatingCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Joe"
+count++
+
+iterateMutatingCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Pat"
+sawAdded = true
+count++
+
+iterateMutatingCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Ron"
+count++
+
+iterateMutatingCursor():
+cursor = event.target.result
+PASS cursor.value.name is "Sue"
+count++
+
+iterateMutatingCursor():
+cursor = event.target.result
+
+checkMutatingCursorResults():
+PASS count is objectStoreData.length - 1
+PASS sawAdded is true
+PASS sawRemoved is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/storage/indexeddb/mozilla/cursor-mutation.html (0 => 106165)
--- trunk/LayoutTests/storage/indexeddb/mozilla/cursor-mutation.html (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/mozilla/cursor-mutation.html 2012-01-28 00:04:52 UTC (rev 106165)
@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<!--
+ original test: http://mxr.mozilla.org/mozilla2.0/source/dom/indexedDB/test/test_cursor_mutation.html?force=1
+ license of original test:
+ " Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ "
+-->
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+
+description("Test IndexedDB's cursor mutation");
+if (window.layoutTestController)
+ layoutTestController.waitUntilDone();
+
+function test()
+{
+ indexedDB = evalAndLog("indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB");
+ shouldBeFalse("indexedDB == null");
+ IDBDatabaseException = evalAndLog("IDBDatabaseException = window.IDBDatabaseException || window.webkitIDBDatabaseException");
+ shouldBeFalse("IDBDatabaseException == null");
+ IDBTransaction = evalAndLog("IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction");
+ shouldBeFalse("IDBTransaction == null");
+
+ debug("");
+ name = 'cursor-mutation';
+ request = evalAndLog("indexedDB.deleteDatabase(name)");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = function () {
+ request = evalAndLog("indexedDB.open(name)");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = function () {
+ evalAndLog("db = event.target.result");
+ request = evalAndLog("db.setVersion('1')");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = setupObjectStoreAndCreateIndex;
+ };
+ };
+}
+
+function setupObjectStoreAndCreateIndex()
+{
+ debug("");
+ debug("setupObjectStoreAndCreateIndex():");
+
+ trans = evalAndLog("trans = request.result");
+
+ objectStore = evalAndLog("objectStore = db.createObjectStore('foo', { keyPath: 'ss' })");
+ index = evalAndLog("index = objectStore.createIndex('name', 'name', { unique: true })");
+ objectStoreData = evalAndLog("objectStoreData = [\n" +
+ // To be removed.
+" { ss: '237-23-7732', name: 'Bob' },\n" +
+
+ // Always present.
+" { ss: '237-23-7733', name: 'Ann' },\n" +
+" { ss: '237-23-7734', name: 'Ron' },\n" +
+" { ss: '237-23-7735', name: 'Sue' },\n" +
+" { ss: '237-23-7736', name: 'Joe' },\n" +
+
+ // To be added.
+" { ss: '237-23-7737', name: 'Pat' }\n" +
+" ]");
+
+ for (i = 0; i < objectStoreData.length - 1; i++) {
+ evalAndLog("objectStore.add(objectStoreData[" + i + "])");
+ }
+
+ evalAndLog("trans._oncomplete_ = checkCursorResults");
+ setupCursor();
+}
+
+function setupCursor()
+{
+ debug("");
+ debug("setupCursor():");
+
+ count = evalAndLog("count = 0");
+ sawAdded = evalAndLog("sawAdded = false");
+ sawRemoved = evalAndLog("sawRemoved = false");
+
+ request = evalAndLog("request = objectStore.openCursor()");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = iterateCursor;
+}
+
+function iterateCursor()
+{
+ debug("");
+ debug("iterateCursor():");
+ cursor = evalAndLog("cursor = event.target.result");
+ if (cursor) {
+ shouldBeEqualToString("cursor.value.name", objectStoreData[count].name);
+ if (cursor.value.name == objectStoreData[0].name) {
+ sawRemoved = evalAndLog("sawRemoved = true");
+ }
+ if (cursor.value.name == objectStoreData[objectStoreData.length - 1].name) {
+ sawAdded = evalAndLog("sawAdded = true");
+ }
+ evalAndLog("count++");
+ evalAndLog("cursor.continue()");
+ }
+}
+
+function checkCursorResults()
+{
+ debug("");
+ debug("checkCursorResults():");
+ shouldBe("count", "objectStoreData.length - 1");
+ shouldBe("sawAdded", "false");
+ shouldBe("sawRemoved", "true");
+
+ setupMutatingCursor();
+}
+
+function setupMutatingCursor()
+{
+ debug("");
+ debug("setupMutatingCursor():");
+
+ count = evalAndLog("count = 0");
+ sawAdded = evalAndLog("sawAdded = false");
+ sawRemoved = evalAndLog("sawRemoved = false");
+ debug("[objectStoreDataNameSort is an array of indexes into objectStoreData in alphabetical order by name]");
+ objectStoreDataNameSort = evalAndLog("objectStoreDataNameSort = [ 1, 4, 5, 2, 3 ]");
+
+ debug("");
+
+ trans = evalAndLog("trans = db.transaction('foo', IDBTransaction.READ_WRITE)");
+ objectStore = evalAndLog("objectStore = trans.objectStore('foo')");
+ request = evalAndLog("request = objectStore.index('name').openCursor()");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = iterateMutatingCursor;
+ evalAndLog("trans._oncomplete_ = checkMutatingCursorResults");
+}
+
+function iterateMutatingCursor()
+{
+ debug("");
+ debug("iterateMutatingCursor():");
+ cursor = evalAndLog("cursor = event.target.result");
+ if (cursor) {
+ shouldBeEqualToString("cursor.value.name", objectStoreData[objectStoreDataNameSort[count]].name);
+ if (cursor.value.name == objectStoreData[0].name) {
+ sawRemoved = evalAndLog("sawRemoved = true");
+ }
+ if (cursor.value.name == objectStoreData[objectStoreData.length - 1].name) {
+ sawAdded = evalAndLog("sawAdded = true");
+ }
+ evalAndLog("count++");
+
+ if (count == 1) {
+ debug("");
+ debug("Mutating the object store:");
+
+ debug("Removing " + objectStoreData[0].name);
+ request = evalAndLog("request = objectStore.delete(objectStoreData[0].ss)");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = addFinalData;
+
+ } else {
+ cursor.continue();
+ }
+ }
+}
+
+function addFinalData()
+{
+ debug("");
+ debug("addFinalData():");
+ debug("Adding " + objectStoreData[objectStoreData.length - 1].name);
+ request = evalAndLog("request = objectStore.add(objectStoreData[objectStoreData.length - 1])");
+ request._onerror_ = unexpectedErrorCallback;
+ request._onsuccess_ = function () {
+ cursor.continue();
+ }
+}
+
+function checkMutatingCursorResults()
+{
+ debug("");
+ debug("checkMutatingCursorResults():");
+ shouldBe("count", "objectStoreData.length - 1");
+ shouldBe("sawAdded", "true");
+ shouldBe("sawRemoved", "false");
+ done();
+}
+
+test();
+
+</script>
+</body>
+</html>
+