storage/test/unit/head_storage.js

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 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 const Ci = Components.interfaces;
     6 const Cc = Components.classes;
     7 const Cr = Components.results;
     8 const Cu = Components.utils;
    10 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    11 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
    12     "resource://gre/modules/Promise.jsm");
    15 do_get_profile();
    16 var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
    17              getService(Ci.nsIProperties);
    19 function getTestDB()
    20 {
    21   var db = dirSvc.get("ProfD", Ci.nsIFile);
    22   db.append("test_storage.sqlite");
    23   return db;
    24 }
    26 /**
    27  * Obtains a corrupt database to test against.
    28  */
    29 function getCorruptDB()
    30 {
    31   return do_get_file("corruptDB.sqlite");
    32 }
    34 /**
    35  * Obtains a fake (non-SQLite format) database to test against.
    36  */
    37 function getFakeDB()
    38 {
    39   return do_get_file("fakeDB.sqlite");
    40 }
    42 function cleanup()
    43 {
    44   // close the connection
    45   print("*** Storage Tests: Trying to close!");
    46   getOpenedDatabase().close();
    48   // we need to null out the database variable to get a new connection the next
    49   // time getOpenedDatabase is called
    50   gDBConn = null;
    52   // removing test db
    53   print("*** Storage Tests: Trying to remove file!");
    54   var dbFile = getTestDB();
    55   if (dbFile.exists())
    56     try { dbFile.remove(false); } catch(e) { /* stupid windows box */ }
    57 }
    59 /**
    60  * Use asyncClose to cleanup a connection.  Synchronous by means of internally
    61  * spinning an event loop.
    62  */
    63 function asyncCleanup()
    64 {
    65   let closed = false;
    67   // close the connection
    68   print("*** Storage Tests: Trying to asyncClose!");
    69   getOpenedDatabase().asyncClose(function() { closed = true; });
    71   let curThread = Components.classes["@mozilla.org/thread-manager;1"]
    72                             .getService().currentThread;
    73   while (!closed)
    74     curThread.processNextEvent(true);
    76   // we need to null out the database variable to get a new connection the next
    77   // time getOpenedDatabase is called
    78   gDBConn = null;
    80   // removing test db
    81   print("*** Storage Tests: Trying to remove file!");
    82   var dbFile = getTestDB();
    83   if (dbFile.exists())
    84     try { dbFile.remove(false); } catch(e) { /* stupid windows box */ }
    85 }
    87 function getService()
    88 {
    89   return Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService);
    90 }
    92 var gDBConn = null;
    94 /**
    95  * Get a connection to the test database.  Creates and caches the connection
    96  * if necessary, otherwise reuses the existing cached connection. This
    97  * connection shares its cache.
    98  *
    99  * @returns the mozIStorageConnection for the file.
   100  */
   101 function getOpenedDatabase()
   102 {
   103   if (!gDBConn) {
   104     gDBConn = getService().openDatabase(getTestDB());
   105   }
   106   return gDBConn;
   107 }
   109 /**
   110  * Get a connection to the test database.  Creates and caches the connection
   111  * if necessary, otherwise reuses the existing cached connection. This
   112  * connection doesn't share its cache.
   113  *
   114  * @returns the mozIStorageConnection for the file.
   115  */
   116 function getOpenedUnsharedDatabase()
   117 {
   118   if (!gDBConn) {
   119     gDBConn = getService().openUnsharedDatabase(getTestDB());
   120   }
   121   return gDBConn;
   122 }
   124 /**
   125  * Obtains a specific database to use.
   126  *
   127  * @param aFile
   128  *        The nsIFile representing the db file to open.
   129  * @returns the mozIStorageConnection for the file.
   130  */
   131 function getDatabase(aFile)
   132 {
   133   return getService().openDatabase(aFile);
   134 }
   136 function createStatement(aSQL)
   137 {
   138   return getOpenedDatabase().createStatement(aSQL);
   139 }
   141 /**
   142  * Creates an asynchronous SQL statement.
   143  *
   144  * @param aSQL
   145  *        The SQL to parse into a statement.
   146  * @returns a mozIStorageAsyncStatement from aSQL.
   147  */
   148 function createAsyncStatement(aSQL)
   149 {
   150   return getOpenedDatabase().createAsyncStatement(aSQL);
   151 }
   153 /**
   154  * Invoke the given function and assert that it throws an exception expressing
   155  * the provided error code in its 'result' attribute.  JS function expressions
   156  * can be used to do this concisely.
   157  *
   158  * Example:
   159  *  expectError(Cr.NS_ERROR_INVALID_ARG, function() explodingFunction());
   160  *
   161  * @param aErrorCode
   162  *        The error code to expect from invocation of aFunction.
   163  * @param aFunction
   164  *        The function to invoke and expect an XPCOM-style error from.
   165  */
   166 function expectError(aErrorCode, aFunction)
   167 {
   168   let exceptionCaught = false;
   169   try {
   170     aFunction();
   171   }
   172   catch(e) {
   173     if (e.result != aErrorCode) {
   174       do_throw("Got an exception, but the result code was not the expected " +
   175                "one.  Expected " + aErrorCode + ", got " + e.result);
   176     }
   177     exceptionCaught = true;
   178   }
   179   if (!exceptionCaught)
   180     do_throw(aFunction + " should have thrown an exception but did not!");
   181 }
   183 /**
   184  * Run a query synchronously and verify that we get back the expected results.
   185  *
   186  * @param aSQLString
   187  *        The SQL string for the query.
   188  * @param aBind
   189  *        The value to bind at index 0.
   190  * @param aResults
   191  *        A list of the expected values returned in the sole result row.
   192  *        Express blobs as lists.
   193  */
   194 function verifyQuery(aSQLString, aBind, aResults)
   195 {
   196   let stmt = getOpenedDatabase().createStatement(aSQLString);
   197   stmt.bindByIndex(0, aBind);
   198   try {
   199     do_check_true(stmt.executeStep());
   200     let nCols = stmt.numEntries;
   201     if (aResults.length != nCols)
   202       do_throw("Expected " + aResults.length + " columns in result but " +
   203                "there are only " + aResults.length + "!");
   204     for (let iCol = 0; iCol < nCols; iCol++) {
   205       let expectedVal = aResults[iCol];
   206       let valType = stmt.getTypeOfIndex(iCol);
   207       if (expectedVal === null) {
   208         do_check_eq(stmt.VALUE_TYPE_NULL, valType);
   209         do_check_true(stmt.getIsNull(iCol));
   210       }
   211       else if (typeof(expectedVal) == "number") {
   212         if (Math.floor(expectedVal) == expectedVal) {
   213           do_check_eq(stmt.VALUE_TYPE_INTEGER, valType);
   214           do_check_eq(expectedVal, stmt.getInt32(iCol));
   215         }
   216         else {
   217           do_check_eq(stmt.VALUE_TYPE_FLOAT, valType);
   218           do_check_eq(expectedVal, stmt.getDouble(iCol));
   219         }
   220       }
   221       else if (typeof(expectedVal) == "string") {
   222         do_check_eq(stmt.VALUE_TYPE_TEXT, valType);
   223         do_check_eq(expectedVal, stmt.getUTF8String(iCol));
   224       }
   225       else { // blob
   226         do_check_eq(stmt.VALUE_TYPE_BLOB, valType);
   227         let count = { value: 0 }, blob = { value: null };
   228         stmt.getBlob(iCol, count, blob);
   229         do_check_eq(count.value, expectedVal.length);
   230         for (let i = 0; i < count.value; i++) {
   231           do_check_eq(expectedVal[i], blob.value[i]);
   232         }
   233       }
   234     }
   235   }
   236   finally {
   237     stmt.finalize();
   238   }
   239 }
   241 /**
   242  * Return the number of rows in the able with the given name using a synchronous
   243  * query.
   244  *
   245  * @param aTableName
   246  *        The name of the table.
   247  * @return The number of rows.
   248  */
   249 function getTableRowCount(aTableName)
   250 {
   251   var currentRows = 0;
   252   var countStmt = getOpenedDatabase().createStatement(
   253     "SELECT COUNT(1) AS count FROM " + aTableName
   254   );
   255   try {
   256     do_check_true(countStmt.executeStep());
   257     currentRows = countStmt.row.count;
   258   }
   259   finally {
   260     countStmt.finalize();
   261   }
   262   return currentRows;
   263 }
   265 cleanup();

mercurial