support.js (7832B)
1 'use strict'; 2 /* Delete created databases 3 * 4 * Go through each finished test, see if it has an associated database. Close 5 * that and delete the database. */ 6 add_completion_callback(function(tests) 7 { 8 for (var i in tests) 9 { 10 if(tests[i].db) 11 { 12 tests[i].db.close(); 13 self.indexedDB.deleteDatabase(tests[i].db.name); 14 } 15 } 16 }); 17 18 function fail(test, desc) { 19 return test.step_func(function(e) { 20 if (e && e.message && e.target.error) 21 assert_unreached(desc + " (" + e.target.error.name + ": " + e.message + ")"); 22 else if (e && e.message) 23 assert_unreached(desc + " (" + e.message + ")"); 24 else if (e && e.target.readyState === 'done' && e.target.error) 25 assert_unreached(desc + " (" + e.target.error.name + ")"); 26 else 27 assert_unreached(desc); 28 }); 29 } 30 31 function createdb(test, dbname, version) 32 { 33 var rq_open = createdb_for_multiple_tests(dbname, version); 34 return rq_open.setTest(test); 35 } 36 37 function createdb_for_multiple_tests(dbname, version) { 38 var rq_open, 39 fake_open = {}, 40 test = null, 41 dbname = (dbname ? dbname : "testdb-" + new Date().getTime() + Math.random() ); 42 43 if (version) 44 rq_open = self.indexedDB.open(dbname, version); 45 else 46 rq_open = self.indexedDB.open(dbname); 47 48 function auto_fail(evt, current_test) { 49 /* Fail handlers, if we haven't set on/whatever/, don't 50 * expect to get event whatever. */ 51 rq_open.manually_handled = {}; 52 53 rq_open.addEventListener(evt, function(e) { 54 if (current_test !== test) { 55 return; 56 } 57 58 test.step(function() { 59 if (!rq_open.manually_handled[evt]) { 60 assert_unreached("unexpected open." + evt + " event"); 61 } 62 63 if (e.target.result + '' == '[object IDBDatabase]' && 64 !this.db) { 65 this.db = e.target.result; 66 67 this.db.onerror = fail(test, 'unexpected db.error'); 68 this.db.onabort = fail(test, 'unexpected db.abort'); 69 this.db.onversionchange = 70 fail(test, 'unexpected db.versionchange'); 71 } 72 }); 73 }); 74 rq_open.__defineSetter__("on" + evt, function(h) { 75 rq_open.manually_handled[evt] = true; 76 if (!h) 77 rq_open.addEventListener(evt, function() {}); 78 else 79 rq_open.addEventListener(evt, test.step_func(h)); 80 }); 81 } 82 83 // add a .setTest method to the IDBOpenDBRequest object 84 Object.defineProperty(rq_open, 'setTest', { 85 enumerable: false, 86 value: function(t) { 87 test = t; 88 89 auto_fail("upgradeneeded", test); 90 auto_fail("success", test); 91 auto_fail("blocked", test); 92 auto_fail("error", test); 93 94 return this; 95 } 96 }); 97 98 return rq_open; 99 } 100 101 function assert_key_equals(actual, expected, description) { 102 assert_equals(indexedDB.cmp(actual, expected), 0, description); 103 } 104 105 // Usage: 106 // indexeddb_test( 107 // (test_object, db_connection, upgrade_tx, open_request) => { 108 // // Database creation logic. 109 // }, 110 // (test_object, db_connection, open_request) => { 111 // // Test logic. 112 // test_object.done(); 113 // }, 114 // 'Test case description'); 115 function indexeddb_test(upgrade_func, open_func, description, options) { 116 async_test(function(t) { 117 options = Object.assign({upgrade_will_abort: false}, options); 118 var dbname = location + '-' + t.name; 119 var del = indexedDB.deleteDatabase(dbname); 120 del.onerror = t.unreached_func('deleteDatabase should succeed'); 121 var open = indexedDB.open(dbname, 1); 122 open.onupgradeneeded = t.step_func(function() { 123 var db = open.result; 124 t.add_cleanup(function() { 125 // If open didn't succeed already, ignore the error. 126 open.onerror = function(e) { 127 e.preventDefault(); 128 }; 129 db.close(); 130 indexedDB.deleteDatabase(db.name); 131 }); 132 var tx = open.transaction; 133 upgrade_func(t, db, tx, open); 134 }); 135 if (options.upgrade_will_abort) { 136 open.onsuccess = t.unreached_func('open should not succeed'); 137 } else { 138 open.onerror = t.unreached_func('open should succeed'); 139 open.onsuccess = t.step_func(function() { 140 var db = open.result; 141 if (open_func) 142 open_func(t, db, open); 143 }); 144 } 145 }, description); 146 } 147 148 // Call with a Test and an array of expected results in order. Returns 149 // a function; call the function when a result arrives and when the 150 // expected number appear the order will be asserted and test 151 // completed. 152 function expect(t, expected) { 153 var results = []; 154 return result => { 155 results.push(result); 156 if (results.length === expected.length) { 157 assert_array_equals(results, expected); 158 t.done(); 159 } 160 }; 161 } 162 163 // Checks to see if the passed transaction is active (by making 164 // requests against the named store). 165 function is_transaction_active(tx, store_name) { 166 try { 167 const request = tx.objectStore(store_name).get(0); 168 request.onerror = e => { 169 e.preventDefault(); 170 e.stopPropagation(); 171 }; 172 return true; 173 } catch (ex) { 174 assert_equals(ex.name, 'TransactionInactiveError', 175 'Active check should either not throw anything, or throw ' + 176 'TransactionInactiveError'); 177 return false; 178 } 179 } 180 181 // Keeps the passed transaction alive indefinitely (by making requests 182 // against the named store). Returns a function that asserts that the 183 // transaction has not already completed and then ends the request loop so that 184 // the transaction may autocommit and complete. 185 function keep_alive(tx, store_name) { 186 let completed = false; 187 tx.addEventListener('complete', () => { completed = true; }); 188 189 let keepSpinning = true; 190 191 function spin() { 192 if (!keepSpinning) 193 return; 194 tx.objectStore(store_name).get(0).onsuccess = spin; 195 } 196 spin(); 197 198 return () => { 199 assert_false(completed, 'Transaction completed while kept alive'); 200 keepSpinning = false; 201 }; 202 } 203 204 // Returns a new function. After it is called |count| times, |func| 205 // will be called. 206 function barrier_func(count, func) { 207 let n = 0; 208 return () => { 209 if (++n === count) 210 func(); 211 }; 212 } 213 214 // Create an IndexedDB by executing script on the given remote context 215 // with |dbName| and |version|. 216 async function createIndexedDBForTesting(rc, dbName, version) { 217 await rc.executeScript((dbName, version) => { 218 let request = indexedDB.open(dbName, version); 219 request.onupgradeneeded = () => { 220 if (version == 1) { 221 // Only create the object store once. 222 request.result.createObjectStore('store'); 223 } 224 } 225 request.onversionchange = () => { 226 fail(t, 'unexpectedly received versionchange event.'); 227 } 228 }, [dbName, version]); 229 } 230 231 // Create an IndexedDB by executing script on the given remote context 232 // with |dbName| and |version|, and wait for the reuslt. 233 async function waitUntilIndexedDBOpenForTesting(rc, dbName, version) { 234 await rc.executeScript(async (dbName, version) => { 235 await new Promise((resolve, reject) => { 236 let request = indexedDB.open(dbName, version); 237 request.onsuccess = resolve; 238 request.onerror = reject; 239 }); 240 }, [dbName, version]); 241 } 242 243 // Returns a detached ArrayBuffer by transferring it to a message port. 244 function createDetachedArrayBuffer() { 245 const array = new Uint8Array([1, 2, 3, 4]); 246 const buffer = array.buffer; 247 assert_equals(array.byteLength, 4); 248 249 const channel = new MessageChannel(); 250 channel.port1.postMessage('', [buffer]); 251 assert_equals(array.byteLength, 0); 252 return array; 253 }