Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /**
2 * Any copyright is dedicated to the Public Domain.
3 * http://creativecommons.org/publicdomain/zero/1.0/
4 */
5 "use strict";
7 var self = this;
9 var testGenerator = testSteps();
11 function testSteps()
12 {
13 const dbName = self.window ? window.location.pathname : "test_lowDiskSpace";
14 const dbVersion = 1;
16 const objectStoreName = "foo";
17 const objectStoreOptions = { keyPath: "foo" };
19 const indexName = "bar";
20 const indexOptions = { unique: true };
22 const dbData = [
23 { foo: 0, bar: 0 },
24 { foo: 1, bar: 10 },
25 { foo: 2, bar: 20 },
26 { foo: 3, bar: 30 },
27 { foo: 4, bar: 40 },
28 { foo: 5, bar: 50 },
29 { foo: 6, bar: 60 },
30 { foo: 7, bar: 70 },
31 { foo: 8, bar: 80 },
32 { foo: 9, bar: 90 }
33 ];
35 let lowDiskMode = false;
36 function setLowDiskMode(val) {
37 let data = val ? "full" : "free";
39 if (val == lowDiskMode) {
40 info("Low disk mode is: " + data);
41 }
42 else {
43 info("Changing low disk mode to: " + data);
44 SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
45 data);
46 lowDiskMode = val;
47 }
48 }
50 { // Make sure opening works from the beginning.
51 info("Test 1");
53 setLowDiskMode(false);
55 let request = indexedDB.open(dbName, dbVersion);
56 request.onerror = errorHandler;
57 request.onsuccess = grabEventAndContinueHandler;
58 let event = yield undefined;
60 is(event.type, "success", "Opened database without setting low disk mode");
62 let db = event.target.result;
63 db.close();
64 }
66 { // Make sure delete works in low disk mode.
67 info("Test 2");
69 setLowDiskMode(true);
71 let request = indexedDB.deleteDatabase(dbName);
72 request.onerror = errorHandler;
73 request.onsuccess = grabEventAndContinueHandler;
74 let event = yield undefined;
76 is(event.type, "success", "Deleted database after setting low disk mode");
77 }
79 { // Make sure creating a db in low disk mode fails.
80 info("Test 3");
82 setLowDiskMode(true);
84 let request = indexedDB.open(dbName, dbVersion);
85 request.onerror = expectedErrorHandler("QuotaExceededError");
86 request.onupgradeneeded = unexpectedSuccessHandler;
87 request.onsuccess = unexpectedSuccessHandler;
88 let event = yield undefined;
90 is(event.type, "error", "Didn't create new database in low disk mode");
91 }
93 { // Make sure opening an already-existing db in low disk mode succeeds.
94 info("Test 4");
96 setLowDiskMode(false);
98 let request = indexedDB.open(dbName, dbVersion);
99 request.onerror = errorHandler;
100 request.onupgradeneeded = grabEventAndContinueHandler;
101 request.onsuccess = unexpectedSuccessHandler;
102 let event = yield undefined;
104 is(event.type, "upgradeneeded", "Upgrading database");
106 let db = event.target.result;
107 db.onerror = errorHandler;
109 request.onupgradeneeded = unexpectedSuccessHandler;
110 request.onsuccess = grabEventAndContinueHandler;
111 event = yield undefined;
113 is(event.type, "success", "Created database");
114 ok(event.target.result === db, "Got the same database");
116 db.close();
118 setLowDiskMode(true);
120 request = indexedDB.open(dbName);
121 request.onerror = errorHandler;
122 request.onupgradeneeded = unexpectedSuccessHandler;
123 request.onsuccess = grabEventAndContinueHandler;
124 event = yield undefined;
126 is(event.type, "success", "Opened existing database in low disk mode");
128 db = event.target.result;
129 db.close();
130 }
132 { // Make sure upgrading an already-existing db in low disk mode succeeds.
133 info("Test 5");
135 setLowDiskMode(true);
137 let request = indexedDB.open(dbName, dbVersion + 1);
138 request.onerror = errorHandler;
139 request.onupgradeneeded = grabEventAndContinueHandler;
140 request.onsuccess = unexpectedSuccessHandler;
142 let event = yield undefined;
144 is(event.type, "upgradeneeded", "Upgrading database");
146 let db = event.target.result;
147 db.onerror = errorHandler;
149 request.onupgradeneeded = unexpectedSuccessHandler;
150 request.onsuccess = grabEventAndContinueHandler;
151 event = yield undefined;
153 is(event.type, "success", "Created database");
154 ok(event.target.result === db, "Got the same database");
156 db.close();
157 }
159 { // Make sure creating objectStores in low disk mode fails.
160 info("Test 6");
162 setLowDiskMode(true);
164 let request = indexedDB.open(dbName, dbVersion + 2);
165 request.onerror = expectedErrorHandler("QuotaExceededError");
166 request.onupgradeneeded = grabEventAndContinueHandler;
167 request.onsuccess = unexpectedSuccessHandler;
169 let event = yield undefined;
171 is(event.type, "upgradeneeded", "Upgrading database");
173 let db = event.target.result;
174 db.onerror = errorHandler;
176 let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions);
178 request.onupgradeneeded = unexpectedSuccessHandler;
179 event = yield undefined;
181 is(event.type, "error", "Failed database upgrade");
182 }
184 { // Make sure creating indexes in low disk mode fails.
185 info("Test 7");
187 setLowDiskMode(false);
189 let request = indexedDB.open(dbName, dbVersion + 2);
190 request.onerror = errorHandler;
191 request.onupgradeneeded = grabEventAndContinueHandler;
192 request.onsuccess = unexpectedSuccessHandler;
194 let event = yield undefined;
196 is(event.type, "upgradeneeded", "Upgrading database");
198 let db = event.target.result;
199 db.onerror = errorHandler;
201 let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions);
203 request.onupgradeneeded = unexpectedSuccessHandler;
204 request.onsuccess = grabEventAndContinueHandler;
205 event = yield undefined;
207 is(event.type, "success", "Upgraded database");
208 ok(event.target.result === db, "Got the same database");
210 db.close();
212 setLowDiskMode(true);
214 request = indexedDB.open(dbName, dbVersion + 3);
215 request.onerror = expectedErrorHandler("QuotaExceededError");
216 request.onupgradeneeded = grabEventAndContinueHandler;
217 request.onsuccess = unexpectedSuccessHandler;
218 event = yield undefined;
220 is(event.type, "upgradeneeded", "Upgrading database");
222 db = event.target.result;
223 db.onerror = errorHandler;
225 objectStore = event.target.transaction.objectStore(objectStoreName);
226 let index = objectStore.createIndex(indexName, indexName, indexOptions);
228 request.onupgradeneeded = unexpectedSuccessHandler;
229 event = yield undefined;
231 is(event.type, "error", "Failed database upgrade");
232 }
234 { // Make sure deleting indexes in low disk mode succeeds.
235 info("Test 8");
237 setLowDiskMode(false);
239 let request = indexedDB.open(dbName, dbVersion + 3);
240 request.onerror = errorHandler;
241 request.onupgradeneeded = grabEventAndContinueHandler;
242 request.onsuccess = unexpectedSuccessHandler;
244 let event = yield undefined;
246 is(event.type, "upgradeneeded", "Upgrading database");
248 let db = event.target.result;
249 db.onerror = errorHandler;
251 let objectStore = event.target.transaction.objectStore(objectStoreName);
252 let index = objectStore.createIndex(indexName, indexName, indexOptions);
254 request.onupgradeneeded = unexpectedSuccessHandler;
255 request.onsuccess = grabEventAndContinueHandler;
256 event = yield undefined;
258 is(event.type, "success", "Upgraded database");
259 ok(event.target.result === db, "Got the same database");
261 db.close();
263 setLowDiskMode(true);
265 request = indexedDB.open(dbName, dbVersion + 4);
266 request.onerror = errorHandler;
267 request.onupgradeneeded = grabEventAndContinueHandler;
268 request.onsuccess = unexpectedSuccessHandler;
269 event = yield undefined;
271 is(event.type, "upgradeneeded", "Upgrading database");
273 db = event.target.result;
274 db.onerror = errorHandler;
276 objectStore = event.target.transaction.objectStore(objectStoreName);
277 objectStore.deleteIndex(indexName);
279 request.onupgradeneeded = unexpectedSuccessHandler;
280 request.onsuccess = grabEventAndContinueHandler;
281 event = yield undefined;
283 is(event.type, "success", "Upgraded database");
284 ok(event.target.result === db, "Got the same database");
286 db.close();
287 }
289 { // Make sure deleting objectStores in low disk mode succeeds.
290 info("Test 9");
292 setLowDiskMode(true);
294 let request = indexedDB.open(dbName, dbVersion + 5);
295 request.onerror = errorHandler;
296 request.onupgradeneeded = grabEventAndContinueHandler;
297 request.onsuccess = unexpectedSuccessHandler;
299 let event = yield undefined;
301 is(event.type, "upgradeneeded", "Upgrading database");
303 let db = event.target.result;
304 db.onerror = errorHandler;
306 db.deleteObjectStore(objectStoreName);
308 request.onupgradeneeded = unexpectedSuccessHandler;
309 request.onsuccess = grabEventAndContinueHandler;
310 event = yield undefined;
312 is(event.type, "success", "Upgraded database");
313 ok(event.target.result === db, "Got the same database");
315 db.close();
317 // Reset everything.
318 indexedDB.deleteDatabase(dbName);
319 }
322 { // Add data that the rest of the tests will use.
323 info("Adding test data");
325 setLowDiskMode(false);
327 let request = indexedDB.open(dbName, dbVersion);
328 request.onerror = errorHandler;
329 request.onupgradeneeded = grabEventAndContinueHandler;
330 request.onsuccess = unexpectedSuccessHandler;
331 let event = yield undefined;
333 is(event.type, "upgradeneeded", "Upgrading database");
335 let db = event.target.result;
336 db.onerror = errorHandler;
338 let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions);
339 let index = objectStore.createIndex(indexName, indexName, indexOptions);
341 for each (let data in dbData) {
342 objectStore.add(data);
343 }
345 request.onupgradeneeded = unexpectedSuccessHandler;
346 request.onsuccess = grabEventAndContinueHandler;
347 event = yield undefined;
349 is(event.type, "success", "Upgraded database");
350 ok(event.target.result === db, "Got the same database");
352 db.close();
353 }
355 { // Make sure read operations in readonly transactions succeed in low disk
356 // mode.
357 info("Test 10");
359 setLowDiskMode(true);
361 let request = indexedDB.open(dbName, dbVersion);
362 request.onerror = errorHandler;
363 request.onupgradeneeded = unexpectedSuccessHandler;
364 request.onsuccess = grabEventAndContinueHandler;
365 let event = yield undefined;
367 let db = event.target.result;
368 db.onerror = errorHandler;
370 let transaction = db.transaction(objectStoreName);
371 let objectStore = transaction.objectStore(objectStoreName);
372 let index = objectStore.index(indexName);
374 let data = dbData[0];
376 let requestCounter = new RequestCounter();
378 objectStore.get(data.foo).onsuccess = requestCounter.handler();
379 objectStore.mozGetAll().onsuccess = requestCounter.handler();
380 objectStore.count().onsuccess = requestCounter.handler();
381 index.get(data.bar).onsuccess = requestCounter.handler();
382 index.mozGetAll().onsuccess = requestCounter.handler();
383 index.getKey(data.bar).onsuccess = requestCounter.handler();
384 index.mozGetAllKeys().onsuccess = requestCounter.handler();
385 index.count().onsuccess = requestCounter.handler();
387 let objectStoreDataCount = 0;
389 request = objectStore.openCursor();
390 request.onsuccess = function(event) {
391 let cursor = event.target.result;
392 if (cursor) {
393 objectStoreDataCount++;
394 objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
395 }
396 else {
397 is(objectStoreDataCount, dbData.length, "Saw all data");
398 requestCounter.decr();
399 }
400 };
401 requestCounter.incr();
403 let indexDataCount = 0;
405 request = index.openCursor();
406 request.onsuccess = function(event) {
407 let cursor = event.target.result;
408 if (cursor) {
409 indexDataCount++;
410 indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
411 }
412 else {
413 is(indexDataCount, dbData.length, "Saw all data");
414 requestCounter.decr();
415 }
416 };
417 requestCounter.incr();
419 let indexKeyDataCount = 0;
421 request = index.openCursor();
422 request.onsuccess = function(event) {
423 let cursor = event.target.result;
424 if (cursor) {
425 indexKeyDataCount++;
426 indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
427 }
428 else {
429 is(indexKeyDataCount, dbData.length, "Saw all data");
430 requestCounter.decr();
431 }
432 };
433 requestCounter.incr();
435 // Wait for all requests.
436 yield undefined;
438 transaction.oncomplete = grabEventAndContinueHandler;
439 event = yield undefined;
441 is(event.type, "complete", "Transaction succeeded");
443 db.close();
444 }
446 { // Make sure read operations in readwrite transactions succeed in low disk
447 // mode.
448 info("Test 11");
450 setLowDiskMode(true);
452 let request = indexedDB.open(dbName, dbVersion);
453 request.onerror = errorHandler;
454 request.onupgradeneeded = unexpectedSuccessHandler;
455 request.onsuccess = grabEventAndContinueHandler;
456 let event = yield undefined;
458 let db = event.target.result;
459 db.onerror = errorHandler;
461 let transaction = db.transaction(objectStoreName, "readwrite");
462 let objectStore = transaction.objectStore(objectStoreName);
463 let index = objectStore.index(indexName);
465 let data = dbData[0];
467 let requestCounter = new RequestCounter();
469 objectStore.get(data.foo).onsuccess = requestCounter.handler();
470 objectStore.mozGetAll().onsuccess = requestCounter.handler();
471 objectStore.count().onsuccess = requestCounter.handler();
472 index.get(data.bar).onsuccess = requestCounter.handler();
473 index.mozGetAll().onsuccess = requestCounter.handler();
474 index.getKey(data.bar).onsuccess = requestCounter.handler();
475 index.mozGetAllKeys().onsuccess = requestCounter.handler();
476 index.count().onsuccess = requestCounter.handler();
478 let objectStoreDataCount = 0;
480 request = objectStore.openCursor();
481 request.onsuccess = function(event) {
482 let cursor = event.target.result;
483 if (cursor) {
484 objectStoreDataCount++;
485 objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
486 }
487 else {
488 is(objectStoreDataCount, dbData.length, "Saw all data");
489 requestCounter.decr();
490 }
491 };
492 requestCounter.incr();
494 let indexDataCount = 0;
496 request = index.openCursor();
497 request.onsuccess = function(event) {
498 let cursor = event.target.result;
499 if (cursor) {
500 indexDataCount++;
501 indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
502 }
503 else {
504 is(indexDataCount, dbData.length, "Saw all data");
505 requestCounter.decr();
506 }
507 };
508 requestCounter.incr();
510 let indexKeyDataCount = 0;
512 request = index.openCursor();
513 request.onsuccess = function(event) {
514 let cursor = event.target.result;
515 if (cursor) {
516 indexKeyDataCount++;
517 indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
518 }
519 else {
520 is(indexKeyDataCount, dbData.length, "Saw all data");
521 requestCounter.decr();
522 }
523 };
524 requestCounter.incr();
526 // Wait for all requests.
527 yield undefined;
529 transaction.oncomplete = grabEventAndContinueHandler;
530 event = yield undefined;
532 is(event.type, "complete", "Transaction succeeded");
534 db.close();
535 }
537 { // Make sure write operations in readwrite transactions fail in low disk
538 // mode.
539 info("Test 12");
541 setLowDiskMode(true);
543 let request = indexedDB.open(dbName, dbVersion);
544 request.onerror = errorHandler;
545 request.onupgradeneeded = unexpectedSuccessHandler;
546 request.onsuccess = grabEventAndContinueHandler;
547 let event = yield undefined;
549 let db = event.target.result;
550 db.onerror = errorHandler;
552 let transaction = db.transaction(objectStoreName, "readwrite");
553 let objectStore = transaction.objectStore(objectStoreName);
554 let index = objectStore.index(indexName);
556 let data = dbData[0];
557 let newData = { foo: 999, bar: 999 };
559 let requestCounter = new RequestCounter();
561 objectStore.add(newData).onerror = requestCounter.errorHandler();
562 objectStore.put(newData).onerror = requestCounter.errorHandler();
564 objectStore.get(data.foo).onsuccess = requestCounter.handler();
565 objectStore.mozGetAll().onsuccess = requestCounter.handler();
566 objectStore.count().onsuccess = requestCounter.handler();
567 index.get(data.bar).onsuccess = requestCounter.handler();
568 index.mozGetAll().onsuccess = requestCounter.handler();
569 index.getKey(data.bar).onsuccess = requestCounter.handler();
570 index.mozGetAllKeys().onsuccess = requestCounter.handler();
571 index.count().onsuccess = requestCounter.handler();
573 let objectStoreDataCount = 0;
575 request = objectStore.openCursor();
576 request.onsuccess = function(event) {
577 let cursor = event.target.result;
578 if (cursor) {
579 objectStoreDataCount++;
580 cursor.update(cursor.value).onerror = requestCounter.errorHandler();
581 objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1);
582 }
583 else {
584 is(objectStoreDataCount, dbData.length, "Saw all data");
585 requestCounter.decr();
586 }
587 };
588 requestCounter.incr();
590 let indexDataCount = 0;
592 request = index.openCursor();
593 request.onsuccess = function(event) {
594 let cursor = event.target.result;
595 if (cursor) {
596 indexDataCount++;
597 cursor.update(cursor.value).onerror = requestCounter.errorHandler();
598 indexDataCount % 2 ? cursor.continue() : cursor.advance(1);
599 }
600 else {
601 is(indexDataCount, dbData.length, "Saw all data");
602 requestCounter.decr();
603 }
604 };
605 requestCounter.incr();
607 let indexKeyDataCount = 0;
609 request = index.openCursor();
610 request.onsuccess = function(event) {
611 let cursor = event.target.result;
612 if (cursor) {
613 indexKeyDataCount++;
614 cursor.update(cursor.value).onerror = requestCounter.errorHandler();
615 indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1);
616 }
617 else {
618 is(indexKeyDataCount, dbData.length, "Saw all data");
619 requestCounter.decr();
620 }
621 };
622 requestCounter.incr();
624 // Wait for all requests.
625 yield undefined;
627 transaction.oncomplete = grabEventAndContinueHandler;
628 event = yield undefined;
630 is(event.type, "complete", "Transaction succeeded");
632 db.close();
633 }
635 { // Make sure deleting operations in readwrite transactions succeed in low
636 // disk mode.
637 info("Test 13");
639 setLowDiskMode(true);
641 let request = indexedDB.open(dbName, dbVersion);
642 request.onerror = errorHandler;
643 request.onupgradeneeded = unexpectedSuccessHandler;
644 request.onsuccess = grabEventAndContinueHandler;
645 let event = yield undefined;
647 let db = event.target.result;
648 db.onerror = errorHandler;
650 let transaction = db.transaction(objectStoreName, "readwrite");
651 let objectStore = transaction.objectStore(objectStoreName);
652 let index = objectStore.index(indexName);
654 let dataIndex = 0;
655 let data = dbData[dataIndex++];
657 let requestCounter = new RequestCounter();
659 objectStore.delete(data.foo).onsuccess = requestCounter.handler();
661 objectStore.openCursor().onsuccess = function(event) {
662 let cursor = event.target.result;
663 if (cursor) {
664 cursor.delete().onsuccess = requestCounter.handler();
665 }
666 requestCounter.decr();
667 };
668 requestCounter.incr();
670 index.openCursor(null, "prev").onsuccess = function(event) {
671 let cursor = event.target.result;
672 if (cursor) {
673 cursor.delete().onsuccess = requestCounter.handler();
674 }
675 requestCounter.decr();
676 };
677 requestCounter.incr();
679 yield undefined;
681 objectStore.count().onsuccess = grabEventAndContinueHandler;
682 event = yield undefined;
684 is(event.target.result, dbData.length - 3, "Actually deleted something");
686 objectStore.clear();
687 objectStore.count().onsuccess = grabEventAndContinueHandler;
688 event = yield undefined;
690 is(event.target.result, 0, "Actually cleared");
692 transaction.oncomplete = grabEventAndContinueHandler;
693 event = yield undefined;
695 is(event.type, "complete", "Transaction succeeded");
697 db.close();
698 }
700 finishTest();
701 yield undefined;
702 }
704 function RequestCounter(expectedType) {
705 this._counter = 0;
706 }
707 RequestCounter.prototype = {
708 incr: function() {
709 this._counter++;
710 },
712 decr: function() {
713 if (!--this._counter) {
714 continueToNextStepSync();
715 }
716 },
718 handler: function(type, preventDefault) {
719 this.incr();
720 return function(event) {
721 is(event.type, type || "success", "Correct type");
722 this.decr();
723 }.bind(this);
724 },
726 errorHandler: function(eventType, errorName) {
727 this.incr();
728 return function(event) {
729 is(event.type, eventType || "error", "Correct type");
730 is(event.target.error.name, errorName || "QuotaExceededError",
731 "Correct error name");
732 event.preventDefault();
733 event.stopPropagation();
734 this.decr();
735 }.bind(this);
736 }
737 };