From d4bc3be9f924dc4f5bb7e03afde525927a3ff435 Mon Sep 17 00:00:00 2001 From: "sra@google.com" Date: Fri, 5 Oct 2012 04:24:39 +0000 Subject: [PATCH] Update indexeddb tests to work with both methods of upgrading a database. The 'unpgradeNeeded' method is standard and supported by FireFox and Chrome tip. The 'setVersions' method will be needed until Chrome Stable is Chrome 24. The tests work locally for FireFox 15 provided they are run from a http:// URL. Running from a file:// URL disables IndexedDB for security reasons. Review URL: https://codereview.chromium.org//11052023 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@13271 260f80e4-7a28-3924-810f-c04153c831b5 --- tests/html/html.status | 9 ++- tests/html/indexeddb_1_test.dart | 85 +++++++++++++++++++--------- tests/html/indexeddb_2_test.dart | 52 ++++++++++------- tests/html/indexeddb_3_test.dart | 91 +++++++++++++++++++----------- tests/html/indexeddb_4_test.dart | 97 ++++++++++++++++++++------------ 5 files changed, 215 insertions(+), 119 deletions(-) diff --git a/tests/html/html.status b/tests/html/html.status index fc2af65ac76..5573fc09eba 100644 --- a/tests/html/html.status +++ b/tests/html/html.status @@ -120,7 +120,6 @@ indexeddb_1_test: Fail # indexedDB not in Safari 6. indexeddb_2_test: Fail # indexedDB not in Safari 6. indexeddb_3_test: Fail # indexedDB not in Safari 6. indexeddb_4_test: Fail # indexedDB not in Safari 6. -indexeddb_1_test: Fail # indexedDB not in Safari 6. fileapi_test: Fail # requestFileSystem not supported in Safari 6. datalistelement_test: Fail # HTMLDataListElement not yet supported in Safari. contentelement_test: Fail # Safari 6 does not support content element. @@ -163,10 +162,10 @@ documentfragment_test: Fail element_test: Fail exceptions_test: Fail # Uses webkitotifications, no analogue in moz fileapi_test: Fail # FF does not support filesystem APIs. -indexeddb_1_test: Fail # Need window.mozIndexedDB instead of window.webkitIndexedDB -indexeddb_2_test: Fail # Need window.mozIndexedDB instead of window.webkitIndexedDB -indexeddb_3_test: Fail # Need window.mozIndexedDB instead of window.webkitIndexedDB -indexeddb_4_test: Fail # Need window.mozIndexedDB instead of window.webkitIndexedDB +indexeddb_1_test: Fail # FF disables indexedDB from file URLs. +indexeddb_2_test: Fail # FF disables indexedDB from file URLs. +indexeddb_3_test: Fail # FF disables indexedDB from file URLs. +indexeddb_4_test: Fail # FF disables indexedDB from file URLs. # setup code fails. prepare. (DOM callback has errors) Caught [object Event] inner_frame_test: Skip # Interfaces not implemented: SVGTests, SVGLangSpace, SVGExternalResourcesRequired, SVGStylable diff --git a/tests/html/indexeddb_1_test.dart b/tests/html/indexeddb_1_test.dart index a587f8e31c7..3a8eb4c501f 100644 --- a/tests/html/indexeddb_1_test.dart +++ b/tests/html/indexeddb_1_test.dart @@ -5,7 +5,7 @@ const String DB_NAME = 'Test'; const String STORE_NAME = 'TEST'; -const String VERSION = '1'; +const int VERSION = 1; testReadWrite(key, value, check, [dbName = DB_NAME, @@ -15,13 +15,13 @@ testReadWrite(key, value, check, fail(e) { guardAsync(() { - Expect.fail('IndexedDB failure'); + throw const Exception('IndexedDB failure'); }); } - createObjectStore() { + createObjectStore(db) { var store = db.createObjectStore(storeName); - Expect.isNotNull(store); + expect(store, isNotNull); } step2(e) { @@ -29,6 +29,7 @@ testReadWrite(key, value, check, var request = transaction.objectStore(storeName).getObject(key); request.on.success.add(expectAsync1((e) { var object = e.target.result; + db.close(); check(value, object); })); request.on.error.add(fail); @@ -44,14 +45,11 @@ testReadWrite(key, value, check, initDb(e) { db = e.target.result; if (version != db.version) { - // TODO. Some browsers do this the w3 way - passing the version to the - // open call and listening to onversionchange. Can we feature-detect the - // difference and make it work? - var request = db.setVersion(version); + // Legacy 'setVersion' upgrade protocol. Chrome 23 and earlier. + var request = db.setVersion('$version'); request.on.success.add( expectAsync1((e) { - createObjectStore(); - + createObjectStore(db); var transaction = e.target.result; transaction.on.complete.add(expectAsync1((e) => step1())); transaction.on.error.add(fail); @@ -63,10 +61,26 @@ testReadWrite(key, value, check, } } - var request = window.indexedDB.open(dbName); - Expect.isNotNull(request); - request.on.success.add(expectAsync1(initDb)); - request.on.error.add(fail); + openDb(e) { + var request = window.indexedDB.open(dbName, version); + expect(request, isNotNull); + request.on.success.add(expectAsync1(initDb)); + request.on.error.add(fail); + if (request is IDBOpenDBRequest) { + // New upgrade protocol. Old API has no 'upgradeNeeded' and uses + // setVersion instead. This path take by FireFox 15, Chrome 24. + request.on.upgradeNeeded.add((e) { + guardAsync(() { + createObjectStore(e.target.result); + }); + }); + } + } + + // Delete any existing DB. + var deleteRequest = window.indexedDB.deleteDatabase(dbName); + deleteRequest.on.success.add(expectAsync1(openDb)); + deleteRequest.on.error.add(fail); }; testReadWriteTyped(key, value, check, @@ -77,13 +91,13 @@ testReadWriteTyped(key, value, check, fail(e) { guardAsync(() { - Expect.fail('IndexedDB failure'); + throw const Exception('IndexedDB failure'); }); } - createObjectStore() { + createObjectStore(db) { IDBObjectStore store = db.createObjectStore(storeName); - Expect.isNotNull(store); + expect(store, isNotNull); } step2(e) { @@ -91,14 +105,14 @@ testReadWriteTyped(key, value, check, IDBRequest request = transaction.objectStore(storeName).getObject(key); request.on.success.add(expectAsync1((e) { var object = e.target.result; + db.close(); check(value, object); })); request.on.error.add(fail); } step1() { - IDBTransaction transaction = - db.transaction([storeName], 'readwrite'); + IDBTransaction transaction = db.transaction([storeName], 'readwrite'); IDBRequest request = transaction.objectStore(storeName).put(value, key); request.on.success.add(expectAsync1(step2)); request.on.error.add(fail); @@ -107,11 +121,14 @@ testReadWriteTyped(key, value, check, initDb(e) { db = e.target.result; if (version != db.version) { - IDBRequest request = db.setVersion(version); + // Legacy 'setVersion' upgrade protocol. + IDBRequest request = db.setVersion('$version'); request.on.success.add( expectAsync1((e) { - createObjectStore(); - step1(); + createObjectStore(db); + IDBTransaction transaction = e.target.result; + transaction.on.complete.add(expectAsync1((e) => step1())); + transaction.on.error.add(fail); }) ); request.on.error.add(fail); @@ -120,10 +137,26 @@ testReadWriteTyped(key, value, check, } } - IDBRequest request = window.indexedDB.open(dbName); - Expect.isNotNull(request); - request.on.success.add(expectAsync1(initDb)); - request.on.error.add(fail); + openDb(e) { + IDBRequest request = window.indexedDB.open(dbName, version); + expect(request, isNotNull); + request.on.success.add(expectAsync1(initDb)); + request.on.error.add(fail); + if (request is IDBOpenDBRequest) { + // New upgrade protocol. Old API has no 'upgradeNeeded' and uses + // setVersion instead. + request.on.upgradeNeeded.add((e) { + guardAsync(() { + createObjectStore(e.target.result); + }); + }); + } + } + + // Delete any existing DB. + IDBRequest deleteRequest = window.indexedDB.deleteDatabase(dbName); + deleteRequest.on.success.add(expectAsync1(openDb)); + deleteRequest.on.error.add(fail); }; tests_dynamic() { diff --git a/tests/html/indexeddb_2_test.dart b/tests/html/indexeddb_2_test.dart index 8ab3a005ff9..7a643137bdd 100644 --- a/tests/html/indexeddb_2_test.dart +++ b/tests/html/indexeddb_2_test.dart @@ -9,7 +9,7 @@ const String DB_NAME = 'Test'; const String STORE_NAME = 'TEST'; -const String VERSION = '1'; +const int VERSION = 1; testReadWrite(key, value, check, [dbName = DB_NAME, @@ -19,23 +19,23 @@ testReadWrite(key, value, check, fail(e) { guardAsync(() { - Expect.fail('IndexedDB failure'); + throw const Exception('IndexedDB failure'); }); } - createObjectStore() { + createObjectStore(db) { var store = db.createObjectStore(storeName); - Expect.isNotNull(store); + expect(store, isNotNull); } step2(e) { var transaction = db.transaction(storeName, 'readonly'); var request = transaction.objectStore(storeName).getObject(key); request.on.success.add(expectAsync1((e) { - var object = e.target.result; - check(value, object); - }) - ); + var object = e.target.result; + db.close(); + check(value, object); + })); request.on.error.add(fail); } @@ -49,14 +49,11 @@ testReadWrite(key, value, check, initDb(e) { db = e.target.result; if (version != db.version) { - // TODO. Some browsers do this the w3 way - passing the version to the - // open call and listening to onversionchange. Can we feature-detect the - // difference and make it work? - var request = db.setVersion(version); + // Legacy 'setVersion' upgrade protocol. + var request = db.setVersion('$version'); request.on.success.add( expectAsync1((e) { - createObjectStore(); - + createObjectStore(db); var transaction = e.target.result; transaction.on.complete.add(expectAsync1((e) => step1())); transaction.on.error.add(fail); @@ -68,10 +65,26 @@ testReadWrite(key, value, check, } } - var request = window.indexedDB.open(dbName); - Expect.isNotNull(request); - request.on.success.add(expectAsync1(initDb)); - request.on.error.add(fail); + openDb(e) { + var request = window.indexedDB.open(dbName, version); + expect(request, isNotNull); + request.on.success.add(expectAsync1(initDb)); + request.on.error.add(fail); + if (request is IDBOpenDBRequest) { + // New upgrade protocol. Old API has no 'upgradeNeeded' and uses + // setVersion instead. + request.on.upgradeNeeded.add((e) { + guardAsync(() { + createObjectStore(e.target.result); + }); + }); + } + } + + // Delete any existing DB. + var deleteRequest = window.indexedDB.deleteDatabase(dbName); + deleteRequest.on.success.add(expectAsync1(openDb)); + deleteRequest.on.error.add(fail); }; @@ -96,7 +109,6 @@ main() { test('test_verifyGraph', () { // Nice to know verifyGraph is working before we rely on it. - Expect.mapEquals(obj4, obj4); verifyGraph(obj4, obj4); verifyGraph(obj1, new Map.from(obj1)); verifyGraph(obj4, new Map.from(obj4)); @@ -104,7 +116,7 @@ main() { var l1 = [1,2,3]; var l2 = [const [1, 2, 3], const [1, 2, 3]]; verifyGraph([l1, l1], l2); - Expect.throws(() => verifyGraph([[1, 2, 3], [1, 2, 3]], l2)); + expect(() => verifyGraph([[1, 2, 3], [1, 2, 3]], l2), throws); verifyGraph(cyclic_list, cyclic_list); }); diff --git a/tests/html/indexeddb_3_test.dart b/tests/html/indexeddb_3_test.dart index 8413c4d9052..8914add798c 100644 --- a/tests/html/indexeddb_3_test.dart +++ b/tests/html/indexeddb_3_test.dart @@ -7,38 +7,68 @@ const String DB_NAME = 'Test'; const String STORE_NAME = 'TEST'; -const String VERSION = '1'; +const int VERSION = 1; class Test { - var db; + fail(message) => (e) { + guardAsync(() { + Expect.fail('IndexedDB failure: $message'); + }); + }; - start() { - var request = window.indexedDB.open(DB_NAME); - Expect.isNotNull(request); - request.on.success.add(expectAsync1(initDb)); - request.on.error.add(fail('open')); + _createObjectStore(db) { + try { + // Nuke object store if it already exists. + db.deleteObjectStore(STORE_NAME); + } + on IDBDatabaseException catch(e) { } // Chrome + on DOMException catch(e) { } // Firefox + db.createObjectStore(STORE_NAME); } - initDb(e) { - db = e.target.result; - // TODO. Some browsers do this the w3 way - passing the VERSION to the - // open call and listening to onversionchange. Can we feature-detect the - // difference and make it work? - var request = db.setVersion(VERSION); - request.on.success.add( - expectAsync1((e) { - try { - // Nuke object store if it already exists. - db.deleteObjectStore(STORE_NAME); - } on IDBDatabaseException catch(e) { } - db.createObjectStore(STORE_NAME); + var db; - var transaction = e.target.result; - transaction.on.complete.add(expectAsync1((e) => writeItems(0))); - transaction.on.error.add(fail); - }) - ); - request.on.error.add(fail('setVersion error')); + _openDb(afterOpen()) { + var request = window.indexedDB.open(DB_NAME, VERSION); + if (request is IDBOpenDBRequest) { + // New upgrade protocol. FireFox 15, Chrome 24, hopefully IE10. + request.on.success.add(expectAsync1((e) { + db = e.target.result; + afterOpen(); + })); + request.on.upgradeNeeded.add((e) { + guardAsync(() { + _createObjectStore(e.target.result); + }); + }); + request.on.error.add(fail('open')); + } else { + // Legacy setVersion upgrade protocol. Chrome < 23. + request.on.success.add(expectAsync1((e) { + db = e.target.result; + if (db.version != '$VERSION') { + var setRequest = db.setVersion('$VERSION'); + setRequest.on.success.add( + expectAsync1((e) { + _createObjectStore(db); + var transaction = e.target.result; + transaction.on.complete.add( + expectAsync1((e) => afterOpen())); + transaction.on.error.add(fail('Upgrade')); + })); + setRequest.on.error.add(fail('setVersion error')); + } else { + afterOpen(); + } + })); + request.on.error.add(fail('open')); + } + } + + _createAndOpenDb(afterOpen()) { + var request = window.indexedDB.deleteDatabase(DB_NAME); + request.on.success.add(expectAsync1((e) { _openDb(afterOpen); })); + request.on.error.add(fail('delete old Db')); } writeItems(int index) { @@ -54,11 +84,7 @@ class Test { } } - fail(message) => (e) { - guardAsync(() { - Expect.fail('IndexedDB failure: $message'); - }); - }; + setupDb() { _createAndOpenDb(() => writeItems(0)); } readAllViaCursor() { IDBTransaction txn = db.transaction(STORE_NAME, 'readonly'); @@ -73,6 +99,7 @@ class Test { lastKey = cursor.key; itemCount += 1; sumKeys += cursor.key; + window.console.log('${cursor.key} ${cursor.value}'); Expect.equals('Item ${cursor.key}', cursor.value); cursor.continueFunction(); } else { @@ -116,7 +143,7 @@ main() { useHtmlConfiguration(); var test_ = new Test(); - test('prepare', test_.start); + test('prepare', test_.setupDb); test('readAll1', test_.readAllViaCursor); test('readAll2', test_.readAllReversedViaCursor); } diff --git a/tests/html/indexeddb_4_test.dart b/tests/html/indexeddb_4_test.dart index 16c4be57a13..28ddc12224e 100644 --- a/tests/html/indexeddb_4_test.dart +++ b/tests/html/indexeddb_4_test.dart @@ -7,38 +7,68 @@ const String DB_NAME = 'Test'; const String STORE_NAME = 'TEST'; -const String VERSION = '1'; +const int VERSION = 1; class Test { - var db; + fail(message) => (e) { + guardAsync(() { + Expect.fail('IndexedDB failure: $message'); + }); + }; - start() { - var request = window.indexedDB.open(DB_NAME); - Expect.isNotNull(request); - request.on.success.add(expectAsync1(initDb)); - request.on.error.add(fail('open')); + _createObjectStore(db) { + try { + // Nuke object store if it already exists. + db.deleteObjectStore(STORE_NAME); + } + on IDBDatabaseException catch(e) { } // Chrome + on DOMException catch(e) { } // Firefox + db.createObjectStore(STORE_NAME); } - initDb(e) { - db = e.target.result; - // TODO. Some browsers do this the w3 way - passing the VERSION to the - // open call and listening to onversionchange. Can we feature-detect the - // difference and make it work? - var request = db.setVersion(VERSION); - request.on.success.add( - expectAsync1((e) { - try { - // Nuke object store if it already exists. - db.deleteObjectStore(STORE_NAME); - } on IDBDatabaseException catch (e) { } - db.createObjectStore(STORE_NAME); + var db; - var transaction = e.target.result; - transaction.on.complete.add(expectAsync1((e) => writeItems(0))); - transaction.on.error.add(fail); - }) - ); - request.on.error.add(fail('setVersion error')); + _openDb(afterOpen()) { + var request = window.indexedDB.open(DB_NAME, VERSION); + if (request is IDBOpenDBRequest) { + // New upgrade protocol. + request.on.success.add(expectAsync1((e) { + db = e.target.result; + afterOpen(); + })); + request.on.upgradeNeeded.add((e) { + guardAsync(() { + _createObjectStore(e.target.result); + }); + }); + request.on.error.add(fail('open')); + } else { + // Legacy setVersion upgrade protocol. + request.on.success.add(expectAsync1((e) { + db = e.target.result; + if (db.version != '$VERSION') { + var setRequest = db.setVersion('$VERSION'); + setRequest.on.success.add( + expectAsync1((e) { + _createObjectStore(db); + var transaction = e.target.result; + transaction.on.complete.add( + expectAsync1((e) => afterOpen())); + transaction.on.error.add(fail('Upgrade')); + })); + setRequest.on.error.add(fail('setVersion error')); + } else { + afterOpen(); + } + })); + request.on.error.add(fail('open')); + } + } + + _createAndOpenDb(afterOpen()) { + var request = window.indexedDB.deleteDatabase(DB_NAME); + request.on.success.add(expectAsync1((e) { _openDb(afterOpen); })); + request.on.error.add(fail('delete old Db')); } writeItems(int index) { @@ -46,20 +76,15 @@ class Test { var transaction = db.transaction([STORE_NAME], 'readwrite'); var request = transaction.objectStore(STORE_NAME) .put('Item $index', index); - request.on.success.add( - expectAsync1((e) { + request.on.success.add(expectAsync1((e) { writeItems(index + 1); - }) - ); + } + )); request.on.error.add(fail('put')); } } - fail(message) => (e) { - guardAsync(() { - Expect.fail('IndexedDB failure: $message'); - }); - }; + setupDb() { _createAndOpenDb(() => writeItems(0)); } testRange(range, expectedFirst, expectedLast) { IDBTransaction txn = db.transaction(STORE_NAME, 'readonly'); @@ -126,7 +151,7 @@ main() { useHtmlConfiguration(); var test_ = new Test(); - test('prepare', test_.start); + test('prepare', test_.setupDb); test('only1', test_.only1); test('only2', test_.only2);