1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
#include "storage_test_harness.h"
#include "prthread.h"
#include "nsIInterfaceRequestorUtils.h"
#include "sqlite3.h"
////////////////////////////////////////////////////////////////////////////////
//// Async Helpers
/**
* Spins the events loop for current thread until aCondition is true.
*/
void spin_events_loop_until_true(const bool* const aCondition) {
nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
nsresult rv = NS_OK;
bool processed = true;
while (!(*aCondition) && NS_SUCCEEDED(rv)) {
rv = thread->ProcessNextEvent(true, &processed);
}
}
////////////////////////////////////////////////////////////////////////////////
//// mozIStorageStatementCallback implementation
class UnownedCallback final : public mozIStorageStatementCallback {
public:
NS_DECL_ISUPPORTS
// Whether the object has been destroyed.
static bool sAlive;
// Whether the first result was received.
static bool sResult;
// Whether an error was received.
static bool sError;
explicit UnownedCallback(mozIStorageConnection* aDBConn)
: mDBConn(aDBConn), mCompleted(false) {
sAlive = true;
sResult = false;
sError = false;
}
private:
~UnownedCallback() {
sAlive = false;
blocking_async_close(mDBConn);
}
public:
NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet) override {
sResult = true;
spin_events_loop_until_true(&mCompleted);
if (!sAlive) {
MOZ_CRASH("The statement callback was destroyed prematurely.");
}
return NS_OK;
}
NS_IMETHOD HandleError(mozIStorageError* aError) override {
sError = true;
spin_events_loop_until_true(&mCompleted);
if (!sAlive) {
MOZ_CRASH("The statement callback was destroyed prematurely.");
}
return NS_OK;
}
NS_IMETHOD HandleCompletion(uint16_t aReason) override {
mCompleted = true;
return NS_OK;
}
protected:
nsCOMPtr<mozIStorageConnection> mDBConn;
bool mCompleted;
};
NS_IMPL_ISUPPORTS(UnownedCallback, mozIStorageStatementCallback)
bool UnownedCallback::sAlive = false;
bool UnownedCallback::sResult = false;
bool UnownedCallback::sError = false;
////////////////////////////////////////////////////////////////////////////////
//// Tests
TEST(storage_async_callbacks_with_spun_event_loops,
SpinEventsLoopInHandleResult)
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// Create a test table and populate it.
nsCOMPtr<mozIStorageStatement> stmt;
db->CreateStatement("CREATE TABLE test (id INTEGER PRIMARY KEY)"_ns,
getter_AddRefs(stmt));
stmt->Execute();
stmt->Finalize();
db->CreateStatement("INSERT INTO test (id) VALUES (?)"_ns,
getter_AddRefs(stmt));
for (int32_t i = 0; i < 30; ++i) {
stmt->BindInt32ByIndex(0, i);
stmt->Execute();
stmt->Reset();
}
stmt->Finalize();
db->CreateStatement("SELECT * FROM test"_ns, getter_AddRefs(stmt));
nsCOMPtr<mozIStoragePendingStatement> ps;
do_check_success(
stmt->ExecuteAsync(new UnownedCallback(db), getter_AddRefs(ps)));
stmt->Finalize();
spin_events_loop_until_true(&UnownedCallback::sResult);
}
TEST(storage_async_callbacks_with_spun_event_loops, SpinEventsLoopInHandleError)
{
nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
// Create a test table and populate it.
nsCOMPtr<mozIStorageStatement> stmt;
db->CreateStatement("CREATE TABLE test (id INTEGER PRIMARY KEY)"_ns,
getter_AddRefs(stmt));
stmt->Execute();
stmt->Finalize();
db->CreateStatement("INSERT INTO test (id) VALUES (1)"_ns,
getter_AddRefs(stmt));
stmt->Execute();
stmt->Finalize();
// This will cause a constraint error.
db->CreateStatement("INSERT INTO test (id) VALUES (1)"_ns,
getter_AddRefs(stmt));
nsCOMPtr<mozIStoragePendingStatement> ps;
do_check_success(
stmt->ExecuteAsync(new UnownedCallback(db), getter_AddRefs(ps)));
stmt->Finalize();
spin_events_loop_until_true(&UnownedCallback::sError);
}
|