1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/indexedDB/test/unit/test_transaction_abort.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,392 @@ 1.4 +/** 1.5 + * Any copyright is dedicated to the Public Domain. 1.6 + * http://creativecommons.org/publicdomain/zero/1.0/ 1.7 + */ 1.8 + 1.9 +var testGenerator = testSteps(); 1.10 + 1.11 +var abortFired = false; 1.12 + 1.13 +function abortListener(evt) 1.14 +{ 1.15 + abortFired = true; 1.16 + is(evt.target.error, null, "Expect a null error for an aborted transaction"); 1.17 +} 1.18 + 1.19 +function testSteps() 1.20 +{ 1.21 + const Ci = Components.interfaces; 1.22 + 1.23 + const name = this.window ? window.location.pathname : "Splendid Test"; 1.24 + 1.25 + let request = indexedDB.open(name, 1); 1.26 + request.onerror = errorHandler; 1.27 + request.onupgradeneeded = grabEventAndContinueHandler; 1.28 + request.onsuccess = grabEventAndContinueHandler; 1.29 + let event = yield undefined; 1.30 + 1.31 + let db = event.target.result; 1.32 + db.onabort = abortListener; 1.33 + 1.34 + let transaction; 1.35 + let objectStore; 1.36 + let index; 1.37 + 1.38 + transaction = event.target.transaction; 1.39 + 1.40 + try { 1.41 + let error = transaction.error; 1.42 + ok(false, "Expect an exception"); 1.43 + } catch(e) { 1.44 + ok(true, "Got an exception."); 1.45 + is(e.name, "InvalidStateError", "Got the right exception"); 1.46 + } 1.47 + 1.48 + objectStore = db.createObjectStore("foo", { autoIncrement: true }); 1.49 + index = objectStore.createIndex("fooindex", "indexKey", { unique: true }); 1.50 + 1.51 + is(transaction.db, db, "Correct database"); 1.52 + is(transaction.mode, "versionchange", "Correct mode"); 1.53 + is(transaction.objectStoreNames.length, 1, "Correct names length"); 1.54 + is(transaction.objectStoreNames.item(0), "foo", "Correct name"); 1.55 + is(transaction.objectStore("foo"), objectStore, "Can get stores"); 1.56 + is(transaction.oncomplete, null, "No complete listener"); 1.57 + is(transaction.onabort, null, "No abort listener"); 1.58 + 1.59 + is(objectStore.name, "foo", "Correct name"); 1.60 + is(objectStore.keyPath, null, "Correct keyPath"); 1.61 + 1.62 + is(objectStore.indexNames.length, 1, "Correct indexNames length"); 1.63 + is(objectStore.indexNames[0], "fooindex", "Correct indexNames name"); 1.64 + is(objectStore.index("fooindex"), index, "Can get index"); 1.65 + 1.66 + // Wait until it's complete! 1.67 + transaction.oncomplete = grabEventAndContinueHandler; 1.68 + event = yield undefined; 1.69 + 1.70 + is(transaction.db, db, "Correct database"); 1.71 + is(transaction.mode, "versionchange", "Correct mode"); 1.72 + is(transaction.objectStoreNames.length, 1, "Correct names length"); 1.73 + is(transaction.objectStoreNames.item(0), "foo", "Correct name"); 1.74 + is(transaction.onabort, null, "No abort listener"); 1.75 + 1.76 + try { 1.77 + is(transaction.objectStore("foo").name, "foo", "Can't get stores"); 1.78 + ok(false, "Should have thrown"); 1.79 + } 1.80 + catch (e) { 1.81 + ok(true, "Out of scope transaction can't make stores"); 1.82 + } 1.83 + 1.84 + is(objectStore.name, "foo", "Correct name"); 1.85 + is(objectStore.keyPath, null, "Correct keyPath"); 1.86 + 1.87 + is(objectStore.indexNames.length, 1, "Correct indexNames length"); 1.88 + is(objectStore.indexNames[0], "fooindex", "Correct indexNames name"); 1.89 + 1.90 + try { 1.91 + objectStore.add({}); 1.92 + ok(false, "Should have thrown"); 1.93 + } 1.94 + catch (e) { 1.95 + ok(true, "Add threw"); 1.96 + } 1.97 + 1.98 + try { 1.99 + objectStore.put({}, 1); 1.100 + ok(false, "Should have thrown"); 1.101 + } 1.102 + catch (e) { 1.103 + ok(true, "Put threw"); 1.104 + } 1.105 + 1.106 + try { 1.107 + objectStore.put({}, 1); 1.108 + ok(false, "Should have thrown"); 1.109 + } 1.110 + catch (e) { 1.111 + ok(true, "Put threw"); 1.112 + } 1.113 + 1.114 + try { 1.115 + objectStore.delete(1); 1.116 + ok(false, "Should have thrown"); 1.117 + } 1.118 + catch (e) { 1.119 + ok(true, "Remove threw"); 1.120 + } 1.121 + 1.122 + try { 1.123 + objectStore.get(1); 1.124 + ok(false, "Should have thrown"); 1.125 + } 1.126 + catch (e) { 1.127 + ok(true, "Get threw"); 1.128 + } 1.129 + 1.130 + try { 1.131 + objectStore.getAll(null); 1.132 + ok(false, "Should have thrown"); 1.133 + } 1.134 + catch (e) { 1.135 + ok(true, "GetAll threw"); 1.136 + } 1.137 + 1.138 + try { 1.139 + objectStore.openCursor(); 1.140 + ok(false, "Should have thrown"); 1.141 + } 1.142 + catch (e) { 1.143 + ok(true, "OpenCursor threw"); 1.144 + } 1.145 + 1.146 + try { 1.147 + objectStore.createIndex("bar", "id"); 1.148 + ok(false, "Should have thrown"); 1.149 + } 1.150 + catch (e) { 1.151 + ok(true, "CreateIndex threw"); 1.152 + } 1.153 + 1.154 + try { 1.155 + objectStore.index("bar"); 1.156 + ok(false, "Should have thrown"); 1.157 + } 1.158 + catch (e) { 1.159 + ok(true, "Index threw"); 1.160 + } 1.161 + 1.162 + try { 1.163 + objectStore.deleteIndex("bar"); 1.164 + ok(false, "Should have thrown"); 1.165 + } 1.166 + catch (e) { 1.167 + ok(true, "RemoveIndex threw"); 1.168 + } 1.169 + 1.170 + yield undefined; 1.171 + 1.172 + request = db.transaction("foo", "readwrite").objectStore("foo").add({}); 1.173 + request.onerror = errorHandler; 1.174 + request.onsuccess = grabEventAndContinueHandler; 1.175 + event = yield undefined; 1.176 + 1.177 + event.target.transaction.onabort = function(event) { 1.178 + ok(false, "Shouldn't see an abort event!"); 1.179 + }; 1.180 + event.target.transaction.oncomplete = grabEventAndContinueHandler; 1.181 + event = yield undefined; 1.182 + 1.183 + is(event.type, "complete", "Right kind of event"); 1.184 + 1.185 + let key; 1.186 + 1.187 + request = db.transaction("foo", "readwrite").objectStore("foo").add({}); 1.188 + request.onerror = errorHandler; 1.189 + request.onsuccess = grabEventAndContinueHandler; 1.190 + event = yield undefined; 1.191 + 1.192 + key = event.target.result; 1.193 + 1.194 + event.target.transaction.onabort = grabEventAndContinueHandler; 1.195 + event.target.transaction.oncomplete = function(event) { 1.196 + ok(false, "Shouldn't see a complete event here!"); 1.197 + }; 1.198 + 1.199 + event.target.transaction.abort(); 1.200 + 1.201 + event = yield undefined; 1.202 + 1.203 + is(event.type, "abort", "Right kind of event"); 1.204 + 1.205 + request = db.transaction("foo").objectStore("foo").get(key); 1.206 + request.onerror = errorHandler; 1.207 + request.onsuccess = grabEventAndContinueHandler; 1.208 + event = yield undefined; 1.209 + 1.210 + is(event.target.result, undefined, "Object was removed"); 1.211 + 1.212 + executeSoon(function() { testGenerator.next(); }); 1.213 + yield undefined; 1.214 + 1.215 + let keys = []; 1.216 + let abortEventCount = 0; 1.217 + function abortErrorHandler(event) { 1.218 + is(event.target.error.name, "AbortError", 1.219 + "Good error"); 1.220 + abortEventCount++; 1.221 + event.preventDefault(); 1.222 + }; 1.223 + objectStore = db.transaction("foo", "readwrite").objectStore("foo"); 1.224 + 1.225 + for (let i = 0; i < 10; i++) { 1.226 + request = objectStore.add({}); 1.227 + request.onerror = abortErrorHandler; 1.228 + request.onsuccess = function(event) { 1.229 + keys.push(event.target.result); 1.230 + if (keys.length == 5) { 1.231 + event.target.transaction.onabort = grabEventAndContinueHandler; 1.232 + event.target.transaction.abort(); 1.233 + } 1.234 + }; 1.235 + } 1.236 + event = yield undefined; 1.237 + 1.238 + is(event.type, "abort", "Got abort event"); 1.239 + is(keys.length, 5, "Added 5 items in this transaction"); 1.240 + is(abortEventCount, 5, "Got 5 abort error events"); 1.241 + 1.242 + for (let i in keys) { 1.243 + request = db.transaction("foo").objectStore("foo").get(keys[i]); 1.244 + request.onerror = errorHandler; 1.245 + request.onsuccess = grabEventAndContinueHandler; 1.246 + event = yield undefined; 1.247 + 1.248 + is(event.target.result, undefined, "Object was removed by abort"); 1.249 + } 1.250 + 1.251 + // Set up some predictible data 1.252 + transaction = db.transaction("foo", "readwrite"); 1.253 + objectStore = transaction.objectStore("foo"); 1.254 + objectStore.clear(); 1.255 + objectStore.add({}, 1); 1.256 + objectStore.add({}, 2); 1.257 + request = objectStore.add({}, 1); 1.258 + request.onsuccess = function() { 1.259 + ok(false, "inserting duplicate key should fail"); 1.260 + } 1.261 + request.onerror = function(event) { 1.262 + ok(true, "inserting duplicate key should fail"); 1.263 + event.preventDefault(); 1.264 + } 1.265 + transaction.oncomplete = grabEventAndContinueHandler; 1.266 + yield undefined; 1.267 + 1.268 + // Check when aborting is allowed 1.269 + abortEventCount = 0; 1.270 + let expectedAbortEventCount = 0; 1.271 + 1.272 + // During INITIAL 1.273 + transaction = db.transaction("foo"); 1.274 + transaction.abort(); 1.275 + try { 1.276 + transaction.abort(); 1.277 + ok(false, "second abort should throw an error"); 1.278 + } 1.279 + catch (ex) { 1.280 + ok(true, "second abort should throw an error"); 1.281 + } 1.282 + 1.283 + // During LOADING 1.284 + transaction = db.transaction("foo"); 1.285 + transaction.objectStore("foo").get(1).onerror = abortErrorHandler; 1.286 + expectedAbortEventCount++; 1.287 + transaction.abort(); 1.288 + try { 1.289 + transaction.abort(); 1.290 + ok(false, "second abort should throw an error"); 1.291 + } 1.292 + catch (ex) { 1.293 + ok(true, "second abort should throw an error"); 1.294 + } 1.295 + 1.296 + // During LOADING from callback 1.297 + transaction = db.transaction("foo"); 1.298 + transaction.objectStore("foo").get(1).onsuccess = grabEventAndContinueHandler; 1.299 + event = yield undefined; 1.300 + transaction.objectStore("foo").get(1).onerror = abortErrorHandler; 1.301 + expectedAbortEventCount++ 1.302 + transaction.abort(); 1.303 + try { 1.304 + transaction.abort(); 1.305 + ok(false, "second abort should throw an error"); 1.306 + } 1.307 + catch (ex) { 1.308 + ok(true, "second abort should throw an error"); 1.309 + } 1.310 + 1.311 + // During LOADING from error callback 1.312 + transaction = db.transaction("foo", "readwrite"); 1.313 + transaction.objectStore("foo").add({}, 1).onerror = function(event) { 1.314 + event.preventDefault(); 1.315 + 1.316 + transaction.objectStore("foo").get(1).onerror = abortErrorHandler; 1.317 + expectedAbortEventCount++ 1.318 + 1.319 + transaction.abort(); 1.320 + continueToNextStep(); 1.321 + } 1.322 + yield undefined; 1.323 + 1.324 + // In between callbacks 1.325 + transaction = db.transaction("foo"); 1.326 + function makeNewRequest() { 1.327 + let r = transaction.objectStore("foo").get(1); 1.328 + r.onsuccess = makeNewRequest; 1.329 + r.onerror = abortErrorHandler; 1.330 + } 1.331 + makeNewRequest(); 1.332 + transaction.objectStore("foo").get(1).onsuccess = function(event) { 1.333 + executeSoon(function() { 1.334 + transaction.abort(); 1.335 + expectedAbortEventCount++; 1.336 + continueToNextStep(); 1.337 + }); 1.338 + }; 1.339 + yield undefined; 1.340 + 1.341 + // During COMMITTING 1.342 + transaction = db.transaction("foo", "readwrite"); 1.343 + transaction.objectStore("foo").put({hello: "world"}, 1).onsuccess = function(event) { 1.344 + continueToNextStep(); 1.345 + }; 1.346 + yield undefined; 1.347 + try { 1.348 + transaction.abort(); 1.349 + ok(false, "second abort should throw an error"); 1.350 + } 1.351 + catch (ex) { 1.352 + ok(true, "second abort should throw an error"); 1.353 + } 1.354 + transaction.oncomplete = grabEventAndContinueHandler; 1.355 + event = yield undefined; 1.356 + 1.357 + // Since the previous transaction shouldn't have caused any error events, 1.358 + // we know that all events should have fired by now. 1.359 + is(abortEventCount, expectedAbortEventCount, 1.360 + "All abort errors fired"); 1.361 + 1.362 + // Abort both failing and succeeding requests 1.363 + transaction = db.transaction("foo", "readwrite"); 1.364 + transaction.onabort = transaction.oncomplete = grabEventAndContinueHandler; 1.365 + transaction.objectStore("foo").add({indexKey: "key"}).onsuccess = function(event) { 1.366 + transaction.abort(); 1.367 + }; 1.368 + let request1 = transaction.objectStore("foo").add({indexKey: "key"}); 1.369 + request1.onsuccess = grabEventAndContinueHandler; 1.370 + request1.onerror = grabEventAndContinueHandler; 1.371 + let request2 = transaction.objectStore("foo").get(1); 1.372 + request2.onsuccess = grabEventAndContinueHandler; 1.373 + request2.onerror = grabEventAndContinueHandler; 1.374 + 1.375 + event = yield undefined; 1.376 + is(event.type, "error", "abort() should make all requests fail"); 1.377 + is(event.target, request1, "abort() should make all requests fail"); 1.378 + is(event.target.error.name, "AbortError", "abort() should make all requests fail"); 1.379 + event.preventDefault(); 1.380 + 1.381 + event = yield undefined; 1.382 + is(event.type, "error", "abort() should make all requests fail"); 1.383 + is(event.target, request2, "abort() should make all requests fail"); 1.384 + is(event.target.error.name, "AbortError", "abort() should make all requests fail"); 1.385 + event.preventDefault(); 1.386 + 1.387 + event = yield undefined; 1.388 + is(event.type, "abort", "transaction should fail"); 1.389 + is(event.target, transaction, "transaction should fail"); 1.390 + 1.391 + ok(abortFired, "Abort should have fired!"); 1.392 + 1.393 + finishTest(); 1.394 + yield undefined; 1.395 +} 1.396 \ No newline at end of file