toolkit/components/satchel/test/unit/test_history_api.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/components/satchel/test/unit/test_history_api.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,417 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +var testnum = 0;
     1.9 +let dbConnection; // used for deleted table tests
    1.10 +
    1.11 +Cu.import("resource://gre/modules/Promise.jsm");
    1.12 +
    1.13 +function countDeletedEntries(expected)
    1.14 +{
    1.15 +  let deferred = Promise.defer();
    1.16 +  let stmt = dbConnection.createAsyncStatement("SELECT COUNT(*) AS numEntries FROM moz_deleted_formhistory");
    1.17 +  stmt.executeAsync({
    1.18 +    handleResult: function(resultSet) {
    1.19 +      do_check_eq(expected, resultSet.getNextRow().getResultByName("numEntries"));
    1.20 +      deferred.resolve();
    1.21 +    },
    1.22 +    handleError : function () {
    1.23 +      do_throw("Error occurred counting deleted entries: " + error);
    1.24 +      deferred.reject();
    1.25 +    },
    1.26 +    handleCompletion : function () {
    1.27 +      stmt.finalize();
    1.28 +    }
    1.29 +  });
    1.30 +  return deferred.promise;
    1.31 +}
    1.32 +
    1.33 +function checkTimeDeleted(guid, checkFunction)
    1.34 +{
    1.35 +  let deferred = Promise.defer();
    1.36 +  let stmt = dbConnection.createAsyncStatement("SELECT timeDeleted FROM moz_deleted_formhistory WHERE guid = :guid");
    1.37 +  stmt.params.guid = guid;
    1.38 +  stmt.executeAsync({
    1.39 +    handleResult: function(resultSet) {
    1.40 +      checkFunction(resultSet.getNextRow().getResultByName("timeDeleted"));
    1.41 +      deferred.resolve();
    1.42 +    },
    1.43 +    handleError : function () {
    1.44 +      do_throw("Error occurred getting deleted entries: " + error);
    1.45 +      deferred.reject();
    1.46 +    },
    1.47 +    handleCompletion : function () {
    1.48 +      stmt.finalize();
    1.49 +    }
    1.50 +  });
    1.51 +  return deferred.promise;
    1.52 +}
    1.53 +
    1.54 +function promiseUpdateEntry(op, name, value)
    1.55 +{
    1.56 +  var change = { op: op };
    1.57 +  if (name !== null)
    1.58 +    change.fieldname = name;
    1.59 +  if (value !== null)
    1.60 +    change.value = value;
    1.61 +  return promiseUpdate(change);
    1.62 +}
    1.63 +
    1.64 +function promiseUpdate(change)
    1.65 +{
    1.66 +  let deferred = Promise.defer();
    1.67 +  FormHistory.update(change,
    1.68 +                     { handleError: function (error) {
    1.69 +                         do_throw("Error occurred updating form history: " + error);
    1.70 +                         deferred.reject(error);
    1.71 +                       },
    1.72 +                       handleCompletion: function (reason) { if (!reason) deferred.resolve(); }
    1.73 +                     });
    1.74 +  return deferred.promise;
    1.75 +}
    1.76 +
    1.77 +function promiseSearchEntries(terms, params)
    1.78 +{
    1.79 +  let deferred = Promise.defer();
    1.80 +  let results = [];
    1.81 +  FormHistory.search(terms, params,
    1.82 +                     { handleResult: function(result) results.push(result),
    1.83 +                       handleError: function (error) {
    1.84 +                         do_throw("Error occurred searching form history: " + error);
    1.85 +                         deferred.reject(error);
    1.86 +                       },
    1.87 +                       handleCompletion: function (reason) { if (!reason) deferred.resolve(results); }
    1.88 +                     });
    1.89 +  return deferred.promise;
    1.90 +}
    1.91 +
    1.92 +function promiseCountEntries(name, value, checkFn)
    1.93 +{
    1.94 +  let deferred = Promise.defer();
    1.95 +  countEntries(name, value, function (result) { checkFn(result); deferred.resolve(); } );
    1.96 +  return deferred.promise;
    1.97 +}
    1.98 +
    1.99 +add_task(function ()
   1.100 +{
   1.101 +  let oldSupportsDeletedTable = FormHistory._supportsDeletedTable;
   1.102 +  FormHistory._supportsDeletedTable = true;
   1.103 +
   1.104 +  try {
   1.105 +
   1.106 +  // ===== test init =====
   1.107 +  var testfile = do_get_file("formhistory_apitest.sqlite");
   1.108 +  var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
   1.109 +
   1.110 +  // Cleanup from any previous tests or failures.
   1.111 +  var destFile = profileDir.clone();
   1.112 +  destFile.append("formhistory.sqlite");
   1.113 +  if (destFile.exists())
   1.114 +    destFile.remove(false);
   1.115 +
   1.116 +  testfile.copyTo(profileDir, "formhistory.sqlite");
   1.117 +
   1.118 +  function checkExists(num) { do_check_true(num > 0); }
   1.119 +  function checkNotExists(num) { do_check_true(num == 0); }
   1.120 +
   1.121 +  // ===== 1 =====
   1.122 +  // Check initial state is as expected
   1.123 +  testnum++;
   1.124 +  yield promiseCountEntries("name-A", null, checkExists);
   1.125 +  yield promiseCountEntries("name-B", null, checkExists);
   1.126 +  yield promiseCountEntries("name-C", null, checkExists);
   1.127 +  yield promiseCountEntries("name-D", null, checkExists);
   1.128 +  yield promiseCountEntries("name-A", "value-A", checkExists);
   1.129 +  yield promiseCountEntries("name-B", "value-B1", checkExists);
   1.130 +  yield promiseCountEntries("name-B", "value-B2", checkExists);
   1.131 +  yield promiseCountEntries("name-C", "value-C", checkExists);
   1.132 +  yield promiseCountEntries("name-D", "value-D", checkExists);
   1.133 +  // time-A/B/C/D checked below.
   1.134 +
   1.135 +  // Delete anything from the deleted table
   1.136 +  let dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile).clone();
   1.137 +  dbFile.append("formhistory.sqlite");
   1.138 +  dbConnection = Services.storage.openUnsharedDatabase(dbFile);
   1.139 +
   1.140 +  let deferred = Promise.defer();
   1.141 +
   1.142 +  let stmt = dbConnection.createAsyncStatement("DELETE FROM moz_deleted_formhistory");
   1.143 +  stmt.executeAsync({
   1.144 +    handleResult: function(resultSet) { },
   1.145 +    handleError : function () {
   1.146 +      do_throw("Error occurred counting deleted all entries: " + error);
   1.147 +    },
   1.148 +    handleCompletion : function () {
   1.149 +      stmt.finalize();
   1.150 +      deferred.resolve();
   1.151 +    }
   1.152 +  });
   1.153 +  yield deferred.promise;
   1.154 +
   1.155 +  // ===== 2 =====
   1.156 +  // Test looking for nonexistent / bogus data.
   1.157 +  testnum++;
   1.158 +  yield promiseCountEntries("blah", null, checkNotExists);
   1.159 +  yield promiseCountEntries("", null, checkNotExists);
   1.160 +  yield promiseCountEntries("name-A", "blah", checkNotExists);
   1.161 +  yield promiseCountEntries("name-A", "", checkNotExists);
   1.162 +  yield promiseCountEntries("name-A", null, checkExists);
   1.163 +  yield promiseCountEntries("blah", "value-A", checkNotExists);
   1.164 +  yield promiseCountEntries("", "value-A", checkNotExists);
   1.165 +  yield promiseCountEntries(null, "value-A", checkExists);
   1.166 +
   1.167 +  // Cannot use promiseCountEntries when name and value are null because it treats null values as not set
   1.168 +  // and here a search should be done explicity for null.
   1.169 +  deferred = Promise.defer();
   1.170 +  yield FormHistory.count({ fieldname: null, value: null },
   1.171 +                          { handleResult: function(result) checkNotExists(result),
   1.172 +                            handleError: function (error) {
   1.173 +                              do_throw("Error occurred searching form history: " + error);
   1.174 +                            },
   1.175 +                            handleCompletion: function(reason) { if (!reason) deferred.resolve() }
   1.176 +                          });
   1.177 +  yield deferred.promise;
   1.178 +
   1.179 +  // ===== 3 =====
   1.180 +  // Test removeEntriesForName with a single matching value
   1.181 +  testnum++;
   1.182 +  yield promiseUpdateEntry("remove", "name-A", null);
   1.183 +
   1.184 +  yield promiseCountEntries("name-A", "value-A", checkNotExists);
   1.185 +  yield promiseCountEntries("name-B", "value-B1", checkExists);
   1.186 +  yield promiseCountEntries("name-B", "value-B2", checkExists);
   1.187 +  yield promiseCountEntries("name-C", "value-C", checkExists);
   1.188 +  yield promiseCountEntries("name-D", "value-D", checkExists);
   1.189 +  yield countDeletedEntries(1);
   1.190 +
   1.191 +  // ===== 4 =====
   1.192 +  // Test removeEntriesForName with multiple matching values
   1.193 +  testnum++;
   1.194 +  yield promiseUpdateEntry("remove", "name-B", null);
   1.195 +
   1.196 +  yield promiseCountEntries("name-A", "value-A", checkNotExists);
   1.197 +  yield promiseCountEntries("name-B", "value-B1", checkNotExists);
   1.198 +  yield promiseCountEntries("name-B", "value-B2", checkNotExists);
   1.199 +  yield promiseCountEntries("name-C", "value-C", checkExists);
   1.200 +  yield promiseCountEntries("name-D", "value-D", checkExists);
   1.201 +  yield countDeletedEntries(3);
   1.202 +
   1.203 +  // ===== 5 =====
   1.204 +  // Test removing by time range (single entry, not surrounding entries)
   1.205 +  testnum++;
   1.206 +  yield promiseCountEntries("time-A", null, checkExists); // firstUsed=1000, lastUsed=1000
   1.207 +  yield promiseCountEntries("time-B", null, checkExists); // firstUsed=1000, lastUsed=1099
   1.208 +  yield promiseCountEntries("time-C", null, checkExists); // firstUsed=1099, lastUsed=1099
   1.209 +  yield promiseCountEntries("time-D", null, checkExists); // firstUsed=2001, lastUsed=2001
   1.210 +  yield promiseUpdate({ op : "remove", firstUsedStart: 1050, firstUsedEnd: 2000 });
   1.211 +
   1.212 +  yield promiseCountEntries("time-A", null, checkExists);
   1.213 +  yield promiseCountEntries("time-B", null, checkExists);
   1.214 +  yield promiseCountEntries("time-C", null, checkNotExists);
   1.215 +  yield promiseCountEntries("time-D", null, checkExists);
   1.216 +  yield countDeletedEntries(4);
   1.217 +
   1.218 +  // ===== 6 =====
   1.219 +  // Test removing by time range (multiple entries)
   1.220 +  testnum++;
   1.221 +  yield promiseUpdate({ op : "remove", firstUsedStart: 1000, firstUsedEnd: 2000 });
   1.222 +
   1.223 +  yield promiseCountEntries("time-A", null, checkNotExists);
   1.224 +  yield promiseCountEntries("time-B", null, checkNotExists);
   1.225 +  yield promiseCountEntries("time-C", null, checkNotExists);
   1.226 +  yield promiseCountEntries("time-D", null, checkExists);
   1.227 +  yield countDeletedEntries(6);
   1.228 +
   1.229 +  // ===== 7 =====
   1.230 +  // test removeAllEntries
   1.231 +  testnum++;
   1.232 +  yield promiseUpdateEntry("remove", null, null);
   1.233 +
   1.234 +  yield promiseCountEntries("name-C", null, checkNotExists);
   1.235 +  yield promiseCountEntries("name-D", null, checkNotExists);
   1.236 +  yield promiseCountEntries("name-C", "value-C", checkNotExists);
   1.237 +  yield promiseCountEntries("name-D", "value-D", checkNotExists);
   1.238 +
   1.239 +  yield promiseCountEntries(null, null, checkNotExists);
   1.240 +  yield countDeletedEntries(6);
   1.241 +
   1.242 +  // ===== 8 =====
   1.243 +  // Add a single entry back
   1.244 +  testnum++;
   1.245 +  yield promiseUpdateEntry("add", "newname-A", "newvalue-A");
   1.246 +  yield promiseCountEntries("newname-A", "newvalue-A", checkExists);
   1.247 +
   1.248 +  // ===== 9 =====
   1.249 +  // Remove the single entry
   1.250 +  testnum++;
   1.251 +  yield promiseUpdateEntry("remove", "newname-A", "newvalue-A");
   1.252 +  yield promiseCountEntries("newname-A", "newvalue-A", checkNotExists);
   1.253 +
   1.254 +  // ===== 10 =====
   1.255 +  // Add a single entry
   1.256 +  testnum++;
   1.257 +  yield promiseUpdateEntry("add", "field1", "value1");
   1.258 +  yield promiseCountEntries("field1", "value1", checkExists);
   1.259 +
   1.260 +  let processFirstResult = function processResults(results)
   1.261 +  {
   1.262 +    // Only handle the first result
   1.263 +    if (results.length > 0) {
   1.264 +      let result = results[0];
   1.265 +      return [result.timesUsed, result.firstUsed, result.lastUsed, result.guid];
   1.266 +    }
   1.267 +  }
   1.268 +
   1.269 +  results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
   1.270 +                                       { fieldname: "field1", value: "value1" });
   1.271 +  let [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
   1.272 +  do_check_eq(1, timesUsed);
   1.273 +  do_check_true(firstUsed > 0);
   1.274 +  do_check_true(lastUsed > 0);
   1.275 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 1));
   1.276 +
   1.277 +  // ===== 11 =====
   1.278 +  // Add another single entry
   1.279 +  testnum++;
   1.280 +  yield promiseUpdateEntry("add", "field1", "value1b");
   1.281 +  yield promiseCountEntries("field1", "value1", checkExists);
   1.282 +  yield promiseCountEntries("field1", "value1b", checkExists);
   1.283 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
   1.284 +
   1.285 +  // ===== 12 =====
   1.286 +  // Update a single entry
   1.287 +  testnum++;
   1.288 +
   1.289 +  results = yield promiseSearchEntries(["guid"], { fieldname: "field1", value: "value1" });
   1.290 +  let guid = processFirstResult(results)[3];
   1.291 +
   1.292 +  yield promiseUpdate({ op : "update", guid: guid, value: "modifiedValue" });
   1.293 +  yield promiseCountEntries("field1", "modifiedValue", checkExists);
   1.294 +  yield promiseCountEntries("field1", "value1", checkNotExists);
   1.295 +  yield promiseCountEntries("field1", "value1b", checkExists);
   1.296 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
   1.297 +
   1.298 +  // ===== 13 =====
   1.299 +  // Add a single entry with times
   1.300 +  testnum++;
   1.301 +  yield promiseUpdate({ op : "add", fieldname: "field2", value: "value2",
   1.302 +                        timesUsed: 20, firstUsed: 100, lastUsed: 500 });
   1.303 +
   1.304 +  results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
   1.305 +                                       { fieldname: "field2", value: "value2" });
   1.306 +  [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
   1.307 +
   1.308 +  do_check_eq(20, timesUsed);
   1.309 +  do_check_eq(100, firstUsed);
   1.310 +  do_check_eq(500, lastUsed);
   1.311 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
   1.312 +
   1.313 +  // ===== 14 =====
   1.314 +  // Bump an entry, which updates its lastUsed field
   1.315 +  testnum++;
   1.316 +  yield promiseUpdate({ op : "bump", fieldname: "field2", value: "value2",
   1.317 +                        timesUsed: 20, firstUsed: 100, lastUsed: 500 });
   1.318 +  results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
   1.319 +                                       { fieldname: "field2", value: "value2" });
   1.320 +  [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
   1.321 +  do_check_eq(21, timesUsed);
   1.322 +  do_check_eq(100, firstUsed);
   1.323 +  do_check_true(lastUsed > 500);
   1.324 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
   1.325 +
   1.326 +  // ===== 15 =====
   1.327 +  // Bump an entry that does not exist
   1.328 +  testnum++;
   1.329 +  yield promiseUpdate({ op : "bump", fieldname: "field3", value: "value3",
   1.330 +                        timesUsed: 10, firstUsed: 50, lastUsed: 400 });
   1.331 +  results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
   1.332 +                                       { fieldname: "field3", value: "value3" });
   1.333 +  [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
   1.334 +  do_check_eq(10, timesUsed);
   1.335 +  do_check_eq(50, firstUsed);
   1.336 +  do_check_eq(400, lastUsed);
   1.337 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
   1.338 +
   1.339 +  // ===== 16 =====
   1.340 +  // Bump an entry with a guid
   1.341 +  testnum++;
   1.342 +  results = yield promiseSearchEntries(["guid"], { fieldname: "field3", value: "value3" });
   1.343 +  guid = processFirstResult(results)[3];
   1.344 +  yield promiseUpdate({ op : "bump", guid: guid, timesUsed: 20, firstUsed: 55, lastUsed: 400 });
   1.345 +  results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
   1.346 +                                       { fieldname: "field3", value: "value3" });
   1.347 +  [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
   1.348 +  do_check_eq(11, timesUsed);
   1.349 +  do_check_eq(50, firstUsed);
   1.350 +  do_check_true(lastUsed > 400);
   1.351 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
   1.352 +
   1.353 +  // ===== 17 =====
   1.354 +  // Remove an entry
   1.355 +  testnum++;
   1.356 +  yield countDeletedEntries(7);
   1.357 +
   1.358 +  results = yield promiseSearchEntries(["guid"], { fieldname: "field1", value: "value1b" });
   1.359 +  guid = processFirstResult(results)[3];
   1.360 +
   1.361 +  yield promiseUpdate({ op : "remove", guid: guid});
   1.362 +  yield promiseCountEntries("field1", "modifiedValue", checkExists);
   1.363 +  yield promiseCountEntries("field1", "value1b", checkNotExists);
   1.364 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
   1.365 +
   1.366 +  yield countDeletedEntries(8);
   1.367 +  yield checkTimeDeleted(guid, function (timeDeleted) do_check_true(timeDeleted > 10000));
   1.368 +
   1.369 +  // ===== 18 =====
   1.370 +  // Add yet another single entry
   1.371 +  testnum++;
   1.372 +  yield promiseUpdate({ op : "add", fieldname: "field4", value: "value4",
   1.373 +                        timesUsed: 5, firstUsed: 230, lastUsed: 600 });
   1.374 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
   1.375 +
   1.376 +  // ===== 19 =====
   1.377 +  // Remove an entry by time
   1.378 +  testnum++;
   1.379 +  yield promiseUpdate({ op : "remove", firstUsedStart: 60, firstUsedEnd: 250 });
   1.380 +  yield promiseCountEntries("field1", "modifiedValue", checkExists);
   1.381 +  yield promiseCountEntries("field2", "value2", checkNotExists);
   1.382 +  yield promiseCountEntries("field3", "value3", checkExists);
   1.383 +  yield promiseCountEntries("field4", "value4", checkNotExists);
   1.384 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
   1.385 +  yield countDeletedEntries(10);
   1.386 +
   1.387 +  // ===== 20 =====
   1.388 +  // Bump multiple existing entries at once
   1.389 +  testnum++;
   1.390 +
   1.391 +  yield promiseUpdate([{ op : "add", fieldname: "field5", value: "value5",
   1.392 +                         timesUsed: 5, firstUsed: 230, lastUsed: 600 },
   1.393 +                       { op : "add", fieldname: "field6", value: "value6",
   1.394 +                         timesUsed: 12, firstUsed: 430, lastUsed: 700 }]);
   1.395 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
   1.396 +
   1.397 +  yield promiseUpdate([
   1.398 +                       { op : "bump", fieldname: "field5", value: "value5" },
   1.399 +                       { op : "bump", fieldname: "field6", value: "value6" }]);
   1.400 +  results = yield promiseSearchEntries(["fieldname", "timesUsed", "firstUsed", "lastUsed"], { });
   1.401 +
   1.402 +  do_check_eq(6, results[2].timesUsed);
   1.403 +  do_check_eq(13, results[3].timesUsed);
   1.404 +  do_check_eq(230, results[2].firstUsed);
   1.405 +  do_check_eq(430, results[3].firstUsed);
   1.406 +  do_check_true(results[2].lastUsed > 600);
   1.407 +  do_check_true(results[3].lastUsed > 700);
   1.408 +
   1.409 +  yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
   1.410 +
   1.411 +  } catch (e) {
   1.412 +    throw "FAILED in test #" + testnum + " -- " + e;
   1.413 +  }
   1.414 +  finally {
   1.415 +    FormHistory._supportsDeletedTable = oldSupportsDeletedTable;
   1.416 +    dbConnection.asyncClose(do_test_finished);
   1.417 +  }
   1.418 +});
   1.419 +
   1.420 +function run_test() run_next_test();

mercurial