test_true_async.cpp (5520B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "storage_test_harness.h" 8 9 //////////////////////////////////////////////////////////////////////////////// 10 //// Tests 11 12 TEST(storage_true_async, TrueAsyncStatement) 13 { 14 HookSqliteMutex hook; 15 16 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); 17 18 // Start watching for forbidden mutex usage. 19 watch_for_mutex_use_on_this_thread(); 20 21 // - statement with nothing to bind 22 nsCOMPtr<mozIStorageAsyncStatement> stmt; 23 db->CreateAsyncStatement("CREATE TABLE test (id INTEGER PRIMARY KEY)"_ns, 24 getter_AddRefs(stmt)); 25 blocking_async_execute(stmt); 26 stmt->Finalize(); 27 do_check_false(mutex_used_on_watched_thread); 28 29 // - statement with something to bind ordinally 30 db->CreateAsyncStatement("INSERT INTO test (id) VALUES (?)"_ns, 31 getter_AddRefs(stmt)); 32 stmt->BindInt32ByIndex(0, 1); 33 blocking_async_execute(stmt); 34 stmt->Finalize(); 35 do_check_false(mutex_used_on_watched_thread); 36 37 // - statement with something to bind by name 38 db->CreateAsyncStatement("INSERT INTO test (id) VALUES (:id)"_ns, 39 getter_AddRefs(stmt)); 40 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray; 41 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray)); 42 nsCOMPtr<mozIStorageBindingParams> params; 43 paramsArray->NewBindingParams(getter_AddRefs(params)); 44 params->BindInt32ByName("id"_ns, 2); 45 paramsArray->AddParams(params); 46 params = nullptr; 47 stmt->BindParameters(paramsArray); 48 paramsArray = nullptr; 49 blocking_async_execute(stmt); 50 stmt->Finalize(); 51 do_check_false(mutex_used_on_watched_thread); 52 53 // - now, make sure creating a sync statement does trigger our guard. 54 // (If this doesn't happen, our test is bunk and it's important to know that.) 55 nsCOMPtr<mozIStorageStatement> syncStmt; 56 db->CreateStatement("SELECT * FROM test"_ns, getter_AddRefs(syncStmt)); 57 syncStmt->Finalize(); 58 do_check_true(mutex_used_on_watched_thread); 59 60 blocking_async_close(db); 61 } 62 63 /** 64 * Test that cancellation before a statement is run successfully stops the 65 * statement from executing. 66 */ 67 TEST(storage_true_async, AsyncCancellation) 68 { 69 HookSqliteMutex hook; 70 71 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); 72 73 // -- wedge the thread 74 nsCOMPtr<nsIThread> target(get_conn_async_thread(db)); 75 do_check_true(target); 76 RefPtr<ThreadWedger> wedger(new ThreadWedger(target)); 77 78 // -- create statements and cancel them 79 // - async 80 nsCOMPtr<mozIStorageAsyncStatement> asyncStmt; 81 db->CreateAsyncStatement( 82 "CREATE TABLE asyncTable (id INTEGER PRIMARY KEY)"_ns, 83 getter_AddRefs(asyncStmt)); 84 85 RefPtr<AsyncStatementSpinner> asyncSpin(new AsyncStatementSpinner()); 86 nsCOMPtr<mozIStoragePendingStatement> asyncPend; 87 (void)asyncStmt->ExecuteAsync(asyncSpin, getter_AddRefs(asyncPend)); 88 do_check_true(asyncPend); 89 asyncPend->Cancel(); 90 91 // - sync 92 nsCOMPtr<mozIStorageStatement> syncStmt; 93 db->CreateStatement("CREATE TABLE syncTable (id INTEGER PRIMARY KEY)"_ns, 94 getter_AddRefs(syncStmt)); 95 96 RefPtr<AsyncStatementSpinner> syncSpin(new AsyncStatementSpinner()); 97 nsCOMPtr<mozIStoragePendingStatement> syncPend; 98 (void)syncStmt->ExecuteAsync(syncSpin, getter_AddRefs(syncPend)); 99 do_check_true(syncPend); 100 syncPend->Cancel(); 101 102 // -- unwedge the async thread 103 wedger->unwedge(); 104 105 // -- verify that both statements report they were canceled 106 asyncSpin->SpinUntilCompleted(); 107 do_check_true(asyncSpin->completionReason == 108 mozIStorageStatementCallback::REASON_CANCELED); 109 110 syncSpin->SpinUntilCompleted(); 111 do_check_true(syncSpin->completionReason == 112 mozIStorageStatementCallback::REASON_CANCELED); 113 114 // -- verify that neither statement constructed their tables 115 nsresult rv; 116 bool exists; 117 rv = db->TableExists("asyncTable"_ns, &exists); 118 do_check_true(rv == NS_OK); 119 do_check_false(exists); 120 rv = db->TableExists("syncTable"_ns, &exists); 121 do_check_true(rv == NS_OK); 122 do_check_false(exists); 123 124 // -- cleanup 125 asyncStmt->Finalize(); 126 syncStmt->Finalize(); 127 blocking_async_close(db); 128 } 129 130 /** 131 * Test that the destructor for an asynchronous statement which has a 132 * sqlite3_stmt will dispatch that statement to the async thread for 133 * finalization rather than trying to finalize it on the main thread 134 * (and thereby running afoul of our mutex use detector). 135 */ 136 TEST(storage_true_async, AsyncDestructorFinalizesOnAsyncThread) 137 { 138 HookSqliteMutex hook; 139 140 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); 141 watch_for_mutex_use_on_this_thread(); 142 143 // -- create an async statement 144 nsCOMPtr<mozIStorageAsyncStatement> stmt; 145 db->CreateAsyncStatement("CREATE TABLE test (id INTEGER PRIMARY KEY)"_ns, 146 getter_AddRefs(stmt)); 147 148 // -- execute it so it gets a sqlite3_stmt that needs to be finalized 149 blocking_async_execute(stmt); 150 do_check_false(mutex_used_on_watched_thread); 151 152 // -- forget our reference 153 stmt = nullptr; 154 155 // -- verify the mutex was not touched 156 do_check_false(mutex_used_on_watched_thread); 157 158 // -- make sure the statement actually gets finalized / cleanup 159 // the close will assert if we failed to finalize! 160 blocking_async_close(db); 161 }