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