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