Bumping manifests a=b2g-bump
[gecko.git] / storage / test / test_unlock_notify.cpp
blob73ae74ebbd38cfc855fdc13bb16009af8f657eaa
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim set:sw=2 ts=2 et lcs=trail\:.,tab\:>~ : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "storage_test_harness.h"
9 #include "mozilla/ReentrantMonitor.h"
10 #include "nsThreadUtils.h"
11 #include "mozIStorageStatement.h"
13 /**
14 * This file tests that our implementation around sqlite3_unlock_notify works
15 * as expected.
18 ////////////////////////////////////////////////////////////////////////////////
19 //// Helpers
21 enum State {
22 STARTING,
23 WRITE_LOCK,
24 READ_LOCK,
25 TEST_DONE
28 class DatabaseLocker : public nsRunnable
30 public:
31 DatabaseLocker(const char* aSQL)
32 : monitor("DatabaseLocker::monitor")
33 , mSQL(aSQL)
34 , mState(STARTING)
38 void RunInBackground()
40 (void)NS_NewThread(getter_AddRefs(mThread));
41 do_check_true(mThread);
43 do_check_success(mThread->Dispatch(this, NS_DISPATCH_NORMAL));
46 NS_IMETHOD Run()
48 mozilla::ReentrantMonitorAutoEnter lock(monitor);
50 nsCOMPtr<mozIStorageConnection> db(getDatabase());
52 nsCString sql(mSQL);
53 nsCOMPtr<mozIStorageStatement> stmt;
54 do_check_success(db->CreateStatement(sql, getter_AddRefs(stmt)));
56 bool hasResult;
57 do_check_success(stmt->ExecuteStep(&hasResult));
59 Notify(WRITE_LOCK);
60 WaitFor(TEST_DONE);
62 return NS_OK;
65 void WaitFor(State aState)
67 monitor.AssertCurrentThreadIn();
68 while (mState != aState) {
69 do_check_success(monitor.Wait());
73 void Notify(State aState)
75 monitor.AssertCurrentThreadIn();
76 mState = aState;
77 do_check_success(monitor.Notify());
80 mozilla::ReentrantMonitor monitor;
82 protected:
83 nsCOMPtr<nsIThread> mThread;
84 const char *const mSQL;
85 State mState;
88 class DatabaseTester : public DatabaseLocker
90 public:
91 DatabaseTester(mozIStorageConnection *aConnection,
92 const char* aSQL)
93 : DatabaseLocker(aSQL)
94 , mConnection(aConnection)
98 NS_IMETHOD Run()
100 mozilla::ReentrantMonitorAutoEnter lock(monitor);
101 WaitFor(READ_LOCK);
103 nsCString sql(mSQL);
104 nsCOMPtr<mozIStorageStatement> stmt;
105 do_check_success(mConnection->CreateStatement(sql, getter_AddRefs(stmt)));
107 bool hasResult;
108 nsresult rv = stmt->ExecuteStep(&hasResult);
109 do_check_eq(rv, NS_ERROR_FILE_IS_LOCKED);
111 // Finalize our statement and null out our connection before notifying to
112 // ensure that we close on the proper thread.
113 rv = stmt->Finalize();
114 do_check_eq(rv, NS_ERROR_FILE_IS_LOCKED);
115 mConnection = nullptr;
117 Notify(TEST_DONE);
119 return NS_OK;
122 private:
123 nsCOMPtr<mozIStorageConnection> mConnection;
126 ////////////////////////////////////////////////////////////////////////////////
127 //// Test Functions
129 void
130 setup()
132 nsCOMPtr<mozIStorageConnection> db(getDatabase());
134 // Create and populate a dummy table.
135 nsresult rv = db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
136 "CREATE TABLE test (id INTEGER PRIMARY KEY, data STRING)"
138 do_check_success(rv);
139 rv = db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
140 "INSERT INTO test (data) VALUES ('foo')"
142 do_check_success(rv);
143 rv = db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
144 "INSERT INTO test (data) VALUES ('bar')"
146 do_check_success(rv);
147 rv = db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
148 "CREATE UNIQUE INDEX unique_data ON test (data)"
150 do_check_success(rv);
153 void
154 test_step_locked_does_not_block_main_thread()
156 nsCOMPtr<mozIStorageConnection> db(getDatabase());
158 // Need to prepare our statement ahead of time so we make sure to only test
159 // step and not prepare.
160 nsCOMPtr<mozIStorageStatement> stmt;
161 nsresult rv = db->CreateStatement(NS_LITERAL_CSTRING(
162 "INSERT INTO test (data) VALUES ('test1')"
163 ), getter_AddRefs(stmt));
164 do_check_success(rv);
166 nsRefPtr<DatabaseLocker> locker(new DatabaseLocker("SELECT * FROM test"));
167 do_check_true(locker);
168 mozilla::ReentrantMonitorAutoEnter lock(locker->monitor);
169 locker->RunInBackground();
171 // Wait for the locker to notify us that it has locked the database properly.
172 locker->WaitFor(WRITE_LOCK);
174 bool hasResult;
175 rv = stmt->ExecuteStep(&hasResult);
176 do_check_eq(rv, NS_ERROR_FILE_IS_LOCKED);
178 locker->Notify(TEST_DONE);
181 void
182 test_drop_index_does_not_loop()
184 nsCOMPtr<mozIStorageConnection> db(getDatabase());
186 // Need to prepare our statement ahead of time so we make sure to only test
187 // step and not prepare.
188 nsCOMPtr<mozIStorageStatement> stmt;
189 nsresult rv = db->CreateStatement(NS_LITERAL_CSTRING(
190 "SELECT * FROM test"
191 ), getter_AddRefs(stmt));
192 do_check_success(rv);
194 nsRefPtr<DatabaseTester> tester =
195 new DatabaseTester(db, "DROP INDEX unique_data");
196 do_check_true(tester);
197 mozilla::ReentrantMonitorAutoEnter lock(tester->monitor);
198 tester->RunInBackground();
200 // Hold a read lock on the database, and then let the tester try to execute.
201 bool hasResult;
202 rv = stmt->ExecuteStep(&hasResult);
203 do_check_success(rv);
204 do_check_true(hasResult);
205 tester->Notify(READ_LOCK);
207 // Make sure the tester finishes its test before we move on.
208 tester->WaitFor(TEST_DONE);
211 void
212 test_drop_table_does_not_loop()
214 nsCOMPtr<mozIStorageConnection> db(getDatabase());
216 // Need to prepare our statement ahead of time so we make sure to only test
217 // step and not prepare.
218 nsCOMPtr<mozIStorageStatement> stmt;
219 nsresult rv = db->CreateStatement(NS_LITERAL_CSTRING(
220 "SELECT * FROM test"
221 ), getter_AddRefs(stmt));
222 do_check_success(rv);
224 nsRefPtr<DatabaseTester> tester(new DatabaseTester(db, "DROP TABLE test"));
225 do_check_true(tester);
226 mozilla::ReentrantMonitorAutoEnter lock(tester->monitor);
227 tester->RunInBackground();
229 // Hold a read lock on the database, and then let the tester try to execute.
230 bool hasResult;
231 rv = stmt->ExecuteStep(&hasResult);
232 do_check_success(rv);
233 do_check_true(hasResult);
234 tester->Notify(READ_LOCK);
236 // Make sure the tester finishes its test before we move on.
237 tester->WaitFor(TEST_DONE);
240 void (*gTests[])(void) = {
241 setup,
242 test_step_locked_does_not_block_main_thread,
243 test_drop_index_does_not_loop,
244 test_drop_table_does_not_loop,
247 const char *file = __FILE__;
248 #define TEST_NAME "sqlite3_unlock_notify"
249 #define TEST_FILE file
250 #include "storage_test_harness_tail.h"