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.

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

mercurial