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.

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

mercurial