mirror of
https://github.com/servo/servo.git
synced 2025-08-25 07:08:21 +01:00
Update web-platform-tests to revision e8bfc205e36ad699601212cd50083870bad9a75d
This commit is contained in:
parent
65dd6d4340
commit
ccdb0a3458
1428 changed files with 118036 additions and 9786 deletions
|
@ -0,0 +1,382 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<meta name="timeout" content="long">
|
||||
<title>IDBCursor.continuePrimaryKey() - Exception Orders </title>
|
||||
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
|
||||
<link rel="help" href="http://w3c.github.io/IndexedDB/#dom-idbcursor-continueprimarykey">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support.js"></script>
|
||||
|
||||
<script>
|
||||
function setup_test_store(db) {
|
||||
var records = [ { iKey: "A", pKey: 1 },
|
||||
{ iKey: "A", pKey: 2 },
|
||||
{ iKey: "A", pKey: 3 },
|
||||
{ iKey: "A", pKey: 4 },
|
||||
{ iKey: "B", pKey: 5 },
|
||||
{ iKey: "B", pKey: 6 },
|
||||
{ iKey: "B", pKey: 7 },
|
||||
{ iKey: "C", pKey: 8 },
|
||||
{ iKey: "C", pKey: 9 },
|
||||
{ iKey: "D", pKey: 10 } ];
|
||||
|
||||
var store = db.createObjectStore("test", { keyPath: "pKey" });
|
||||
var index = store.createIndex("idx", "iKey");
|
||||
|
||||
for(var i = 0; i < records.length; i++) {
|
||||
store.add(records[i]);
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var index = store.index("idx");
|
||||
var cursor_rq = index.openCursor();
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
store.deleteIndex("idx");
|
||||
});
|
||||
txn.oncomplete = function() {
|
||||
assert_throws("TransactionInactiveError", function() {
|
||||
cursor.continuePrimaryKey("A", 4);
|
||||
}, "transaction-state check should precede deletion check");
|
||||
t.done();
|
||||
};
|
||||
},
|
||||
null,
|
||||
"TransactionInactiveError v.s. InvalidStateError(deleted index)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var cursor_rq = store.openCursor();
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
db.deleteObjectStore("test");
|
||||
|
||||
assert_throws("InvalidStateError", function() {
|
||||
cursor.continuePrimaryKey("A", 4);
|
||||
}, "deletion check should precede index source check");
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"InvalidStateError(deleted source) v.s. InvalidAccessError(incorrect source)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var index = store.index("idx");
|
||||
var cursor_rq = index.openCursor(null, "nextunique");
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
store.deleteIndex("idx");
|
||||
|
||||
assert_throws("InvalidStateError", function() {
|
||||
cursor.continuePrimaryKey("A", 4);
|
||||
}, "deletion check should precede cursor direction check");
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"InvalidStateError(deleted source) v.s. InvalidAccessError(incorrect direction)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = db.createObjectStore("test", {keyPath:"pKey"});
|
||||
var index = store.createIndex("idx", "iKey");
|
||||
|
||||
store.add({ iKey: "A", pKey: 1 });
|
||||
|
||||
var cursor_rq = index.openCursor(null, "nextunique");
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
if (e.target.result) {
|
||||
cursor = e.target.result;
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
assert_throws("InvalidAccessError", function() {
|
||||
cursor.continuePrimaryKey("A", 4);
|
||||
}, "direction check should precede got_value_flag check");
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"InvalidAccessError(incorrect direction) v.s. InvalidStateError(iteration complete)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = db.createObjectStore("test", {keyPath:"pKey"});
|
||||
var index = store.createIndex("idx", "iKey");
|
||||
|
||||
store.add({ iKey: "A", pKey: 1 });
|
||||
|
||||
var cursor_rq = index.openCursor(null, "nextunique");
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
if (!cursor) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
cursor.continue();
|
||||
|
||||
assert_throws("InvalidAccessError", function() {
|
||||
cursor.continuePrimaryKey("A", 4);
|
||||
}, "direction check should precede iteration ongoing check");
|
||||
t.done();
|
||||
}
|
||||
});
|
||||
},
|
||||
null,
|
||||
"InvalidAccessError(incorrect direction) v.s. InvalidStateError(iteration ongoing)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var cursor_rq = store.openCursor();
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
if (!cursor) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
cursor.continue();
|
||||
|
||||
assert_throws("InvalidAccessError", function() {
|
||||
cursor.continuePrimaryKey("A", 4);
|
||||
}, "index source check should precede iteration ongoing check");
|
||||
t.done();
|
||||
}
|
||||
});
|
||||
},
|
||||
null,
|
||||
"InvalidAccessError(incorrect source) v.s. InvalidStateError(iteration ongoing)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = db.createObjectStore("test", {keyPath:"pKey"});
|
||||
|
||||
store.add({ iKey: "A", pKey: 1 });
|
||||
|
||||
var cursor_rq = store.openCursor();
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
if (e.target.result) {
|
||||
cursor = e.target.result;
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
assert_throws("InvalidAccessError", function() {
|
||||
cursor.continuePrimaryKey("A", 4);
|
||||
}, "index source check should precede got_value_flag check");
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"InvalidAccessError(incorrect source) v.s. InvalidStateError(iteration complete)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var index = store.index("idx");
|
||||
var cursor_rq = index.openCursor();
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
if (!cursor) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
cursor.continue();
|
||||
|
||||
assert_throws("InvalidStateError", function() {
|
||||
cursor.continuePrimaryKey(null, 4);
|
||||
}, "iteration ongoing check should precede unset key check");
|
||||
t.done();
|
||||
}
|
||||
});
|
||||
},
|
||||
null,
|
||||
"InvalidStateError(iteration ongoing) v.s. DataError(unset key)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = db.createObjectStore("test", {keyPath:"pKey"});
|
||||
var index = store.createIndex("idx", "iKey");
|
||||
|
||||
store.add({ iKey: "A", pKey: 1 });
|
||||
|
||||
var cursor_rq = index.openCursor();
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
if (e.target.result) {
|
||||
cursor = e.target.result;
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
assert_throws("InvalidStateError", function() {
|
||||
cursor.continuePrimaryKey(null, 4);
|
||||
}, "got_value_flag check should precede unset key check");
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"InvalidStateError(iteration complete) v.s. DataError(unset key)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var index = store.index("idx");
|
||||
var cursor_rq = index.openCursor();
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
assert_throws("DataError", function() {
|
||||
cursor.continuePrimaryKey(null, 4);
|
||||
}, "DataError is expected if key is unset.");
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"DataError(unset key)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var index = store.index("idx");
|
||||
var cursor_rq = index.openCursor();
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
assert_throws("DataError", function() {
|
||||
cursor.continuePrimaryKey("A", null);
|
||||
}, "DataError is expected if primary key is unset.");
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"DataError(unset primary key)"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var index = store.index("idx");
|
||||
var cursor_rq = index.openCursor(IDBKeyRange.lowerBound("B"));
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
assert_equals(cursor.key, "B", "expected key");
|
||||
assert_equals(cursor.primaryKey, 5, "expected primary key");
|
||||
|
||||
assert_throws("DataError", function() {
|
||||
cursor.continuePrimaryKey("A", 6);
|
||||
}, "DataError is expected if key is lower then current one.");
|
||||
|
||||
assert_throws("DataError", function() {
|
||||
cursor.continuePrimaryKey("B", 5);
|
||||
}, "DataError is expected if primary key is equal to current one.");
|
||||
|
||||
assert_throws("DataError", function() {
|
||||
cursor.continuePrimaryKey("B", 4);
|
||||
}, "DataError is expected if primary key is lower than current one.");
|
||||
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"DataError(keys are lower then current one) in 'next' direction"
|
||||
);
|
||||
|
||||
indexeddb_test(
|
||||
function(t, db, txn) {
|
||||
var store = setup_test_store(db);
|
||||
var index = store.index("idx");
|
||||
var cursor_rq = index.openCursor(IDBKeyRange.upperBound("B"), "prev");
|
||||
var cursor;
|
||||
|
||||
cursor_rq.onerror = t.unreached_func('openCursor should succeed');
|
||||
cursor_rq.onsuccess = t.step_func(function(e) {
|
||||
cursor = e.target.result;
|
||||
assert_true(!!cursor, "acquire cursor");
|
||||
|
||||
assert_equals(cursor.key, "B", "expected key");
|
||||
assert_equals(cursor.primaryKey, 7, "expected primary key");
|
||||
|
||||
assert_throws("DataError", function() {
|
||||
cursor.continuePrimaryKey("C", 6);
|
||||
}, "DataError is expected if key is larger then current one.");
|
||||
|
||||
assert_throws("DataError", function() {
|
||||
cursor.continuePrimaryKey("B", 7);
|
||||
}, "DataError is expected if primary key is equal to current one.");
|
||||
|
||||
assert_throws("DataError", function() {
|
||||
cursor.continuePrimaryKey("B", 8);
|
||||
}, "DataError is expected if primary key is larger than current one.");
|
||||
|
||||
t.done();
|
||||
});
|
||||
},
|
||||
null,
|
||||
"DataError(keys are larger then current one) in 'prev' direction"
|
||||
);
|
||||
</script>
|
||||
|
||||
<div id="log"></div>
|
|
@ -0,0 +1,110 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: index renaming support in aborted transactions</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/IndexedDB/#dom-idbindex-name">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
const dbName = databaseName(testCase);
|
||||
let authorIndex = null, authorIndex2 = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
authorIndex = store.index('by_author');
|
||||
authorIndex.name = 'renamed_by_author';
|
||||
|
||||
transaction.abort();
|
||||
|
||||
assert_equals(
|
||||
authorIndex.name, 'by_author',
|
||||
'IDBIndex.name should not reflect the rename any more ' +
|
||||
'immediately after transaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'IDBObjectStore.indexNames should not reflect the rename any ' +
|
||||
'more immediately after transaction.abort() returns');
|
||||
})).then(event => {
|
||||
assert_equals(
|
||||
authorIndex.name, 'by_author',
|
||||
'IDBIndex.name should not reflect the rename any more after the ' +
|
||||
'versionchange transaction is aborted');
|
||||
|
||||
const request = indexedDB.open(dbName, 1);
|
||||
return requestWatcher(testCase, request).wait_for('success');
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'IDBDatabase.objectStoreNames should not reflect the rename ' +
|
||||
'after the versionchange transaction is aborted');
|
||||
|
||||
authorIndex2 = store.index('by_author');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, authorIndex2,
|
||||
'Aborting an index rename transaction should not change the ' +
|
||||
"index's records").then(() => database.close());
|
||||
}).then(() => {
|
||||
assert_equals(
|
||||
authorIndex.name, 'by_author',
|
||||
'IDBIndex used in aborted rename transaction should not reflect ' +
|
||||
'the rename after the transaction is aborted');
|
||||
assert_equals(authorIndex2.name, 'by_author',
|
||||
'IDBIndex obtained after an aborted rename transaction should ' +
|
||||
'not reflect the rename');
|
||||
});
|
||||
}, 'IndexedDB index rename in aborted transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
const dbName = databaseName(testCase);
|
||||
let authorIndex = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('not_books');
|
||||
authorIndex = store.createIndex('by_author', 'author');
|
||||
authorIndex.name = 'by_author_renamed';
|
||||
authorIndex.name = 'by_author_renamed_again';
|
||||
|
||||
transaction.abort();
|
||||
|
||||
assert_equals(
|
||||
authorIndex.name, 'by_author_renamed_again',
|
||||
'IDBIndex.name should reflect the last rename immediately after ' +
|
||||
'transaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should not reflect the creation or ' +
|
||||
'the rename immediately after transaction.abort() returns');
|
||||
})).then(event => {
|
||||
assert_equals(
|
||||
authorIndex.name, 'by_author_renamed_again',
|
||||
'IDBIndex.name should reflect the last rename after the ' +
|
||||
'versionchange transaction is aborted');
|
||||
|
||||
const request = indexedDB.open(dbName, 1);
|
||||
return requestWatcher(testCase, request).wait_for('success');
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
const transaction = database.transaction('not_books', 'readonly');
|
||||
const store = transaction.objectStore('not_books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBDatabase.objectStoreNames should not reflect the creation or ' +
|
||||
'the rename after the versionchange transaction is aborted');
|
||||
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB index creation and rename in an aborted transaction');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,130 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: index renaming error handling</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/IndexedDB/#dom-idbindex-name">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
store.deleteIndex('by_author');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.name = 'renamed_by_author');
|
||||
})).then(database => database.close());
|
||||
}, 'IndexedDB deleted index rename throws');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.name = 'renamed_by_author');
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB index rename throws in a readonly transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readwrite');
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.name = 'renamed_by_author');
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB index rename throws in a readwrite transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
let authorIndex = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
const store = createBooksStore(testCase, database);
|
||||
authorIndex = store.index('by_author');
|
||||
}).then(database => {
|
||||
assert_throws(
|
||||
'TransactionInactiveError',
|
||||
() => authorIndex.name = 'renamed_by_author');
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB index rename throws in an inactive transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
|
||||
assert_throws('ConstraintError', () => index.name = 'by_title');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'An index rename that throws an exception should not change the ' +
|
||||
"index's IDBObjectStore.indexNames");
|
||||
})).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'Committing a transaction with a failed store rename attempt ' +
|
||||
"should not change the index's IDBObjectStore.indexNames");
|
||||
const index = store.index('by_author');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, index,
|
||||
'Committing a transaction with a failed rename attempt should ' +
|
||||
"not change the index's contents").then(() => database.close());
|
||||
});
|
||||
}, 'IndexedDB index rename to the name of another index throws');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
|
||||
assert_throws(
|
||||
{ name: 'Custom stringifying error' },
|
||||
() => {
|
||||
index.name = {
|
||||
toString: () => { throw { name: 'Custom stringifying error'}; }
|
||||
};
|
||||
}, 'IDBObjectStore rename should re-raise toString() exception');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'An index rename that throws an exception should not change the ' +
|
||||
"index's IDBObjectStore.indexNames");
|
||||
})).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'Committing a transaction with a failed store rename attempt ' +
|
||||
"should not change the index's IDBObjectStore.indexNames");
|
||||
const index = store.index('by_author');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, index,
|
||||
'Committing a transaction with a failed rename attempt should ' +
|
||||
"not change the index's contents").then(() => database.close());
|
||||
});
|
||||
}, 'IndexedDB index rename handles exceptions when stringifying names');
|
||||
|
||||
</script>
|
298
tests/wpt/web-platform-tests/IndexedDB/idbindex-rename.html
Normal file
298
tests/wpt/web-platform-tests/IndexedDB/idbindex-rename.html
Normal file
|
@ -0,0 +1,298 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: index renaming support</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/IndexedDB/#dom-idbindex-name">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
let authorIndex = null, authorIndex2 = null;
|
||||
let renamedAuthorIndex = null, renamedAuthorIndex2 = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
const store = createBooksStore(testCase, database);
|
||||
authorIndex = store.index('by_author');
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'Test setup should have created two indexes');
|
||||
authorIndex2 = store.index('by_author');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, authorIndex2,
|
||||
'The index should have the expected contents before any renaming').
|
||||
then(() => database.close());
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
renamedAuthorIndex = store.index('by_author');
|
||||
renamedAuthorIndex.name = 'renamed_by_author';
|
||||
|
||||
assert_equals(
|
||||
renamedAuthorIndex.name, 'renamed_by_author',
|
||||
'IDBIndex name should change immediately after a rename');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_title', 'renamed_by_author'],
|
||||
'IDBObjectStore.indexNames should immediately reflect the rename');
|
||||
assert_equals(
|
||||
store.index('renamed_by_author'), renamedAuthorIndex,
|
||||
'IDBObjectStore.index should return the renamed index store when ' +
|
||||
'queried using the new name immediately after the rename');
|
||||
assert_throws(
|
||||
'NotFoundError', () => store.index('by_author'),
|
||||
'IDBObjectStore.index should throw when queried using the ' +
|
||||
"renamed index's old name immediately after the rename");
|
||||
})).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_title', 'renamed_by_author'],
|
||||
'IDBObjectStore.indexNames should still reflect the rename after ' +
|
||||
'the versionchange transaction commits');
|
||||
renamedAuthorIndex2 = store.index('renamed_by_author');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, renamedAuthorIndex2,
|
||||
'Renaming an index should not change its contents').then(
|
||||
() => database.close());
|
||||
}).then(() => {
|
||||
assert_equals(
|
||||
authorIndex.name, 'by_author',
|
||||
'IDBIndex obtained before the rename transaction should not ' +
|
||||
'reflect the rename');
|
||||
assert_equals(
|
||||
authorIndex2.name, 'by_author',
|
||||
'IDBIndex obtained before the rename transaction should not ' +
|
||||
'reflect the rename');
|
||||
assert_equals(
|
||||
renamedAuthorIndex.name, 'renamed_by_author',
|
||||
'IDBIndex used in the rename transaction should keep reflecting ' +
|
||||
'the new name after the transaction is committed');
|
||||
assert_equals(
|
||||
renamedAuthorIndex2.name, 'renamed_by_author',
|
||||
'IDBIndex obtained after the rename transaction should reflect ' +
|
||||
'the new name');
|
||||
});
|
||||
}, 'IndexedDB index rename in new transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
let renamedAuthorIndex = null, renamedAuthorIndex2 = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
const store = createBooksStore(testCase, database);
|
||||
renamedAuthorIndex = store.index('by_author');
|
||||
renamedAuthorIndex.name = 'renamed_by_author';
|
||||
|
||||
assert_equals(
|
||||
renamedAuthorIndex.name, 'renamed_by_author',
|
||||
'IDBIndex name should change immediately after a rename');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_title', 'renamed_by_author'],
|
||||
'IDBObjectStore.indexNames should immediately reflect the rename');
|
||||
assert_equals(
|
||||
store.index('renamed_by_author'), renamedAuthorIndex,
|
||||
'IDBObjectStore.index should return the renamed index store when ' +
|
||||
'queried using the new name immediately after the rename');
|
||||
assert_throws(
|
||||
'NotFoundError', () => store.index('by_author'),
|
||||
'IDBObjectStore.index should throw when queried using the ' +
|
||||
"renamed index's old name immediately after the rename");
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_title', 'renamed_by_author'],
|
||||
'IDBObjectStore.indexNames should still reflect the rename after ' +
|
||||
'the versionchange transaction commits');
|
||||
renamedAuthorIndex2 = store.index('renamed_by_author');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, renamedAuthorIndex2,
|
||||
'Renaming an index should not change its contents').then(
|
||||
() => database.close());
|
||||
}).then(() => {
|
||||
assert_equals(
|
||||
renamedAuthorIndex.name, 'renamed_by_author',
|
||||
'IDBIndex used in the rename transaction should keep reflecting ' +
|
||||
'the new name after the transaction is committed');
|
||||
assert_equals(
|
||||
renamedAuthorIndex2.name, 'renamed_by_author',
|
||||
'IDBIndex obtained after the rename transaction should reflect ' +
|
||||
'the new name');
|
||||
});
|
||||
}, 'IndexedDB index rename in the transaction where it is created');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
index.name = 'by_author';
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'Renaming an index to the same name should not change the ' +
|
||||
"index's IDBObjectStore.indexNames");
|
||||
})).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'Committing a transaction that renames a store to the same name ' +
|
||||
"should not change the index's IDBObjectStore.indexNames");
|
||||
const index = store.index('by_author');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, index,
|
||||
'Committing a transaction that renames an index to the same name ' +
|
||||
"should not change the index's contents").then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB index rename to the same name succeeds');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
store.deleteIndex('by_title');
|
||||
index.name = 'by_title';
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_title'],
|
||||
'IDBObjectStore.indexNames should immediately reflect the rename');
|
||||
})).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_title'],
|
||||
'IDBObjectStore.indexNames should still reflect the rename after ' +
|
||||
'the versionchange transaction commits');
|
||||
const index = store.index('by_title');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, index,
|
||||
'Renaming an index should not change its contents').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB index rename to the name of a deleted index succeeds');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
store.index('by_author').name = 'tmp';
|
||||
store.index('by_title').name = 'by_author';
|
||||
store.index('tmp').name = 'by_title';
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'IDBObjectStore.indexNames should reflect the swap immediately ' +
|
||||
'after the renames');
|
||||
return checkTitleIndexContents(
|
||||
testCase, store.index('by_author'),
|
||||
'Renaming an index should not change its contents');
|
||||
})).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'IDBObjectStore.indexNames should still reflect the swap after ' +
|
||||
'the versionchange transaction commits');
|
||||
const index = store.index('by_title');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, index,
|
||||
'Renaming an index should not change its contents').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB index swapping via renames succeeds');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
|
||||
index.name = 42;
|
||||
assert_equals(index.name, '42',
|
||||
'IDBIndex name should change immediately after a rename to a ' +
|
||||
'number');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['42', 'by_title'],
|
||||
'IDBObjectStore.indexNames should immediately reflect the ' +
|
||||
'stringifying rename');
|
||||
|
||||
index.name = true;
|
||||
assert_equals(index.name, 'true',
|
||||
'IDBIndex name should change immediately after a rename to a ' +
|
||||
'boolean');
|
||||
|
||||
index.name = {};
|
||||
assert_equals(index.name, '[object Object]',
|
||||
'IDBIndex name should change immediately after a rename to an ' +
|
||||
'object');
|
||||
|
||||
index.name = () => null;
|
||||
assert_equals(index.name, '() => null',
|
||||
'IDBIndex name should change immediately after a rename to a ' +
|
||||
'function');
|
||||
|
||||
index.name = undefined;
|
||||
assert_equals(index.name, 'undefined',
|
||||
'IDBIndex name should change immediately after a rename to ' +
|
||||
'undefined');
|
||||
})).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_title', 'undefined'],
|
||||
'IDBObjectStore.indexNames should reflect the last rename ' +
|
||||
'after the versionchange transaction commits');
|
||||
const index = store.index('undefined');
|
||||
return checkAuthorIndexContents(
|
||||
testCase, index,
|
||||
'Renaming an index should not change its contents').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB index rename stringifies non-string names');
|
||||
|
||||
for (let escapedName of ['', '\\u0000', '\\uDC00\\uD800']) ((escapedName) => {
|
||||
const name = JSON.parse('"' + escapedName + '"');
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
const index = store.index('by_author');
|
||||
|
||||
index.name = name;
|
||||
assert_equals(index.name, name,
|
||||
'IDBIndex name should change immediately after the rename');
|
||||
assert_array_equals(
|
||||
store.indexNames, [name, 'by_title'].sort(),
|
||||
'IDBObjectStore.indexNames should immediately reflect the rename');
|
||||
})).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_array_equals(
|
||||
store.indexNames, [name, 'by_title'].sort(),
|
||||
'IDBObjectStore.indexNames should reflect the rename ' +
|
||||
'after the versionchange transaction commits');
|
||||
const index = store.index(name);
|
||||
return checkAuthorIndexContents(
|
||||
testCase, index,
|
||||
'Renaming an index should not change its contents').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB index can be renamed to "' + escapedName + '"');
|
||||
})(escapedName);
|
||||
|
||||
</script>
|
|
@ -0,0 +1,120 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: object store renaming support in aborted transactions</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
const dbName = databaseName(testCase);
|
||||
let bookStore = null, bookStore2 = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
bookStore = transaction.objectStore('books');
|
||||
bookStore.name = 'renamed_books';
|
||||
|
||||
transaction.abort();
|
||||
|
||||
assert_equals(
|
||||
bookStore.name, 'books',
|
||||
'IDBObjectStore.name should not reflect the rename any more ' +
|
||||
'immediately after transaction.abort() returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should not reflect the rename ' +
|
||||
'any more immediately after transaction.abort() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should not reflect the ' +
|
||||
'rename any more immediately after transaction.abort() returns');
|
||||
})).then(event => {
|
||||
assert_equals(bookStore.name, 'books',
|
||||
'IDBObjectStore.name should not reflect the rename any more ' +
|
||||
'after the versionchange transaction is aborted');
|
||||
const request = indexedDB.open(dbName, 1);
|
||||
return requestWatcher(testCase, request).wait_for('success');
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should not reflect the rename ' +
|
||||
'after the versionchange transaction is aborted');
|
||||
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
bookStore2 = transaction.objectStore('books');
|
||||
return checkStoreContents(
|
||||
testCase, bookStore2,
|
||||
'Aborting an object store rename transaction should not change ' +
|
||||
"the store's records").then(() => database.close());
|
||||
}).then(() => {
|
||||
assert_equals(
|
||||
bookStore.name, 'books',
|
||||
'IDBObjectStore used in aborted rename transaction should not ' +
|
||||
'reflect the rename after the transaction is aborted');
|
||||
assert_equals(
|
||||
bookStore2.name, 'books',
|
||||
'IDBObjectStore obtained after an aborted rename transaction ' +
|
||||
'should not reflect the rename');
|
||||
});
|
||||
}, 'IndexedDB object store rename in aborted transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
const dbName = databaseName(testCase);
|
||||
let notBookStore = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
notBookStore = createNotBooksStore(testCase, database);
|
||||
notBookStore.name = 'not_books_renamed';
|
||||
notBookStore.name = 'not_books_renamed_again';
|
||||
|
||||
transaction.abort();
|
||||
|
||||
assert_equals(
|
||||
notBookStore.name, 'not_books_renamed_again',
|
||||
'IDBObjectStore.name should reflect the last rename ' +
|
||||
'immediately after transaction.abort() returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, [],
|
||||
'IDBDatabase.objectStoreNames should not reflect the creation ' +
|
||||
'or the rename any more immediately after transaction.abort() ' +
|
||||
'returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, [],
|
||||
'IDBTransaction.objectStoreNames should not reflect the ' +
|
||||
'creation or the rename any more immediately after ' +
|
||||
'transaction.abort() returns');
|
||||
assert_array_equals(notBookStore.indexNames, [],
|
||||
'IDBObjectStore.indexNames for the newly created store ' +
|
||||
'should be empty immediately after transaction.abort() ' +
|
||||
'returns');
|
||||
})).then(event => {
|
||||
assert_equals(
|
||||
notBookStore.name, 'not_books_renamed_again',
|
||||
'IDBObjectStore.name should reflect the last rename after the ' +
|
||||
'versionchange transaction is aborted');
|
||||
assert_array_equals(notBookStore.indexNames, [],
|
||||
'IDBObjectStore.indexNames for the newly created store ' +
|
||||
'should be empty after the versionchange transaction is aborted ' +
|
||||
'returns');
|
||||
const request = indexedDB.open(dbName, 1);
|
||||
return requestWatcher(testCase, request).wait_for('success');
|
||||
}).then(event => {
|
||||
const database = event.target.result;
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, [],
|
||||
'IDBDatabase.objectStoreNames should not reflect the creation or ' +
|
||||
'the rename after the versionchange transaction is aborted');
|
||||
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB object store creation and rename in an aborted transaction');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,118 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: object store renaming error handling</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
database.deleteObjectStore('books');
|
||||
assert_throws('InvalidStateError', () => store.name = 'renamed_books');
|
||||
})).then(database => {
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB deleted object store rename throws');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
assert_throws('InvalidStateError', () => store.name = 'renamed_books');
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB object store rename throws in a readonly transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readwrite');
|
||||
const store = transaction.objectStore('books');
|
||||
|
||||
assert_throws('InvalidStateError', () => store.name = 'renamed_books');
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB object store rename throws in a readwrite transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
let bookStore = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
bookStore = createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
assert_throws('TransactionInactiveError',
|
||||
() => { bookStore.name = 'renamed_books'; });
|
||||
database.close();
|
||||
});
|
||||
}, 'IndexedDB object store rename throws in an inactive transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
assert_throws('ConstraintError', () => store.name = 'not_books');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'A store rename that throws an exception should not change the ' +
|
||||
"store's IDBDatabase.objectStoreNames");
|
||||
})).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'Committing a transaction with a failed store rename attempt ' +
|
||||
"should not change the store's IDBDatabase.objectStoreNames");
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
return checkStoreContents(
|
||||
testCase, store,
|
||||
'Committing a transaction with a failed rename attempt should ' +
|
||||
"not change the store's contents").then(() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store rename to the name of another store throws');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
assert_throws(
|
||||
{ name: 'Custom stringifying error' },
|
||||
() => {
|
||||
store.name = {
|
||||
toString: () => { throw { name: 'Custom stringifying error'}; }
|
||||
};
|
||||
}, 'IDBObjectStore rename should re-raise toString() exception');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'A store rename that throws an exception should not change the ' +
|
||||
"store's IDBDatabase.objectStoreNames");
|
||||
})).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'Committing a transaction with a failed store rename attempt ' +
|
||||
"should not change the store's IDBDatabase.objectStoreNames");
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
return checkStoreContents(
|
||||
testCase, store,
|
||||
'Committing a transaction with a failed rename attempt should ' +
|
||||
"not change the store's contents").then(() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store rename handles exceptions when stringifying names');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,366 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: object store renaming support</title>
|
||||
<link rel="help"
|
||||
href="https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
// Renames the 'books' store to 'renamed_books'.
|
||||
//
|
||||
// Returns a promise that resolves to an IndexedDB database. The caller must
|
||||
// close the database.
|
||||
const renameBooksStore = (testCase) => {
|
||||
return migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
store.name = 'renamed_books';
|
||||
});
|
||||
};
|
||||
|
||||
promise_test(testCase => {
|
||||
let bookStore = null, bookStore2 = null;
|
||||
let renamedBookStore = null, renamedBookStore2 = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
bookStore = createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'Test setup should have created a "books" object store');
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
bookStore2 = transaction.objectStore('books');
|
||||
return checkStoreContents(
|
||||
testCase, bookStore2,
|
||||
'The store should have the expected contents before any renaming').
|
||||
then(() => database.close());
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
renamedBookStore = transaction.objectStore('books');
|
||||
renamedBookStore.name = 'renamed_books';
|
||||
|
||||
assert_equals(
|
||||
renamedBookStore.name, 'renamed_books',
|
||||
'IDBObjectStore name should change immediately after a rename');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['renamed_books'],
|
||||
'IDBDatabase.objectStoreNames should immediately reflect the ' +
|
||||
'rename');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['renamed_books'],
|
||||
'IDBTransaction.objectStoreNames should immediately reflect the ' +
|
||||
'rename');
|
||||
assert_equals(
|
||||
transaction.objectStore('renamed_books'), renamedBookStore,
|
||||
'IDBTransaction.objectStore should return the renamed object ' +
|
||||
'store when queried using the new name immediately after the ' +
|
||||
'rename');
|
||||
assert_throws(
|
||||
'NotFoundError', () => transaction.objectStore('books'),
|
||||
'IDBTransaction.objectStore should throw when queried using the ' +
|
||||
"renamed object store's old name immediately after the rename");
|
||||
})).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['renamed_books'],
|
||||
'IDBDatabase.objectStoreNames should still reflect the rename ' +
|
||||
'after the versionchange transaction commits');
|
||||
const transaction = database.transaction('renamed_books', 'readonly');
|
||||
renamedBookStore2 = transaction.objectStore('renamed_books');
|
||||
return checkStoreContents(
|
||||
testCase, renamedBookStore2,
|
||||
'Renaming an object store should not change its records').then(
|
||||
() => database.close());
|
||||
}).then(() => {
|
||||
assert_equals(
|
||||
bookStore.name, 'books',
|
||||
'IDBObjectStore obtained before the rename transaction should ' +
|
||||
'not reflect the rename');
|
||||
assert_equals(
|
||||
bookStore2.name, 'books',
|
||||
'IDBObjectStore obtained before the rename transaction should ' +
|
||||
'not reflect the rename');
|
||||
assert_equals(
|
||||
renamedBookStore.name, 'renamed_books',
|
||||
'IDBObjectStore used in the rename transaction should keep ' +
|
||||
'reflecting the new name after the transaction is committed');
|
||||
assert_equals(
|
||||
renamedBookStore2.name, 'renamed_books',
|
||||
'IDBObjectStore obtained after the rename transaction should ' +
|
||||
'reflect the new name');
|
||||
});
|
||||
}, 'IndexedDB object store rename in new transaction');
|
||||
|
||||
promise_test(testCase => {
|
||||
let renamedBookStore = null, renamedBookStore2 = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
renamedBookStore = createBooksStore(testCase, database);
|
||||
renamedBookStore.name = 'renamed_books';
|
||||
|
||||
assert_equals(
|
||||
renamedBookStore.name, 'renamed_books',
|
||||
'IDBObjectStore name should change immediately after a rename');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['renamed_books'],
|
||||
'IDBDatabase.objectStoreNames should immediately reflect the ' +
|
||||
'rename');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['renamed_books'],
|
||||
'IDBTransaction.objectStoreNames should immediately reflect the ' +
|
||||
'rename');
|
||||
assert_equals(
|
||||
transaction.objectStore('renamed_books'), renamedBookStore,
|
||||
'IDBTransaction.objectStore should return the renamed object ' +
|
||||
'store when queried using the new name immediately after the ' +
|
||||
'rename');
|
||||
assert_throws(
|
||||
'NotFoundError', () => transaction.objectStore('books'),
|
||||
'IDBTransaction.objectStore should throw when queried using the ' +
|
||||
"renamed object store's old name immediately after the rename");
|
||||
}).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['renamed_books'],
|
||||
'IDBDatabase.objectStoreNames should still reflect the rename ' +
|
||||
'after the versionchange transaction commits');
|
||||
const transaction = database.transaction('renamed_books', 'readonly');
|
||||
renamedBookStore2 = transaction.objectStore('renamed_books');
|
||||
return checkStoreContents(
|
||||
testCase, renamedBookStore2,
|
||||
'Renaming an object store should not change its records').then(
|
||||
() => database.close());
|
||||
}).then(() => {
|
||||
assert_equals(
|
||||
renamedBookStore.name, 'renamed_books',
|
||||
'IDBObjectStore used in the rename transaction should keep ' +
|
||||
'reflecting the new name after the transaction is committed');
|
||||
assert_equals(
|
||||
renamedBookStore2.name, 'renamed_books',
|
||||
'IDBObjectStore obtained after the rename transaction should ' +
|
||||
'reflect the new name');
|
||||
});
|
||||
}, 'IndexedDB object store rename in the transaction where it is created');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
return checkStoreIndexes(
|
||||
testCase, store,
|
||||
'The object store index should have the expected contens before ' +
|
||||
'any renaming').then(
|
||||
() => database.close());
|
||||
}).then(() => renameBooksStore(testCase)
|
||||
).then(database => {
|
||||
const transaction = database.transaction('renamed_books', 'readonly');
|
||||
const store = transaction.objectStore('renamed_books');
|
||||
return checkStoreIndexes(
|
||||
testCase, store,
|
||||
'Renaming an object store should not change its indexes').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store rename covers index');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction('books', 'readwrite');
|
||||
const store = transaction.objectStore('books');
|
||||
return checkStoreGenerator(
|
||||
testCase, store, 345679,
|
||||
'The object store key generator should have the expected state ' +
|
||||
'before any renaming').then(() => database.close());
|
||||
}).then(() => renameBooksStore(testCase)
|
||||
).then(database => {
|
||||
const transaction = database.transaction('renamed_books', 'readwrite');
|
||||
const store = transaction.objectStore('renamed_books');
|
||||
return checkStoreGenerator(
|
||||
testCase, store, 345680,
|
||||
'Renaming an object store should not change the state of its key ' +
|
||||
'generator').then(() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store rename covers key generator');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
store.name = 'books';
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'Renaming a store to the same name should not change ' +
|
||||
"the store's IDBDatabase.objectStoreNames");
|
||||
})).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'Committing a transaction that renames a store to the same name ' +
|
||||
"should not change the store's IDBDatabase.objectStoreNames");
|
||||
const transaction = database.transaction('books', 'readonly');
|
||||
const store = transaction.objectStore('books');
|
||||
return checkStoreContents(
|
||||
testCase, store,
|
||||
'Committing a transaction that renames a store to the same name ' +
|
||||
"should not change the store's contents").then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store rename to the same name succeeds');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
database.deleteObjectStore('not_books');
|
||||
store.name = 'not_books';
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['not_books'],
|
||||
'IDBDatabase.objectStoreNames should immediately reflect the ' +
|
||||
'rename');
|
||||
})).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['not_books'],
|
||||
'IDBDatabase.objectStoreNames should still reflect the rename ' +
|
||||
'after the versionchange transaction commits');
|
||||
const transaction = database.transaction('not_books', 'readonly');
|
||||
const store = transaction.objectStore('not_books');
|
||||
return checkStoreContents(
|
||||
testCase, store,
|
||||
'Renaming an object store should not change its records').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store rename to the name of a deleted store succeeds');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const bookStore = transaction.objectStore('books');
|
||||
const notBookStore = transaction.objectStore('not_books');
|
||||
|
||||
transaction.objectStore('books').name = 'tmp';
|
||||
transaction.objectStore('not_books').name = 'books';
|
||||
transaction.objectStore('tmp').name = 'not_books';
|
||||
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should immediately reflect the swap');
|
||||
|
||||
assert_equals(
|
||||
transaction.objectStore('books'), notBookStore,
|
||||
'IDBTransaction.objectStore should return the original "books" ' +
|
||||
'store when queried with "not_books" after the swap');
|
||||
assert_equals(
|
||||
transaction.objectStore('not_books'), bookStore,
|
||||
'IDBTransaction.objectStore should return the original ' +
|
||||
'"not_books" store when queried with "books" after the swap');
|
||||
})).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should still reflect the swap ' +
|
||||
'after the versionchange transaction commits');
|
||||
const transaction = database.transaction('not_books', 'readonly');
|
||||
const store = transaction.objectStore('not_books');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'],
|
||||
'"not_books" index names should still reflect the swap after the ' +
|
||||
'versionchange transaction commits');
|
||||
return checkStoreContents(
|
||||
testCase, store,
|
||||
'Swapping two object stores should not change their records').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store swapping via renames succeeds');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
|
||||
store.name = 42;
|
||||
assert_equals(store.name, '42',
|
||||
'IDBObjectStore name should change immediately after a ' +
|
||||
'rename to a number');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['42'],
|
||||
'IDBDatabase.objectStoreNames should immediately reflect the ' +
|
||||
'stringifying rename');
|
||||
|
||||
store.name = true;
|
||||
assert_equals(store.name, 'true',
|
||||
'IDBObjectStore name should change immediately after a ' +
|
||||
'rename to a boolean');
|
||||
|
||||
store.name = {};
|
||||
assert_equals(store.name, '[object Object]',
|
||||
'IDBObjectStore name should change immediately after a ' +
|
||||
'rename to an object');
|
||||
|
||||
store.name = () => null;
|
||||
assert_equals(store.name, '() => null',
|
||||
'IDBObjectStore name should change immediately after a ' +
|
||||
'rename to a function');
|
||||
|
||||
store.name = undefined;
|
||||
assert_equals(store.name, 'undefined',
|
||||
'IDBObjectStore name should change immediately after a ' +
|
||||
'rename to undefined');
|
||||
})).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['undefined'],
|
||||
'IDBDatabase.objectStoreNames should reflect the last rename ' +
|
||||
'after the versionchange transaction commits');
|
||||
const transaction = database.transaction('undefined', 'readonly');
|
||||
const store = transaction.objectStore('undefined');
|
||||
return checkStoreContents(
|
||||
testCase, store,
|
||||
'Renaming an object store should not change its records').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store rename stringifies non-string names');
|
||||
|
||||
for (let escapedName of ['', '\\u0000', '\\uDC00\\uD800']) ((escapedName) => {
|
||||
const name = JSON.parse('"' + escapedName + '"');
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
const store = transaction.objectStore('books');
|
||||
|
||||
store.name = name;
|
||||
assert_equals(store.name, name,
|
||||
'IDBObjectStore name should change immediately after the ' +
|
||||
'rename');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, [name],
|
||||
'IDBDatabase.objectStoreNames should immediately reflect the ' +
|
||||
'rename');
|
||||
})).then(database => {
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, [name],
|
||||
'IDBDatabase.objectStoreNames should reflect the rename ' +
|
||||
'after the versionchange transaction commits');
|
||||
const transaction = database.transaction(name, 'readonly');
|
||||
const store = transaction.objectStore(name);
|
||||
return checkStoreContents(
|
||||
testCase, store,
|
||||
'Renaming an object store should not change its records').then(
|
||||
() => database.close());
|
||||
});
|
||||
}, 'IndexedDB object store can be renamed to "' + escapedName + '"');
|
||||
})(escapedName);
|
||||
|
||||
</script>
|
|
@ -21,8 +21,8 @@ setup(function() {
|
|||
var idls = request.responseText;
|
||||
|
||||
idlArray.add_untested_idls("[PrimaryGlobal] interface Window { };");
|
||||
idlArray.add_untested_idls("interface Event { };");
|
||||
idlArray.add_untested_idls("interface EventTarget { };");
|
||||
idlArray.add_untested_idls("[Exposed=(Window,Worker)] interface Event { };");
|
||||
idlArray.add_untested_idls("[Exposed=(Window,Worker)] interface EventTarget { };");
|
||||
|
||||
// From Indexed DB:
|
||||
idlArray.add_idls(idls);
|
||||
|
|
|
@ -9,6 +9,7 @@ enum IDBRequestReadyState {
|
|||
"done"
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBKeyRange {
|
||||
readonly attribute any lower;
|
||||
readonly attribute any upper;
|
||||
|
@ -42,6 +43,7 @@ dictionary IDBVersionChangeEventInit : EventInit {
|
|||
unsigned long long? newVersion = null;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBRequest : EventTarget {
|
||||
readonly attribute any result;
|
||||
readonly attribute DOMError error;
|
||||
|
@ -52,12 +54,14 @@ interface IDBRequest : EventTarget {
|
|||
attribute EventHandler onerror;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBOpenDBRequest : IDBRequest {
|
||||
attribute EventHandler onblocked;
|
||||
attribute EventHandler onupgradeneeded;
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)]
|
||||
[Exposed=(Window,Worker),
|
||||
Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)]
|
||||
interface IDBVersionChangeEvent : Event {
|
||||
readonly attribute unsigned long long oldVersion;
|
||||
readonly attribute unsigned long long? newVersion;
|
||||
|
@ -68,12 +72,14 @@ interface IDBEnvironment {
|
|||
readonly attribute IDBFactory indexedDB;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBFactory {
|
||||
IDBOpenDBRequest open (DOMString name, [EnforceRange] optional unsigned long long version);
|
||||
IDBOpenDBRequest deleteDatabase (DOMString name);
|
||||
short cmp (any first, any second);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBDatabase : EventTarget {
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute unsigned long long version;
|
||||
|
@ -88,6 +94,7 @@ interface IDBDatabase : EventTarget {
|
|||
attribute EventHandler onversionchange;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBObjectStore {
|
||||
attribute DOMString name;
|
||||
readonly attribute any keyPath;
|
||||
|
@ -106,6 +113,7 @@ interface IDBObjectStore {
|
|||
IDBRequest count (optional any key);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBIndex {
|
||||
attribute DOMString name;
|
||||
readonly attribute IDBObjectStore objectStore;
|
||||
|
@ -119,6 +127,7 @@ interface IDBIndex {
|
|||
IDBRequest count (optional any key);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBCursor {
|
||||
readonly attribute (IDBObjectStore or IDBIndex) source;
|
||||
readonly attribute IDBCursorDirection direction;
|
||||
|
@ -130,10 +139,12 @@ interface IDBCursor {
|
|||
IDBRequest delete ();
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBCursorWithValue : IDBCursor {
|
||||
readonly attribute any value;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBTransaction : EventTarget {
|
||||
readonly attribute IDBTransactionMode mode;
|
||||
readonly attribute IDBDatabase db;
|
||||
|
|
|
@ -10,9 +10,9 @@ request.onload = function() {
|
|||
var idlArray = new IdlArray();
|
||||
var idls = request.responseText;
|
||||
|
||||
idlArray.add_untested_idls("interface WorkerGlobalScope {};");
|
||||
idlArray.add_untested_idls("interface Event { };");
|
||||
idlArray.add_untested_idls("interface EventTarget { };");
|
||||
idlArray.add_untested_idls("[Exposed=Worker] interface WorkerGlobalScope {};");
|
||||
idlArray.add_untested_idls("[Exposed=(Window,Worker)] interface Event { };");
|
||||
idlArray.add_untested_idls("[Exposed=(Window,Worker)] interface EventTarget { };");
|
||||
|
||||
// From Indexed DB:
|
||||
idlArray.add_idls("WorkerGlobalScope implements IDBEnvironment;");
|
||||
|
|
200
tests/wpt/web-platform-tests/IndexedDB/support-promises.js
Normal file
200
tests/wpt/web-platform-tests/IndexedDB/support-promises.js
Normal file
|
@ -0,0 +1,200 @@
|
|||
// Returns an IndexedDB database name likely to be unique to the test case.
|
||||
const databaseName = (testCase) => {
|
||||
return 'db' + self.location.pathname + '-' + testCase.name;
|
||||
};
|
||||
|
||||
// Creates an EventWatcher covering all the events that can be issued by
|
||||
// IndexedDB requests and transactions.
|
||||
const requestWatcher = (testCase, request) => {
|
||||
return new EventWatcher(testCase, request,
|
||||
['error', 'success', 'upgradeneeded']);
|
||||
};
|
||||
|
||||
// Migrates an IndexedDB database whose name is unique for the test case.
|
||||
//
|
||||
// newVersion must be greater than the database's current version.
|
||||
//
|
||||
// migrationCallback will be called during a versionchange transaction and will
|
||||
// be given the created database and the versionchange transaction.
|
||||
//
|
||||
// Returns a promise. If the versionchange transaction goes through, the promise
|
||||
// resolves to an IndexedDB database that must be closed by the caller. If the
|
||||
// versionchange transaction is aborted, the promise resolves to an error.
|
||||
const migrateDatabase = (testCase, newVersion, migrationCallback) => {
|
||||
// We cannot use eventWatcher.wait_for('upgradeneeded') here, because
|
||||
// the versionchange transaction auto-commits before the Promise's then
|
||||
// callback gets called.
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(databaseName(testCase), newVersion);
|
||||
request.onupgradeneeded = testCase.step_func(event => {
|
||||
const database = event.target.result;
|
||||
const transaction = event.target.transaction;
|
||||
let abortCalled = false;
|
||||
|
||||
// We wrap IDBTransaction.abort so we can set up the correct event
|
||||
// listeners and expectations if the test chooses to abort the
|
||||
// versionchange transaction.
|
||||
const transactionAbort = transaction.abort.bind(transaction);
|
||||
transaction.abort = () => {
|
||||
request.onerror = event => {
|
||||
event.preventDefault();
|
||||
resolve(event);
|
||||
};
|
||||
request.onsuccess = () => reject(new Error(
|
||||
'indexedDB.open should not succeed after the ' +
|
||||
'versionchange transaction is aborted'));
|
||||
transactionAbort();
|
||||
abortCalled = true;
|
||||
}
|
||||
|
||||
migrationCallback(database, transaction);
|
||||
if (!abortCalled) {
|
||||
request.onsuccess = null;
|
||||
resolve(requestWatcher(testCase, request).wait_for('success'));
|
||||
}
|
||||
});
|
||||
request.onerror = event => reject(event.target.error);
|
||||
request.onsuccess = () => reject(new Error(
|
||||
'indexedDB.open should not succeed without creating a ' +
|
||||
'versionchange transaction'));
|
||||
}).then(event => event.target.result || event.target.error);
|
||||
};
|
||||
|
||||
// Creates an IndexedDB database whose name is unique for the test case.
|
||||
//
|
||||
// setupCallback will be called during a versionchange transaction, and will be
|
||||
// given the created database and the versionchange transaction.
|
||||
//
|
||||
// Returns a promise that resolves to an IndexedDB database. The caller must
|
||||
// close the database.
|
||||
const createDatabase = (testCase, setupCallback) => {
|
||||
const request = indexedDB.deleteDatabase(databaseName(testCase));
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
|
||||
return eventWatcher.wait_for('success').then(event =>
|
||||
migrateDatabase(testCase, 1, setupCallback));
|
||||
};
|
||||
|
||||
// Opens an IndexedDB database without performing schema changes.
|
||||
//
|
||||
// The given version number must match the database's current version.
|
||||
//
|
||||
// Returns a promise that resolves to an IndexedDB database. The caller must
|
||||
// close the database.
|
||||
const openDatabase = (testCase, version) => {
|
||||
const request = indexedDB.open(databaseName(testCase), version);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(
|
||||
event => event.target.result);
|
||||
}
|
||||
|
||||
// The data in the 'books' object store records in the first example of the
|
||||
// IndexedDB specification.
|
||||
const BOOKS_RECORD_DATA = [
|
||||
{ title: 'Quarry Memories', author: 'Fred', isbn: 123456 },
|
||||
{ title: 'Water Buffaloes', author: 'Fred', isbn: 234567 },
|
||||
{ title: 'Bedrock Nights', author: 'Barney', isbn: 345678 },
|
||||
];
|
||||
|
||||
// Creates a 'books' object store whose contents closely resembles the first
|
||||
// example in the IndexedDB specification.
|
||||
const createBooksStore = (testCase, database) => {
|
||||
const store = database.createObjectStore('books',
|
||||
{ keyPath: 'isbn', autoIncrement: true });
|
||||
store.createIndex('by_author', 'author');
|
||||
store.createIndex('by_title', 'title', { unique: true });
|
||||
for (let record of BOOKS_RECORD_DATA)
|
||||
store.put(record);
|
||||
return store;
|
||||
};
|
||||
|
||||
// Creates a 'not_books' object store used to test renaming into existing or
|
||||
// deleted store names.
|
||||
const createNotBooksStore = (testCase, database) => {
|
||||
const store = database.createObjectStore('not_books');
|
||||
store.createIndex('not_by_author', 'author');
|
||||
store.createIndex('not_by_title', 'title', { unique: true });
|
||||
return store;
|
||||
};
|
||||
|
||||
// Verifies that an object store's indexes match the indexes used to create the
|
||||
// books store in the test database's version 1.
|
||||
//
|
||||
// The errorMessage is used if the assertions fail. It can state that the
|
||||
// IndexedDB implementation being tested is incorrect, or that the testing code
|
||||
// is using it incorrectly.
|
||||
const checkStoreIndexes = (testCase, store, errorMessage) => {
|
||||
assert_array_equals(
|
||||
store.indexNames, ['by_author', 'by_title'], errorMessage);
|
||||
const authorIndex = store.index('by_author');
|
||||
const titleIndex = store.index('by_title');
|
||||
return Promise.all([
|
||||
checkAuthorIndexContents(testCase, authorIndex, errorMessage),
|
||||
checkTitleIndexContents(testCase, titleIndex, errorMessage),
|
||||
]);
|
||||
};
|
||||
|
||||
// Verifies that an object store's key generator is in the same state as the
|
||||
// key generator created for the books store in the test database's version 1.
|
||||
//
|
||||
// The errorMessage is used if the assertions fail. It can state that the
|
||||
// IndexedDB implementation being tested is incorrect, or that the testing code
|
||||
// is using it incorrectly.
|
||||
const checkStoreGenerator = (testCase, store, expectedKey, errorMessage) => {
|
||||
const request = store.put(
|
||||
{ title: 'Bedrock Nights ' + expectedKey, author: 'Barney' });
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const result = request.result;
|
||||
assert_equals(result, expectedKey, errorMessage);
|
||||
});
|
||||
};
|
||||
|
||||
// Verifies that an object store's contents matches the contents used to create
|
||||
// the books store in the test database's version 1.
|
||||
//
|
||||
// The errorMessage is used if the assertions fail. It can state that the
|
||||
// IndexedDB implementation being tested is incorrect, or that the testing code
|
||||
// is using it incorrectly.
|
||||
const checkStoreContents = (testCase, store, errorMessage) => {
|
||||
const request = store.get(123456);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const result = request.result;
|
||||
assert_equals(result.isbn, BOOKS_RECORD_DATA[0].isbn, errorMessage);
|
||||
assert_equals(result.author, BOOKS_RECORD_DATA[0].author, errorMessage);
|
||||
assert_equals(result.title, BOOKS_RECORD_DATA[0].title, errorMessage);
|
||||
});
|
||||
};
|
||||
|
||||
// Verifies that index matches the 'by_author' index used to create the
|
||||
// by_author books store in the test database's version 1.
|
||||
//
|
||||
// The errorMessage is used if the assertions fail. It can state that the
|
||||
// IndexedDB implementation being tested is incorrect, or that the testing code
|
||||
// is using it incorrectly.
|
||||
const checkAuthorIndexContents = (testCase, index, errorMessage) => {
|
||||
const request = index.get(BOOKS_RECORD_DATA[2].author);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const result = request.result;
|
||||
assert_equals(result.isbn, BOOKS_RECORD_DATA[2].isbn, errorMessage);
|
||||
assert_equals(result.title, BOOKS_RECORD_DATA[2].title, errorMessage);
|
||||
});
|
||||
};
|
||||
|
||||
// Verifies that an index matches the 'by_title' index used to create the books
|
||||
// store in the test database's version 1.
|
||||
//
|
||||
// The errorMessage is used if the assertions fail. It can state that the
|
||||
// IndexedDB implementation being tested is incorrect, or that the testing code
|
||||
// is using it incorrectly.
|
||||
const checkTitleIndexContents = (testCase, index, errorMessage) => {
|
||||
const request = index.get(BOOKS_RECORD_DATA[2].title);
|
||||
const eventWatcher = requestWatcher(testCase, request);
|
||||
return eventWatcher.wait_for('success').then(() => {
|
||||
const result = request.result;
|
||||
assert_equals(result.isbn, BOOKS_RECORD_DATA[2].isbn, errorMessage);
|
||||
assert_equals(result.author, BOOKS_RECORD_DATA[2].author, errorMessage);
|
||||
});
|
||||
};
|
|
@ -0,0 +1,108 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: aborting transactions reverts an object store's key generator state</title>
|
||||
<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(databaseName(testCase), 2);
|
||||
request.onupgradeneeded = testCase.step_func(event => {
|
||||
const database = event.target.result;
|
||||
const transaction = event.target.transaction;
|
||||
const store = transaction.objectStore('books');
|
||||
const request2 = store.put(
|
||||
{ title: 'Bedrock Nights II', author: 'Barney' });
|
||||
request2.onerror = testCase.unreached_func(
|
||||
'IDBObjectStore.put() should not receive an error request');
|
||||
request2.onsuccess = testCase.step_func(event => {
|
||||
assert_equals(
|
||||
event.target.result, 345679,
|
||||
"The key generator's current number should be set by " +
|
||||
'the last put operation in the database creation ' +
|
||||
'transaction');
|
||||
|
||||
request.onerror = event => {
|
||||
event.preventDefault();
|
||||
resolve(event);
|
||||
};
|
||||
request.onsuccess = () => reject(new Error(
|
||||
'indexedDB.open should not succeed after the ' +
|
||||
'versionchange transaction is aborted'));
|
||||
|
||||
transaction.abort();
|
||||
});
|
||||
});
|
||||
request.onerror = event => reject(event.target.error);
|
||||
request.onsuccess = () => reject(new Error(
|
||||
'indexedDB.open should not succeed without creating a ' +
|
||||
'versionchange transaction'));
|
||||
});
|
||||
}).then(() => {
|
||||
return openDatabase(testCase, 1);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction(['books'], 'readwrite');
|
||||
const store = transaction.objectStore('books');
|
||||
|
||||
return checkStoreGenerator(
|
||||
testCase, store, 345679,
|
||||
"The key generator's current number should be reverted after the " +
|
||||
'transaction modifying it is aborted').then(() => database.close());
|
||||
});
|
||||
}, 'The current number of a key generator is reverted when a versionchange ' +
|
||||
'transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = database.transaction(['books'], 'readwrite');
|
||||
const store = transaction.objectStore('books');
|
||||
const request = store.put(
|
||||
{ title: 'Bedrock Nights II', author: 'Barney' });
|
||||
request.onerror = testCase.unreached_func(
|
||||
'IDBObjectStore.put() should not receive an error request');
|
||||
request.onsuccess = testCase.step_func(event => {
|
||||
assert_equals(
|
||||
event.target.result, 345679,
|
||||
"The key generator's current number should be set by the " +
|
||||
'last put operation in the database creation transaction');
|
||||
|
||||
transaction.onabort = event => {
|
||||
event.preventDefault();
|
||||
resolve(event);
|
||||
}
|
||||
transaction.abort();
|
||||
});
|
||||
transaction.onabort = () => reject(new Error(
|
||||
'The aborted readwrite transaction should not receive an ' +
|
||||
'abort event before IDBTransaction.abort() is called'));
|
||||
transaction.oncomplete = () => reject(new Error(
|
||||
'The aborted readwrite transaction should not receive a ' +
|
||||
'completed event'));
|
||||
transaction.onerror = () => reject(new Error(
|
||||
'The aborted readwrite transaction should not receive an ' +
|
||||
'error event'));
|
||||
}).then(() => database);
|
||||
}).then(database => {
|
||||
const transaction = database.transaction(['books'], 'readwrite');
|
||||
const store = transaction.objectStore('books');
|
||||
|
||||
return checkStoreGenerator(
|
||||
testCase, store, 345679,
|
||||
"The key generator's current number should be reverted after the " +
|
||||
'transaction modifying it is aborted').then(() => database.close());
|
||||
});
|
||||
}, 'The current number of a key generator is reverted when a readwrite ' +
|
||||
'transaction aborts');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,276 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: aborting transactions reverts index metadata</title>
|
||||
<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = createNotBooksStore(testCase, database);
|
||||
index = store.index('not_by_author');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should include newly created indexes ' +
|
||||
'before the transaction is aborted');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should stop including the newly ' +
|
||||
'created indexes immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, after the transaction is ' +
|
||||
'aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should stop including the newly ' +
|
||||
'created indexes after the transaction is aborted');
|
||||
});
|
||||
}, 'Created stores get their indexes marked as deleted after the transaction ' +
|
||||
'that created them aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = transaction.objectStore('not_books');
|
||||
index = store.index('not_by_author');
|
||||
|
||||
database.deleteObjectStore('not_books');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should be empty immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => index.get('query'),
|
||||
'IDBIndex.get should throw TransactionInactiveError, indicating ' +
|
||||
'that the index is no longer marked for deletion, immediately ' +
|
||||
'after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should include the deleted indexes ' +
|
||||
'immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => index.get('query'),
|
||||
'IDBIndex.get should throw TransactionInactiveError, indicating ' +
|
||||
'that the index is no longer marked for deletion, after the ' +
|
||||
'transaction is aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should include the deleted indexes ' +
|
||||
'after the transaction is aborted');
|
||||
});
|
||||
}, 'Deleted stores get their indexes marked as not-deleted after the ' +
|
||||
'transaction that deleted them aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = createNotBooksStore(testCase, database);
|
||||
index = store.index('not_by_author');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should include newly created indexes ' +
|
||||
'before the transaction is aborted');
|
||||
|
||||
database.deleteObjectStore('not_books');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should be empty immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should not include the newly ' +
|
||||
'created indexes immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, after the transaction ' +
|
||||
'is aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should not include the newly ' +
|
||||
'created indexes after the transaction is aborted');
|
||||
});
|
||||
}, 'Created+deleted stores still have their indexes marked as deleted after ' +
|
||||
'the transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = transaction.objectStore('not_books');
|
||||
index = store.createIndex('not_by_isbn', 'isbn');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_isbn', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should include newly created indexes ' +
|
||||
'before the transaction is aborted');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should stop including the newly ' +
|
||||
'created index immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, after the transaction is ' +
|
||||
'aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should stop including the newly ' +
|
||||
'created index after the transaction is aborted');
|
||||
});
|
||||
}, 'Created indexes get marked as deleted after their transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = transaction.objectStore('not_books');
|
||||
index = store.index('not_by_author');
|
||||
|
||||
store.deleteIndex('not_by_author');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBObjectStore.deleteIndex() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_title'],
|
||||
'IDBObjectStore.indexNames should not include the deleted index ' +
|
||||
'immediately after IDBObjectStore.deleteIndex() returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => index.get('query'),
|
||||
'IDBIndex.get should throw TransactionInactiveError, indicating ' +
|
||||
'that the index is no longer marked for deletion, immediately ' +
|
||||
'after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should include the deleted indexes ' +
|
||||
'immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => index.get('query'),
|
||||
'IDBIndex.get should throw TransactionInactiveError, indicating ' +
|
||||
'that the index is no longer marked for deletion, after the ' +
|
||||
'transaction is aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should include the deleted indexes ' +
|
||||
'after the transaction is aborted');
|
||||
});
|
||||
}, 'Deleted indexes get marked as not-deleted after the transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = transaction.objectStore('not_books');
|
||||
index = store.createIndex('not_by_isbn', 'isbn');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_isbn', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should include newly created indexes ' +
|
||||
'before the transaction is aborted');
|
||||
|
||||
store.deleteIndex('not_by_isbn');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBObjectStore.deleteIndex() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should not include the deleted index ' +
|
||||
'immediately after IDBObjectStore.deleteIndex() returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should stop including the newly ' +
|
||||
'created index immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, after the transaction is ' +
|
||||
'aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames should stop including the newly ' +
|
||||
'created index after the transaction is aborted');
|
||||
});
|
||||
}, 'Created+deleted indexes are still marked as deleted after their ' +
|
||||
'transaction aborts');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,291 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: aborting transactions reverts multiple operations on the same metadata</title>
|
||||
<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
let migrationTransaction = null, migrationDatabase = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = createNotBooksStore(testCase, database);
|
||||
migrationDatabase = database;
|
||||
migrationTransaction = transaction;
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include a newly created ' +
|
||||
'store before the transaction is aborted');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include a newly created ' +
|
||||
'store before the transaction is aborted');
|
||||
|
||||
index = store.index('not_by_author');
|
||||
store.deleteIndex('not_by_author');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBObjectStore.deleteIndex() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_title'],
|
||||
'IDBObjectStore.indexNames should not include the deleted index ' +
|
||||
'immediately after IDBObjectStore.deleteIndex() returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames for the newly created store should be ' +
|
||||
'empty immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is marked for deletion, after the transaction is ' +
|
||||
'aborted');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, after the transaction ' +
|
||||
'is aborted');
|
||||
assert_array_equals(
|
||||
migrationDatabase.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationTransaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the newly ' +
|
||||
'created store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames for the newly created store should be ' +
|
||||
'empty after the transaction is aborted');
|
||||
});
|
||||
}, 'Deleted indexes in newly created stores are still marked as deleted ' +
|
||||
'after the transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
let migrationTransaction = null, migrationDatabase = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
migrationDatabase = database;
|
||||
migrationTransaction = transaction;
|
||||
store = transaction.objectStore('not_books');
|
||||
index = store.index('not_by_author');
|
||||
store.deleteIndex('not_by_author');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBObjectStore.deleteIndex() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_title'],
|
||||
'IDBObjectStore.indexNames should not include the deleted index ' +
|
||||
'immediately after IDBObjectStore.deleteIndex() returns');
|
||||
|
||||
database.deleteObjectStore('not_books');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is marked for deletion, immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, immediately after ' +
|
||||
'IDBObjectStore.deleteIndex() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the ' +
|
||||
'deleted store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames for the deleted store should be empty ' +
|
||||
'immediately after IDBDatabase.deleteObjectStore() returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw TransactionInactiveError, ' +
|
||||
'indicating that the store is no longer marked for deletion, ' +
|
||||
'immediately after IDBTransaction.abort() returns');
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => index.get('query'),
|
||||
'IDBIndex.get should throw TransactionInactiveError, indicating ' +
|
||||
'that the index is no longer marked for deletion, immediately ' +
|
||||
'after IDBObjectStore.deleteIndex() returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include the deleted store ' +
|
||||
'store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include the deleted ' +
|
||||
'store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames for the deleted store should not be ' +
|
||||
'empty any more immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw TransactionInactiveError, ' +
|
||||
'indicating that the store is no longer marked for deletion, ' +
|
||||
'after the transaction is aborted');
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => index.get('query'),
|
||||
'IDBIndex.get should throw TransactionInactiveError, indicating ' +
|
||||
'that the index is no longer marked for deletion, after the ' +
|
||||
'transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationDatabase.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include the previously ' +
|
||||
'deleted store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationTransaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include the previously ' +
|
||||
'deleted store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_author', 'not_by_title'],
|
||||
'IDBObjectStore.indexNames for the deleted store should not be ' +
|
||||
'empty after the transaction is aborted');
|
||||
});
|
||||
}, 'Deleted indexes in deleted stores are still marked as not-deleted after ' +
|
||||
'the transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, index = null;
|
||||
let migrationTransaction = null, migrationDatabase = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = createNotBooksStore(testCase, database);
|
||||
migrationDatabase = database;
|
||||
migrationTransaction = transaction;
|
||||
index = store.index('not_by_author');
|
||||
store.deleteIndex('not_by_author');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is marked for deletion, immediately after ' +
|
||||
'IDBObjectStore.deleteIndex() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, ['not_by_title'],
|
||||
'IDBObjectStore.indexNames should not include the deleted index ' +
|
||||
'immediately after IDBObjectStore.deleteIndex() returns');
|
||||
|
||||
database.deleteObjectStore('not_books');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is marked for deletion, immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the ' +
|
||||
'deleted store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should be empty immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is still marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should not include the newly ' +
|
||||
'created store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should not include the newly ' +
|
||||
'created store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should be empty immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is still marked for deletion, after the ' +
|
||||
'transaction is aborted');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => index.get('query'),
|
||||
'IDBIndex.get should throw InvalidStateError, indicating that ' +
|
||||
'the index is still marked for deletion, after the transaction ' +
|
||||
'is aborted');
|
||||
assert_array_equals(
|
||||
migrationDatabase.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should not include the newly ' +
|
||||
'created store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationTransaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should not include the newly ' +
|
||||
'created store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
store.indexNames, [],
|
||||
'IDBObjectStore.indexNames should be empty after the transaction ' +
|
||||
'is aborted');
|
||||
});
|
||||
}, 'Deleted indexes in created+deleted stores are still marked as deleted ' +
|
||||
'after their transaction aborts');
|
||||
|
||||
</script>
|
|
@ -0,0 +1,233 @@
|
|||
<!DOCTYPE html>
|
||||
<title>IndexedDB: aborting transactions reverts object store metadata</title>
|
||||
<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="support-promises.js"></script>
|
||||
<script>
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, migrationTransaction = null, migrationDatabase = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = createNotBooksStore(testCase, database);
|
||||
migrationDatabase = database;
|
||||
migrationTransaction = transaction;
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include a newly created ' +
|
||||
'store before the transaction is aborted');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include a newly created ' +
|
||||
'store before the transaction is aborted');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is marked for deletion, after the transaction is ' +
|
||||
'aborted');
|
||||
assert_array_equals(
|
||||
migrationDatabase.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationTransaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the newly ' +
|
||||
'created store after the transaction is aborted');
|
||||
});
|
||||
}, 'Created stores get marked as deleted after their transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, migrationTransaction = null, migrationDatabase = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
migrationDatabase = database;
|
||||
migrationTransaction = transaction;
|
||||
store = transaction.objectStore('not_books');
|
||||
|
||||
database.deleteObjectStore('not_books');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is marked for deletion, immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the ' +
|
||||
'deleted store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw TransactionInactiveError, ' +
|
||||
'indicating that the store is no longer marked for deletion, ' +
|
||||
'immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include the deleted store ' +
|
||||
'store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include the deleted ' +
|
||||
'store immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'TransactionInactiveError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw TransactionInactiveError, ' +
|
||||
'indicating that the store is no longer marked for deletion, ' +
|
||||
'after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationDatabase.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include the previously ' +
|
||||
'deleted store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationTransaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include the previously ' +
|
||||
'deleted store after the transaction is aborted');
|
||||
});
|
||||
}, 'Deleted stores get marked as not-deleted after the transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let store = null, migrationTransaction = null, migrationDatabase = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
store = createNotBooksStore(testCase, database);
|
||||
migrationDatabase = database;
|
||||
migrationTransaction = transaction;
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include a newly created ' +
|
||||
'store before the transaction is aborted');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include a newly created ' +
|
||||
'store before the transaction is aborted');
|
||||
|
||||
database.deleteObjectStore('not_books');
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is marked for deletion, immediately after ' +
|
||||
'IDBDatabase.deleteObjectStore() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the ' +
|
||||
'deleted store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is still marked for deletion, immediately after ' +
|
||||
'IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should not include the newly ' +
|
||||
'created store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should not include the newly ' +
|
||||
'created store immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_throws(
|
||||
'InvalidStateError', () => store.get('query'),
|
||||
'IDBObjectStore.get should throw InvalidStateError, indicating ' +
|
||||
'that the store is still marked for deletion, after the ' +
|
||||
'transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationDatabase.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should not include the newly ' +
|
||||
'created store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationTransaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should not include the newly ' +
|
||||
'created store after the transaction is aborted');
|
||||
});
|
||||
}, 'Created+deleted stores are still marked as deleted after their ' +
|
||||
'transaction aborts');
|
||||
|
||||
promise_test(testCase => {
|
||||
let migrationTransaction = null, migrationDatabase = null;
|
||||
return createDatabase(testCase, (database, transaction) => {
|
||||
createBooksStore(testCase, database);
|
||||
createNotBooksStore(testCase, database);
|
||||
}).then(database => {
|
||||
database.close();
|
||||
}).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
|
||||
migrationDatabase = database;
|
||||
migrationTransaction = transaction;
|
||||
|
||||
database.deleteObjectStore('not_books');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books'],
|
||||
'IDBTransaction.objectStoreNames should stop including the ' +
|
||||
'deleted store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books'],
|
||||
'IDBDatabase.objectStoreNames should stop including the newly ' +
|
||||
'created store immediately after IDBDatabase.deleteObjectStore() ' +
|
||||
'returns');
|
||||
|
||||
transaction.abort();
|
||||
assert_array_equals(
|
||||
database.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include the deleted store ' +
|
||||
'store immediately after IDBTransaction.abort() returns');
|
||||
assert_array_equals(
|
||||
transaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include the deleted ' +
|
||||
'store immediately after IDBTransaction.abort() returns');
|
||||
})).then(() => {
|
||||
assert_array_equals(
|
||||
migrationDatabase.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBDatabase.objectStoreNames should include the previously ' +
|
||||
'deleted store after the transaction is aborted');
|
||||
assert_array_equals(
|
||||
migrationTransaction.objectStoreNames, ['books', 'not_books'],
|
||||
'IDBTransaction.objectStoreNames should include the previously ' +
|
||||
'deleted store after the transaction is aborted');
|
||||
});
|
||||
}, 'Un-instantiated deleted stores get marked as not-deleted after the ' +
|
||||
'transaction aborts');
|
||||
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue