Chromium Code Reviews| Index: third_party/WebKit/LayoutTests/storage/indexeddb/rename-object-store.html |
| diff --git a/third_party/WebKit/LayoutTests/storage/indexeddb/rename-object-store.html b/third_party/WebKit/LayoutTests/storage/indexeddb/rename-object-store.html |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7bd4417abd3dc85eb06213d262cd490e20b0e929 |
| --- /dev/null |
| +++ b/third_party/WebKit/LayoutTests/storage/indexeddb/rename-object-store.html |
| @@ -0,0 +1,651 @@ |
| +<!DOCTYPE html> |
| +<title>IndexedDB: object store renaming support</title> |
| +<script src='../../resources/testharness.js'></script> |
| +<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/testharnessreport.js'></script> |
| +<script> |
| + |
| +// Returns an IndexedDB database name likely to be unique to the test case. |
| +const databaseName = function(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 = function(testCase, request) { |
| + return new EventWatcher(testCase, request, |
| + ['error', 'success', 'upgradeneeded']); |
| +}; |
| + |
| +// Migrates 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 migrateDatabase = function(testCase, newVersion, setupCallback) { |
| + // 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 = event => { |
| + const eventWatcher = requestWatcher(testCase, request); |
| + const database = event.target.result; |
| + const transaction = event.target.transaction; |
| + setupCallback(database, transaction); |
| + resolve(eventWatcher.wait_for('success')); |
| + }; |
| + request.onerror = event => reject(event.target.error); |
| + }).then(event => event.target.result); |
| +}; |
| + |
| +// 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 = function(testCase, setupCallback) { |
| + const request = indexedDB.deleteDatabase(databaseName(testCase)); |
| + const eventWatcher = requestWatcher(testCase, request); |
| + |
| + return eventWatcher.wait_for('success').then(event => |
| + migrateDatabase(testCase, 1, setupCallback)); |
| +}; |
| + |
| +// Creates a 'books' object store whose contents closely resembles the first |
| +// example in the IndexedDB specification. |
| +const createBooksStore = function(testCase, database) { |
| + const store = database.createObjectStore('books', |
| + { keyPath: 'isbn', autoIncrement: true }); |
| + store.createIndex('by_author', 'author'); |
| + store.createIndex('by_title', 'title', { unique: true }); |
| + store.put({ title: 'Quarry Memories', author: 'Fred', isbn: 123456 }); |
| + store.put({ title: 'Water Buffaloes', author: 'Fred', isbn: 234567 }); |
| + store.put({ title: 'Bedrock Nights', author: 'Barney', isbn: 345678 }); |
| + return store; |
| +}; |
| + |
| +// Creates a 'not_books' object store used to test renaming into existing or |
| +// deleted store names. |
| +const createNotBooksStore = function(testCase, database) { |
| + return database.createObjectStore('not_books'); |
| +}; |
| + |
| +// Renames the 'books' store to 'renamed_books'. |
| +// |
| +// Returns a promise that resolves to an IndexedDB database. The caller must |
| +// close the database. |
| +const renameBooksStore = function(testCase) { |
| + return migrateDatabase(testCase, 2, (database, transaction) => { |
| + const store = transaction.objectStore('books'); |
| + store.name = 'renamed_books'; |
| + }); |
| +}; |
| + |
| +// 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 = function(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, 123456, errorMessage); |
| + assert_equals(result.author, 'Fred', errorMessage); |
| + assert_equals(result.title, 'Quarry Memories', errorMessage); |
| + }); |
| +}; |
| + |
| +// Verifies that an object store's index matches the 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 checkStoreIndex = function(testCase, store, errorMessage) { |
| + assert_array_equals( |
| + store.indexNames, ['by_author', 'by_title'], errorMessage); |
| + const index = store.index('by_author'); |
| + const request = index.get('Barney'); |
| + const eventWatcher = requestWatcher(testCase, request); |
| + return eventWatcher.wait_for('success').then(() => { |
| + const result = request.result; |
| + assert_equals(result.isbn, 345678, errorMessage); |
| + assert_equals(result.title, 'Bedrock Nights', 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 = function(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); |
| + }); |
| +}; |
| + |
| +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 content checks should pass 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_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_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 checkStoreIndex( |
| + testCase, store, |
| + 'The object store index should pass before any renaming').then( |
|
jsbell
2016/09/02 22:57:37
Maybe rephrase "should pass", e.g. "should have ex
pwnall
2016/09/03 06:01:19
Done.
|
| + () => database.close()); |
| + }).then(() => renameBooksStore(testCase) |
| + ).then(database => { |
| + const transaction = database.transaction('renamed_books', 'readonly'); |
| + const store = transaction.objectStore('renamed_books'); |
| + return checkStoreIndex( |
| + 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 state test should pass before ' + |
| + 'any renaming').then(() => database.close()); |
|
jsbell
2016/09/02 22:57:37
Nit: extra space in string
pwnall
2016/09/03 06:01:19
Done.
|
| + }).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'); |
| + 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); |
| + }).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'); |
| + 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); |
| + 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'); |
| + |
| +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'); |
| + |
| +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); |
| + |
| +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(() => new Promise((resolve, reject) => { |
| + const request = indexedDB.open(dbName, 2); |
| + request.onupgradeneeded = event => { |
| + const database = event.target.result; |
| + const transaction = event.target.transaction; |
| + bookStore = transaction.objectStore('books'); |
| + bookStore.name = 'renamed_books'; |
| + |
| + request.onerror = event => { |
| + event.preventDefault(); |
| + resolve(event); |
| + }; |
| + transaction.abort(); |
| + |
| + assert_equals( |
| + bookStore.name, 'books', |
| + 'IDBObjectStore.name should not reflect the rename anymore ' + |
| + 'immediately after transaction.abort() returns'); |
| + assert_array_equals( |
| + database.objectStoreNames, ['books'], |
| + 'IDBDatabase.objectStoreNames should not reflect the rename ' + |
| + 'anymore immediately after transaction.abort() returns'); |
| + }; |
| + request.onerror = event => reject(event.target.error); |
| + request.onsuccess = () => reject(new Error( |
| + 'indexedDB.open was not supposed to succeed')); |
| + })).then(event => { |
| + assert_equals(bookStore.name, 'books', |
| + 'IDBObjectStore.name should not reflect the rename anymore ' + |
| + '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'); |
| +</script> |