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

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: finished up rename-object-store tests. 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 v2: object store renaming support</title>
jsbell 2016/08/26 23:20:50 nit: I wouldn't bother with the 'v2' here. (I thin
pwnall 2016/08/29 19:24:12 Done.
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>
9
10 // Returns an IndexedDB database name likely to be unique to the test case.
11 const databaseName = function(testCase) {
12 return 'db' + self.location.pathname + '-' + testCase.name;
13 };
14
15 // Creates an EventWatcher covering all the events that can be issued by
16 // IndexedDB requests and transactions.
17 const requestWatcher = function(testCase, request) {
18 return new EventWatcher(testCase, request,
19 ['abort', 'complete', 'error', 'success', 'upgradeneeded']);
jsbell 2016/08/26 23:20:50 This is only used for requests here, so I'd remove
pwnall 2016/08/29 19:24:12 Done.
20 };
21
22 // Migrates an IndexedDB database whose name is unique for the test case.
23 //
24 // setupCallback will be called during a versionchange transaction, and will be
25 // given the created database and the versionchange transaction.
26 //
27 // Returns a promise that yields an IndexedDB open success event.
28 const migrateDatabase = function(testCase, newVersion, setupCallback) {
29 // We cannot use eventWatcher.wait_for('upgradeneeded') here, because
30 // the versionchange transaction auto-commits before the Promise's then
31 // callback gets called.
32 return new Promise((resolve, reject) => {
33 const request = indexedDB.open(databaseName(testCase), newVersion);
34 request.onupgradeneeded = (event) => {
jsbell 2016/08/26 23:20:50 nit: don't need () around single argument (here an
pwnall 2016/08/29 19:24:12 Done.
35 const eventWatcher = requestWatcher(testCase, request);
36 const database = event.target.result;
37 const transaction = event.target.transaction;
38 setupCallback(database, transaction);
39 resolve(eventWatcher.wait_for('success'));
40 };
41 request.onerror =
jsbell 2016/08/26 23:20:50 Do you need to reject() here or does that get hand
pwnall 2016/08/29 19:24:12 Done. You were right, I needed the reject(). Witho
42 testCase.unreached_func('indexedDB.open issued an error event');
43 });
44 };
45
46 // Creates an IndexedDB database whose name is unique for the test case.
47 //
48 // setupCallback will be called during a versionchange transaction, and will be
49 // given the created database and the versionchange transaction.
50 //
51 // Returns a promise that yields an IndexedDB open success event.
jsbell 2016/08/26 23:20:50 In every use of this, only the result is used not
pwnall 2016/08/29 19:24:12 Done.
52 const createDatabase = function(testCase, setupCallback) {
53 const request = indexedDB.deleteDatabase(databaseName(testCase));
54 const eventWatcher = requestWatcher(testCase, request);
55
56 return eventWatcher.wait_for('success').then((event) => {
57 return migrateDatabase(testCase, 1, setupCallback);
jsbell 2016/08/26 23:20:50 ... => { return y; } can be simplified to: ... =
pwnall 2016/08/29 19:24:12 Done. I did this simplification whenever possible
58 });
59 };
60
61 // Creates a 'books' object store whose contents closely resembles the first
62 // example in the IndexedDB specification.
63 const createBooksStore = function(testCase, database) {
64 const store = database.createObjectStore('books',
65 { keyPath: 'isbn', autoIncrement: true });
66 const index = store.createIndex('by_author', 'author');
67 store.put({title: 'Quarry Memories', author: 'Fred', isbn: 123456});
68 store.put({title: 'Water Buffaloes', author: 'Fred', isbn: 234567});
69 store.put({title: 'Bedrock Nights', author: 'Barney', isbn: 345678});
70 return store;
71 };
72
73 // Creates a 'not_books' object store used to test renaming into existing or
74 // deleted store names.
75 const createNotBooksStore = function(testCase, database) {
76 const store = database.createObjectStore('not_books');
77 return store;
78 };
79
80 // Renames the 'books' store into a 'not books' store.
81 //
82 // Returns a Promise that yields an IndexedDB open success event.
83 const renameBooksStore = function(testCase) {
84 return migrateDatabase(testCase, 2, (database, transaction) => {
85 const store = transaction.objectStore('books');
86 store.name = 'renamed_books';
87 });
88 };
89
90 // Verifies that an object store's contents matches the contents used to create
91 // the books store in the test database's version 1.
92 const checkStoreContents = function(testCase, store) {
93 const request = store.get(123456);
94 const eventWatcher = requestWatcher(testCase, request);
95 return eventWatcher.wait_for('success').then(() => {
96 let result = request.result;
97 testCase.step(() => {
98 assert_equals(result.isbn, 123456);
99 assert_equals(result.author, 'Fred');
100 assert_equals(result.title, 'Quarry Memories');
101 });
102 });
103 };
104
105 // Verifies that an object store's index matches the index used to create the
106 // books store in the test database's version 1.
107 const checkStoreIndex = function(testCase, store) {
108 testCase.step(() => {
109 assert_array_equals(store.indexNames, ['by_author']);
110 });
111 const index = store.index('by_author');
112 const request = index.get('Barney');
113 const eventWatcher = requestWatcher(testCase, request);
114 return eventWatcher.wait_for('success').then(() => {
115 let result = request.result;
116 testCase.step(() => {
117 assert_equals(result.isbn, 345678);
118 assert_equals(result.title, 'Bedrock Nights');
119 });
120 });
121 };
122
123 // Verifies that an object store's key generator is in the same state as the
124 // key generator created for the books store in the test database's version 1.
125 const checkStoreGenerator = function(testCase, store, expectedKey) {
126 const request = store.put({title: 'Bedrock Nights II', author: 'Barney'});
127 const eventWatcher = requestWatcher(testCase, request);
128 return eventWatcher.wait_for('success').then(() => {
129 let result = request.result;
130 testCase.step(() => {
131 assert_equals(result, expectedKey);
132 });
133 });
134 };
135
136 promise_test(testCase => {
137 let bookStore = null, bookStore2 = null;
138 let renamedBookStore = null, renamedBookStore2 = null;
139 return createDatabase(testCase, (database, transaction) => {
140 bookStore = createBooksStore(testCase, database);
141 }).then((event) => {
142 const database = event.target.result;
143 testCase.step(() => {
144 assert_array_equals(database.objectStoreNames, ['books']);
145 });
146 const transaction = database.transaction('books', 'readonly');
147 bookStore2 = transaction.objectStore('books');
148 // If checkStoreContents fails here, its implementation is incorrect.
149 return checkStoreContents(testCase, bookStore2).then(() => {
150 database.close();
151 });
152 }).then(() => {
153 return migrateDatabase(testCase, 2, (database, transaction) => {
154 renamedBookStore = transaction.objectStore('books');
155 renamedBookStore.name = 'renamed_books';
156 testCase.step(() => {
157 assert_equals(renamedBookStore.name, 'renamed_books');
158 });
159 });
160 }).then((event) => {
161 const database = event.target.result;
162 testCase.step(() => {
163 assert_array_equals(database.objectStoreNames, ['renamed_books']);
164 });
165 const transaction = database.transaction('renamed_books', 'readonly');
166 renamedBookStore2 = transaction.objectStore('renamed_books');
167 return checkStoreContents(testCase, renamedBookStore2).then(() => {
168 database.close();
169 });
170 }).then(() => {
171 testCase.step(() => {
172 assert_equals(bookStore.name, 'books');
173 assert_equals(bookStore2.name, 'books');
174 assert_equals(renamedBookStore.name, 'renamed_books');
175 assert_equals(renamedBookStore2.name, 'renamed_books');
176 });
177 });
178 }, 'IndexedDB object store rename in new transaction', {
179 assert: 'An object store can be renamed in a new version change transaction' ,
jsbell 2016/08/26 23:20:50 Does this assert: test property add much? They're
pwnall 2016/08/29 19:24:12 I removed all of them. I was following the guide b
180 });
181
182 promise_test(testCase => {
183 let renamedBookStore = null, renamedBookStore2 = null;
184 return createDatabase(testCase, (database, transaction) => {
185 renamedBookStore = createBooksStore(testCase, database);
186 renamedBookStore.name = 'renamed_books';
187 testCase.step(() => {
188 assert_equals(renamedBookStore.name, 'renamed_books');
189 });
190 }).then((event) => {
191 const database = event.target.result;
192 testCase.step(() => {
193 assert_array_equals(database.objectStoreNames, ['renamed_books']);
194 });
195 const transaction = database.transaction('renamed_books', 'readonly');
196 renamedBookStore2 = transaction.objectStore('renamed_books');
197 return checkStoreContents(testCase, renamedBookStore2).then(() => {
198 database.close();
199 });
200 }).then(() => {
201 testCase.step(() => {
202 assert_equals(renamedBookStore.name, 'renamed_books');
203 assert_equals(renamedBookStore2.name, 'renamed_books');
204 });
205 });
206 }, 'IndexedDB object store rename in the transaction where it is created', {
207 assert:
208 'An object store can be renamed in the transaction where it is created',
209 });
210
211 promise_test(testCase => {
212 return createDatabase(testCase, (database, transaction) => {
213 createBooksStore(testCase, database);
214 }).then((event) => {
215 const database = event.target.result;
216 const transaction = database.transaction('books', 'readonly');
217 const store = transaction.objectStore('books');
218 // If checkStoreIndex fails here, its implementation is incorrect.
219 return checkStoreIndex(testCase, store).then(() => {
220 database.close();
221 });
222 }).then(() => {
223 return renameBooksStore(testCase);
224 }).then((event) => {
225 const database = event.target.result;
226 const transaction = database.transaction('renamed_books', 'readonly');
227 const store = transaction.objectStore('renamed_books');
228 return checkStoreIndex(testCase, store).then(() => {
229 database.close();
230 });
231 });
232 }, 'IndexedDB object store rename covers index', {
233 assert: 'Renaming an object store maintains its indexes',
234 });
235
236 promise_test(testCase => {
237 return createDatabase(testCase, (database, transaction) => {
238 createBooksStore(testCase, database);
239 }).then((event) => {
240 const database = event.target.result;
241 const transaction = database.transaction('books', 'readwrite');
242 // If checkStoreGenerator fails here, its implementation is incorrect.
243 const store = transaction.objectStore('books');
244 return checkStoreGenerator(testCase, store, 345679).then(() => {
245 database.close();
246 });
247 }).then(() => {
248 return renameBooksStore(testCase);
249 }).then((event) => {
250 const database = event.target.result;
251 const transaction = database.transaction('renamed_books', 'readwrite');
252 const store = transaction.objectStore('renamed_books');
253 return checkStoreGenerator(testCase, store, 345680).then(() => {
254 database.close();
255 });
256 });
257 }, 'IndexedDB object store rename covers key generator', {
258 assert: 'Renaming an object store maintains its key generator',
259 });
260
261 promise_test(testCase => {
262 const dbName = databaseName(testCase);
263 let bookStore = null, bookStore2 = null, bookStore3 = null;
264 return createDatabase(testCase, (database, transaction) => {
265 bookStore = createBooksStore(testCase, database);
266 }).then((event) => {
267 const database = event.target.result;
268 database.close();
269 }).then(() => {
270 return new Promise((resolve, reject) => {
271 const request = indexedDB.open(dbName, 2);
272 request.onupgradeneeded = (event) => {
273 const database = event.target.result;
274 const transaction = event.target.transaction;
275 bookStore2 = transaction.objectStore('books');
276 bookStore2.name = 'renamed_books';
277 testCase.step(() => {
278 assert_equals(bookStore.name, 'books');
279 assert_equals(bookStore2.name, 'renamed_books');
280 });
281 request.onerror = (event) => {
282 event.preventDefault();
283 resolve(event);
284 }
285 transaction.onabort = () => null;
286 transaction.onerror = () => null;
287 transaction.abort();
288 };
289 request.onerror =
290 testCase.unreached_func('indexedDB.open issued an error event');
291 request.onsuccess = testCase.unreached_func(
292 'indexedDB.open was not supposed to succeed');
293 });
294 }).then((event) => {
295 testCase.step(() => {
296 assert_equals(bookStore.name, 'books',
297 'object store rename not reverted after transaction abort');
298 });
299
300 const request = indexedDB.open(dbName, 1);
301 const eventWatcher = requestWatcher(testCase, request);
302 return eventWatcher.wait_for('success');
303 }).then((event) => {
304 const database = event.target.result;
305 const transaction = database.transaction('books', 'readonly');
306 bookStore3 = transaction.objectStore('books');
307 return checkStoreContents(testCase, bookStore3).then(() => {
308 database.close();
309 });
310 }).then(() => {
311 testCase.step(() => {
312 assert_equals(bookStore.name, 'books');
313 assert_equals(bookStore2.name, 'books');
314 assert_equals(bookStore3.name, 'books');
315 });
316 });
317 }, 'IndexedDB object store rename in aborted transaction', {
318 assert: 'An object store rename is correctly reverted',
319 });
320
321 promise_test(testCase => {
322 return createDatabase(testCase, (database, transaction) => {
323 createBooksStore(testCase, database);
324 }).then((event) => {
325 const database = event.target.result;
326 database.close();
327 }).then(() => {
328 return migrateDatabase(testCase, 2, (database, transaction) => {
329 const store = transaction.objectStore('books');
330 database.deleteObjectStore('books');
331 testCase.step(() => {
332 assert_throws('InvalidStateError',
333 () => { store.name = 'renamed_books'; });
334 });
335 });
336 }).then((event) => {
337 const database = event.target.result;
338 database.close();
339 });
340 }, 'IndexedDB object store rename covers key generator', {
341 assert: 'Renaming an object store maintains its key generator',
342 });
343
344 promise_test(testCase => {
345 return createDatabase(testCase, (database, transaction) => {
346 createBooksStore(testCase, database);
347 }).then((event) => {
348 const database = event.target.result;
349 const transaction = database.transaction('books', 'readonly');
350 const store = transaction.objectStore('books');
351
352 testCase.step(() => {
353 assert_throws('InvalidStateError',
354 () => { store.name = 'renamed_books'; });
355 });
356 database.close();
357 });
358 }, 'IndexedDB deleted object store rename throws', {
359 assert: 'Renaming a deleted object store throws InvalidStateError',
360 });
361
362 promise_test(testCase => {
363 return createDatabase(testCase, (database, transaction) => {
364 createBooksStore(testCase, database);
365 }).then((event) => {
366 const database = event.target.result;
367 const transaction = database.transaction('books', 'readonly');
368 const store = transaction.objectStore('books');
369
370 testCase.step(() => {
371 assert_throws('InvalidStateError',
372 () => { store.name = 'renamed_books'; });
373 });
374 database.close();
375 });
376 }, 'IndexedDB object store rename throws in a readwrite transaction', {
377 assert: 'Renaming an object store in a readwrite transaction throws InvalidS tateError',
378 });
379
380 promise_test(testCase => {
381 let bookStore = null;
382 return createDatabase(testCase, (database, transaction) => {
383 bookStore = createBooksStore(testCase, database);
384 }).then((event) => {
385 testCase.step(() => {
386 assert_throws('TransactionInactiveError',
387 () => { bookStore.name = 'renamed_books'; });
388 });
389 const database = event.target.result;
390 database.close();
391 });
392 }, 'IndexedDB object store rename throws in an inactive transaction', {
393 assert: 'Renaming an object store in an inactive transaction throws Transact ionInactiveError',
394 });
395
396 promise_test(testCase => {
397 return createDatabase(testCase, (database, transaction) => {
398 createBooksStore(testCase, database);
399 }).then((event) => {
400 const database = event.target.result;
401 database.close();
402 }).then(() => {
403 return migrateDatabase(testCase, 2, (database, transaction) => {
404 const store = transaction.objectStore('books');
405 store.name = 'books';
406 });
407 }).then((event) => {
408 const database = event.target.result;
409 testCase.step(() => {
410 assert_array_equals(database.objectStoreNames, ['books']);
411 });
412 const transaction = database.transaction('books', 'readonly');
413 const store = transaction.objectStore('books');
414 return checkStoreContents(testCase, store).then(() => {
415 database.close();
416 });
417 });
418 }, 'IndexedDB object store rename to the same name succeeds', {
419 assert: 'Renaming an object store to the same name does not throw',
420 });
421
422 promise_test(testCase => {
423 return createDatabase(testCase, (database, transaction) => {
424 createBooksStore(testCase, database);
425 createNotBooksStore(testCase, database);
426 }).then((event) => {
427 const database = event.target.result;
428 database.close();
429 }).then(() => {
430 return migrateDatabase(testCase, 2, (database, transaction) => {
431 const store = transaction.objectStore('books');
432
433 testCase.step(() => {
434 assert_throws('ConstraintError',
435 () => { store.name = 'not_books'; });
436 });
437 });
438 }).then((event) => {
439 const database = event.target.result;
440 testCase.step(() => {
441 assert_array_equals(database.objectStoreNames,
442 ['books', 'not_books']);
443 });
444 const transaction = database.transaction('books', 'readonly');
445 const store = transaction.objectStore('books');
446 return checkStoreContents(testCase, store).then(() => {
447 database.close();
448 });
449 });
450 }, 'IndexedDB object store rename to the name of another store throws', {
451 assert: 'Renaming an object store to the name of another store throws Constr aintError',
452 });
453
454 promise_test(testCase => {
455 return createDatabase(testCase, (database, transaction) => {
456 createBooksStore(testCase, database);
457 createNotBooksStore(testCase, database);
458 }).then((event) => {
459 const database = event.target.result;
460 database.close();
461 }).then(() => {
462 return migrateDatabase(testCase, 2, (database, transaction) => {
463 const store = transaction.objectStore('books');
464 database.deleteObjectStore('not_books');
465 store.name = 'not_books';
466 });
467 }).then((event) => {
468 const database = event.target.result;
469 testCase.step(() => {
470 assert_array_equals(database.objectStoreNames, ['not_books']);
471 });
472 const transaction = database.transaction('not_books', 'readonly');
473 const store = transaction.objectStore('not_books');
474 return checkStoreContents(testCase, store).then(() => {
475 database.close();
476 });
477 });
478 }, 'IndexedDB object store rename to the name of a deleted store succeeds', {
479 assert: 'Renaming an object store to the name of a deleted store does not th row',
480 });
481
482 promise_test(testCase => {
483 return createDatabase(testCase, (database, transaction) => {
484 createBooksStore(testCase, database);
485 createNotBooksStore(testCase, database);
486 }).then((event) => {
487 const database = event.target.result;
488 database.close();
489 }).then(() => {
490 return migrateDatabase(testCase, 2, (database, transaction) => {
491 const store = transaction.objectStore('books');
492
493 testCase.step(() => {
494 store.name = 42;
495 assert_equals(store.name, "42");
496 store.name = true;
497 assert_equals(store.name, "true");
498 store.name = () => null;
499 assert_equals(store.name, "() => null");
500 store.name = undefined;
501 assert_equals(store.name, "undefined");
502 });
503 });
504 }).then((event) => {
505 const database = event.target.result;
506 testCase.step(() => {
507 assert_array_equals(database.objectStoreNames,
508 ['not_books', 'undefined']);
509 });
510 const transaction = database.transaction('undefined', 'readonly');
511 const store = transaction.objectStore('undefined');
512 return checkStoreContents(testCase, store).then(() => {
513 database.close();
514 });
515 });
516 }, 'IndexedDB object store rename to non-string name XXX', {
517 assert: 'Renaming an object store to the name of another store throws Constr aintError',
518 });
519 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698