addon-sdk/source/test/test-fs.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 "use strict";
     7 const { pathFor, platform } = require("sdk/system");
     8 const fs = require("sdk/io/fs");
     9 const url = require("sdk/url");
    10 const path = require("sdk/fs/path");
    11 const { defer } = require("sdk/core/promise");
    12 const { Buffer } = require("sdk/io/buffer");
    13 const { is } = require("sdk/system/xul-app");
    15 // Use profile directory to list / read / write files.
    16 const profilePath = pathFor("ProfD");
    17 const fileNameInProfile = "compatibility.ini";
    18 const dirNameInProfile = "extensions";
    19 const filePathInProfile = path.join(profilePath, fileNameInProfile);
    20 const dirPathInProfile = path.join(profilePath, dirNameInProfile);
    21 const mkdirPath = path.join(profilePath, "sdk-fixture-mkdir");
    22 const writePath = path.join(profilePath, "sdk-fixture-writeFile");
    23 const unlinkPath = path.join(profilePath, "sdk-fixture-unlink");
    24 const truncatePath = path.join(profilePath, "sdk-fixture-truncate");
    25 const renameFromPath = path.join(profilePath, "sdk-fixture-rename-from");
    26 const renameToPath = path.join(profilePath, "sdk-fixture-rename-to");
    27 const chmodPath = path.join(profilePath, "sdk-fixture-chmod");
    29 const profileEntries = [
    30   "compatibility.ini",
    31   "extensions",
    32   "prefs.js"
    33   // There are likely to be a lot more files but we can"t really
    34   // on consistent list so we limit to this.
    35 ];
    37 const isWindows = platform.indexOf('win') === 0;
    39 exports["test readdir"] = function(assert, end) {
    40   var async = false;
    41   fs.readdir(profilePath, function(error, entries) {
    42     assert.ok(async, "readdir is async");
    43     assert.ok(!error, "there is no error when reading directory");
    44     assert.ok(profileEntries.length <= entries.length,
    45               "got at least number of entries we expect");
    46     assert.ok(profileEntries.every(function(entry) {
    47                 return entries.indexOf(entry) >= 0;
    48               }), "all profiles are present");
    49     end();
    50   });
    52   async = true;
    53 };
    55 exports["test readdir error"] = function(assert, end) {
    56   var async = false;
    57   var path = profilePath + "-does-not-exists";
    58   fs.readdir(path, function(error, entries) {
    59     assert.ok(async, "readdir is async");
    60     assert.equal(error.message, "ENOENT, readdir " + path);
    61     assert.equal(error.code, "ENOENT", "error has a code");
    62     assert.equal(error.path, path, "error has a path");
    63     assert.equal(error.errno, 34, "error has a errno");
    64     end();
    65   });
    67   async = true;
    68 };
    70 exports["test readdirSync"] = function(assert) {
    71   var async = false;
    72   var entries = fs.readdirSync(profilePath);
    73   assert.ok(profileEntries.length <= entries.length,
    74             "got at least number of entries we expect");
    75   assert.ok(profileEntries.every(function(entry) {
    76     return entries.indexOf(entry) >= 0;
    77   }), "all profiles are present");
    78 };
    80 exports["test readdirSync error"] = function(assert) {
    81   var async = false;
    82   var path = profilePath + "-does-not-exists";
    83   try {
    84     fs.readdirSync(path);
    85     assert.fail(Error("No error was thrown"));
    86   } catch (error) {
    87     assert.equal(error.message, "ENOENT, readdir " + path);
    88     assert.equal(error.code, "ENOENT", "error has a code");
    89     assert.equal(error.path, path, "error has a path");
    90     assert.equal(error.errno, 34, "error has a errno");
    91   }
    92 };
    94 exports["test readFile"] = function(assert, end) {
    95   let async = false;
    96   fs.readFile(filePathInProfile, function(error, content) {
    97     assert.ok(async, "readFile is async");
    98     assert.ok(!error, "error is falsy");
   100     assert.ok(Buffer.isBuffer(content), "readFile returns buffer");
   101     assert.ok(typeof(content.length) === "number", "buffer has length");
   102     assert.ok(content.toString().indexOf("[Compatibility]") >= 0,
   103               "content contains expected data");
   104     end();
   105   });
   106   async = true;
   107 };
   109 exports["test readFile error"] = function(assert, end) {
   110   let async = false;
   111   let path = filePathInProfile + "-does-not-exists";
   112   fs.readFile(path, function(error, content) {
   113     assert.ok(async, "readFile is async");
   114     assert.equal(error.message, "ENOENT, open " + path);
   115     assert.equal(error.code, "ENOENT", "error has a code");
   116     assert.equal(error.path, path, "error has a path");
   117     assert.equal(error.errno, 34, "error has a errno");
   119     end();
   120   });
   121   async = true;
   122 };
   124 exports["test readFileSync not implemented"] = function(assert) {
   125   let buffer = fs.readFileSync(filePathInProfile);
   126   assert.ok(buffer.toString().indexOf("[Compatibility]") >= 0,
   127             "read content");
   128 };
   130 exports["test fs.stat file"] = function(assert, end) {
   131   let async = false;
   132   let path = filePathInProfile;
   133   fs.stat(path, function(error, stat) {
   134     assert.ok(async, "fs.stat is async");
   135     assert.ok(!error, "error is falsy");
   136     assert.ok(!stat.isDirectory(), "not a dir");
   137     assert.ok(stat.isFile(), "is a file");
   138     assert.ok(!stat.isSymbolicLink(), "isn't a symlink");
   139     assert.ok(typeof(stat.size) === "number", "size is a number");
   140     assert.ok(stat.exists === true, "file exists");
   141     assert.ok(typeof(stat.isBlockDevice()) === "boolean");
   142     assert.ok(typeof(stat.isCharacterDevice()) === "boolean");
   143     assert.ok(typeof(stat.isFIFO()) === "boolean");
   144     assert.ok(typeof(stat.isSocket()) === "boolean");
   145     assert.ok(typeof(stat.hidden) === "boolean");
   146     assert.ok(typeof(stat.writable) === "boolean")
   147     assert.ok(stat.readable === true);
   149     end();
   150   });
   151   async = true;
   152 };
   154 exports["test fs.stat dir"] = function(assert, end) {
   155   let async = false;
   156   let path = dirPathInProfile;
   157   fs.stat(path, function(error, stat) {
   158     assert.ok(async, "fs.stat is async");
   159     assert.ok(!error, "error is falsy");
   160     assert.ok(stat.isDirectory(), "is a dir");
   161     assert.ok(!stat.isFile(), "not a file");
   162     assert.ok(!stat.isSymbolicLink(), "isn't a symlink");
   163     assert.ok(typeof(stat.size) === "number", "size is a number");
   164     assert.ok(stat.exists === true, "file exists");
   165     assert.ok(typeof(stat.isBlockDevice()) === "boolean");
   166     assert.ok(typeof(stat.isCharacterDevice()) === "boolean");
   167     assert.ok(typeof(stat.isFIFO()) === "boolean");
   168     assert.ok(typeof(stat.isSocket()) === "boolean");
   169     assert.ok(typeof(stat.hidden) === "boolean");
   170     assert.ok(typeof(stat.writable) === "boolean")
   171     assert.ok(typeof(stat.readable) === "boolean");
   173     end();
   174   });
   175   async = true;
   176 };
   178 exports["test fs.stat error"] = function(assert, end) {
   179   let async = false;
   180   let path = filePathInProfile + "-does-not-exists";
   181   fs.stat(path, function(error, stat) {
   182     assert.ok(async, "fs.stat is async");
   183     assert.equal(error.message, "ENOENT, stat " + path);
   184     assert.equal(error.code, "ENOENT", "error has a code");
   185     assert.equal(error.path, path, "error has a path");
   186     assert.equal(error.errno, 34, "error has a errno");
   188     end();
   189   });
   190   async = true;
   191 };
   193 exports["test fs.exists NO"] = function(assert, end) {
   194   let async = false
   195   let path = filePathInProfile + "-does-not-exists";
   196   fs.exists(path, function(error, value) {
   197     assert.ok(async, "fs.exists is async");
   198     assert.ok(!error, "error is falsy");
   199     assert.ok(!value, "file does not exists");
   200     end();
   201   });
   202   async = true;
   203 };
   205 exports["test fs.exists YES"] = function(assert, end) {
   206   let async = false
   207   let path = filePathInProfile
   208   fs.exists(path, function(error, value) {
   209     assert.ok(async, "fs.exists is async");
   210     assert.ok(!error, "error is falsy");
   211     assert.ok(value, "file exists");
   212     end();
   213   });
   214   async = true;
   215 };
   217 exports["test fs.exists NO"] = function(assert, end) {
   218   let async = false
   219   let path = filePathInProfile + "-does-not-exists";
   220   fs.exists(path, function(error, value) {
   221     assert.ok(async, "fs.exists is async");
   222     assert.ok(!error, "error is falsy");
   223     assert.ok(!value, "file does not exists");
   224     end();
   225   });
   226   async = true;
   227 };
   229 exports["test fs.existsSync"] = function(assert) {
   230   let path = filePathInProfile
   231   assert.equal(fs.existsSync(path), true, "exists");
   232   assert.equal(fs.existsSync(path + "-does-not-exists"), false, "exists");
   233 };
   235 exports["test fs.mkdirSync fs.rmdirSync"] = function(assert) {
   236   let path = mkdirPath;
   238   assert.equal(fs.existsSync(path), false, "does not exists");
   239   fs.mkdirSync(path);
   240   assert.equal(fs.existsSync(path), true, "dir was created");
   241   try {
   242     fs.mkdirSync(path);
   243     assert.fail(Error("mkdir on existing should throw"));
   244   } catch (error) {
   245     assert.equal(error.message, "EEXIST, mkdir " + path);
   246     assert.equal(error.code, "EEXIST", "error has a code");
   247     assert.equal(error.path, path, "error has a path");
   248     assert.equal(error.errno, 47, "error has a errno");
   249   }
   250   fs.rmdirSync(path);
   251   assert.equal(fs.existsSync(path), false, "dir was removed");
   252 };
   254 exports["test fs.mkdir"] = function(assert, end) {
   255   let path = mkdirPath;
   257   if (!fs.existsSync(path)) {
   258     let async = false;
   259     fs.mkdir(path, function(error) {
   260       assert.ok(async, "mkdir is async");
   261       assert.ok(!error, "no error");
   262       assert.equal(fs.existsSync(path), true, "dir was created");
   263       fs.rmdirSync(path);
   264       assert.equal(fs.existsSync(path), false, "dir was removed");
   265       end();
   266     });
   267     async = true;
   268   }
   269 };
   271 exports["test fs.mkdir error"] = function(assert, end) {
   272   let path = mkdirPath;
   274   if (!fs.existsSync(path)) {
   275     fs.mkdirSync(path);
   276     let async = false;
   277     fs.mkdir(path, function(error) {
   278       assert.ok(async, "mkdir is async");
   279       assert.equal(error.message, "EEXIST, mkdir " + path);
   280       assert.equal(error.code, "EEXIST", "error has a code");
   281       assert.equal(error.path, path, "error has a path");
   282       assert.equal(error.errno, 47, "error has a errno");
   283       fs.rmdirSync(path);
   284       assert.equal(fs.existsSync(path), false, "dir was removed");
   285       end();
   286     });
   287     async = true;
   288   }
   289 };
   291 exports["test fs.rmdir"] = function(assert, end) {
   292   let path = mkdirPath;
   294   if (!fs.existsSync(path)) {
   295     fs.mkdirSync(path);
   296     assert.equal(fs.existsSync(path), true, "dir exists");
   297     let async = false;
   298     fs.rmdir(path, function(error) {
   299       assert.ok(async, "mkdir is async");
   300       assert.ok(!error, "no error");
   301       assert.equal(fs.existsSync(path), false, "dir was removed");
   302       end();
   303     });
   304     async = true;
   305   }
   306 };
   309 exports["test fs.rmdir error"] = function(assert, end) {
   310   let path = mkdirPath;
   312   if (!fs.existsSync(path)) {
   313     assert.equal(fs.existsSync(path), false, "dir doesn't exists");
   314     let async = false;
   315     fs.rmdir(path, function(error) {
   316       assert.ok(async, "mkdir is async");
   317       assert.equal(error.message, "ENOENT, remove " + path);
   318       assert.equal(error.code, "ENOENT", "error has a code");
   319       assert.equal(error.path, path, "error has a path");
   320       assert.equal(error.errno, 34, "error has a errno");
   321       assert.equal(fs.existsSync(path), false, "dir is removed");
   322       end();
   323     });
   324     async = true;
   325   }
   326 };
   328 exports["test fs.truncateSync fs.unlinkSync"] = function(assert) {
   329   let path = truncatePath;
   331   assert.equal(fs.existsSync(path), false, "does not exists");
   332   fs.truncateSync(path);
   333   assert.equal(fs.existsSync(path), true, "file was created");
   334   fs.truncateSync(path);
   335   fs.unlinkSync(path);
   336   assert.equal(fs.existsSync(path), false, "file was removed");
   337 };
   340 exports["test fs.truncate"] = function(assert, end) {
   341   let path = truncatePath;
   342   if (!fs.existsSync(path)) {
   343     let async = false;
   344     fs.truncate(path, 0, function(error) {
   345       assert.ok(async, "truncate is async");
   346       assert.ok(!error, "no error");
   347       assert.equal(fs.existsSync(path), true, "file was created");
   348       fs.unlinkSync(path);
   349       assert.equal(fs.existsSync(path), false, "file was removed");
   350       end();
   351     })
   352     async = true;
   353   }
   354 };
   356 exports["test fs.unlink"] = function(assert, end) {
   357   let path = unlinkPath;
   358   let async = false;
   359   assert.ok(!fs.existsSync(path), "file doesn't exists yet");
   360   fs.truncateSync(path, 0);
   361   assert.ok(fs.existsSync(path), "file was created");
   362   fs.unlink(path, function(error) {
   363     assert.ok(async, "fs.unlink is async");
   364     assert.ok(!error, "error is falsy");
   365     assert.ok(!fs.existsSync(path), "file was removed");
   366     end();
   367   });
   368   async = true;
   369 };
   371 exports["test fs.unlink error"] = function(assert, end) {
   372   let path = unlinkPath;
   373   let async = false;
   374   assert.ok(!fs.existsSync(path), "file doesn't exists yet");
   375   fs.unlink(path, function(error) {
   376     assert.ok(async, "fs.unlink is async");
   377     assert.equal(error.message, "ENOENT, remove " + path);
   378     assert.equal(error.code, "ENOENT", "error has a code");
   379     assert.equal(error.path, path, "error has a path");
   380     assert.equal(error.errno, 34, "error has a errno");
   381     end();
   382   });
   383   async = true;
   384 };
   386 exports["test fs.rename"] = function(assert, end) {
   387   let fromPath = renameFromPath;
   388   let toPath = renameToPath;
   390   fs.truncateSync(fromPath);
   391   assert.ok(fs.existsSync(fromPath), "source file exists");
   392   assert.ok(!fs.existsSync(toPath), "destination doesn't exists");
   393   var async = false;
   394   fs.rename(fromPath, toPath, function(error) {
   395     assert.ok(async, "fs.rename is async");
   396     assert.ok(!error, "error is falsy");
   397     assert.ok(!fs.existsSync(fromPath), "source path no longer exists");
   398     assert.ok(fs.existsSync(toPath), "destination file exists");
   399     fs.unlinkSync(toPath);
   400     assert.ok(!fs.existsSync(toPath), "cleaned up properly");
   401     end();
   402   });
   403   async = true;
   404 };
   406 exports["test fs.rename (missing source file)"] = function(assert, end) {
   407   let fromPath = renameFromPath;
   408   let toPath = renameToPath;
   410   assert.ok(!fs.existsSync(fromPath), "source file doesn't exists");
   411   assert.ok(!fs.existsSync(toPath), "destination doesn't exists");
   412   var async = false;
   413   fs.rename(fromPath, toPath, function(error) {
   414     assert.ok(async, "fs.rename is async");
   415     assert.equal(error.message, "ENOENT, rename " + fromPath);
   416     assert.equal(error.code, "ENOENT", "error has a code");
   417     assert.equal(error.path, fromPath, "error has a path");
   418     assert.equal(error.errno, 34, "error has a errno");
   419     end();
   420   });
   421   async = true;
   422 };
   424 exports["test fs.rename (existing target file)"] = function(assert, end) {
   425   let fromPath = renameFromPath;
   426   let toPath = renameToPath;
   428   fs.truncateSync(fromPath);
   429   fs.truncateSync(toPath);
   430   assert.ok(fs.existsSync(fromPath), "source file exists");
   431   assert.ok(fs.existsSync(toPath), "destination file exists");
   432   var async = false;
   433   fs.rename(fromPath, toPath, function(error) {
   434     assert.ok(async, "fs.rename is async");
   435     assert.ok(!error, "error is falsy");
   436     assert.ok(!fs.existsSync(fromPath), "source path no longer exists");
   437     assert.ok(fs.existsSync(toPath), "destination file exists");
   438     fs.unlinkSync(toPath);
   439     assert.ok(!fs.existsSync(toPath), "cleaned up properly");
   440     end();
   441   });
   442   async = true;
   443 };
   445 exports["test fs.writeFile"] = function(assert, end) {
   446   let path = writePath;
   447   let content = ["hello world",
   448                  "this is some text"].join("\n");
   450   var async = false;
   451   fs.writeFile(path, content, function(error) {
   452     assert.ok(async, "fs write is async");
   453     assert.ok(!error, "error is falsy");
   454     assert.ok(fs.existsSync(path), "file was created");
   455     assert.equal(fs.readFileSync(path).toString(),
   456                  content,
   457                  "contet was written");
   458     fs.unlinkSync(path);
   459     assert.ok(!fs.exists(path), "file was removed");
   461     end();
   462   });
   463   async = true;
   464 };
   466 exports["test fs.writeFile (with large files)"] = function(assert, end) {
   467   let path = writePath;
   468   let content = "";
   470   for (var i = 0; i < 100000; i++) {
   471     content += "buffer\n";
   472   }
   474   var async = false;
   475   fs.writeFile(path, content, function(error) {
   476     assert.ok(async, "fs write is async");
   477     assert.ok(!error, "error is falsy");
   478     assert.ok(fs.existsSync(path), "file was created");
   479     assert.equal(fs.readFileSync(path).toString(),
   480                  content,
   481                  "contet was written");
   482     fs.unlinkSync(path);
   483     assert.ok(!fs.exists(path), "file was removed");
   485     end();
   486   });
   487   async = true;
   488 };
   490 exports["test fs.writeFile error"] = function (assert, done) {
   491   try {
   492     fs.writeFile({}, 'content', function (err) {
   493       assert.fail('Error thrown from TypeError should not be caught');
   494     });
   495   } catch (e) {
   496     assert.ok(e,
   497       'writeFile with a non-string error should not be caught');
   498     assert.equal(e.name, 'TypeError', 'error should be TypeError');
   499   }
   500   fs.writeFile('not/a/valid/path', 'content', function (err) {
   501     assert.ok(err, 'error caught and handled in callback');
   502     done();
   503   });
   504 };
   506 exports["test fs.chmod"] = function (assert, done) {
   507   let content = ["hej från sverige"];
   509   fs.writeFile(chmodPath, content, function (err) {
   510     testPerm("0755")()
   511       .then(testPerm("0777"))
   512       .then(testPerm("0666"))
   513       .then(testPerm(parseInt("0511", 8)))
   514       .then(testPerm(parseInt("0200", 8)))
   515       .then(testPerm("0040"))
   516       .then(testPerm("0000"))
   517       .then(testPermSync(parseInt("0777", 8)))
   518       .then(testPermSync(parseInt("0666", 8)))
   519       .then(testPermSync("0511"))
   520       .then(testPermSync("0200"))
   521       .then(testPermSync("0040"))
   522       .then(testPermSync("0000"))
   523       .then(() => {
   524         assert.pass("Successful chmod passes");
   525       }, assert.fail)
   526       // Test invalid paths
   527       .then(() => chmod("not-a-valid-file", parseInt("0755", 8)))
   528       .then(assert.fail, (err) => {
   529         checkPermError(err, "not-a-valid-file");
   530       })
   531       .then(() => chmod("not-a-valid-file", parseInt("0755", 8), "sync"))
   532       .then(assert.fail, (err) => {
   533         checkPermError(err, "not-a-valid-file");
   534       })
   535       // Test invalid files
   536       .then(() => chmod("resource://not-a-real-file", parseInt("0755", 8)))
   537       .then(assert.fail, (err) => {
   538         checkPermError(err, "resource://not-a-real-file");
   539       })
   540       .then(() => chmod("resource://not-a-real-file", parseInt("0755", 8), 'sync'))
   541       .then(assert.fail, (err) => {
   542         checkPermError(err, "resource://not-a-real-file");
   543       })
   544       .then(done, assert.fail);
   545   });
   547   function checkPermError (err, path) {
   548     assert.equal(err.message, "ENOENT, chmod " + path);
   549     assert.equal(err.code, "ENOENT", "error has a code");
   550     assert.equal(err.path, path, "error has a path");
   551     assert.equal(err.errno, 34, "error has a errno");
   552   }
   554   function chmod (path, mode, sync) {
   555     let { promise, resolve, reject } = defer();
   556     if (!sync) {
   557       fs.chmod(path, mode, (err) => {
   558         if (err) reject(err);
   559         else resolve();
   560       });
   561     } else {
   562       fs.chmodSync(path, mode);
   563       resolve();
   564     }
   565     return promise;
   566   }
   568   function testPerm (mode, sync) {
   569     return function () {
   570       return chmod(chmodPath, mode, sync)
   571         .then(() => getPerm(chmodPath))
   572         .then(perm => {
   573           let nMode = normalizeMode(mode);
   574           if (isWindows)
   575             assert.equal(perm, nMode,
   576               "mode correctly set to " + mode + " (" + nMode + " on windows)");
   577           else
   578             assert.equal(perm, nMode, "mode correctly set to " + nMode);
   579         });
   580     };
   581   }
   583   function testPermSync (mode) {
   584     return testPerm(mode, true);
   585   }
   587   function getPerm (path) {
   588     let { promise, resolve, reject } = defer();
   589     fs.stat(path, function (err, stat) {
   590       if (err) reject(err);
   591       else resolve(stat.mode);
   592     });
   593     return promise;
   594   }
   596   /*
   597    * Converts a unix mode `0755` into a Windows version of unix permissions
   598    */
   599   function normalizeMode (mode) {
   600     if (typeof mode === "string")
   601       mode = parseInt(mode, 8);
   603     if (!isWindows)
   604       return mode;
   606     var ANY_READ = parseInt("0444", 8);
   607     var ANY_WRITE = parseInt("0222", 8);
   608     var winMode = 0;
   610     // On Windows, if WRITE is true, then READ is also true
   611     if (mode & ANY_WRITE)
   612       winMode |= ANY_WRITE | ANY_READ;
   613     // Minimum permissions are READ for Windows
   614     else
   615       winMode |= ANY_READ;
   617     return winMode;
   618   }
   619 };
   621 require("test").run(exports);

mercurial