michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * This file tests the functionality of mozIStorageConnection::executeAsync for michael@0: * both mozIStorageStatement and mozIStorageAsyncStatement. michael@0: */ michael@0: michael@0: const INTEGER = 1; michael@0: const TEXT = "this is test text"; michael@0: const REAL = 3.23; michael@0: const BLOB = [1, 2]; michael@0: michael@0: function test_create_and_add() michael@0: { michael@0: getOpenedDatabase().executeSimpleSQL( michael@0: "CREATE TABLE test (" + michael@0: "id INTEGER, " + michael@0: "string TEXT, " + michael@0: "number REAL, " + michael@0: "nuller NULL, " + michael@0: "blober BLOB" + michael@0: ")" michael@0: ); michael@0: michael@0: let stmts = []; michael@0: stmts[0] = getOpenedDatabase().createStatement( michael@0: "INSERT INTO test (id, string, number, nuller, blober) VALUES (?, ?, ?, ?, ?)" michael@0: ); michael@0: stmts[0].bindByIndex(0, INTEGER); michael@0: stmts[0].bindByIndex(1, TEXT); michael@0: stmts[0].bindByIndex(2, REAL); michael@0: stmts[0].bindByIndex(3, null); michael@0: stmts[0].bindBlobByIndex(4, BLOB, BLOB.length); michael@0: stmts[1] = getOpenedDatabase().createAsyncStatement( michael@0: "INSERT INTO test (string, number, nuller, blober) VALUES (?, ?, ?, ?)" michael@0: ); michael@0: stmts[1].bindByIndex(0, TEXT); michael@0: stmts[1].bindByIndex(1, REAL); michael@0: stmts[1].bindByIndex(2, null); michael@0: stmts[1].bindBlobByIndex(3, BLOB, BLOB.length); michael@0: michael@0: getOpenedDatabase().executeAsync(stmts, stmts.length, { michael@0: handleResult: function(aResultSet) michael@0: { michael@0: dump("handleResult("+aResultSet+")\n"); michael@0: do_throw("unexpected results obtained!"); michael@0: }, michael@0: handleError: function(aError) michael@0: { michael@0: dump("handleError("+aError.result+")\n"); michael@0: do_throw("unexpected error!"); michael@0: }, michael@0: handleCompletion: function(aReason) michael@0: { michael@0: dump("handleCompletion("+aReason+")\n"); michael@0: do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason); michael@0: michael@0: // Check that the result is in the table michael@0: let stmt = getOpenedDatabase().createStatement( michael@0: "SELECT string, number, nuller, blober FROM test WHERE id = ?" michael@0: ); michael@0: stmt.bindByIndex(0, INTEGER); michael@0: try { michael@0: do_check_true(stmt.executeStep()); michael@0: do_check_eq(TEXT, stmt.getString(0)); michael@0: do_check_eq(REAL, stmt.getDouble(1)); michael@0: do_check_true(stmt.getIsNull(2)); michael@0: let count = { value: 0 }; michael@0: let blob = { value: null }; michael@0: stmt.getBlob(3, count, blob); michael@0: do_check_eq(BLOB.length, count.value); michael@0: for (let i = 0; i < BLOB.length; i++) michael@0: do_check_eq(BLOB[i], blob.value[i]); michael@0: } michael@0: finally { michael@0: stmt.finalize(); michael@0: } michael@0: michael@0: // Make sure we have two rows in the table michael@0: stmt = getOpenedDatabase().createStatement( michael@0: "SELECT COUNT(1) FROM test" michael@0: ); michael@0: try { michael@0: do_check_true(stmt.executeStep()); michael@0: do_check_eq(2, stmt.getInt32(0)); michael@0: } michael@0: finally { michael@0: stmt.finalize(); michael@0: } michael@0: michael@0: // Run the next test. michael@0: run_next_test(); michael@0: } michael@0: }); michael@0: stmts[0].finalize(); michael@0: stmts[1].finalize(); michael@0: } michael@0: michael@0: function test_multiple_bindings_on_statements() michael@0: { michael@0: // This tests to make sure that we pass all the statements multiply bound michael@0: // parameters when we call executeAsync. michael@0: const AMOUNT_TO_ADD = 5; michael@0: const ITERATIONS = 5; michael@0: michael@0: let stmts = []; michael@0: let db = getOpenedDatabase(); michael@0: let sqlString = "INSERT INTO test (id, string, number, nuller, blober) " + michael@0: "VALUES (:int, :text, :real, :null, :blob)"; michael@0: // We run the same statement twice, and should insert 2 * AMOUNT_TO_ADD. michael@0: for (let i = 0; i < ITERATIONS; i++) { michael@0: // alternate the type of statement we create michael@0: if (i % 2) michael@0: stmts[i] = db.createStatement(sqlString); michael@0: else michael@0: stmts[i] = db.createAsyncStatement(sqlString); michael@0: michael@0: let params = stmts[i].newBindingParamsArray(); michael@0: for (let j = 0; j < AMOUNT_TO_ADD; j++) { michael@0: let bp = params.newBindingParams(); michael@0: bp.bindByName("int", INTEGER); michael@0: bp.bindByName("text", TEXT); michael@0: bp.bindByName("real", REAL); michael@0: bp.bindByName("null", null); michael@0: bp.bindBlobByName("blob", BLOB, BLOB.length); michael@0: params.addParams(bp); michael@0: } michael@0: stmts[i].bindParameters(params); michael@0: } michael@0: michael@0: // Get our current number of rows in the table. michael@0: let currentRows = 0; michael@0: let countStmt = getOpenedDatabase().createStatement( michael@0: "SELECT COUNT(1) AS count FROM test" michael@0: ); michael@0: try { michael@0: do_check_true(countStmt.executeStep()); michael@0: currentRows = countStmt.row.count; michael@0: } michael@0: finally { michael@0: countStmt.reset(); michael@0: } michael@0: michael@0: // Execute asynchronously. michael@0: getOpenedDatabase().executeAsync(stmts, stmts.length, { michael@0: handleResult: function(aResultSet) michael@0: { michael@0: do_throw("Unexpected call to handleResult!"); michael@0: }, michael@0: handleError: function(aError) michael@0: { michael@0: print("Error code " + aError.result + " with message '" + michael@0: aError.message + "' returned."); michael@0: do_throw("Unexpected error!"); michael@0: }, michael@0: handleCompletion: function(aReason) michael@0: { michael@0: print("handleCompletion(" + aReason + michael@0: ") for test_multiple_bindings_on_statements"); michael@0: do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason); michael@0: michael@0: // Check to make sure we added all of our rows. michael@0: try { michael@0: do_check_true(countStmt.executeStep()); michael@0: do_check_eq(currentRows + (ITERATIONS * AMOUNT_TO_ADD), michael@0: countStmt.row.count); michael@0: } michael@0: finally { michael@0: countStmt.finalize(); michael@0: } michael@0: michael@0: // Run the next test. michael@0: run_next_test(); michael@0: } michael@0: }); michael@0: stmts.forEach(function(stmt) stmt.finalize()); michael@0: } michael@0: michael@0: function test_asyncClose_does_not_complete_before_statements() michael@0: { michael@0: let stmt = createStatement("SELECT * FROM sqlite_master"); michael@0: let executed = false; michael@0: stmt.executeAsync({ michael@0: handleResult: function(aResultSet) michael@0: { michael@0: }, michael@0: handleError: function(aError) michael@0: { michael@0: print("Error code " + aError.result + " with message '" + michael@0: aError.message + "' returned."); michael@0: do_throw("Unexpected error!"); michael@0: }, michael@0: handleCompletion: function(aReason) michael@0: { michael@0: print("handleCompletion(" + aReason + michael@0: ") for test_asyncClose_does_not_complete_before_statements"); michael@0: do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason); michael@0: executed = true; michael@0: } michael@0: }); michael@0: stmt.finalize(); michael@0: michael@0: getOpenedDatabase().asyncClose(function() { michael@0: // Ensure that the statement executed to completion. michael@0: do_check_true(executed); michael@0: michael@0: // Reset gDBConn so that later tests will get a new connection object. michael@0: gDBConn = null; michael@0: run_next_test(); michael@0: }); michael@0: } michael@0: michael@0: function test_asyncClose_does_not_throw_no_callback() michael@0: { michael@0: getOpenedDatabase().asyncClose(); michael@0: michael@0: // Reset gDBConn so that later tests will get a new connection object. michael@0: gDBConn = null; michael@0: run_next_test(); michael@0: } michael@0: michael@0: function test_double_asyncClose_throws() michael@0: { michael@0: let conn = getOpenedDatabase(); michael@0: conn.asyncClose(); michael@0: try { michael@0: conn.asyncClose(); michael@0: do_throw("should have thrown"); michael@0: // There is a small race condition here, which can cause either of michael@0: // Cr.NS_ERROR_NOT_INITIALIZED or Cr.NS_ERROR_UNEXPECTED to be thrown. michael@0: } catch (e if "result" in e && e.result == Cr.NS_ERROR_NOT_INITIALIZED) { michael@0: do_print("NS_ERROR_NOT_INITIALIZED"); michael@0: } catch (e if "result" in e && e.result == Cr.NS_ERROR_UNEXPECTED) { michael@0: do_print("NS_ERROR_UNEXPECTED"); michael@0: } catch (e) { michael@0: } michael@0: michael@0: // Reset gDBConn so that later tests will get a new connection object. michael@0: gDBConn = null; michael@0: run_next_test(); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Test Runner michael@0: michael@0: [ michael@0: test_create_and_add, michael@0: test_multiple_bindings_on_statements, michael@0: test_asyncClose_does_not_complete_before_statements, michael@0: test_asyncClose_does_not_throw_no_callback, michael@0: test_double_asyncClose_throws, michael@0: ].forEach(add_test); michael@0: michael@0: function run_test() michael@0: { michael@0: cleanup(); michael@0: run_next_test(); michael@0: }