Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(378)

Side by Side Diff: third_party/WebKit/LayoutTests/storage/indexeddb/rename-object-store.html

Issue 2276593002: Support renaming of IndexedDB indexes and object stores. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed review and buildbot feedback. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!DOCTYPE html>
2 <title>IndexedDB: object store renaming support</title>
3 <script src='../../resources/testharness.js'></script>
4 <link rel="help"
5 href="https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name">
6 <link rel="author" href="pwnall@chromium.org" title="Victor Costan">
7 <script src='../../resources/testharnessreport.js'></script>
8 <script src='resources/rename-common.js'></script>
9 <script>
10
11 // Renames the 'books' store to 'renamed_books'.
12 //
13 // Returns a promise that resolves to an IndexedDB database. The caller must
14 // close the database.
15 const renameBooksStore = function(testCase) {
16 return migrateDatabase(testCase, 2, (database, transaction) => {
17 const store = transaction.objectStore('books');
18 store.name = 'renamed_books';
19 });
20 };
21
22 promise_test(testCase => {
23 let bookStore = null, bookStore2 = null;
24 let renamedBookStore = null, renamedBookStore2 = null;
25 return createDatabase(testCase, (database, transaction) => {
26 bookStore = createBooksStore(testCase, database);
27 }).then(database => {
28 assert_array_equals(
29 database.objectStoreNames, ['books'],
30 'Test setup should have created a "books" object store');
31 const transaction = database.transaction('books', 'readonly');
32 bookStore2 = transaction.objectStore('books');
33 return checkStoreContents(
34 testCase, bookStore2,
35 'The store should have the expected contents before any renaming').
36 then(() => database.close());
37 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
38 renamedBookStore = transaction.objectStore('books');
39 renamedBookStore.name = 'renamed_books';
40
41 assert_equals(
42 renamedBookStore.name, 'renamed_books',
43 'IDBObjectStore name should change immediately after a rename');
44 assert_array_equals(
45 database.objectStoreNames, ['renamed_books'],
46 'IDBDatabase.objectStoreNames should immediately reflect the ' +
47 'rename');
48 assert_equals(
49 transaction.objectStore('renamed_books'), renamedBookStore,
50 'IDBTransaction.objectStore should return the renamed object ' +
51 'store when queried using the new name immediately after the ' +
52 'rename');
53 assert_throws(
54 'NotFoundError', () => transaction.objectStore('books'),
55 'IDBTransaction.objectStore should throw when queried using the ' +
56 "renamed object store's old name immediately after the rename");
57 })).then(database => {
58 assert_array_equals(
59 database.objectStoreNames, ['renamed_books'],
60 'IDBDatabase.objectStoreNames should still reflect the rename ' +
61 'after the versionchange transaction commits');
62 const transaction = database.transaction('renamed_books', 'readonly');
63 renamedBookStore2 = transaction.objectStore('renamed_books');
64 return checkStoreContents(
65 testCase, renamedBookStore2,
66 'Renaming an object store should not change its records').then(
67 () => database.close());
68 }).then(() => {
69 assert_equals(
70 bookStore.name, 'books',
71 'IDBObjectStore obtained before the rename transaction should ' +
72 'not reflect the rename');
73 assert_equals(
74 bookStore2.name, 'books',
75 'IDBObjectStore obtained before the rename transaction should ' +
76 'not reflect the rename');
77 assert_equals(
78 renamedBookStore.name, 'renamed_books',
79 'IDBObjectStore used in the rename transaction should keep ' +
80 'reflecting the new name after the transaction is committed');
81 assert_equals(
82 renamedBookStore2.name, 'renamed_books',
83 'IDBObjectStore obtained after the rename transaction should ' +
84 'reflect the new name');
85 });
86 }, 'IndexedDB object store rename in new transaction');
87
88 promise_test(testCase => {
89 let renamedBookStore = null, renamedBookStore2 = null;
90 return createDatabase(testCase, (database, transaction) => {
91 renamedBookStore = createBooksStore(testCase, database);
92 renamedBookStore.name = 'renamed_books';
93
94 assert_equals(
95 renamedBookStore.name, 'renamed_books',
96 'IDBObjectStore name should change immediately after a rename');
97 assert_array_equals(
98 database.objectStoreNames, ['renamed_books'],
99 'IDBDatabase.objectStoreNames should immediately reflect the ' +
100 'rename');
101 assert_equals(
102 transaction.objectStore('renamed_books'), renamedBookStore,
103 'IDBTransaction.objectStore should return the renamed object ' +
104 'store when queried using the new name immediately after the ' +
105 'rename');
106 assert_throws(
107 'NotFoundError', () => transaction.objectStore('books'),
108 'IDBTransaction.objectStore should throw when queried using the ' +
109 "renamed object store's old name immediately after the rename");
110 }).then(database => {
111 assert_array_equals(
112 database.objectStoreNames, ['renamed_books'],
113 'IDBDatabase.objectStoreNames should still reflect the rename ' +
114 'after the versionchange transaction commits');
115 const transaction = database.transaction('renamed_books', 'readonly');
116 renamedBookStore2 = transaction.objectStore('renamed_books');
117 return checkStoreContents(
118 testCase, renamedBookStore2,
119 'Renaming an object store should not change its records').then(
120 () => database.close());
121 }).then(() => {
122 assert_equals(
123 renamedBookStore.name, 'renamed_books',
124 'IDBObjectStore used in the rename transaction should keep ' +
125 'reflecting the new name after the transaction is committed');
126 assert_equals(
127 renamedBookStore2.name, 'renamed_books',
128 'IDBObjectStore obtained after the rename transaction should ' +
129 'reflect the new name');
130 });
131 }, 'IndexedDB object store rename in the transaction where it is created');
132
133 promise_test(testCase => {
134 return createDatabase(testCase, (database, transaction) => {
135 createBooksStore(testCase, database);
136 }).then(database => {
137 const transaction = database.transaction('books', 'readonly');
138 const store = transaction.objectStore('books');
139 return checkStoreIndexes(
140 testCase, store,
141 'The object store index should have the expected contens before ' +
142 'any renaming').then(
143 () => database.close());
144 }).then(() => renameBooksStore(testCase)
145 ).then(database => {
146 const transaction = database.transaction('renamed_books', 'readonly');
147 const store = transaction.objectStore('renamed_books');
148 return checkStoreIndexes(
149 testCase, store,
150 'Renaming an object store should not change its indexes').then(
151 () => database.close());
152 });
153 }, 'IndexedDB object store rename covers index');
154
155 promise_test(testCase => {
156 return createDatabase(testCase, (database, transaction) => {
157 createBooksStore(testCase, database);
158 }).then(database => {
159 const transaction = database.transaction('books', 'readwrite');
160 const store = transaction.objectStore('books');
161 return checkStoreGenerator(
162 testCase, store, 345679,
163 'The object store key generator should have the expected state ' +
164 'before any renaming').then(() => database.close());
165 }).then(() => renameBooksStore(testCase)
166 ).then(database => {
167 const transaction = database.transaction('renamed_books', 'readwrite');
168 const store = transaction.objectStore('renamed_books');
169 return checkStoreGenerator(
170 testCase, store, 345680,
171 'Renaming an object store should not change the state of its key ' +
172 'generator').then(() => database.close());
173 });
174 }, 'IndexedDB object store rename covers key generator');
175
176 promise_test(testCase => {
177 return createDatabase(testCase, (database, transaction) => {
178 createBooksStore(testCase, database);
179 }).then(database => {
180 database.close();
181 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
182 const store = transaction.objectStore('books');
183 database.deleteObjectStore('books');
184 assert_throws('InvalidStateError', () => store.name = 'renamed_books');
185 })).then(database => {
186 database.close();
187 });
188 }, 'IndexedDB deleted object store rename throws');
189
190 promise_test(testCase => {
191 return createDatabase(testCase, (database, transaction) => {
192 createBooksStore(testCase, database);
193 }).then(database => {
194 const transaction = database.transaction('books', 'readonly');
195 const store = transaction.objectStore('books');
196 assert_throws('InvalidStateError', () => store.name = 'renamed_books');
197 database.close();
198 });
199 }, 'IndexedDB object store rename throws in a readonly transaction');
200
201 promise_test(testCase => {
202 return createDatabase(testCase, (database, transaction) => {
203 createBooksStore(testCase, database);
204 }).then(database => {
205 const transaction = database.transaction('books', 'readwrite');
206 const store = transaction.objectStore('books');
207
208 assert_throws('InvalidStateError', () => store.name = 'renamed_books');
209 database.close();
210 });
211 }, 'IndexedDB object store rename throws in a readwrite transaction');
212
213 promise_test(testCase => {
214 let bookStore = null;
215 return createDatabase(testCase, (database, transaction) => {
216 bookStore = createBooksStore(testCase, database);
217 }).then(database => {
218 assert_throws('TransactionInactiveError',
219 () => { bookStore.name = 'renamed_books'; });
220 database.close();
221 });
222 }, 'IndexedDB object store rename throws in an inactive transaction');
223
224 promise_test(testCase => {
225 return createDatabase(testCase, (database, transaction) => {
226 createBooksStore(testCase, database);
227 }).then(database => {
228 database.close();
229 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
230 const store = transaction.objectStore('books');
231 store.name = 'books';
232 assert_array_equals(
233 database.objectStoreNames, ['books'],
234 'Renaming a store to the same name should not change ' +
235 "the store's IDBDatabase.objectStoreNames");
236 })).then(database => {
237 assert_array_equals(
238 database.objectStoreNames, ['books'],
239 'Committing a transaction that renames a store to the same name ' +
240 "should not change the store's IDBDatabase.objectStoreNames");
241 const transaction = database.transaction('books', 'readonly');
242 const store = transaction.objectStore('books');
243 return checkStoreContents(
244 testCase, store,
245 'Committing a transaction that renames a store to the same name ' +
246 "should not change the store's contents").then(
247 () => database.close());
248 });
249 }, 'IndexedDB object store rename to the same name succeeds');
250
251 promise_test(testCase => {
252 return createDatabase(testCase, (database, transaction) => {
253 createBooksStore(testCase, database);
254 createNotBooksStore(testCase, database);
255 }).then(database => {
256 database.close();
257 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
258 const store = transaction.objectStore('books');
259 assert_throws('ConstraintError', () => store.name = 'not_books');
260 assert_array_equals(
261 database.objectStoreNames, ['books', 'not_books'],
262 'A store rename that throws an exception should not change the ' +
263 "store's IDBDatabase.objectStoreNames");
264 })).then(database => {
265 assert_array_equals(
266 database.objectStoreNames, ['books', 'not_books'],
267 'Committing a transaction with a failed store rename attempt ' +
268 "should not change the store's IDBDatabase.objectStoreNames");
269 const transaction = database.transaction('books', 'readonly');
270 const store = transaction.objectStore('books');
271 return checkStoreContents(
272 testCase, store,
273 'Committing a transaction with a failed rename attempt should not' +
274 "change the store's contents").then(() => database.close());
275 });
276 }, 'IndexedDB object store rename to the name of another store throws');
277
278 promise_test(testCase => {
279 return createDatabase(testCase, (database, transaction) => {
280 createBooksStore(testCase, database);
281 createNotBooksStore(testCase, database);
282 }).then(database => {
283 database.close();
284 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
285 const store = transaction.objectStore('books');
286 database.deleteObjectStore('not_books');
287 store.name = 'not_books';
288 assert_array_equals(
289 database.objectStoreNames, ['not_books'],
290 'IDBDatabase.objectStoreNames should immediately reflect the ' +
291 'rename');
292 })).then(database => {
293 assert_array_equals(
294 database.objectStoreNames, ['not_books'],
295 'IDBDatabase.objectStoreNames should still reflect the rename ' +
296 'after the versionchange transaction commits');
297 const transaction = database.transaction('not_books', 'readonly');
298 const store = transaction.objectStore('not_books');
299 return checkStoreContents(
300 testCase, store,
301 'Renaming an object store should not change its records').then(
302 () => database.close());
303 });
304 }, 'IndexedDB object store rename to the name of a deleted store succeeds');
305
306 promise_test(testCase => {
307 return createDatabase(testCase, (database, transaction) => {
308 createBooksStore(testCase, database);
309 createNotBooksStore(testCase, database);
310 }).then(database => {
311 database.close();
312 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
313 const bookStore = transaction.objectStore('books');
314 const notBookStore = transaction.objectStore('not_books');
315
316 transaction.objectStore('books').name = 'tmp';
317 transaction.objectStore('not_books').name = 'books';
318 transaction.objectStore('tmp').name = 'not_books';
319
320 assert_array_equals(
321 database.objectStoreNames, ['books', 'not_books'],
322 'IDBDatabase.objectStoreNames should immediately reflect the swap');
323
324 assert_equals(
325 transaction.objectStore('books'), notBookStore,
326 'IDBTransaction.objectStore should return the original "books" ' +
327 'store when queried with "not_books" after the swap');
328 assert_equals(
329 transaction.objectStore('not_books'), bookStore,
330 'IDBTransaction.objectStore should return the original ' +
331 '"not_books" store when queried with "books" after the swap');
332 })).then(database => {
333 assert_array_equals(
334 database.objectStoreNames, ['books', 'not_books'],
335 'IDBDatabase.objectStoreNames should still reflect the swap ' +
336 'after the versionchange transaction commits');
337 const transaction = database.transaction('not_books', 'readonly');
338 const store = transaction.objectStore('not_books');
339 assert_array_equals(
340 store.indexNames, ['by_author', 'by_title'],
341 '"not_books" index names should still reflect the swap after the ' +
342 'versionchange transaction commits');
343 return checkStoreContents(
344 testCase, store,
345 'Swapping two object stores should not change their records').then(
346 () => database.close());
347 });
348 }, 'IndexedDB object store swapping via renames succeeds');
349
350 promise_test(testCase => {
351 return createDatabase(testCase, (database, transaction) => {
352 createBooksStore(testCase, database);
353 }).then(database => {
354 database.close();
355 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
356 const store = transaction.objectStore('books');
357
358 store.name = 42;
359 assert_equals(store.name, '42',
360 'IDBObjectStore name should change immediately after a ' +
361 'rename to a number');
362 assert_array_equals(
363 database.objectStoreNames, ['42'],
364 'IDBDatabase.objectStoreNames should immediately reflect the ' +
365 'stringifying rename');
366
367 store.name = true;
368 assert_equals(store.name, 'true',
369 'IDBObjectStore name should change immediately after a ' +
370 'rename to a boolean');
371
372 store.name = {};
373 assert_equals(store.name, '[object Object]',
374 'IDBObjectStore name should change immediately after a ' +
375 'rename to an object');
376
377 store.name = () => null;
378 assert_equals(store.name, '() => null',
379 'IDBObjectStore name should change immediately after a ' +
380 'rename to a function');
381
382 store.name = undefined;
383 assert_equals(store.name, 'undefined',
384 'IDBObjectStore name should change immediately after a ' +
385 'rename to undefined');
386 })).then(database => {
387 assert_array_equals(
388 database.objectStoreNames, ['undefined'],
389 'IDBDatabase.objectStoreNames should reflect the last rename ' +
390 'after the versionchange transaction commits');
391 const transaction = database.transaction('undefined', 'readonly');
392 const store = transaction.objectStore('undefined');
393 return checkStoreContents(
394 testCase, store,
395 'Renaming an object store should not change its records').then(
396 () => database.close());
397 });
398 }, 'IndexedDB object store rename stringifies non-string names');
399
400 promise_test(testCase => {
401 return createDatabase(testCase, (database, transaction) => {
402 createBooksStore(testCase, database);
403 }).then(database => {
404 database.close();
405 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
406 const store = transaction.objectStore('books');
407 assert_throws(
408 { name: 'Custom stringifying error'},
409 () => {
410 store.name = {
411 toString: () => { throw { name: 'Custom stringifying error'}; }
412 };
413 }, 'IDBObjectStore rename should re-raise toString() exception');
414 assert_array_equals(
415 database.objectStoreNames, ['books'],
416 'A store rename that throws an exception should not change the ' +
417 "store's IDBDatabase.objectStoreNames");
418 })).then(database => {
419 assert_array_equals(
420 database.objectStoreNames, ['books'],
421 'Committing a transaction with a failed store rename attempt ' +
422 "should not change the store's IDBDatabase.objectStoreNames");
423 const transaction = database.transaction('books', 'readonly');
424 const store = transaction.objectStore('books');
425 return checkStoreContents(
426 testCase, store,
427 'Committing a transaction with a failed rename attempt should not' +
428 "change the store's contents").then(() => database.close());
429 });
430 }, 'IndexedDB object store rename handles exceptions when stringifying names');
431
432 for (let escapedName of ['', '\\u0000', '\\uDC00\\uD800']) ((escapedName) => {
433 const name = JSON.parse('"' + escapedName + '"');
434 promise_test(testCase => {
435 return createDatabase(testCase, (database, transaction) => {
436 createBooksStore(testCase, database);
437 }).then(database => {
438 database.close();
439 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
440 const store = transaction.objectStore('books');
441
442 store.name = name;
443 assert_equals(store.name, name,
444 'IDBObjectStore name should change immediately after the ' +
445 'rename');
446 assert_array_equals(
447 database.objectStoreNames, [name],
448 'IDBDatabase.objectStoreNames should immediately reflect the ' +
449 'rename');
450 })).then(database => {
451 assert_array_equals(
452 database.objectStoreNames, [name],
453 'IDBDatabase.objectStoreNames should reflect the rename ' +
454 'after the versionchange transaction commits');
455 const transaction = database.transaction(name, 'readonly');
456 const store = transaction.objectStore(name);
457 return checkStoreContents(
458 testCase, store,
459 'Renaming an object store should not change its records').then(
460 () => database.close());
461 });
462 }, 'IndexedDB object store can be renamed to "' + escapedName + '"');
463 })(escapedName);
464
465 promise_test(testCase => {
466 const dbName = databaseName(testCase);
467 let bookStore = null, bookStore2 = null;
468 return createDatabase(testCase, (database, transaction) => {
469 createBooksStore(testCase, database);
470 }).then(database => {
471 database.close();
472 }).then(() => new Promise((resolve, reject) => {
473 const request = indexedDB.open(dbName, 2);
474 request.onupgradeneeded = event => {
475 const database = event.target.result;
476 const transaction = event.target.transaction;
477 bookStore = transaction.objectStore('books');
478 bookStore.name = 'renamed_books';
479
480 request.onerror = event => {
481 event.preventDefault();
482 resolve(event);
483 };
484 transaction.abort();
485
486 assert_equals(
487 bookStore.name, 'books',
488 'IDBObjectStore.name should not reflect the rename anymore ' +
489 'immediately after transaction.abort() returns');
490 assert_array_equals(
491 database.objectStoreNames, ['books'],
492 'IDBDatabase.objectStoreNames should not reflect the rename ' +
493 'anymore immediately after transaction.abort() returns');
494 };
495 request.onerror = event => reject(event.target.error);
496 request.onsuccess = () => reject(new Error(
497 'indexedDB.open was not supposed to succeed'));
498 })).then(event => {
499 assert_equals(bookStore.name, 'books',
500 'IDBObjectStore.name should not reflect the rename anymore ' +
501 'after the versionchange transaction is aborted');
502 const request = indexedDB.open(dbName, 1);
503 return requestWatcher(testCase, request).wait_for('success');
504 }).then(event => {
505 const database = event.target.result;
506 assert_array_equals(
507 database.objectStoreNames, ['books'],
508 'IDBDatabase.objectStoreNames should not reflect the rename ' +
509 'after the versionchange transaction is aborted');
510
511 const transaction = database.transaction('books', 'readonly');
512 bookStore2 = transaction.objectStore('books');
513 return checkStoreContents(
514 testCase, bookStore2,
515 'Aborting an object store rename transaction should not change ' +
516 "the store's records").then(() => database.close());
517 }).then(() => {
518 assert_equals(
519 bookStore.name, 'books',
520 'IDBObjectStore used in aborted rename transaction should not ' +
521 'reflect the rename after the transaction is aborted');
522 assert_equals(
523 bookStore2.name, 'books',
524 'IDBObjectStore obtained after an aborted rename transaction ' +
525 'should not reflect the rename');
526 });
527 }, 'IndexedDB object store rename in aborted transaction');
528 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698