addon-sdk/source/test/test-simple-storage.js

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
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 file = require("sdk/io/file");
michael@0 6 const prefs = require("sdk/preferences/service");
michael@0 7
michael@0 8 const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota";
michael@0 9 const WRITE_PERIOD_PREF = "extensions.addon-sdk.simple-storage.writePeriod";
michael@0 10
michael@0 11 let {Cc,Ci} = require("chrome");
michael@0 12
michael@0 13 const { Loader } = require("sdk/test/loader");
michael@0 14 const { id } = require("sdk/self");
michael@0 15
michael@0 16 let storeFile = Cc["@mozilla.org/file/directory_service;1"].
michael@0 17 getService(Ci.nsIProperties).
michael@0 18 get("ProfD", Ci.nsIFile);
michael@0 19 storeFile.append("jetpack");
michael@0 20 storeFile.append(id);
michael@0 21 storeFile.append("simple-storage");
michael@0 22 file.mkpath(storeFile.path);
michael@0 23 storeFile.append("store.json");
michael@0 24 let storeFilename = storeFile.path;
michael@0 25
michael@0 26 function manager(loader) loader.sandbox("sdk/simple-storage").manager;
michael@0 27
michael@0 28 exports.testSetGet = function (assert, done) {
michael@0 29 // Load the module once, set a value.
michael@0 30 let loader = Loader(module);
michael@0 31 let ss = loader.require("sdk/simple-storage");
michael@0 32 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 33 assert.ok(file.exists(storeFilename), "Store file should exist");
michael@0 34
michael@0 35 // Load the module again and make sure the value stuck.
michael@0 36 loader = Loader(module);
michael@0 37 ss = loader.require("sdk/simple-storage");
michael@0 38 assert.equal(ss.storage.foo, val, "Value should persist");
michael@0 39 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 40 assert.fail("Nothing should be written since `storage` was not changed.");
michael@0 41 };
michael@0 42 loader.unload();
michael@0 43 file.remove(storeFilename);
michael@0 44 done();
michael@0 45 };
michael@0 46 let val = "foo";
michael@0 47 ss.storage.foo = val;
michael@0 48 assert.equal(ss.storage.foo, val, "Value read should be value set");
michael@0 49 loader.unload();
michael@0 50 };
michael@0 51
michael@0 52 exports.testSetGetRootArray = function (assert, done) {
michael@0 53 setGetRoot(assert, done, [1, 2, 3], function (arr1, arr2) {
michael@0 54 if (arr1.length !== arr2.length)
michael@0 55 return false;
michael@0 56 for (let i = 0; i < arr1.length; i++) {
michael@0 57 if (arr1[i] !== arr2[i])
michael@0 58 return false;
michael@0 59 }
michael@0 60 return true;
michael@0 61 });
michael@0 62 };
michael@0 63
michael@0 64 exports.testSetGetRootBool = function (assert, done) {
michael@0 65 setGetRoot(assert, done, true);
michael@0 66 };
michael@0 67
michael@0 68 exports.testSetGetRootFunction = function (assert, done) {
michael@0 69 setGetRootError(assert, done, function () {},
michael@0 70 "Setting storage to a function should fail");
michael@0 71 };
michael@0 72
michael@0 73 exports.testSetGetRootNull = function (assert, done) {
michael@0 74 setGetRoot(assert, done, null);
michael@0 75 };
michael@0 76
michael@0 77 exports.testSetGetRootNumber = function (assert, done) {
michael@0 78 setGetRoot(assert, done, 3.14);
michael@0 79 };
michael@0 80
michael@0 81 exports.testSetGetRootObject = function (assert, done) {
michael@0 82 setGetRoot(assert, done, { foo: 1, bar: 2 }, function (obj1, obj2) {
michael@0 83 for (let prop in obj1) {
michael@0 84 if (!(prop in obj2) || obj2[prop] !== obj1[prop])
michael@0 85 return false;
michael@0 86 }
michael@0 87 for (let prop in obj2) {
michael@0 88 if (!(prop in obj1) || obj1[prop] !== obj2[prop])
michael@0 89 return false;
michael@0 90 }
michael@0 91 return true;
michael@0 92 });
michael@0 93 };
michael@0 94
michael@0 95 exports.testSetGetRootString = function (assert, done) {
michael@0 96 setGetRoot(assert, done, "sho' 'nuff");
michael@0 97 };
michael@0 98
michael@0 99 exports.testSetGetRootUndefined = function (assert, done) {
michael@0 100 setGetRootError(assert, done, undefined, "Setting storage to undefined should fail");
michael@0 101 };
michael@0 102
michael@0 103 exports.testEmpty = function (assert) {
michael@0 104 let loader = Loader(module);
michael@0 105 let ss = loader.require("sdk/simple-storage");
michael@0 106 loader.unload();
michael@0 107 assert.ok(!file.exists(storeFilename), "Store file should not exist");
michael@0 108 };
michael@0 109
michael@0 110 exports.testStorageDataRecovery = function(assert) {
michael@0 111 const data = {
michael@0 112 a: true,
michael@0 113 b: [3, 13],
michael@0 114 c: "guilty!",
michael@0 115 d: { e: 1, f: 2 }
michael@0 116 };
michael@0 117 let stream = file.open(storeFilename, "w");
michael@0 118 stream.write(JSON.stringify(data));
michael@0 119 stream.close();
michael@0 120 let loader = Loader(module);
michael@0 121 let ss = loader.require("sdk/simple-storage");
michael@0 122 assert.deepEqual(ss.storage, data, "Recovered data should be the same as written");
michael@0 123 file.remove(storeFilename);
michael@0 124 loader.unload();
michael@0 125 }
michael@0 126
michael@0 127 exports.testMalformed = function (assert) {
michael@0 128 let stream = file.open(storeFilename, "w");
michael@0 129 stream.write("i'm not json");
michael@0 130 stream.close();
michael@0 131 let loader = Loader(module);
michael@0 132 let ss = loader.require("sdk/simple-storage");
michael@0 133 let empty = true;
michael@0 134 for (let key in ss.storage) {
michael@0 135 empty = false;
michael@0 136 break;
michael@0 137 }
michael@0 138 assert.ok(empty, "Malformed storage should cause root to be empty");
michael@0 139 file.remove(storeFilename);
michael@0 140 loader.unload();
michael@0 141 };
michael@0 142
michael@0 143 // Go over quota and handle it by listener.
michael@0 144 exports.testQuotaExceededHandle = function (assert, done) {
michael@0 145 prefs.set(QUOTA_PREF, 18);
michael@0 146
michael@0 147 let loader = Loader(module);
michael@0 148 let ss = loader.require("sdk/simple-storage");
michael@0 149 ss.on("OverQuota", function () {
michael@0 150 assert.pass("OverQuota was emitted as expected");
michael@0 151 assert.equal(this, ss, "`this` should be simple storage");
michael@0 152 ss.storage = { x: 4, y: 5 };
michael@0 153
michael@0 154 manager(loader).jsonStore.onWrite = function () {
michael@0 155 loader = Loader(module);
michael@0 156 ss = loader.require("sdk/simple-storage");
michael@0 157 let numProps = 0;
michael@0 158 for (let prop in ss.storage)
michael@0 159 numProps++;
michael@0 160 assert.ok(numProps, 2,
michael@0 161 "Store should contain 2 values: " + ss.storage.toSource());
michael@0 162 assert.equal(ss.storage.x, 4, "x value should be correct");
michael@0 163 assert.equal(ss.storage.y, 5, "y value should be correct");
michael@0 164 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 165 assert.fail("Nothing should be written since `storage` was not changed.");
michael@0 166 };
michael@0 167 loader.unload();
michael@0 168 prefs.reset(QUOTA_PREF);
michael@0 169 done();
michael@0 170 };
michael@0 171 loader.unload();
michael@0 172 });
michael@0 173 // This will be JSON.stringify()ed to: {"a":1,"b":2,"c":3} (19 bytes)
michael@0 174 ss.storage = { a: 1, b: 2, c: 3 };
michael@0 175 manager(loader).jsonStore.write();
michael@0 176 };
michael@0 177
michael@0 178 // Go over quota but don't handle it. The last good state should still persist.
michael@0 179 exports.testQuotaExceededNoHandle = function (assert, done) {
michael@0 180 prefs.set(QUOTA_PREF, 5);
michael@0 181
michael@0 182 let loader = Loader(module);
michael@0 183 let ss = loader.require("sdk/simple-storage");
michael@0 184
michael@0 185 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 186 loader = Loader(module);
michael@0 187 ss = loader.require("sdk/simple-storage");
michael@0 188 assert.equal(ss.storage, val,
michael@0 189 "Value should have persisted: " + ss.storage);
michael@0 190 ss.storage = "some very long string that is very long";
michael@0 191 ss.on("OverQuota", function () {
michael@0 192 assert.pass("OverQuota emitted as expected");
michael@0 193 manager(loader).jsonStore.onWrite = function () {
michael@0 194 assert.fail("Over-quota value should not have been written");
michael@0 195 };
michael@0 196 loader.unload();
michael@0 197
michael@0 198 loader = Loader(module);
michael@0 199 ss = loader.require("sdk/simple-storage");
michael@0 200 assert.equal(ss.storage, val,
michael@0 201 "Over-quota value should not have been written, " +
michael@0 202 "old value should have persisted: " + ss.storage);
michael@0 203 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 204 assert.fail("Nothing should be written since `storage` was not changed.");
michael@0 205 };
michael@0 206 loader.unload();
michael@0 207 prefs.reset(QUOTA_PREF);
michael@0 208 done();
michael@0 209 });
michael@0 210 manager(loader).jsonStore.write();
michael@0 211 };
michael@0 212
michael@0 213 let val = "foo";
michael@0 214 ss.storage = val;
michael@0 215 loader.unload();
michael@0 216 };
michael@0 217
michael@0 218 exports.testQuotaUsage = function (assert, done) {
michael@0 219 let quota = 21;
michael@0 220 prefs.set(QUOTA_PREF, quota);
michael@0 221
michael@0 222 let loader = Loader(module);
michael@0 223 let ss = loader.require("sdk/simple-storage");
michael@0 224
michael@0 225 // {"a":1} (7 bytes)
michael@0 226 ss.storage = { a: 1 };
michael@0 227 assert.equal(ss.quotaUsage, 7 / quota, "quotaUsage should be correct");
michael@0 228
michael@0 229 // {"a":1,"bb":2} (14 bytes)
michael@0 230 ss.storage = { a: 1, bb: 2 };
michael@0 231 assert.equal(ss.quotaUsage, 14 / quota, "quotaUsage should be correct");
michael@0 232
michael@0 233 // {"a":1,"bb":2,"cc":3} (21 bytes)
michael@0 234 ss.storage = { a: 1, bb: 2, cc: 3 };
michael@0 235 assert.equal(ss.quotaUsage, 21 / quota, "quotaUsage should be correct");
michael@0 236
michael@0 237 manager(loader).jsonStore.onWrite = function () {
michael@0 238 prefs.reset(QUOTA_PREF);
michael@0 239 done();
michael@0 240 };
michael@0 241 loader.unload();
michael@0 242 };
michael@0 243
michael@0 244 exports.testUninstall = function (assert, done) {
michael@0 245 let loader = Loader(module);
michael@0 246 let ss = loader.require("sdk/simple-storage");
michael@0 247 manager(loader).jsonStore.onWrite = function () {
michael@0 248 assert.ok(file.exists(storeFilename), "Store file should exist");
michael@0 249
michael@0 250 loader = Loader(module);
michael@0 251 ss = loader.require("sdk/simple-storage");
michael@0 252 loader.unload("uninstall");
michael@0 253 assert.ok(!file.exists(storeFilename), "Store file should be removed");
michael@0 254 done();
michael@0 255 };
michael@0 256 ss.storage.foo = "foo";
michael@0 257 loader.unload();
michael@0 258 };
michael@0 259
michael@0 260 exports.testChangeInnerArray = function(assert, done) {
michael@0 261 prefs.set(WRITE_PERIOD_PREF, 10);
michael@0 262
michael@0 263 let expected = {
michael@0 264 x: [5, 7],
michael@0 265 y: [7, 28],
michael@0 266 z: [6, 2]
michael@0 267 };
michael@0 268
michael@0 269 // Load the module, set a value.
michael@0 270 let loader = Loader(module);
michael@0 271 let ss = loader.require("sdk/simple-storage");
michael@0 272 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 273 assert.ok(file.exists(storeFilename), "Store file should exist");
michael@0 274
michael@0 275 // Load the module again and check the result
michael@0 276 loader = Loader(module);
michael@0 277 ss = loader.require("sdk/simple-storage");
michael@0 278 assert.equal(JSON.stringify(ss.storage),
michael@0 279 JSON.stringify(expected), "Should see the expected object");
michael@0 280
michael@0 281 // Add a property
michael@0 282 ss.storage.x.push(["bar"]);
michael@0 283 expected.x.push(["bar"]);
michael@0 284 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 285 assert.equal(JSON.stringify(ss.storage),
michael@0 286 JSON.stringify(expected), "Should see the expected object");
michael@0 287
michael@0 288 // Modify a property
michael@0 289 ss.storage.y[0] = 42;
michael@0 290 expected.y[0] = 42;
michael@0 291 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 292 assert.equal(JSON.stringify(ss.storage),
michael@0 293 JSON.stringify(expected), "Should see the expected object");
michael@0 294
michael@0 295 // Delete a property
michael@0 296 delete ss.storage.z[1];
michael@0 297 delete expected.z[1];
michael@0 298 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 299 assert.equal(JSON.stringify(ss.storage),
michael@0 300 JSON.stringify(expected), "Should see the expected object");
michael@0 301
michael@0 302 // Modify the new inner-object
michael@0 303 ss.storage.x[2][0] = "baz";
michael@0 304 expected.x[2][0] = "baz";
michael@0 305 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 306 assert.equal(JSON.stringify(ss.storage),
michael@0 307 JSON.stringify(expected), "Should see the expected object");
michael@0 308
michael@0 309 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 310 assert.fail("Nothing should be written since `storage` was not changed.");
michael@0 311 };
michael@0 312 loader.unload();
michael@0 313
michael@0 314 // Load the module again and check the result
michael@0 315 loader = Loader(module);
michael@0 316 ss = loader.require("sdk/simple-storage");
michael@0 317 assert.equal(JSON.stringify(ss.storage),
michael@0 318 JSON.stringify(expected), "Should see the expected object");
michael@0 319 loader.unload();
michael@0 320 file.remove(storeFilename);
michael@0 321 prefs.reset(WRITE_PERIOD_PREF);
michael@0 322 done();
michael@0 323 };
michael@0 324 };
michael@0 325 };
michael@0 326 };
michael@0 327 };
michael@0 328
michael@0 329 ss.storage = {
michael@0 330 x: [5, 7],
michael@0 331 y: [7, 28],
michael@0 332 z: [6, 2]
michael@0 333 };
michael@0 334 assert.equal(JSON.stringify(ss.storage),
michael@0 335 JSON.stringify(expected), "Should see the expected object");
michael@0 336
michael@0 337 loader.unload();
michael@0 338 };
michael@0 339
michael@0 340 exports.testChangeInnerObject = function(assert, done) {
michael@0 341 prefs.set(WRITE_PERIOD_PREF, 10);
michael@0 342
michael@0 343 let expected = {
michael@0 344 x: {
michael@0 345 a: 5,
michael@0 346 b: 7
michael@0 347 },
michael@0 348 y: {
michael@0 349 c: 7,
michael@0 350 d: 28
michael@0 351 },
michael@0 352 z: {
michael@0 353 e: 6,
michael@0 354 f: 2
michael@0 355 }
michael@0 356 };
michael@0 357
michael@0 358 // Load the module, set a value.
michael@0 359 let loader = Loader(module);
michael@0 360 let ss = loader.require("sdk/simple-storage");
michael@0 361 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 362 assert.ok(file.exists(storeFilename), "Store file should exist");
michael@0 363
michael@0 364 // Load the module again and check the result
michael@0 365 loader = Loader(module);
michael@0 366 ss = loader.require("sdk/simple-storage");
michael@0 367 assert.equal(JSON.stringify(ss.storage),
michael@0 368 JSON.stringify(expected), "Should see the expected object");
michael@0 369
michael@0 370 // Add a property
michael@0 371 ss.storage.x.g = {foo: "bar"};
michael@0 372 expected.x.g = {foo: "bar"};
michael@0 373 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 374 assert.equal(JSON.stringify(ss.storage),
michael@0 375 JSON.stringify(expected), "Should see the expected object");
michael@0 376
michael@0 377 // Modify a property
michael@0 378 ss.storage.y.c = 42;
michael@0 379 expected.y.c = 42;
michael@0 380 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 381 assert.equal(JSON.stringify(ss.storage),
michael@0 382 JSON.stringify(expected), "Should see the expected object");
michael@0 383
michael@0 384 // Delete a property
michael@0 385 delete ss.storage.z.f;
michael@0 386 delete expected.z.f;
michael@0 387 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 388 assert.equal(JSON.stringify(ss.storage),
michael@0 389 JSON.stringify(expected), "Should see the expected object");
michael@0 390
michael@0 391 // Modify the new inner-object
michael@0 392 ss.storage.x.g.foo = "baz";
michael@0 393 expected.x.g.foo = "baz";
michael@0 394 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 395 assert.equal(JSON.stringify(ss.storage),
michael@0 396 JSON.stringify(expected), "Should see the expected object");
michael@0 397
michael@0 398 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 399 assert.fail("Nothing should be written since `storage` was not changed.");
michael@0 400 };
michael@0 401 loader.unload();
michael@0 402
michael@0 403 // Load the module again and check the result
michael@0 404 loader = Loader(module);
michael@0 405 ss = loader.require("sdk/simple-storage");
michael@0 406 assert.equal(JSON.stringify(ss.storage),
michael@0 407 JSON.stringify(expected), "Should see the expected object");
michael@0 408 loader.unload();
michael@0 409 file.remove(storeFilename);
michael@0 410 prefs.reset(WRITE_PERIOD_PREF);
michael@0 411 done();
michael@0 412 };
michael@0 413 };
michael@0 414 };
michael@0 415 };
michael@0 416 };
michael@0 417
michael@0 418 ss.storage = {
michael@0 419 x: {
michael@0 420 a: 5,
michael@0 421 b: 7
michael@0 422 },
michael@0 423 y: {
michael@0 424 c: 7,
michael@0 425 d: 28
michael@0 426 },
michael@0 427 z: {
michael@0 428 e: 6,
michael@0 429 f: 2
michael@0 430 }
michael@0 431 };
michael@0 432 assert.equal(JSON.stringify(ss.storage),
michael@0 433 JSON.stringify(expected), "Should see the expected object");
michael@0 434
michael@0 435 loader.unload();
michael@0 436 };
michael@0 437
michael@0 438 exports.testSetNoSetRead = function (assert, done) {
michael@0 439 // Load the module, set a value.
michael@0 440 let loader = Loader(module);
michael@0 441 let ss = loader.require("sdk/simple-storage");
michael@0 442 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 443 assert.ok(file.exists(storeFilename), "Store file should exist");
michael@0 444
michael@0 445 // Load the module again but don't access ss.storage.
michael@0 446 loader = Loader(module);
michael@0 447 ss = loader.require("sdk/simple-storage");
michael@0 448 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 449 assert.fail("Nothing should be written since `storage` was not accessed.");
michael@0 450 };
michael@0 451 loader.unload();
michael@0 452
michael@0 453 // Load the module a third time and make sure the value stuck.
michael@0 454 loader = Loader(module);
michael@0 455 ss = loader.require("sdk/simple-storage");
michael@0 456 assert.equal(ss.storage.foo, val, "Value should persist");
michael@0 457 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 458 assert.fail("Nothing should be written since `storage` was not changed.");
michael@0 459 };
michael@0 460 loader.unload();
michael@0 461 file.remove(storeFilename);
michael@0 462 done();
michael@0 463 };
michael@0 464 let val = "foo";
michael@0 465 ss.storage.foo = val;
michael@0 466 assert.equal(ss.storage.foo, val, "Value read should be value set");
michael@0 467 loader.unload();
michael@0 468 };
michael@0 469
michael@0 470
michael@0 471 function setGetRoot(assert, done, val, compare) {
michael@0 472 compare = compare || function (a, b) a === b;
michael@0 473
michael@0 474 // Load the module once, set a value.
michael@0 475 let loader = Loader(module);
michael@0 476 let ss = loader.require("sdk/simple-storage");
michael@0 477 manager(loader).jsonStore.onWrite = function () {
michael@0 478 assert.ok(file.exists(storeFilename), "Store file should exist");
michael@0 479
michael@0 480 // Load the module again and make sure the value stuck.
michael@0 481 loader = Loader(module);
michael@0 482 ss = loader.require("sdk/simple-storage");
michael@0 483 assert.ok(compare(ss.storage, val), "Value should persist");
michael@0 484 manager(loader).jsonStore.onWrite = function (storage) {
michael@0 485 assert.fail("Nothing should be written since `storage` was not changed.");
michael@0 486 };
michael@0 487 loader.unload();
michael@0 488 file.remove(storeFilename);
michael@0 489 done();
michael@0 490 };
michael@0 491 ss.storage = val;
michael@0 492 assert.ok(compare(ss.storage, val), "Value read should be value set");
michael@0 493 loader.unload();
michael@0 494 }
michael@0 495
michael@0 496 function setGetRootError(assert, done, val, msg) {
michael@0 497 let pred = new RegExp("storage must be one of the following types: " +
michael@0 498 "array, boolean, null, number, object, string");
michael@0 499 let loader = Loader(module);
michael@0 500 let ss = loader.require("sdk/simple-storage");
michael@0 501 assert.throws(function () ss.storage = val, pred, msg);
michael@0 502 done();
michael@0 503 loader.unload();
michael@0 504 }
michael@0 505
michael@0 506 require('sdk/test').run(exports);

mercurial