storage/test/test_unlock_notify.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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.
    16  */
    18 ////////////////////////////////////////////////////////////////////////////////
    19 //// Helpers
    21 enum State {
    22   STARTING,
    23   WRITE_LOCK,
    24   READ_LOCK,
    25   TEST_DONE
    26 };
    28 class DatabaseLocker : public nsRunnable
    29 {
    30 public:
    31   DatabaseLocker(const char* aSQL)
    32   : monitor("DatabaseLocker::monitor")
    33   , mSQL(aSQL)
    34   , mState(STARTING)
    35   {
    36   }
    38   void RunInBackground()
    39   {
    40     (void)NS_NewThread(getter_AddRefs(mThread));
    41     do_check_true(mThread);
    43     do_check_success(mThread->Dispatch(this, NS_DISPATCH_NORMAL));
    44   }
    46   NS_IMETHOD Run()
    47   {
    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;
    63   }
    65   void WaitFor(State aState)
    66   {
    67     monitor.AssertCurrentThreadIn();
    68     while (mState != aState) {
    69       do_check_success(monitor.Wait());
    70     }
    71   }
    73   void Notify(State aState)
    74   {
    75     monitor.AssertCurrentThreadIn();
    76     mState = aState;
    77     do_check_success(monitor.Notify());
    78   }
    80   mozilla::ReentrantMonitor monitor;
    82 protected:
    83   nsCOMPtr<nsIThread> mThread;
    84   const char *const mSQL;
    85   State mState;
    86 };
    88 class DatabaseTester : public DatabaseLocker
    89 {
    90 public:
    91   DatabaseTester(mozIStorageConnection *aConnection,
    92                  const char* aSQL)
    93   : DatabaseLocker(aSQL)
    94   , mConnection(aConnection)
    95   {
    96   }
    98   NS_IMETHOD Run()
    99   {
   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;
   120   }
   122 private:
   123   nsCOMPtr<mozIStorageConnection> mConnection;
   124 };
   126 ////////////////////////////////////////////////////////////////////////////////
   127 //// Test Functions
   129 void
   130 setup()
   131 {
   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)"
   137   ));
   138   do_check_success(rv);
   139   rv = db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   140     "INSERT INTO test (data) VALUES ('foo')"
   141   ));
   142   do_check_success(rv);
   143   rv = db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   144     "INSERT INTO test (data) VALUES ('bar')"
   145   ));
   146   do_check_success(rv);
   147   rv = db->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   148     "CREATE UNIQUE INDEX unique_data ON test (data)"
   149   ));
   150   do_check_success(rv);
   151 }
   153 void
   154 test_step_locked_does_not_block_main_thread()
   155 {
   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);
   179 }
   181 void
   182 test_drop_index_does_not_loop()
   183 {
   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);
   209 }
   211 void
   212 test_drop_table_does_not_loop()
   213 {
   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);
   238 }
   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,
   245 };
   247 const char *file = __FILE__;
   248 #define TEST_NAME "sqlite3_unlock_notify"
   249 #define TEST_FILE file
   250 #include "storage_test_harness_tail.h"

mercurial