|
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 |
|
6 #include "nsIEventTarget.h" |
|
7 #include "mozStorageConnection.h" |
|
8 |
|
9 #include "sqlite3.h" |
|
10 |
|
11 using namespace mozilla; |
|
12 using namespace mozilla::storage; |
|
13 |
|
14 //////////////////////////////////////////////////////////////////////////////// |
|
15 //// Helpers |
|
16 |
|
17 /** |
|
18 * Commit hook to detect transactions. |
|
19 * |
|
20 * @param aArg |
|
21 * An integer pointer that will be incremented for each commit. |
|
22 */ |
|
23 int commit_hook(void *aArg) |
|
24 { |
|
25 int *arg = static_cast<int *>(aArg); |
|
26 (*arg)++; |
|
27 return 0; |
|
28 } |
|
29 |
|
30 /** |
|
31 * Executes the passed-in statements and checks if a transaction is created. |
|
32 * When done statements are finalized and database connection is closed. |
|
33 * |
|
34 * @param aDB |
|
35 * The database connection. |
|
36 * @param aStmts |
|
37 * Vector of statements. |
|
38 * @param aStmtsLen |
|
39 * Number of statements. |
|
40 * @param aTransactionExpected |
|
41 * Whether a transaction is expected or not. |
|
42 */ |
|
43 void |
|
44 check_transaction(mozIStorageConnection *aDB, |
|
45 mozIStorageBaseStatement **aStmts, |
|
46 uint32_t aStmtsLen, |
|
47 bool aTransactionExpected) |
|
48 { |
|
49 // -- install a transaction commit hook. |
|
50 int commit = 0; |
|
51 static_cast<Connection *>(aDB)->setCommitHook(commit_hook, &commit); |
|
52 |
|
53 nsRefPtr<AsyncStatementSpinner> asyncSpin(new AsyncStatementSpinner()); |
|
54 nsCOMPtr<mozIStoragePendingStatement> asyncPend; |
|
55 do_check_success(aDB->ExecuteAsync(aStmts, aStmtsLen, asyncSpin, |
|
56 getter_AddRefs(asyncPend))); |
|
57 do_check_true(asyncPend); |
|
58 |
|
59 // -- complete the execution |
|
60 asyncSpin->SpinUntilCompleted(); |
|
61 |
|
62 // -- uninstall the transaction commit hook. |
|
63 static_cast<Connection *>(aDB)->setCommitHook(nullptr); |
|
64 |
|
65 // -- check transaction |
|
66 do_check_eq(aTransactionExpected, !!commit); |
|
67 |
|
68 // -- check that only one transaction was created. |
|
69 if (aTransactionExpected) { |
|
70 do_check_eq(1, commit); |
|
71 } |
|
72 |
|
73 // -- cleanup |
|
74 for (uint32_t i = 0; i < aStmtsLen; ++i) { |
|
75 aStmts[i]->Finalize(); |
|
76 } |
|
77 blocking_async_close(aDB); |
|
78 } |
|
79 |
|
80 //////////////////////////////////////////////////////////////////////////////// |
|
81 //// Tests |
|
82 |
|
83 /** |
|
84 * Test that executing multiple readonly AsyncStatements doesn't create a |
|
85 * transaction. |
|
86 */ |
|
87 void |
|
88 test_MultipleAsyncReadStatements() |
|
89 { |
|
90 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
91 |
|
92 // -- create statements and execute them |
|
93 nsCOMPtr<mozIStorageAsyncStatement> stmt1; |
|
94 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
95 "SELECT * FROM sqlite_master" |
|
96 ), getter_AddRefs(stmt1)); |
|
97 |
|
98 nsCOMPtr<mozIStorageAsyncStatement> stmt2; |
|
99 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
100 "SELECT * FROM sqlite_master" |
|
101 ), getter_AddRefs(stmt2)); |
|
102 |
|
103 mozIStorageBaseStatement *stmts[] = { |
|
104 stmt1, |
|
105 stmt2, |
|
106 }; |
|
107 |
|
108 check_transaction(db, stmts, ArrayLength(stmts), false); |
|
109 } |
|
110 |
|
111 /** |
|
112 * Test that executing multiple readonly Statements doesn't create a |
|
113 * transaction. |
|
114 */ |
|
115 void |
|
116 test_MultipleReadStatements() |
|
117 { |
|
118 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
119 |
|
120 // -- create statements and execute them |
|
121 nsCOMPtr<mozIStorageStatement> stmt1; |
|
122 db->CreateStatement(NS_LITERAL_CSTRING( |
|
123 "SELECT * FROM sqlite_master" |
|
124 ), getter_AddRefs(stmt1)); |
|
125 |
|
126 nsCOMPtr<mozIStorageStatement> stmt2; |
|
127 db->CreateStatement(NS_LITERAL_CSTRING( |
|
128 "SELECT * FROM sqlite_master" |
|
129 ), getter_AddRefs(stmt2)); |
|
130 |
|
131 mozIStorageBaseStatement *stmts[] = { |
|
132 stmt1, |
|
133 stmt2, |
|
134 }; |
|
135 |
|
136 check_transaction(db, stmts, ArrayLength(stmts), false); |
|
137 } |
|
138 |
|
139 /** |
|
140 * Test that executing multiple AsyncStatements causing writes creates a |
|
141 * transaction. |
|
142 */ |
|
143 void |
|
144 test_MultipleAsyncReadWriteStatements() |
|
145 { |
|
146 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
147 |
|
148 // -- create statements and execute them |
|
149 nsCOMPtr<mozIStorageAsyncStatement> stmt1; |
|
150 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
151 "SELECT * FROM sqlite_master" |
|
152 ), getter_AddRefs(stmt1)); |
|
153 |
|
154 nsCOMPtr<mozIStorageAsyncStatement> stmt2; |
|
155 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
156 "CREATE TABLE test (id INTEGER PRIMARY KEY)" |
|
157 ), getter_AddRefs(stmt2)); |
|
158 |
|
159 mozIStorageBaseStatement *stmts[] = { |
|
160 stmt1, |
|
161 stmt2, |
|
162 }; |
|
163 |
|
164 check_transaction(db, stmts, ArrayLength(stmts), true); |
|
165 } |
|
166 |
|
167 /** |
|
168 * Test that executing multiple Statements causing writes creates a transaction. |
|
169 */ |
|
170 void |
|
171 test_MultipleReadWriteStatements() |
|
172 { |
|
173 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
174 |
|
175 // -- create statements and execute them |
|
176 nsCOMPtr<mozIStorageStatement> stmt1; |
|
177 db->CreateStatement(NS_LITERAL_CSTRING( |
|
178 "SELECT * FROM sqlite_master" |
|
179 ), getter_AddRefs(stmt1)); |
|
180 |
|
181 nsCOMPtr<mozIStorageStatement> stmt2; |
|
182 db->CreateStatement(NS_LITERAL_CSTRING( |
|
183 "CREATE TABLE test (id INTEGER PRIMARY KEY)" |
|
184 ), getter_AddRefs(stmt2)); |
|
185 |
|
186 mozIStorageBaseStatement *stmts[] = { |
|
187 stmt1, |
|
188 stmt2, |
|
189 }; |
|
190 |
|
191 check_transaction(db, stmts, ArrayLength(stmts), true); |
|
192 } |
|
193 |
|
194 /** |
|
195 * Test that executing multiple AsyncStatements causing writes creates a |
|
196 * single transaction. |
|
197 */ |
|
198 void |
|
199 test_MultipleAsyncWriteStatements() |
|
200 { |
|
201 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
202 |
|
203 // -- create statements and execute them |
|
204 nsCOMPtr<mozIStorageAsyncStatement> stmt1; |
|
205 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
206 "CREATE TABLE test1 (id INTEGER PRIMARY KEY)" |
|
207 ), getter_AddRefs(stmt1)); |
|
208 |
|
209 nsCOMPtr<mozIStorageAsyncStatement> stmt2; |
|
210 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
211 "CREATE TABLE test2 (id INTEGER PRIMARY KEY)" |
|
212 ), getter_AddRefs(stmt2)); |
|
213 |
|
214 mozIStorageBaseStatement *stmts[] = { |
|
215 stmt1, |
|
216 stmt2, |
|
217 }; |
|
218 |
|
219 check_transaction(db, stmts, ArrayLength(stmts), true); |
|
220 } |
|
221 |
|
222 /** |
|
223 * Test that executing multiple Statements causing writes creates a |
|
224 * single transaction. |
|
225 */ |
|
226 void |
|
227 test_MultipleWriteStatements() |
|
228 { |
|
229 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
230 |
|
231 // -- create statements and execute them |
|
232 nsCOMPtr<mozIStorageStatement> stmt1; |
|
233 db->CreateStatement(NS_LITERAL_CSTRING( |
|
234 "CREATE TABLE test1 (id INTEGER PRIMARY KEY)" |
|
235 ), getter_AddRefs(stmt1)); |
|
236 |
|
237 nsCOMPtr<mozIStorageStatement> stmt2; |
|
238 db->CreateStatement(NS_LITERAL_CSTRING( |
|
239 "CREATE TABLE test2 (id INTEGER PRIMARY KEY)" |
|
240 ), getter_AddRefs(stmt2)); |
|
241 |
|
242 mozIStorageBaseStatement *stmts[] = { |
|
243 stmt1, |
|
244 stmt2, |
|
245 }; |
|
246 |
|
247 check_transaction(db, stmts, ArrayLength(stmts), true); |
|
248 } |
|
249 |
|
250 /** |
|
251 * Test that executing a single read-only AsyncStatement doesn't create a |
|
252 * transaction. |
|
253 */ |
|
254 void |
|
255 test_SingleAsyncReadStatement() |
|
256 { |
|
257 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
258 |
|
259 // -- create statements and execute them |
|
260 nsCOMPtr<mozIStorageAsyncStatement> stmt; |
|
261 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
262 "SELECT * FROM sqlite_master" |
|
263 ), getter_AddRefs(stmt)); |
|
264 |
|
265 mozIStorageBaseStatement *stmts[] = { |
|
266 stmt, |
|
267 }; |
|
268 |
|
269 check_transaction(db, stmts, ArrayLength(stmts), false); |
|
270 } |
|
271 |
|
272 /** |
|
273 * Test that executing a single read-only Statement doesn't create a |
|
274 * transaction. |
|
275 */ |
|
276 void |
|
277 test_SingleReadStatement() |
|
278 { |
|
279 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
280 |
|
281 // -- create statements and execute them |
|
282 nsCOMPtr<mozIStorageStatement> stmt; |
|
283 db->CreateStatement(NS_LITERAL_CSTRING( |
|
284 "SELECT * FROM sqlite_master" |
|
285 ), getter_AddRefs(stmt)); |
|
286 |
|
287 mozIStorageBaseStatement *stmts[] = { |
|
288 stmt, |
|
289 }; |
|
290 |
|
291 check_transaction(db, stmts, ArrayLength(stmts), false); |
|
292 } |
|
293 |
|
294 /** |
|
295 * Test that executing a single AsyncStatement causing writes creates a |
|
296 * transaction. |
|
297 */ |
|
298 void |
|
299 test_SingleAsyncWriteStatement() |
|
300 { |
|
301 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
302 |
|
303 // -- create statements and execute them |
|
304 nsCOMPtr<mozIStorageAsyncStatement> stmt; |
|
305 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
306 "CREATE TABLE test (id INTEGER PRIMARY KEY)" |
|
307 ), getter_AddRefs(stmt)); |
|
308 |
|
309 mozIStorageBaseStatement *stmts[] = { |
|
310 stmt, |
|
311 }; |
|
312 |
|
313 check_transaction(db, stmts, ArrayLength(stmts), true); |
|
314 } |
|
315 |
|
316 /** |
|
317 * Test that executing a single Statement causing writes creates a transaction. |
|
318 */ |
|
319 void |
|
320 test_SingleWriteStatement() |
|
321 { |
|
322 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
323 |
|
324 // -- create statements and execute them |
|
325 nsCOMPtr<mozIStorageStatement> stmt; |
|
326 db->CreateStatement(NS_LITERAL_CSTRING( |
|
327 "CREATE TABLE test (id INTEGER PRIMARY KEY)" |
|
328 ), getter_AddRefs(stmt)); |
|
329 |
|
330 mozIStorageBaseStatement *stmts[] = { |
|
331 stmt, |
|
332 }; |
|
333 |
|
334 check_transaction(db, stmts, ArrayLength(stmts), true); |
|
335 } |
|
336 |
|
337 /** |
|
338 * Test that executing a single read-only AsyncStatement with multiple params |
|
339 * doesn't create a transaction. |
|
340 */ |
|
341 void |
|
342 test_MultipleParamsAsyncReadStatement() |
|
343 { |
|
344 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
345 |
|
346 // -- create statements and execute them |
|
347 nsCOMPtr<mozIStorageAsyncStatement> stmt; |
|
348 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
349 "SELECT :param FROM sqlite_master" |
|
350 ), getter_AddRefs(stmt)); |
|
351 |
|
352 // -- bind multiple BindingParams |
|
353 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray; |
|
354 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray)); |
|
355 for (int32_t i = 0; i < 2; i++) { |
|
356 nsCOMPtr<mozIStorageBindingParams> params; |
|
357 paramsArray->NewBindingParams(getter_AddRefs(params)); |
|
358 params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1); |
|
359 paramsArray->AddParams(params); |
|
360 } |
|
361 stmt->BindParameters(paramsArray); |
|
362 paramsArray = nullptr; |
|
363 |
|
364 mozIStorageBaseStatement *stmts[] = { |
|
365 stmt, |
|
366 }; |
|
367 |
|
368 check_transaction(db, stmts, ArrayLength(stmts), false); |
|
369 } |
|
370 |
|
371 /** |
|
372 * Test that executing a single read-only Statement with multiple params |
|
373 * doesn't create a transaction. |
|
374 */ |
|
375 void |
|
376 test_MultipleParamsReadStatement() |
|
377 { |
|
378 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
379 |
|
380 // -- create statements and execute them |
|
381 nsCOMPtr<mozIStorageStatement> stmt; |
|
382 db->CreateStatement(NS_LITERAL_CSTRING( |
|
383 "SELECT :param FROM sqlite_master" |
|
384 ), getter_AddRefs(stmt)); |
|
385 |
|
386 // -- bind multiple BindingParams |
|
387 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray; |
|
388 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray)); |
|
389 for (int32_t i = 0; i < 2; i++) { |
|
390 nsCOMPtr<mozIStorageBindingParams> params; |
|
391 paramsArray->NewBindingParams(getter_AddRefs(params)); |
|
392 params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1); |
|
393 paramsArray->AddParams(params); |
|
394 } |
|
395 stmt->BindParameters(paramsArray); |
|
396 paramsArray = nullptr; |
|
397 |
|
398 mozIStorageBaseStatement *stmts[] = { |
|
399 stmt, |
|
400 }; |
|
401 |
|
402 check_transaction(db, stmts, ArrayLength(stmts), false); |
|
403 } |
|
404 |
|
405 /** |
|
406 * Test that executing a single write AsyncStatement with multiple params |
|
407 * creates a transaction. |
|
408 */ |
|
409 void |
|
410 test_MultipleParamsAsyncWriteStatement() |
|
411 { |
|
412 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
413 |
|
414 // -- create a table for writes |
|
415 nsCOMPtr<mozIStorageStatement> tableStmt; |
|
416 db->CreateStatement(NS_LITERAL_CSTRING( |
|
417 "CREATE TABLE test (id INTEGER PRIMARY KEY)" |
|
418 ), getter_AddRefs(tableStmt)); |
|
419 tableStmt->Execute(); |
|
420 tableStmt->Finalize(); |
|
421 |
|
422 // -- create statements and execute them |
|
423 nsCOMPtr<mozIStorageAsyncStatement> stmt; |
|
424 db->CreateAsyncStatement(NS_LITERAL_CSTRING( |
|
425 "DELETE FROM test WHERE id = :param" |
|
426 ), getter_AddRefs(stmt)); |
|
427 |
|
428 // -- bind multiple BindingParams |
|
429 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray; |
|
430 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray)); |
|
431 for (int32_t i = 0; i < 2; i++) { |
|
432 nsCOMPtr<mozIStorageBindingParams> params; |
|
433 paramsArray->NewBindingParams(getter_AddRefs(params)); |
|
434 params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1); |
|
435 paramsArray->AddParams(params); |
|
436 } |
|
437 stmt->BindParameters(paramsArray); |
|
438 paramsArray = nullptr; |
|
439 |
|
440 mozIStorageBaseStatement *stmts[] = { |
|
441 stmt, |
|
442 }; |
|
443 |
|
444 check_transaction(db, stmts, ArrayLength(stmts), true); |
|
445 } |
|
446 |
|
447 /** |
|
448 * Test that executing a single write Statement with multiple params |
|
449 * creates a transaction. |
|
450 */ |
|
451 void |
|
452 test_MultipleParamsWriteStatement() |
|
453 { |
|
454 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase()); |
|
455 |
|
456 // -- create a table for writes |
|
457 nsCOMPtr<mozIStorageStatement> tableStmt; |
|
458 db->CreateStatement(NS_LITERAL_CSTRING( |
|
459 "CREATE TABLE test (id INTEGER PRIMARY KEY)" |
|
460 ), getter_AddRefs(tableStmt)); |
|
461 tableStmt->Execute(); |
|
462 tableStmt->Finalize(); |
|
463 |
|
464 // -- create statements and execute them |
|
465 nsCOMPtr<mozIStorageStatement> stmt; |
|
466 db->CreateStatement(NS_LITERAL_CSTRING( |
|
467 "DELETE FROM test WHERE id = :param" |
|
468 ), getter_AddRefs(stmt)); |
|
469 |
|
470 // -- bind multiple BindingParams |
|
471 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray; |
|
472 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray)); |
|
473 for (int32_t i = 0; i < 2; i++) { |
|
474 nsCOMPtr<mozIStorageBindingParams> params; |
|
475 paramsArray->NewBindingParams(getter_AddRefs(params)); |
|
476 params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1); |
|
477 paramsArray->AddParams(params); |
|
478 } |
|
479 stmt->BindParameters(paramsArray); |
|
480 paramsArray = nullptr; |
|
481 |
|
482 mozIStorageBaseStatement *stmts[] = { |
|
483 stmt, |
|
484 }; |
|
485 |
|
486 check_transaction(db, stmts, ArrayLength(stmts), true); |
|
487 } |
|
488 |
|
489 void (*gTests[])(void) = { |
|
490 test_MultipleAsyncReadStatements, |
|
491 test_MultipleReadStatements, |
|
492 test_MultipleAsyncReadWriteStatements, |
|
493 test_MultipleReadWriteStatements, |
|
494 test_MultipleAsyncWriteStatements, |
|
495 test_MultipleWriteStatements, |
|
496 test_SingleAsyncReadStatement, |
|
497 test_SingleReadStatement, |
|
498 test_SingleAsyncWriteStatement, |
|
499 test_SingleWriteStatement, |
|
500 test_MultipleParamsAsyncReadStatement, |
|
501 test_MultipleParamsReadStatement, |
|
502 test_MultipleParamsAsyncWriteStatement, |
|
503 test_MultipleParamsWriteStatement, |
|
504 }; |
|
505 |
|
506 const char *file = __FILE__; |
|
507 #define TEST_NAME "async statement execution transaction" |
|
508 #define TEST_FILE file |
|
509 #include "storage_test_harness_tail.h" |