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

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: Added tests for create rename in the same aborted transaction. 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_array_equals(
49 transaction.objectStoreNames, ['renamed_books'],
50 'IDBTransaction.objectStoreNames should immediately reflect the ' +
51 'rename');
52 assert_equals(
53 transaction.objectStore('renamed_books'), renamedBookStore,
54 'IDBTransaction.objectStore should return the renamed object ' +
55 'store when queried using the new name immediately after the ' +
56 'rename');
57 assert_throws(
58 'NotFoundError', () => transaction.objectStore('books'),
59 'IDBTransaction.objectStore should throw when queried using the ' +
60 "renamed object store's old name immediately after the rename");
61 })).then(database => {
62 assert_array_equals(
63 database.objectStoreNames, ['renamed_books'],
64 'IDBDatabase.objectStoreNames should still reflect the rename ' +
65 'after the versionchange transaction commits');
66 const transaction = database.transaction('renamed_books', 'readonly');
67 renamedBookStore2 = transaction.objectStore('renamed_books');
68 return checkStoreContents(
69 testCase, renamedBookStore2,
70 'Renaming an object store should not change its records').then(
71 () => database.close());
72 }).then(() => {
73 assert_equals(
74 bookStore.name, 'books',
75 'IDBObjectStore obtained before the rename transaction should ' +
76 'not reflect the rename');
77 assert_equals(
78 bookStore2.name, 'books',
79 'IDBObjectStore obtained before the rename transaction should ' +
80 'not reflect the rename');
81 assert_equals(
82 renamedBookStore.name, 'renamed_books',
83 'IDBObjectStore used in the rename transaction should keep ' +
84 'reflecting the new name after the transaction is committed');
85 assert_equals(
86 renamedBookStore2.name, 'renamed_books',
87 'IDBObjectStore obtained after the rename transaction should ' +
88 'reflect the new name');
89 });
90 }, 'IndexedDB object store rename in new transaction');
91
92 promise_test(testCase => {
93 let renamedBookStore = null, renamedBookStore2 = null;
94 return createDatabase(testCase, (database, transaction) => {
95 renamedBookStore = createBooksStore(testCase, database);
96 renamedBookStore.name = 'renamed_books';
97
98 assert_equals(
99 renamedBookStore.name, 'renamed_books',
100 'IDBObjectStore name should change immediately after a rename');
101 assert_array_equals(
102 database.objectStoreNames, ['renamed_books'],
103 'IDBDatabase.objectStoreNames should immediately reflect the ' +
104 'rename');
105 assert_array_equals(
106 transaction.objectStoreNames, ['renamed_books'],
107 'IDBTransaction.objectStoreNames should immediately reflect the ' +
108 'rename');
109 assert_equals(
110 transaction.objectStore('renamed_books'), renamedBookStore,
111 'IDBTransaction.objectStore should return the renamed object ' +
112 'store when queried using the new name immediately after the ' +
113 'rename');
114 assert_throws(
115 'NotFoundError', () => transaction.objectStore('books'),
116 'IDBTransaction.objectStore should throw when queried using the ' +
117 "renamed object store's old name immediately after the rename");
118 }).then(database => {
119 assert_array_equals(
120 database.objectStoreNames, ['renamed_books'],
121 'IDBDatabase.objectStoreNames should still reflect the rename ' +
122 'after the versionchange transaction commits');
123 const transaction = database.transaction('renamed_books', 'readonly');
124 renamedBookStore2 = transaction.objectStore('renamed_books');
125 return checkStoreContents(
126 testCase, renamedBookStore2,
127 'Renaming an object store should not change its records').then(
128 () => database.close());
129 }).then(() => {
130 assert_equals(
131 renamedBookStore.name, 'renamed_books',
132 'IDBObjectStore used in the rename transaction should keep ' +
133 'reflecting the new name after the transaction is committed');
134 assert_equals(
135 renamedBookStore2.name, 'renamed_books',
136 'IDBObjectStore obtained after the rename transaction should ' +
137 'reflect the new name');
138 });
139 }, 'IndexedDB object store rename in the transaction where it is created');
140
141 promise_test(testCase => {
142 return createDatabase(testCase, (database, transaction) => {
143 createBooksStore(testCase, database);
144 }).then(database => {
145 const transaction = database.transaction('books', 'readonly');
146 const store = transaction.objectStore('books');
147 return checkStoreIndexes(
148 testCase, store,
149 'The object store index should have the expected contens before ' +
150 'any renaming').then(
151 () => database.close());
152 }).then(() => renameBooksStore(testCase)
153 ).then(database => {
154 const transaction = database.transaction('renamed_books', 'readonly');
155 const store = transaction.objectStore('renamed_books');
156 return checkStoreIndexes(
157 testCase, store,
158 'Renaming an object store should not change its indexes').then(
159 () => database.close());
160 });
161 }, 'IndexedDB object store rename covers index');
162
163 promise_test(testCase => {
164 return createDatabase(testCase, (database, transaction) => {
165 createBooksStore(testCase, database);
166 }).then(database => {
167 const transaction = database.transaction('books', 'readwrite');
168 const store = transaction.objectStore('books');
169 return checkStoreGenerator(
170 testCase, store, 345679,
171 'The object store key generator should have the expected state ' +
172 'before any renaming').then(() => database.close());
173 }).then(() => renameBooksStore(testCase)
174 ).then(database => {
175 const transaction = database.transaction('renamed_books', 'readwrite');
176 const store = transaction.objectStore('renamed_books');
177 return checkStoreGenerator(
178 testCase, store, 345680,
179 'Renaming an object store should not change the state of its key ' +
180 'generator').then(() => database.close());
181 });
182 }, 'IndexedDB object store rename covers key generator');
183
184 promise_test(testCase => {
185 return createDatabase(testCase, (database, transaction) => {
186 createBooksStore(testCase, database);
187 }).then(database => {
188 database.close();
189 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
190 const store = transaction.objectStore('books');
191 database.deleteObjectStore('books');
192 assert_throws('InvalidStateError', () => store.name = 'renamed_books');
193 })).then(database => {
194 database.close();
195 });
196 }, 'IndexedDB deleted object store rename throws');
197
198 promise_test(testCase => {
199 return createDatabase(testCase, (database, transaction) => {
200 createBooksStore(testCase, database);
201 }).then(database => {
202 const transaction = database.transaction('books', 'readonly');
203 const store = transaction.objectStore('books');
204 assert_throws('InvalidStateError', () => store.name = 'renamed_books');
205 database.close();
206 });
207 }, 'IndexedDB object store rename throws in a readonly transaction');
208
209 promise_test(testCase => {
210 return createDatabase(testCase, (database, transaction) => {
211 createBooksStore(testCase, database);
212 }).then(database => {
213 const transaction = database.transaction('books', 'readwrite');
214 const store = transaction.objectStore('books');
215
216 assert_throws('InvalidStateError', () => store.name = 'renamed_books');
217 database.close();
218 });
219 }, 'IndexedDB object store rename throws in a readwrite transaction');
220
221 promise_test(testCase => {
222 let bookStore = null;
223 return createDatabase(testCase, (database, transaction) => {
224 bookStore = createBooksStore(testCase, database);
225 }).then(database => {
226 assert_throws('TransactionInactiveError',
227 () => { bookStore.name = 'renamed_books'; });
228 database.close();
229 });
230 }, 'IndexedDB object store rename throws in an inactive transaction');
231
232 promise_test(testCase => {
233 return createDatabase(testCase, (database, transaction) => {
234 createBooksStore(testCase, database);
235 }).then(database => {
236 database.close();
237 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
238 const store = transaction.objectStore('books');
239 store.name = 'books';
240 assert_array_equals(
241 database.objectStoreNames, ['books'],
242 'Renaming a store to the same name should not change ' +
243 "the store's IDBDatabase.objectStoreNames");
244 })).then(database => {
245 assert_array_equals(
246 database.objectStoreNames, ['books'],
247 'Committing a transaction that renames a store to the same name ' +
248 "should not change the store's IDBDatabase.objectStoreNames");
249 const transaction = database.transaction('books', 'readonly');
250 const store = transaction.objectStore('books');
251 return checkStoreContents(
252 testCase, store,
253 'Committing a transaction that renames a store to the same name ' +
254 "should not change the store's contents").then(
255 () => database.close());
256 });
257 }, 'IndexedDB object store rename to the same name succeeds');
258
259 promise_test(testCase => {
260 return createDatabase(testCase, (database, transaction) => {
261 createBooksStore(testCase, database);
262 createNotBooksStore(testCase, database);
263 }).then(database => {
264 database.close();
265 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
266 const store = transaction.objectStore('books');
267 assert_throws('ConstraintError', () => store.name = 'not_books');
268 assert_array_equals(
269 database.objectStoreNames, ['books', 'not_books'],
270 'A store rename that throws an exception should not change the ' +
271 "store's IDBDatabase.objectStoreNames");
272 })).then(database => {
273 assert_array_equals(
274 database.objectStoreNames, ['books', 'not_books'],
275 'Committing a transaction with a failed store rename attempt ' +
276 "should not change the store's IDBDatabase.objectStoreNames");
277 const transaction = database.transaction('books', 'readonly');
278 const store = transaction.objectStore('books');
279 return checkStoreContents(
280 testCase, store,
281 'Committing a transaction with a failed rename attempt should not' +
jsbell 2016/09/07 17:16:14 need a space before the closing '
pwnall 2016/09/07 22:43:52 Done.
282 "change the store's contents").then(() => database.close());
283 });
284 }, 'IndexedDB object store rename to the name of another store throws');
285
286 promise_test(testCase => {
287 return createDatabase(testCase, (database, transaction) => {
288 createBooksStore(testCase, database);
289 createNotBooksStore(testCase, database);
290 }).then(database => {
291 database.close();
292 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
293 const store = transaction.objectStore('books');
294 database.deleteObjectStore('not_books');
295 store.name = 'not_books';
296 assert_array_equals(
297 database.objectStoreNames, ['not_books'],
298 'IDBDatabase.objectStoreNames should immediately reflect the ' +
299 'rename');
300 })).then(database => {
301 assert_array_equals(
302 database.objectStoreNames, ['not_books'],
303 'IDBDatabase.objectStoreNames should still reflect the rename ' +
304 'after the versionchange transaction commits');
305 const transaction = database.transaction('not_books', 'readonly');
306 const store = transaction.objectStore('not_books');
307 return checkStoreContents(
308 testCase, store,
309 'Renaming an object store should not change its records').then(
310 () => database.close());
311 });
312 }, 'IndexedDB object store rename to the name of a deleted store succeeds');
313
314 promise_test(testCase => {
315 return createDatabase(testCase, (database, transaction) => {
316 createBooksStore(testCase, database);
317 createNotBooksStore(testCase, database);
318 }).then(database => {
319 database.close();
320 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
321 const bookStore = transaction.objectStore('books');
322 const notBookStore = transaction.objectStore('not_books');
323
324 transaction.objectStore('books').name = 'tmp';
325 transaction.objectStore('not_books').name = 'books';
326 transaction.objectStore('tmp').name = 'not_books';
327
328 assert_array_equals(
329 database.objectStoreNames, ['books', 'not_books'],
330 'IDBDatabase.objectStoreNames should immediately reflect the swap');
331
332 assert_equals(
333 transaction.objectStore('books'), notBookStore,
334 'IDBTransaction.objectStore should return the original "books" ' +
335 'store when queried with "not_books" after the swap');
336 assert_equals(
337 transaction.objectStore('not_books'), bookStore,
338 'IDBTransaction.objectStore should return the original ' +
339 '"not_books" store when queried with "books" after the swap');
340 })).then(database => {
341 assert_array_equals(
342 database.objectStoreNames, ['books', 'not_books'],
343 'IDBDatabase.objectStoreNames should still reflect the swap ' +
344 'after the versionchange transaction commits');
345 const transaction = database.transaction('not_books', 'readonly');
346 const store = transaction.objectStore('not_books');
347 assert_array_equals(
348 store.indexNames, ['by_author', 'by_title'],
349 '"not_books" index names should still reflect the swap after the ' +
350 'versionchange transaction commits');
351 return checkStoreContents(
352 testCase, store,
353 'Swapping two object stores should not change their records').then(
354 () => database.close());
355 });
356 }, 'IndexedDB object store swapping via renames succeeds');
357
358 promise_test(testCase => {
359 return createDatabase(testCase, (database, transaction) => {
360 createBooksStore(testCase, database);
361 }).then(database => {
362 database.close();
363 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
364 const store = transaction.objectStore('books');
365
366 store.name = 42;
367 assert_equals(store.name, '42',
368 'IDBObjectStore name should change immediately after a ' +
369 'rename to a number');
370 assert_array_equals(
371 database.objectStoreNames, ['42'],
372 'IDBDatabase.objectStoreNames should immediately reflect the ' +
373 'stringifying rename');
374
375 store.name = true;
376 assert_equals(store.name, 'true',
377 'IDBObjectStore name should change immediately after a ' +
378 'rename to a boolean');
379
380 store.name = {};
381 assert_equals(store.name, '[object Object]',
382 'IDBObjectStore name should change immediately after a ' +
383 'rename to an object');
384
385 store.name = () => null;
386 assert_equals(store.name, '() => null',
387 'IDBObjectStore name should change immediately after a ' +
388 'rename to a function');
389
390 store.name = undefined;
391 assert_equals(store.name, 'undefined',
392 'IDBObjectStore name should change immediately after a ' +
393 'rename to undefined');
394 })).then(database => {
395 assert_array_equals(
396 database.objectStoreNames, ['undefined'],
397 'IDBDatabase.objectStoreNames should reflect the last rename ' +
398 'after the versionchange transaction commits');
399 const transaction = database.transaction('undefined', 'readonly');
400 const store = transaction.objectStore('undefined');
401 return checkStoreContents(
402 testCase, store,
403 'Renaming an object store should not change its records').then(
404 () => database.close());
405 });
406 }, 'IndexedDB object store rename stringifies non-string names');
407
408 promise_test(testCase => {
409 return createDatabase(testCase, (database, transaction) => {
410 createBooksStore(testCase, database);
411 }).then(database => {
412 database.close();
413 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
414 const store = transaction.objectStore('books');
415 assert_throws(
416 { name: 'Custom stringifying error'},
417 () => {
418 store.name = {
419 toString: () => { throw { name: 'Custom stringifying error'}; }
420 };
421 }, 'IDBObjectStore rename should re-raise toString() exception');
422 assert_array_equals(
423 database.objectStoreNames, ['books'],
424 'A store rename that throws an exception should not change the ' +
425 "store's IDBDatabase.objectStoreNames");
426 })).then(database => {
427 assert_array_equals(
428 database.objectStoreNames, ['books'],
429 'Committing a transaction with a failed store rename attempt ' +
430 "should not change the store's IDBDatabase.objectStoreNames");
431 const transaction = database.transaction('books', 'readonly');
432 const store = transaction.objectStore('books');
433 return checkStoreContents(
434 testCase, store,
435 'Committing a transaction with a failed rename attempt should not' +
436 "change the store's contents").then(() => database.close());
437 });
438 }, 'IndexedDB object store rename handles exceptions when stringifying names');
439
440 for (let escapedName of ['', '\\u0000', '\\uDC00\\uD800']) ((escapedName) => {
441 const name = JSON.parse('"' + escapedName + '"');
442 promise_test(testCase => {
443 return createDatabase(testCase, (database, transaction) => {
444 createBooksStore(testCase, database);
445 }).then(database => {
446 database.close();
447 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => {
448 const store = transaction.objectStore('books');
449
450 store.name = name;
451 assert_equals(store.name, name,
452 'IDBObjectStore name should change immediately after the ' +
453 'rename');
454 assert_array_equals(
455 database.objectStoreNames, [name],
456 'IDBDatabase.objectStoreNames should immediately reflect the ' +
457 'rename');
458 })).then(database => {
459 assert_array_equals(
460 database.objectStoreNames, [name],
461 'IDBDatabase.objectStoreNames should reflect the rename ' +
462 'after the versionchange transaction commits');
463 const transaction = database.transaction(name, 'readonly');
464 const store = transaction.objectStore(name);
465 return checkStoreContents(
466 testCase, store,
467 'Renaming an object store should not change its records').then(
468 () => database.close());
469 });
470 }, 'IndexedDB object store can be renamed to "' + escapedName + '"');
471 })(escapedName);
472
473 promise_test(testCase => {
474 const dbName = databaseName(testCase);
475 let bookStore = null, bookStore2 = null;
476 return createDatabase(testCase, (database, transaction) => {
477 createBooksStore(testCase, database);
478 }).then(database => {
479 database.close();
480 }).then(() => new Promise((resolve, reject) => {
481 const request = indexedDB.open(dbName, 2);
482 request.onupgradeneeded = event => {
483 const database = event.target.result;
484 const transaction = event.target.transaction;
485 bookStore = transaction.objectStore('books');
486 bookStore.name = 'renamed_books';
487
488 request.onerror = event => {
489 event.preventDefault();
490 resolve(event);
491 };
492 transaction.abort();
493
494 assert_equals(
495 bookStore.name, 'books',
496 'IDBObjectStore.name should not reflect the rename anymore ' +
497 'immediately after transaction.abort() returns');
498 assert_array_equals(
499 database.objectStoreNames, ['books'],
500 'IDBDatabase.objectStoreNames should not reflect the rename ' +
501 'anymore immediately after transaction.abort() returns');
502 assert_array_equals(
503 transaction.objectStoreNames, ['books'],
504 'IDBTransaction.objectStoreNames should not reflect the ' +
505 'rename anymore immediately after transaction.abort() returns');
506 };
507 request.onerror = event => reject(event.target.error);
508 request.onsuccess = () => reject(new Error(
509 'indexedDB.open was not supposed to succeed'));
510 })).then(event => {
511 assert_equals(bookStore.name, 'books',
512 'IDBObjectStore.name should not reflect the rename anymore ' +
513 'after the versionchange transaction is aborted');
514 const request = indexedDB.open(dbName, 1);
515 return requestWatcher(testCase, request).wait_for('success');
516 }).then(event => {
517 const database = event.target.result;
518 assert_array_equals(
519 database.objectStoreNames, ['books'],
520 'IDBDatabase.objectStoreNames should not reflect the rename ' +
521 'after the versionchange transaction is aborted');
522
523 const transaction = database.transaction('books', 'readonly');
524 bookStore2 = transaction.objectStore('books');
525 return checkStoreContents(
526 testCase, bookStore2,
527 'Aborting an object store rename transaction should not change ' +
528 "the store's records").then(() => database.close());
529 }).then(() => {
530 assert_equals(
531 bookStore.name, 'books',
532 'IDBObjectStore used in aborted rename transaction should not ' +
533 'reflect the rename after the transaction is aborted');
534 assert_equals(
535 bookStore2.name, 'books',
536 'IDBObjectStore obtained after an aborted rename transaction ' +
537 'should not reflect the rename');
538 });
539 }, 'IndexedDB object store rename in aborted transaction');
540
541 promise_test(testCase => {
542 const dbName = databaseName(testCase);
543 let notBookStore = null;
544 return createDatabase(testCase, (database, transaction) => {
545 }).then(database => {
546 database.close();
547 }).then(() => new Promise((resolve, reject) => {
548 const request = indexedDB.open(dbName, 2);
549 request.onupgradeneeded = event => {
550 const database = event.target.result;
551 const transaction = event.target.transaction;
552 notBookStore = createNotBooksStore(testCase, database);
553 notBookStore.name = 'not_books_renamed';
554 notBookStore.name = 'not_books_renamed_again';
555
556 request.onerror = event => {
557 event.preventDefault();
558 resolve(event);
559 };
560 transaction.abort();
561
562 assert_equals(
563 notBookStore.name, 'not_books_renamed_again',
564 'IDBObjectStore.name should reflect the last rename ' +
565 'immediately after transaction.abort() returns');
566 assert_array_equals(
567 database.objectStoreNames, [],
568 'IDBDatabase.objectStoreNames should not reflect the creation' +
jsbell 2016/09/07 17:16:14 need a space before the closing '
pwnall 2016/09/07 22:43:52 Done.
569 'or the rename anymore immediately after transaction.abort() ' +
570 'returns');
571 assert_array_equals(
572 transaction.objectStoreNames, [],
573 'IDBTransaction.objectStoreNames should not reflect the ' +
574 'creation or the rename anymore immediately after ' +
575 'transaction.abort() returns');
576 };
577 request.onerror = event => reject(event.target.error);
578 request.onsuccess = () => reject(new Error(
579 'indexedDB.open was not supposed to succeed'));
580 })).then(event => {
581 assert_equals(notBookStore.name, 'not_books_renamed_again',
582 'IDBObjectStore.name should reflect the last rename ' +
583 'after the versionchange transaction is aborted');
584 const request = indexedDB.open(dbName, 1);
585 return requestWatcher(testCase, request).wait_for('success');
586 }).then(event => {
587 const database = event.target.result;
588 assert_array_equals(
589 database.objectStoreNames, [],
590 'IDBDatabase.objectStoreNames should not reflect the creation or ' +
591 'the rename after the versionchange transaction is aborted');
592
593 database.close();
594 });
595 }, 'IndexedDB object store creation and rename in an aborted transaction');
596
597 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698