storage/test/test_unlock_notify.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial