Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | http://creativecommons.org/publicdomain/zero/1.0/ */ |
michael@0 | 3 | |
michael@0 | 4 | #include "storage_test_harness.h" |
michael@0 | 5 | #include "prthread.h" |
michael@0 | 6 | #include "nsIEventTarget.h" |
michael@0 | 7 | #include "nsIInterfaceRequestorUtils.h" |
michael@0 | 8 | #include "mozilla/Attributes.h" |
michael@0 | 9 | |
michael@0 | 10 | #include "sqlite3.h" |
michael@0 | 11 | |
michael@0 | 12 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 13 | //// Async Helpers |
michael@0 | 14 | |
michael@0 | 15 | /** |
michael@0 | 16 | * Spins the events loop for current thread until aCondition is true. |
michael@0 | 17 | */ |
michael@0 | 18 | void |
michael@0 | 19 | spin_events_loop_until_true(const bool* const aCondition) |
michael@0 | 20 | { |
michael@0 | 21 | nsCOMPtr<nsIThread> thread(::do_GetCurrentThread()); |
michael@0 | 22 | nsresult rv = NS_OK; |
michael@0 | 23 | bool processed = true; |
michael@0 | 24 | while (!(*aCondition) && NS_SUCCEEDED(rv)) { |
michael@0 | 25 | rv = thread->ProcessNextEvent(true, &processed); |
michael@0 | 26 | } |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 30 | //// mozIStorageStatementCallback implementation |
michael@0 | 31 | |
michael@0 | 32 | class UnownedCallback MOZ_FINAL : public mozIStorageStatementCallback |
michael@0 | 33 | { |
michael@0 | 34 | public: |
michael@0 | 35 | NS_DECL_ISUPPORTS |
michael@0 | 36 | |
michael@0 | 37 | // Whether the object has been destroyed. |
michael@0 | 38 | static bool sAlive; |
michael@0 | 39 | // Whether the first result was received. |
michael@0 | 40 | static bool sResult; |
michael@0 | 41 | // Whether an error was received. |
michael@0 | 42 | static bool sError; |
michael@0 | 43 | |
michael@0 | 44 | UnownedCallback(mozIStorageConnection* aDBConn) |
michael@0 | 45 | : mDBConn(aDBConn) |
michael@0 | 46 | , mCompleted(false) |
michael@0 | 47 | { |
michael@0 | 48 | sAlive = true; |
michael@0 | 49 | sResult = false; |
michael@0 | 50 | sError = false; |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | ~UnownedCallback() |
michael@0 | 54 | { |
michael@0 | 55 | sAlive = false; |
michael@0 | 56 | blocking_async_close(mDBConn); |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet) |
michael@0 | 60 | { |
michael@0 | 61 | sResult = true; |
michael@0 | 62 | spin_events_loop_until_true(&mCompleted); |
michael@0 | 63 | if (!sAlive) { |
michael@0 | 64 | NS_RUNTIMEABORT("The statement callback was destroyed prematurely."); |
michael@0 | 65 | } |
michael@0 | 66 | return NS_OK; |
michael@0 | 67 | } |
michael@0 | 68 | |
michael@0 | 69 | NS_IMETHOD HandleError(mozIStorageError* aError) |
michael@0 | 70 | { |
michael@0 | 71 | sError = true; |
michael@0 | 72 | spin_events_loop_until_true(&mCompleted); |
michael@0 | 73 | if (!sAlive) { |
michael@0 | 74 | NS_RUNTIMEABORT("The statement callback was destroyed prematurely."); |
michael@0 | 75 | } |
michael@0 | 76 | return NS_OK; |
michael@0 | 77 | } |
michael@0 | 78 | |
michael@0 | 79 | NS_IMETHOD HandleCompletion(uint16_t aReason) |
michael@0 | 80 | { |
michael@0 | 81 | mCompleted = true; |
michael@0 | 82 | return NS_OK; |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | protected: |
michael@0 | 86 | nsCOMPtr<mozIStorageConnection> mDBConn; |
michael@0 | 87 | bool mCompleted; |
michael@0 | 88 | }; |
michael@0 | 89 | |
michael@0 | 90 | NS_IMPL_ISUPPORTS(UnownedCallback, mozIStorageStatementCallback) |
michael@0 | 91 | |
michael@0 | 92 | bool UnownedCallback::sAlive = false; |
michael@0 | 93 | bool UnownedCallback::sResult = false; |
michael@0 | 94 | bool UnownedCallback::sError = false; |
michael@0 | 95 | |
michael@0 | 96 | //////////////////////////////////////////////////////////////////////////////// |
michael@0 | 97 | //// Tests |
michael@0 | 98 | |
michael@0 | 99 | void |
michael@0 | 100 | test_SpinEventsLoopInHandleResult() |
michael@0 | 101 | { |
michael@0 | 102 | nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
michael@0 | 103 | |
michael@0 | 104 | // Create a test table and populate it. |
michael@0 | 105 | nsCOMPtr<mozIStorageStatement> stmt; |
michael@0 | 106 | db->CreateStatement(NS_LITERAL_CSTRING( |
michael@0 | 107 | "CREATE TABLE test (id INTEGER PRIMARY KEY)" |
michael@0 | 108 | ), getter_AddRefs(stmt)); |
michael@0 | 109 | stmt->Execute(); |
michael@0 | 110 | stmt->Finalize(); |
michael@0 | 111 | |
michael@0 | 112 | db->CreateStatement(NS_LITERAL_CSTRING( |
michael@0 | 113 | "INSERT INTO test (id) VALUES (?)" |
michael@0 | 114 | ), getter_AddRefs(stmt)); |
michael@0 | 115 | for (int32_t i = 0; i < 30; ++i) { |
michael@0 | 116 | stmt->BindInt32ByIndex(0, i); |
michael@0 | 117 | stmt->Execute(); |
michael@0 | 118 | stmt->Reset(); |
michael@0 | 119 | } |
michael@0 | 120 | stmt->Finalize(); |
michael@0 | 121 | |
michael@0 | 122 | db->CreateStatement(NS_LITERAL_CSTRING( |
michael@0 | 123 | "SELECT * FROM test" |
michael@0 | 124 | ), getter_AddRefs(stmt)); |
michael@0 | 125 | nsCOMPtr<mozIStoragePendingStatement> ps; |
michael@0 | 126 | do_check_success(stmt->ExecuteAsync(new UnownedCallback(db), |
michael@0 | 127 | getter_AddRefs(ps))); |
michael@0 | 128 | stmt->Finalize(); |
michael@0 | 129 | |
michael@0 | 130 | spin_events_loop_until_true(&UnownedCallback::sResult); |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | void |
michael@0 | 134 | test_SpinEventsLoopInHandleError() |
michael@0 | 135 | { |
michael@0 | 136 | nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
michael@0 | 137 | |
michael@0 | 138 | // Create a test table and populate it. |
michael@0 | 139 | nsCOMPtr<mozIStorageStatement> stmt; |
michael@0 | 140 | db->CreateStatement(NS_LITERAL_CSTRING( |
michael@0 | 141 | "CREATE TABLE test (id INTEGER PRIMARY KEY)" |
michael@0 | 142 | ), getter_AddRefs(stmt)); |
michael@0 | 143 | stmt->Execute(); |
michael@0 | 144 | stmt->Finalize(); |
michael@0 | 145 | |
michael@0 | 146 | db->CreateStatement(NS_LITERAL_CSTRING( |
michael@0 | 147 | "INSERT INTO test (id) VALUES (1)" |
michael@0 | 148 | ), getter_AddRefs(stmt)); |
michael@0 | 149 | stmt->Execute(); |
michael@0 | 150 | stmt->Finalize(); |
michael@0 | 151 | |
michael@0 | 152 | // This will cause a constraint error. |
michael@0 | 153 | db->CreateStatement(NS_LITERAL_CSTRING( |
michael@0 | 154 | "INSERT INTO test (id) VALUES (1)" |
michael@0 | 155 | ), getter_AddRefs(stmt)); |
michael@0 | 156 | nsCOMPtr<mozIStoragePendingStatement> ps; |
michael@0 | 157 | do_check_success(stmt->ExecuteAsync(new UnownedCallback(db), |
michael@0 | 158 | getter_AddRefs(ps))); |
michael@0 | 159 | stmt->Finalize(); |
michael@0 | 160 | |
michael@0 | 161 | spin_events_loop_until_true(&UnownedCallback::sError); |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | void (*gTests[])(void) = { |
michael@0 | 165 | test_SpinEventsLoopInHandleResult, |
michael@0 | 166 | test_SpinEventsLoopInHandleError, |
michael@0 | 167 | }; |
michael@0 | 168 | |
michael@0 | 169 | const char *file = __FILE__; |
michael@0 | 170 | #define TEST_NAME "test async callbacks with spun event loops" |
michael@0 | 171 | #define TEST_FILE file |
michael@0 | 172 | #include "storage_test_harness_tail.h" |