netwerk/test/unit/test_backgroundfilesaver.js

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* Any copyright is dedicated to the Public Domain.
     4  * http://creativecommons.org/publicdomain/zero/1.0/ */
     6 /**
     7  * This file tests components that implement nsIBackgroundFileSaver.
     8  */
    10 ////////////////////////////////////////////////////////////////////////////////
    11 //// Globals
    13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    15 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
    16                                   "resource://gre/modules/FileUtils.jsm");
    17 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
    18                                   "resource://gre/modules/NetUtil.jsm");
    19 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
    20                                   "resource://gre/modules/Promise.jsm");
    21 XPCOMUtils.defineLazyModuleGetter(this, "Task",
    22                                   "resource://gre/modules/Task.jsm");
    24 const BackgroundFileSaverOutputStream = Components.Constructor(
    25       "@mozilla.org/network/background-file-saver;1?mode=outputstream",
    26       "nsIBackgroundFileSaver");
    28 const BackgroundFileSaverStreamListener = Components.Constructor(
    29       "@mozilla.org/network/background-file-saver;1?mode=streamlistener",
    30       "nsIBackgroundFileSaver");
    32 const StringInputStream = Components.Constructor(
    33       "@mozilla.org/io/string-input-stream;1",
    34       "nsIStringInputStream",
    35       "setData");
    37 const REQUEST_SUSPEND_AT = 1024 * 1024 * 4;
    38 const TEST_DATA_SHORT = "This test string is written to the file.";
    39 const TEST_FILE_NAME_1 = "test-backgroundfilesaver-1.txt";
    40 const TEST_FILE_NAME_2 = "test-backgroundfilesaver-2.txt";
    41 const TEST_FILE_NAME_3 = "test-backgroundfilesaver-3.txt";
    43 // A map of test data length to the expected SHA-256 hashes
    44 const EXPECTED_HASHES = {
    45   // No data
    46   0 : "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    47   // TEST_DATA_SHORT
    48   40 : "f37176b690e8744ee990a206c086cba54d1502aa2456c3b0c84ef6345d72a192",
    49   // TEST_DATA_SHORT + TEST_DATA_SHORT
    50   80 : "780c0e91f50bb7ec922cc11e16859e6d5df283c0d9470f61772e3d79f41eeb58",
    51   // TEST_DATA_LONG
    52   8388608 : "e3611a47714c42bdf326acfb2eb6ed9fa4cca65cb7d7be55217770a5bf5e7ff0",
    53   // TEST_DATA_LONG + TEST_DATA_LONG
    54   16777216 : "03a0db69a30140f307587ee746a539247c181bafd85b85c8516a3533c7d9ea1d"
    55 };
    57 const gTextDecoder = new TextDecoder();
    59 // Generate a long string of data in a moderately fast way.
    60 const TEST_256_CHARS = new Array(257).join("-");
    61 const DESIRED_LENGTH = REQUEST_SUSPEND_AT * 2;
    62 const TEST_DATA_LONG = new Array(1 + DESIRED_LENGTH / 256).join(TEST_256_CHARS);
    63 do_check_eq(TEST_DATA_LONG.length, DESIRED_LENGTH);
    65 /**
    66  * Returns a reference to a temporary file.  If the file is then created, it
    67  * will be removed when tests in this file finish.
    68  */
    69 function getTempFile(aLeafName) {
    70   let file = FileUtils.getFile("TmpD", [aLeafName]);
    71   do_register_cleanup(function GTF_cleanup() {
    72     if (file.exists()) {
    73       file.remove(false);
    74     }
    75   });
    76   return file;
    77 }
    79 /**
    80  * Helper function for converting a binary blob to its hex equivalent.
    81  *
    82  * @param str
    83  *        String possibly containing non-printable chars.
    84  * @return A hex-encoded string.
    85  */
    86 function toHex(str) {
    87   var hex = '';
    88   for (var i = 0; i < str.length; i++) {
    89     hex += ('0' + str.charCodeAt(i).toString(16)).slice(-2);
    90   }
    91   return hex;
    92 }
    94 /**
    95  * Ensures that the given file contents are equal to the given string.
    96  *
    97  * @param aFile
    98  *        nsIFile whose contents should be verified.
    99  * @param aExpectedContents
   100  *        String containing the octets that are expected in the file.
   101  *
   102  * @return {Promise}
   103  * @resolves When the operation completes.
   104  * @rejects Never.
   105  */
   106 function promiseVerifyContents(aFile, aExpectedContents) {
   107   let deferred = Promise.defer();
   108   NetUtil.asyncFetch(aFile, function(aInputStream, aStatus) {
   109     do_check_true(Components.isSuccessCode(aStatus));
   110     let contents = NetUtil.readInputStreamToString(aInputStream,
   111                                                    aInputStream.available());
   112     if (contents.length <= TEST_DATA_SHORT.length * 2) {
   113       do_check_eq(contents, aExpectedContents);
   114     } else {
   115       // Do not print the entire content string to the test log.
   116       do_check_eq(contents.length, aExpectedContents.length);
   117       do_check_true(contents == aExpectedContents);
   118     }
   119     deferred.resolve();
   120   });
   121   return deferred.promise;
   122 }
   124 /**
   125  * Waits for the given saver object to complete.
   126  *
   127  * @param aSaver
   128  *        The saver, with the output stream or a stream listener implementation.
   129  * @param aOnTargetChangeFn
   130  *        Optional callback invoked with the target file name when it changes.
   131  *
   132  * @return {Promise}
   133  * @resolves When onSaveComplete is called with a success code.
   134  * @rejects With an exception, if onSaveComplete is called with a failure code.
   135  */
   136 function promiseSaverComplete(aSaver, aOnTargetChangeFn) {
   137   let deferred = Promise.defer();
   138   aSaver.observer = {
   139     onTargetChange: function BFSO_onSaveComplete(aSaver, aTarget)
   140     {
   141       if (aOnTargetChangeFn) {
   142         aOnTargetChangeFn(aTarget);
   143       }
   144     },
   145     onSaveComplete: function BFSO_onSaveComplete(aSaver, aStatus)
   146     {
   147       if (Components.isSuccessCode(aStatus)) {
   148         deferred.resolve();
   149       } else {
   150         deferred.reject(new Components.Exception("Saver failed.", aStatus));
   151       }
   152     },
   153   };
   154   return deferred.promise;
   155 }
   157 /**
   158  * Feeds a string to a BackgroundFileSaverOutputStream.
   159  *
   160  * @param aSourceString
   161  *        The source data to copy.
   162  * @param aSaverOutputStream
   163  *        The BackgroundFileSaverOutputStream to feed.
   164  * @param aCloseWhenDone
   165  *        If true, the output stream will be closed when the copy finishes.
   166  *
   167  * @return {Promise}
   168  * @resolves When the copy completes with a success code.
   169  * @rejects With an exception, if the copy fails.
   170  */
   171 function promiseCopyToSaver(aSourceString, aSaverOutputStream, aCloseWhenDone) {
   172   let deferred = Promise.defer();
   173   let inputStream = new StringInputStream(aSourceString, aSourceString.length);
   174   let copier = Cc["@mozilla.org/network/async-stream-copier;1"]
   175                .createInstance(Ci.nsIAsyncStreamCopier);
   176   copier.init(inputStream, aSaverOutputStream, null, false, true, 0x8000, true,
   177               aCloseWhenDone);
   178   copier.asyncCopy({
   179     onStartRequest: function () { },
   180     onStopRequest: function (aRequest, aContext, aStatusCode)
   181     {
   182       if (Components.isSuccessCode(aStatusCode)) {
   183         deferred.resolve();
   184       } else {
   185         deferred.reject(new Components.Exception(aResult));
   186       }
   187     },
   188   }, null);
   189   return deferred.promise;
   190 }
   192 /**
   193  * Feeds a string to a BackgroundFileSaverStreamListener.
   194  *
   195  * @param aSourceString
   196  *        The source data to copy.
   197  * @param aSaverStreamListener
   198  *        The BackgroundFileSaverStreamListener to feed.
   199  * @param aCloseWhenDone
   200  *        If true, the output stream will be closed when the copy finishes.
   201  *
   202  * @return {Promise}
   203  * @resolves When the operation completes with a success code.
   204  * @rejects With an exception, if the operation fails.
   205  */
   206 function promisePumpToSaver(aSourceString, aSaverStreamListener,
   207                             aCloseWhenDone) {
   208   let deferred = Promise.defer();
   209   aSaverStreamListener.QueryInterface(Ci.nsIStreamListener);
   210   let inputStream = new StringInputStream(aSourceString, aSourceString.length);
   211   let pump = Cc["@mozilla.org/network/input-stream-pump;1"]
   212              .createInstance(Ci.nsIInputStreamPump);
   213   pump.init(inputStream, -1, -1, 0, 0, true);
   214   pump.asyncRead({
   215     onStartRequest: function PPTS_onStartRequest(aRequest, aContext)
   216     {
   217       aSaverStreamListener.onStartRequest(aRequest, aContext);
   218     },
   219     onStopRequest: function PPTS_onStopRequest(aRequest, aContext, aStatusCode)
   220     {
   221       aSaverStreamListener.onStopRequest(aRequest, aContext, aStatusCode);
   222       if (Components.isSuccessCode(aStatusCode)) {
   223         deferred.resolve();
   224       } else {
   225         deferred.reject(new Components.Exception(aResult));
   226       }
   227     },
   228     onDataAvailable: function PPTS_onDataAvailable(aRequest, aContext,
   229                                                    aInputStream, aOffset,
   230                                                    aCount)
   231     {
   232       aSaverStreamListener.onDataAvailable(aRequest, aContext, aInputStream,
   233                                            aOffset, aCount);
   234     },
   235   }, null);
   236   return deferred.promise;
   237 }
   239 let gStillRunning = true;
   241 ////////////////////////////////////////////////////////////////////////////////
   242 //// Tests
   244 function run_test()
   245 {
   246   run_next_test();
   247 }
   249 add_task(function test_setup()
   250 {
   251   // Wait 10 minutes, that is half of the external xpcshell timeout.
   252   do_timeout(10 * 60 * 1000, function() {
   253     if (gStillRunning) {
   254       do_throw("Test timed out.");
   255     }
   256   })
   257 });
   259 add_task(function test_normal()
   260 {
   261   // This test demonstrates the most basic use case.
   262   let destFile = getTempFile(TEST_FILE_NAME_1);
   264   // Create the object implementing the output stream.
   265   let saver = new BackgroundFileSaverOutputStream();
   267   // Set up callbacks for completion and target file name change.
   268   let receivedOnTargetChange = false;
   269   function onTargetChange(aTarget) {
   270     do_check_true(destFile.equals(aTarget));
   271     receivedOnTargetChange = true;
   272   }
   273   let completionPromise = promiseSaverComplete(saver, onTargetChange);
   275   // Set the target file.
   276   saver.setTarget(destFile, false);
   278   // Write some data and close the output stream.
   279   yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
   281   // Indicate that we are ready to finish, and wait for a successful callback.
   282   saver.finish(Cr.NS_OK);
   283   yield completionPromise;
   285   // Only after we receive the completion notification, we can also be sure that
   286   // we've received the target file name change notification before it.
   287   do_check_true(receivedOnTargetChange);
   289   // Clean up.
   290   destFile.remove(false);
   291 });
   293 add_task(function test_combinations()
   294 {
   295   let initialFile = getTempFile(TEST_FILE_NAME_1);
   296   let renamedFile = getTempFile(TEST_FILE_NAME_2);
   298   // Keep track of the current file.
   299   let currentFile = null;
   300   function onTargetChange(aTarget) {
   301     currentFile = null;
   302     do_print("Target file changed to: " + aTarget.leafName);
   303     currentFile = aTarget;
   304   }
   306   // Tests various combinations of events and behaviors for both the stream
   307   // listener and the output stream implementations.
   308   for (let testFlags = 0; testFlags < 32; testFlags++) {
   309     let keepPartialOnFailure = !!(testFlags & 1);
   310     let renameAtSomePoint = !!(testFlags & 2);
   311     let cancelAtSomePoint = !!(testFlags & 4);
   312     let useStreamListener = !!(testFlags & 8);
   313     let useLongData = !!(testFlags & 16);
   315     let startTime = Date.now();
   316     do_print("Starting keepPartialOnFailure = " + keepPartialOnFailure +
   317                     ", renameAtSomePoint = " + renameAtSomePoint +
   318                     ", cancelAtSomePoint = " + cancelAtSomePoint +
   319                     ", useStreamListener = " + useStreamListener +
   320                     ", useLongData = " + useLongData);
   322     // Create the object and register the observers.
   323     currentFile = null;
   324     let saver = useStreamListener
   325                 ? new BackgroundFileSaverStreamListener()
   326                 : new BackgroundFileSaverOutputStream();
   327     saver.enableSha256();
   328     let completionPromise = promiseSaverComplete(saver, onTargetChange);
   330     // Start feeding the first chunk of data to the saver.  In case we are using
   331     // the stream listener, we only write one chunk.
   332     let testData = useLongData ? TEST_DATA_LONG : TEST_DATA_SHORT;
   333     let feedPromise = useStreamListener
   334                       ? promisePumpToSaver(testData + testData, saver)
   335                       : promiseCopyToSaver(testData, saver, false);
   337     // Set a target output file.
   338     saver.setTarget(initialFile, keepPartialOnFailure);
   340     // Wait for the first chunk of data to be copied.
   341     yield feedPromise;
   343     if (renameAtSomePoint) {
   344       saver.setTarget(renamedFile, keepPartialOnFailure);
   345     }
   347     if (cancelAtSomePoint) {
   348       saver.finish(Cr.NS_ERROR_FAILURE);
   349     }
   351     // Feed the second chunk of data to the saver.
   352     if (!useStreamListener) {
   353       yield promiseCopyToSaver(testData, saver, true);
   354     }
   356     // Wait for completion, and ensure we succeeded or failed as expected.
   357     if (!cancelAtSomePoint) {
   358       saver.finish(Cr.NS_OK);
   359     }
   360     try {
   361       yield completionPromise;
   362       if (cancelAtSomePoint) {
   363         do_throw("Failure expected.");
   364       }
   365     } catch (ex if cancelAtSomePoint && ex.result == Cr.NS_ERROR_FAILURE) { }
   367     if (!cancelAtSomePoint) {
   368       // In this case, the file must exist.
   369       do_check_true(currentFile.exists());
   370       let expectedContents = testData + testData;
   371       yield promiseVerifyContents(currentFile, expectedContents);
   372       do_check_eq(EXPECTED_HASHES[expectedContents.length],
   373                   toHex(saver.sha256Hash));
   374       currentFile.remove(false);
   376       // If the target was really renamed, the old file should not exist.
   377       if (renamedFile.equals(currentFile)) {
   378         do_check_false(initialFile.exists());
   379       }
   380     } else if (!keepPartialOnFailure) {
   381       // In this case, the file must not exist.
   382       do_check_false(initialFile.exists());
   383       do_check_false(renamedFile.exists());
   384     } else {
   385       // In this case, the file may or may not exist, because canceling can
   386       // interrupt the asynchronous operation at any point, even before the file
   387       // has been created for the first time.
   388       if (initialFile.exists()) {
   389         initialFile.remove(false);
   390       }
   391       if (renamedFile.exists()) {
   392         renamedFile.remove(false);
   393       }
   394     }
   396     do_print("Test case completed in " + (Date.now() - startTime) + " ms.");
   397   }
   398 });
   400 add_task(function test_setTarget_after_close_stream()
   401 {
   402   // This test checks the case where we close the output stream before we call
   403   // the setTarget method.  All the data should be buffered and written anyway.
   404   let destFile = getTempFile(TEST_FILE_NAME_1);
   406   // Test the case where the file does not already exists first, then the case
   407   // where the file already exists.
   408   for (let i = 0; i < 2; i++) {
   409     let saver = new BackgroundFileSaverOutputStream();
   410     saver.enableSha256();
   411     let completionPromise = promiseSaverComplete(saver);
   413     // Copy some data to the output stream of the file saver.  This data must
   414     // be shorter than the internal component's pipe buffer for the test to
   415     // succeed, because otherwise the test would block waiting for the write to
   416     // complete.
   417     yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
   419     // Set the target file and wait for the output to finish.
   420     saver.setTarget(destFile, false);
   421     saver.finish(Cr.NS_OK);
   422     yield completionPromise;
   424     // Verify results.
   425     yield promiseVerifyContents(destFile, TEST_DATA_SHORT);
   426     do_check_eq(EXPECTED_HASHES[TEST_DATA_SHORT.length],
   427                 toHex(saver.sha256Hash));
   428   }
   430   // Clean up.
   431   destFile.remove(false);
   432 });
   434 add_task(function test_setTarget_fast()
   435 {
   436   // This test checks a fast rename of the target file.
   437   let destFile1 = getTempFile(TEST_FILE_NAME_1);
   438   let destFile2 = getTempFile(TEST_FILE_NAME_2);
   439   let saver = new BackgroundFileSaverOutputStream();
   440   let completionPromise = promiseSaverComplete(saver);
   442   // Set the initial name after the stream is closed, then rename immediately.
   443   yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
   444   saver.setTarget(destFile1, false);
   445   saver.setTarget(destFile2, false);
   447   // Wait for all the operations to complete.
   448   saver.finish(Cr.NS_OK);
   449   yield completionPromise;
   451   // Verify results and clean up.
   452   do_check_false(destFile1.exists());
   453   yield promiseVerifyContents(destFile2, TEST_DATA_SHORT);
   454   destFile2.remove(false);
   455 });
   457 add_task(function test_setTarget_multiple()
   458 {
   459   // This test checks multiple renames of the target file.
   460   let destFile = getTempFile(TEST_FILE_NAME_1);
   461   let saver = new BackgroundFileSaverOutputStream();
   462   let completionPromise = promiseSaverComplete(saver);
   464   // Rename both before and after the stream is closed.
   465   saver.setTarget(getTempFile(TEST_FILE_NAME_2), false);
   466   saver.setTarget(getTempFile(TEST_FILE_NAME_3), false);
   467   yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
   468   saver.setTarget(getTempFile(TEST_FILE_NAME_2), false);
   469   saver.setTarget(destFile, false);
   471   // Wait for all the operations to complete.
   472   saver.finish(Cr.NS_OK);
   473   yield completionPromise;
   475   // Verify results and clean up.
   476   do_check_false(getTempFile(TEST_FILE_NAME_2).exists());
   477   do_check_false(getTempFile(TEST_FILE_NAME_3).exists());
   478   yield promiseVerifyContents(destFile, TEST_DATA_SHORT);
   479   destFile.remove(false);
   480 });
   482 add_task(function test_enableAppend()
   483 {
   484   // This test checks append mode with hashing disabled.
   485   let destFile = getTempFile(TEST_FILE_NAME_1);
   487   // Test the case where the file does not already exists first, then the case
   488   // where the file already exists.
   489   for (let i = 0; i < 2; i++) {
   490     let saver = new BackgroundFileSaverOutputStream();
   491     saver.enableAppend();
   492     let completionPromise = promiseSaverComplete(saver);
   494     saver.setTarget(destFile, false);
   495     yield promiseCopyToSaver(TEST_DATA_LONG, saver, true);
   497     saver.finish(Cr.NS_OK);
   498     yield completionPromise;
   500     // Verify results.
   501     let expectedContents = (i == 0 ? TEST_DATA_LONG
   502                                    : TEST_DATA_LONG + TEST_DATA_LONG);
   503     yield promiseVerifyContents(destFile, expectedContents);
   504   }
   506   // Clean up.
   507   destFile.remove(false);
   508 });
   510 add_task(function test_enableAppend_setTarget_fast()
   511 {
   512   // This test checks a fast rename of the target file in append mode.
   513   let destFile1 = getTempFile(TEST_FILE_NAME_1);
   514   let destFile2 = getTempFile(TEST_FILE_NAME_2);
   516   // Test the case where the file does not already exists first, then the case
   517   // where the file already exists.
   518   for (let i = 0; i < 2; i++) {
   519     let saver = new BackgroundFileSaverOutputStream();
   520     saver.enableAppend();
   521     let completionPromise = promiseSaverComplete(saver);
   523     yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
   525     // The first time, we start appending to the first file and rename to the
   526     // second file.  The second time, we start appending to the second file,
   527     // that was created the first time, and rename back to the first file.
   528     let firstFile = (i == 0) ? destFile1 : destFile2;
   529     let secondFile = (i == 0) ? destFile2 : destFile1;
   530     saver.setTarget(firstFile, false);
   531     saver.setTarget(secondFile, false);
   533     saver.finish(Cr.NS_OK);
   534     yield completionPromise;
   536     // Verify results.
   537     do_check_false(firstFile.exists());
   538     let expectedContents = (i == 0 ? TEST_DATA_SHORT
   539                                    : TEST_DATA_SHORT + TEST_DATA_SHORT);
   540     yield promiseVerifyContents(secondFile, expectedContents);
   541   }
   543   // Clean up.
   544   destFile1.remove(false);
   545 });
   547 add_task(function test_enableAppend_hash()
   548 {
   549   // This test checks append mode, also verifying that the computed hash
   550   // includes the contents of the existing data.
   551   let destFile = getTempFile(TEST_FILE_NAME_1);
   553   // Test the case where the file does not already exists first, then the case
   554   // where the file already exists.
   555   for (let i = 0; i < 2; i++) {
   556     let saver = new BackgroundFileSaverOutputStream();
   557     saver.enableAppend();
   558     saver.enableSha256();
   559     let completionPromise = promiseSaverComplete(saver);
   561     saver.setTarget(destFile, false);
   562     yield promiseCopyToSaver(TEST_DATA_LONG, saver, true);
   564     saver.finish(Cr.NS_OK);
   565     yield completionPromise;
   567     // Verify results.
   568     let expectedContents = (i == 0 ? TEST_DATA_LONG
   569                                    : TEST_DATA_LONG + TEST_DATA_LONG);
   570     yield promiseVerifyContents(destFile, expectedContents);
   571     do_check_eq(EXPECTED_HASHES[expectedContents.length],
   572                 toHex(saver.sha256Hash));
   573   }
   575   // Clean up.
   576   destFile.remove(false);
   577 });
   579 add_task(function test_finish_only()
   580 {
   581   // This test checks creating the object and doing nothing.
   582   let destFile = getTempFile(TEST_FILE_NAME_1);
   583   let saver = new BackgroundFileSaverOutputStream();
   584   function onTargetChange(aTarget) {
   585     do_throw("Should not receive the onTargetChange notification.");
   586   }
   587   let completionPromise = promiseSaverComplete(saver, onTargetChange);
   588   saver.finish(Cr.NS_OK);
   589   yield completionPromise;
   590 });
   592 add_task(function test_empty()
   593 {
   594   // This test checks we still create an empty file when no data is fed.
   595   let destFile = getTempFile(TEST_FILE_NAME_1);
   597   let saver = new BackgroundFileSaverOutputStream();
   598   let completionPromise = promiseSaverComplete(saver);
   600   saver.setTarget(destFile, false);
   601   yield promiseCopyToSaver("", saver, true);
   603   saver.finish(Cr.NS_OK);
   604   yield completionPromise;
   606   // Verify results.
   607   do_check_true(destFile.exists());
   608   do_check_eq(destFile.fileSize, 0);
   610   // Clean up.
   611   destFile.remove(false);
   612 });
   614 add_task(function test_empty_hash()
   615 {
   616   // This test checks the hash of an empty file, both in normal and append mode.
   617   let destFile = getTempFile(TEST_FILE_NAME_1);
   619   // Test normal mode first, then append mode.
   620   for (let i = 0; i < 2; i++) {
   621     let saver = new BackgroundFileSaverOutputStream();
   622     if (i == 1) {
   623       saver.enableAppend();
   624     }
   625     saver.enableSha256();
   626     let completionPromise = promiseSaverComplete(saver);
   628     saver.setTarget(destFile, false);
   629     yield promiseCopyToSaver("", saver, true);
   631     saver.finish(Cr.NS_OK);
   632     yield completionPromise;
   634     // Verify results.
   635     do_check_eq(destFile.fileSize, 0);
   636     do_check_eq(EXPECTED_HASHES[0], toHex(saver.sha256Hash));
   637   }
   639   // Clean up.
   640   destFile.remove(false);
   641 });
   643 add_task(function test_invalid_hash()
   644 {
   645   let saver = new BackgroundFileSaverStreamListener();
   646   let completionPromise = promiseSaverComplete(saver);
   647   // We shouldn't be able to get the hash if hashing hasn't been enabled
   648   try {
   649     let hash = saver.sha256Hash;
   650     do_throw("Shouldn't be able to get hash if hashing not enabled");
   651   } catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
   652   // Enable hashing, but don't feed any data to saver
   653   saver.enableSha256();
   654   let destFile = getTempFile(TEST_FILE_NAME_1);
   655   saver.setTarget(destFile, false);
   656   // We don't wait on promiseSaverComplete, so the hash getter can run before
   657   // or after onSaveComplete is called. However, the expected behavior is the
   658   // same in both cases since the hash is only valid when the save completes
   659   // successfully.
   660   saver.finish(Cr.NS_ERROR_FAILURE);
   661   try {
   662     let hash = saver.sha256Hash;
   663     do_throw("Shouldn't be able to get hash if save did not succeed");
   664   } catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
   665   // Wait for completion so that the worker thread finishes dealing with the
   666   // target file. We expect it to fail.
   667   try {
   668     yield completionPromise;
   669     do_throw("completionPromise should throw");
   670   } catch (ex if ex.result == Cr.NS_ERROR_FAILURE) { }
   671 });
   673 add_task(function test_signature()
   674 {
   675   // Check that we get a signature if the saver is finished.
   676   let destFile = getTempFile(TEST_FILE_NAME_1);
   678   let saver = new BackgroundFileSaverOutputStream();
   679   let completionPromise = promiseSaverComplete(saver);
   681   try {
   682     let signatureInfo = saver.signatureInfo;
   683     do_throw("Can't get signature if saver is not complete");
   684   } catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
   686   saver.enableSignatureInfo();
   687   saver.setTarget(destFile, false);
   688   yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
   690   saver.finish(Cr.NS_OK);
   691   yield completionPromise;
   692   yield promiseVerifyContents(destFile, TEST_DATA_SHORT);
   694   // signatureInfo is an empty nsIArray
   695   do_check_eq(0, saver.signatureInfo.length);
   697   // Clean up.
   698   destFile.remove(false);
   699 });
   701 add_task(function test_signature_not_enabled()
   702 {
   703   // Check that we get a signature if the saver is finished on Windows.
   704   let destFile = getTempFile(TEST_FILE_NAME_1);
   706   let saver = new BackgroundFileSaverOutputStream();
   707   let completionPromise = promiseSaverComplete(saver);
   708   saver.setTarget(destFile, false);
   709   yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
   711   saver.finish(Cr.NS_OK);
   712   yield completionPromise;
   713   try {
   714     let signatureInfo = saver.signatureInfo;
   715     do_throw("Can't get signature if not enabled");
   716   } catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
   718   // Clean up.
   719   destFile.remove(false);
   720 });
   722 add_task(function test_teardown()
   723 {
   724   gStillRunning = false;
   725 });

mercurial