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 */
commit_hook(void * aArg)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
check_transaction(mozIStorageConnection * aDB,mozIStorageBaseStatement ** aStmts,uint32_t aStmtsLen,bool aTransactionExpected)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 RefPtr<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 */
TEST(storage_asyncStatementExecution_transaction,MultipleAsyncReadStatements)87 TEST(storage_asyncStatementExecution_transaction, MultipleAsyncReadStatements)
88 {
89 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
90
91 // -- create statements and execute them
92 nsCOMPtr<mozIStorageAsyncStatement> stmt1;
93 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
94 "SELECT * FROM sqlite_master"
95 ), getter_AddRefs(stmt1));
96
97 nsCOMPtr<mozIStorageAsyncStatement> stmt2;
98 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
99 "SELECT * FROM sqlite_master"
100 ), getter_AddRefs(stmt2));
101
102 mozIStorageBaseStatement *stmts[] = {
103 stmt1,
104 stmt2,
105 };
106
107 check_transaction(db, stmts, ArrayLength(stmts), false);
108 }
109
110 /**
111 * Test that executing multiple readonly Statements doesn't create a
112 * transaction.
113 */
TEST(storage_asyncStatementExecution_transaction,MultipleReadStatements)114 TEST(storage_asyncStatementExecution_transaction, MultipleReadStatements)
115 {
116 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
117
118 // -- create statements and execute them
119 nsCOMPtr<mozIStorageStatement> stmt1;
120 db->CreateStatement(NS_LITERAL_CSTRING(
121 "SELECT * FROM sqlite_master"
122 ), getter_AddRefs(stmt1));
123
124 nsCOMPtr<mozIStorageStatement> stmt2;
125 db->CreateStatement(NS_LITERAL_CSTRING(
126 "SELECT * FROM sqlite_master"
127 ), getter_AddRefs(stmt2));
128
129 mozIStorageBaseStatement *stmts[] = {
130 stmt1,
131 stmt2,
132 };
133
134 check_transaction(db, stmts, ArrayLength(stmts), false);
135 }
136
137 /**
138 * Test that executing multiple AsyncStatements causing writes creates a
139 * transaction.
140 */
TEST(storage_asyncStatementExecution_transaction,MultipleAsyncReadWriteStatements)141 TEST(storage_asyncStatementExecution_transaction, MultipleAsyncReadWriteStatements)
142 {
143 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
144
145 // -- create statements and execute them
146 nsCOMPtr<mozIStorageAsyncStatement> stmt1;
147 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
148 "SELECT * FROM sqlite_master"
149 ), getter_AddRefs(stmt1));
150
151 nsCOMPtr<mozIStorageAsyncStatement> stmt2;
152 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
153 "CREATE TABLE test (id INTEGER PRIMARY KEY)"
154 ), getter_AddRefs(stmt2));
155
156 mozIStorageBaseStatement *stmts[] = {
157 stmt1,
158 stmt2,
159 };
160
161 check_transaction(db, stmts, ArrayLength(stmts), true);
162 }
163
164 /**
165 * Test that executing multiple Statements causing writes creates a transaction.
166 */
TEST(storage_asyncStatementExecution_transaction,MultipleReadWriteStatements)167 TEST(storage_asyncStatementExecution_transaction, MultipleReadWriteStatements)
168 {
169 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
170
171 // -- create statements and execute them
172 nsCOMPtr<mozIStorageStatement> stmt1;
173 db->CreateStatement(NS_LITERAL_CSTRING(
174 "SELECT * FROM sqlite_master"
175 ), getter_AddRefs(stmt1));
176
177 nsCOMPtr<mozIStorageStatement> stmt2;
178 db->CreateStatement(NS_LITERAL_CSTRING(
179 "CREATE TABLE test (id INTEGER PRIMARY KEY)"
180 ), getter_AddRefs(stmt2));
181
182 mozIStorageBaseStatement *stmts[] = {
183 stmt1,
184 stmt2,
185 };
186
187 check_transaction(db, stmts, ArrayLength(stmts), true);
188 }
189
190 /**
191 * Test that executing multiple AsyncStatements causing writes creates a
192 * single transaction.
193 */
TEST(storage_asyncStatementExecution_transaction,MultipleAsyncWriteStatements)194 TEST(storage_asyncStatementExecution_transaction, MultipleAsyncWriteStatements)
195 {
196 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
197
198 // -- create statements and execute them
199 nsCOMPtr<mozIStorageAsyncStatement> stmt1;
200 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
201 "CREATE TABLE test1 (id INTEGER PRIMARY KEY)"
202 ), getter_AddRefs(stmt1));
203
204 nsCOMPtr<mozIStorageAsyncStatement> stmt2;
205 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
206 "CREATE TABLE test2 (id INTEGER PRIMARY KEY)"
207 ), getter_AddRefs(stmt2));
208
209 mozIStorageBaseStatement *stmts[] = {
210 stmt1,
211 stmt2,
212 };
213
214 check_transaction(db, stmts, ArrayLength(stmts), true);
215 }
216
217 /**
218 * Test that executing multiple Statements causing writes creates a
219 * single transaction.
220 */
TEST(storage_asyncStatementExecution_transaction,MultipleWriteStatements)221 TEST(storage_asyncStatementExecution_transaction, MultipleWriteStatements)
222 {
223 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
224
225 // -- create statements and execute them
226 nsCOMPtr<mozIStorageStatement> stmt1;
227 db->CreateStatement(NS_LITERAL_CSTRING(
228 "CREATE TABLE test1 (id INTEGER PRIMARY KEY)"
229 ), getter_AddRefs(stmt1));
230
231 nsCOMPtr<mozIStorageStatement> stmt2;
232 db->CreateStatement(NS_LITERAL_CSTRING(
233 "CREATE TABLE test2 (id INTEGER PRIMARY KEY)"
234 ), getter_AddRefs(stmt2));
235
236 mozIStorageBaseStatement *stmts[] = {
237 stmt1,
238 stmt2,
239 };
240
241 check_transaction(db, stmts, ArrayLength(stmts), true);
242 }
243
244 /**
245 * Test that executing a single read-only AsyncStatement doesn't create a
246 * transaction.
247 */
TEST(storage_asyncStatementExecution_transaction,SingleAsyncReadStatement)248 TEST(storage_asyncStatementExecution_transaction, SingleAsyncReadStatement)
249 {
250 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
251
252 // -- create statements and execute them
253 nsCOMPtr<mozIStorageAsyncStatement> stmt;
254 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
255 "SELECT * FROM sqlite_master"
256 ), getter_AddRefs(stmt));
257
258 mozIStorageBaseStatement *stmts[] = {
259 stmt,
260 };
261
262 check_transaction(db, stmts, ArrayLength(stmts), false);
263 }
264
265 /**
266 * Test that executing a single read-only Statement doesn't create a
267 * transaction.
268 */
TEST(storage_asyncStatementExecution_transaction,SingleReadStatement)269 TEST(storage_asyncStatementExecution_transaction, SingleReadStatement)
270 {
271 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
272
273 // -- create statements and execute them
274 nsCOMPtr<mozIStorageStatement> stmt;
275 db->CreateStatement(NS_LITERAL_CSTRING(
276 "SELECT * FROM sqlite_master"
277 ), getter_AddRefs(stmt));
278
279 mozIStorageBaseStatement *stmts[] = {
280 stmt,
281 };
282
283 check_transaction(db, stmts, ArrayLength(stmts), false);
284 }
285
286 /**
287 * Test that executing a single AsyncStatement causing writes creates a
288 * transaction.
289 */
TEST(storage_asyncStatementExecution_transaction,SingleAsyncWriteStatement)290 TEST(storage_asyncStatementExecution_transaction, SingleAsyncWriteStatement)
291 {
292 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
293
294 // -- create statements and execute them
295 nsCOMPtr<mozIStorageAsyncStatement> stmt;
296 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
297 "CREATE TABLE test (id INTEGER PRIMARY KEY)"
298 ), getter_AddRefs(stmt));
299
300 mozIStorageBaseStatement *stmts[] = {
301 stmt,
302 };
303
304 check_transaction(db, stmts, ArrayLength(stmts), true);
305 }
306
307 /**
308 * Test that executing a single Statement causing writes creates a transaction.
309 */
TEST(storage_asyncStatementExecution_transaction,SingleWriteStatement)310 TEST(storage_asyncStatementExecution_transaction, SingleWriteStatement)
311 {
312 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
313
314 // -- create statements and execute them
315 nsCOMPtr<mozIStorageStatement> stmt;
316 db->CreateStatement(NS_LITERAL_CSTRING(
317 "CREATE TABLE test (id INTEGER PRIMARY KEY)"
318 ), getter_AddRefs(stmt));
319
320 mozIStorageBaseStatement *stmts[] = {
321 stmt,
322 };
323
324 check_transaction(db, stmts, ArrayLength(stmts), true);
325 }
326
327 /**
328 * Test that executing a single read-only AsyncStatement with multiple params
329 * doesn't create a transaction.
330 */
TEST(storage_asyncStatementExecution_transaction,MultipleParamsAsyncReadStatement)331 TEST(storage_asyncStatementExecution_transaction, MultipleParamsAsyncReadStatement)
332 {
333 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
334
335 // -- create statements and execute them
336 nsCOMPtr<mozIStorageAsyncStatement> stmt;
337 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
338 "SELECT :param FROM sqlite_master"
339 ), getter_AddRefs(stmt));
340
341 // -- bind multiple BindingParams
342 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
343 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
344 for (int32_t i = 0; i < 2; i++) {
345 nsCOMPtr<mozIStorageBindingParams> params;
346 paramsArray->NewBindingParams(getter_AddRefs(params));
347 params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
348 paramsArray->AddParams(params);
349 }
350 stmt->BindParameters(paramsArray);
351 paramsArray = nullptr;
352
353 mozIStorageBaseStatement *stmts[] = {
354 stmt,
355 };
356
357 check_transaction(db, stmts, ArrayLength(stmts), false);
358 }
359
360 /**
361 * Test that executing a single read-only Statement with multiple params
362 * doesn't create a transaction.
363 */
TEST(storage_asyncStatementExecution_transaction,MultipleParamsReadStatement)364 TEST(storage_asyncStatementExecution_transaction, MultipleParamsReadStatement)
365 {
366 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
367
368 // -- create statements and execute them
369 nsCOMPtr<mozIStorageStatement> stmt;
370 db->CreateStatement(NS_LITERAL_CSTRING(
371 "SELECT :param FROM sqlite_master"
372 ), getter_AddRefs(stmt));
373
374 // -- bind multiple BindingParams
375 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
376 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
377 for (int32_t i = 0; i < 2; i++) {
378 nsCOMPtr<mozIStorageBindingParams> params;
379 paramsArray->NewBindingParams(getter_AddRefs(params));
380 params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
381 paramsArray->AddParams(params);
382 }
383 stmt->BindParameters(paramsArray);
384 paramsArray = nullptr;
385
386 mozIStorageBaseStatement *stmts[] = {
387 stmt,
388 };
389
390 check_transaction(db, stmts, ArrayLength(stmts), false);
391 }
392
393 /**
394 * Test that executing a single write AsyncStatement with multiple params
395 * creates a transaction.
396 */
TEST(storage_asyncStatementExecution_transaction,MultipleParamsAsyncWriteStatement)397 TEST(storage_asyncStatementExecution_transaction, MultipleParamsAsyncWriteStatement)
398 {
399 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
400
401 // -- create a table for writes
402 nsCOMPtr<mozIStorageStatement> tableStmt;
403 db->CreateStatement(NS_LITERAL_CSTRING(
404 "CREATE TABLE test (id INTEGER PRIMARY KEY)"
405 ), getter_AddRefs(tableStmt));
406 tableStmt->Execute();
407 tableStmt->Finalize();
408
409 // -- create statements and execute them
410 nsCOMPtr<mozIStorageAsyncStatement> stmt;
411 db->CreateAsyncStatement(NS_LITERAL_CSTRING(
412 "DELETE FROM test WHERE id = :param"
413 ), getter_AddRefs(stmt));
414
415 // -- bind multiple BindingParams
416 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
417 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
418 for (int32_t i = 0; i < 2; i++) {
419 nsCOMPtr<mozIStorageBindingParams> params;
420 paramsArray->NewBindingParams(getter_AddRefs(params));
421 params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
422 paramsArray->AddParams(params);
423 }
424 stmt->BindParameters(paramsArray);
425 paramsArray = nullptr;
426
427 mozIStorageBaseStatement *stmts[] = {
428 stmt,
429 };
430
431 check_transaction(db, stmts, ArrayLength(stmts), true);
432 }
433
434 /**
435 * Test that executing a single write Statement with multiple params
436 * creates a transaction.
437 */
TEST(storage_asyncStatementExecution_transaction,MultipleParamsWriteStatement)438 TEST(storage_asyncStatementExecution_transaction, MultipleParamsWriteStatement)
439 {
440 nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
441
442 // -- create a table for writes
443 nsCOMPtr<mozIStorageStatement> tableStmt;
444 db->CreateStatement(NS_LITERAL_CSTRING(
445 "CREATE TABLE test (id INTEGER PRIMARY KEY)"
446 ), getter_AddRefs(tableStmt));
447 tableStmt->Execute();
448 tableStmt->Finalize();
449
450 // -- create statements and execute them
451 nsCOMPtr<mozIStorageStatement> stmt;
452 db->CreateStatement(NS_LITERAL_CSTRING(
453 "DELETE FROM test WHERE id = :param"
454 ), getter_AddRefs(stmt));
455
456 // -- bind multiple BindingParams
457 nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
458 stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
459 for (int32_t i = 0; i < 2; i++) {
460 nsCOMPtr<mozIStorageBindingParams> params;
461 paramsArray->NewBindingParams(getter_AddRefs(params));
462 params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
463 paramsArray->AddParams(params);
464 }
465 stmt->BindParameters(paramsArray);
466 paramsArray = nullptr;
467
468 mozIStorageBaseStatement *stmts[] = {
469 stmt,
470 };
471
472 check_transaction(db, stmts, ArrayLength(stmts), true);
473 }
474