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