/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ /* eslint-disable mozilla/no-arbitrary-setTimeout */ var Cm = Components.manager; const URL_HOST = "http://localhost"; const PR_USEC_PER_MSEC = 1000; var GMPScope = ChromeUtils.import( "resource://gre/modules/GMPInstallManager.jsm", null ); var GMPInstallManager = GMPScope.GMPInstallManager; const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm"); const { FileUtils } = ChromeUtils.import( "resource://gre/modules/FileUtils.jsm" ); const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm"); const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js"); const { Preferences } = ChromeUtils.import( "resource://gre/modules/Preferences.jsm" ); const { UpdateUtils } = ChromeUtils.import( "resource://gre/modules/UpdateUtils.jsm" ); const GMPUtils = ChromeUtils.import("resource://gre/modules/GMPUtils.jsm"); var ProductAddonCheckerScope = ChromeUtils.import( "resource://gre/modules/addons/ProductAddonChecker.jsm", null ); Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true); Services.prefs.setBoolPref("media.gmp-manager.updateEnabled", true); registerCleanupFunction(() => { Services.prefs.clearUserPref("security.allow_eval_with_system_principal"); Services.prefs.clearUserPref("media.gmp-manager.updateEnabled"); }); do_get_profile(); function run_test() { Preferences.set("media.gmp.log.dump", true); Preferences.set("media.gmp.log.level", 0); run_next_test(); } /** * Tests that the helper used for preferences works correctly */ add_task(async function test_prefs() { let addon1 = "addon1", addon2 = "addon2"; GMPScope.GMPPrefs.setString( GMPScope.GMPPrefs.KEY_URL, "http://not-really-used" ); GMPScope.GMPPrefs.setString( GMPScope.GMPPrefs.KEY_URL_OVERRIDE, "http://not-really-used-2" ); GMPScope.GMPPrefs.setInt(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, 1, addon1); GMPScope.GMPPrefs.setString( GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "2", addon1 ); GMPScope.GMPPrefs.setInt(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, 3, addon2); GMPScope.GMPPrefs.setInt(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, 4, addon2); GMPScope.GMPPrefs.setBool( GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, false, addon2 ); GMPScope.GMPPrefs.setBool(GMPScope.GMPPrefs.KEY_CERT_CHECKATTRS, true); Assert.equal( GMPScope.GMPPrefs.getString(GMPScope.GMPPrefs.KEY_URL), "http://not-really-used" ); Assert.equal( GMPScope.GMPPrefs.getString(GMPScope.GMPPrefs.KEY_URL_OVERRIDE), "http://not-really-used-2" ); Assert.equal( GMPScope.GMPPrefs.getInt( GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "", addon1 ), 1 ); Assert.equal( GMPScope.GMPPrefs.getString( GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "", addon1 ), "2" ); Assert.equal( GMPScope.GMPPrefs.getInt( GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "", addon2 ), 3 ); Assert.equal( GMPScope.GMPPrefs.getInt(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "", addon2), 4 ); Assert.equal( GMPScope.GMPPrefs.getBool( GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, undefined, addon2 ), false ); Assert.ok(GMPScope.GMPPrefs.getBool(GMPScope.GMPPrefs.KEY_CERT_CHECKATTRS)); GMPScope.GMPPrefs.setBool( GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, addon2 ); }); /** * Tests that an uninit without a check works fine */ add_task(async function test_checkForAddons_uninitWithoutCheck() { let installManager = new GMPInstallManager(); installManager.uninit(); }); /** * Tests that an uninit without an install works fine */ add_test(function test_checkForAddons_uninitWithoutInstall() { overrideXHR(200, ""); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); promise.then(res => { Assert.ok(res.usedFallback); installManager.uninit(); run_next_test(); }); }); /** * Tests that no response returned rejects */ add_test(function test_checkForAddons_noResponse() { overrideXHR(200, ""); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); promise.then(res => { Assert.ok(res.usedFallback); installManager.uninit(); run_next_test(); }); }); /** * Tests that no addons element returned resolves with no addons */ add_task(async function test_checkForAddons_noAddonsElement() { overrideXHR(200, ""); let installManager = new GMPInstallManager(); let res = await installManager.checkForAddons(); Assert.equal(res.addons.length, 0); installManager.uninit(); }); /** * Tests that empty addons element returned resolves with no addons */ add_task(async function test_checkForAddons_emptyAddonsElement() { overrideXHR(200, ""); let installManager = new GMPInstallManager(); let res = await installManager.checkForAddons(); Assert.equal(res.addons.length, 0); installManager.uninit(); }); /** * Tests that a response with the wrong root element rejects */ add_test(function test_checkForAddons_wrongResponseXML() { overrideXHR(200, "3.141592653589793...."); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); promise.then(res => { Assert.ok(res.usedFallback); installManager.uninit(); run_next_test(); }); }); /** * Tests that a 404 error works as expected */ add_test(function test_checkForAddons_404Error() { overrideXHR(404, ""); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); promise.then(res => { Assert.ok(res.usedFallback); installManager.uninit(); run_next_test(); }); }); /** * Tests that a xhr abort() works as expected */ add_test(function test_checkForAddons_abort() { let overriddenXhr = overrideXHR(200, "", { dropRequest: true }); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); // Since the XHR is created in checkForAddons asynchronously, // we need to delay aborting till the XHR is running. // Since checkForAddons returns a Promise already only after // the abort is triggered, we can't use that, and instead // we'll use a fake timer. setTimeout(() => { overriddenXhr.abort(); }, 100); promise.then(res => { Assert.ok(res.usedFallback); installManager.uninit(); run_next_test(); }); }); /** * Tests that a defensive timeout works as expected */ add_test(function test_checkForAddons_timeout() { overrideXHR(200, "", { dropRequest: true, timeout: true }); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); promise.then(res => { Assert.ok(res.usedFallback); installManager.uninit(); run_next_test(); }); }); /** * Tests that we throw correctly in case of ssl certification error. */ add_test(function test_checkForAddons_bad_ssl() { // // Add random stuff that cause CertUtil to require https. // let PREF_KEY_URL_OVERRIDE_BACKUP = Preferences.get( GMPScope.GMPPrefs.KEY_URL_OVERRIDE, "" ); Preferences.reset(GMPScope.GMPPrefs.KEY_URL_OVERRIDE); let CERTS_BRANCH_DOT_ONE = GMPScope.GMPPrefs.KEY_CERTS_BRANCH + ".1"; let PREF_CERTS_BRANCH_DOT_ONE_BACKUP = Preferences.get( CERTS_BRANCH_DOT_ONE, "" ); Services.prefs.setCharPref(CERTS_BRANCH_DOT_ONE, "funky value"); overrideXHR(200, ""); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); promise.then(res => { Assert.ok(res.usedFallback); installManager.uninit(); if (PREF_KEY_URL_OVERRIDE_BACKUP) { Preferences.set( GMPScope.GMPPrefs.KEY_URL_OVERRIDE, PREF_KEY_URL_OVERRIDE_BACKUP ); } if (PREF_CERTS_BRANCH_DOT_ONE_BACKUP) { Preferences.set(CERTS_BRANCH_DOT_ONE, PREF_CERTS_BRANCH_DOT_ONE_BACKUP); } run_next_test(); }); }); /** * Tests that gettinga a funky non XML response works as expected */ add_test(function test_checkForAddons_notXML() { overrideXHR(200, "3.141592653589793...."); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); promise.then(res => { Assert.ok(res.usedFallback); installManager.uninit(); run_next_test(); }); }); /** * Tests that getting a response with a single addon works as expected */ add_task(async function test_checkForAddons_singleAddon() { let responseXML = '' + "" + " " + ' ' + " " + ""; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let res = await installManager.checkForAddons(); Assert.equal(res.addons.length, 1); let gmpAddon = res.addons[0]; Assert.equal(gmpAddon.id, "gmp-gmpopenh264"); Assert.equal(gmpAddon.URL, "http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip"); Assert.equal(gmpAddon.hashFunction, "sha256"); Assert.equal( gmpAddon.hashValue, "1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee" ); Assert.equal(gmpAddon.version, "1.1"); Assert.ok(gmpAddon.isValid); Assert.ok(!gmpAddon.isInstalled); installManager.uninit(); }); /** * Tests that getting a response with a single addon with the optional size * attribute parses as expected. */ add_task(async function test_checkForAddons_singleAddonWithSize() { let responseXML = '' + "" + " " + ' ' + " " + ""; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let res = await installManager.checkForAddons(); Assert.equal(res.addons.length, 1); let gmpAddon = res.addons[0]; Assert.equal(gmpAddon.id, "openh264-plugin-no-at-symbol"); Assert.equal(gmpAddon.URL, "http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip"); Assert.equal(gmpAddon.hashFunction, "sha256"); Assert.equal( gmpAddon.hashValue, "1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee" ); Assert.equal(gmpAddon.size, 42); Assert.equal(gmpAddon.version, "1.1"); Assert.ok(gmpAddon.isValid); Assert.ok(!gmpAddon.isInstalled); installManager.uninit(); }); /** * Tests that checking for multiple addons work correctly. * Also tests that invalid addons work correctly. */ add_task( async function test_checkForAddons_multipleAddonNoUpdatesSomeInvalid() { let responseXML = '' + "" + " " + // valid openh264 ' ' + // valid not openh264 ' ' + // noid ' ' + // no URL ' ' + // no hash function ' ' + // no hash function ' ' + // not version ' ' + " " + ""; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let res = await installManager.checkForAddons(); Assert.equal(res.addons.length, 7); let gmpAddon = res.addons[0]; Assert.equal(gmpAddon.id, "gmp-gmpopenh264"); Assert.equal(gmpAddon.URL, "http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip"); Assert.equal(gmpAddon.hashFunction, "sha256"); Assert.equal( gmpAddon.hashValue, "1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee" ); Assert.equal(gmpAddon.version, "1.1"); Assert.ok(gmpAddon.isValid); Assert.ok(!gmpAddon.isInstalled); gmpAddon = res.addons[1]; Assert.equal(gmpAddon.id, "NOT-gmp-gmpopenh264"); Assert.equal( gmpAddon.URL, "http://127.0.0.1:8011/NOT-gmp-gmpopenh264-1.1.zip" ); Assert.equal(gmpAddon.hashFunction, "sha512"); Assert.equal( gmpAddon.hashValue, "141592656f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee" ); Assert.equal(gmpAddon.version, "9.1"); Assert.ok(gmpAddon.isValid); Assert.ok(!gmpAddon.isInstalled); for (let i = 2; i < res.addons.length; i++) { Assert.ok(!res.addons[i].isValid); Assert.ok(!res.addons[i].isInstalled); } installManager.uninit(); } ); /** * Tests that checking for addons when there are also updates available * works as expected. */ add_task(async function test_checkForAddons_updatesWithAddons() { let responseXML = '' + " " + ' ' + ' ' + " " + " " + ' ' + " " + ""; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let res = await installManager.checkForAddons(); Assert.equal(res.addons.length, 1); let gmpAddon = res.addons[0]; Assert.equal(gmpAddon.id, "gmp-gmpopenh264"); Assert.equal(gmpAddon.URL, "http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip"); Assert.equal(gmpAddon.hashFunction, "sha256"); Assert.equal( gmpAddon.hashValue, "1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee" ); Assert.equal(gmpAddon.version, "1.1"); Assert.ok(gmpAddon.isValid); Assert.ok(!gmpAddon.isInstalled); installManager.uninit(); }); /** * Tests that installing found addons works as expected */ async function test_checkForAddons_installAddon( id, includeSize, wantInstallReject ) { info( "Running installAddon for id: " + id + ", includeSize: " + includeSize + " and wantInstallReject: " + wantInstallReject ); let httpServer = new HttpServer(); let dir = FileUtils.getDir("TmpD", [], true); httpServer.registerDirectory("/", dir); httpServer.start(-1); let testserverPort = httpServer.identity.primaryPort; let zipFileName = "test_" + id + "_GMP.zip"; let zipURL = URL_HOST + ":" + testserverPort + "/" + zipFileName; info("zipURL: " + zipURL); let data = "e~=0.5772156649"; let zipFile = createNewZipFile(zipFileName, data); let hashFunc = "sha256"; let expectedDigest = await ProductAddonCheckerScope.computeHash( hashFunc, zipFile.path ); let fileSize = zipFile.fileSize; if (wantInstallReject) { fileSize = 1; } let responseXML = '' + "" + " " + ' ' + " " + ""; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let res = await installManager.checkForAddons(); Assert.equal(res.addons.length, 1); let gmpAddon = res.addons[0]; Assert.ok(!gmpAddon.isInstalled); try { let extractedPaths = await installManager.installAddon(gmpAddon); if (wantInstallReject) { Assert.ok(false); // installAddon() should have thrown. } Assert.equal(extractedPaths.length, 1); let extractedPath = extractedPaths[0]; info("Extracted path: " + extractedPath); let extractedFile = Cc["@mozilla.org/file/local;1"].createInstance( Ci.nsIFile ); extractedFile.initWithPath(extractedPath); Assert.ok(extractedFile.exists()); let readData = readStringFromFile(extractedFile); Assert.equal(readData, data); // Make sure the prefs are set correctly Assert.ok( !!GMPScope.GMPPrefs.getInt( GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "", gmpAddon.id ) ); Assert.equal( GMPScope.GMPPrefs.getString( GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "", gmpAddon.id ), "1.1" ); Assert.equal( GMPScope.GMPPrefs.getString( GMPScope.GMPPrefs.KEY_PLUGIN_ABI, "", gmpAddon.id ), UpdateUtils.ABI ); // Make sure it reports as being installed Assert.ok(gmpAddon.isInstalled); // Cleanup extractedFile.parent.remove(true); zipFile.remove(false); httpServer.stop(function() {}); installManager.uninit(); } catch (ex) { zipFile.remove(false); if (!wantInstallReject) { do_throw("install update should not reject " + ex.message); } } } add_task(test_checkForAddons_installAddon.bind(null, "1", true, false)); add_task(test_checkForAddons_installAddon.bind(null, "2", false, false)); add_task(test_checkForAddons_installAddon.bind(null, "3", true, true)); /** * Tests simpleCheckAndInstall when autoupdate is disabled for a GMP */ add_task(async function test_simpleCheckAndInstall_autoUpdateDisabled() { GMPScope.GMPPrefs.setBool( GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, false, GMPUtils.OPEN_H264_ID ); let responseXML = '' + "" + " " + // valid openh264 ' ' + " " + ""; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let result = await installManager.simpleCheckAndInstall(); Assert.equal(result.status, "nothing-new-to-install"); Preferences.reset(GMPScope.GMPPrefs.KEY_UPDATE_LAST_CHECK); GMPScope.GMPPrefs.setBool( GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, GMPUtils.OPEN_H264_ID ); }); /** * Tests simpleCheckAndInstall nothing to install */ add_task(async function test_simpleCheckAndInstall_nothingToInstall() { let responseXML = ''; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let result = await installManager.simpleCheckAndInstall(); Assert.equal(result.status, "nothing-new-to-install"); }); /** * Tests simpleCheckAndInstall too frequent */ add_task(async function test_simpleCheckAndInstall_tooFrequent() { let responseXML = ''; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let result = await installManager.simpleCheckAndInstall(); Assert.equal(result.status, "too-frequent-no-check"); }); /** * Tests that installing addons when there is no server works as expected */ add_test(function test_installAddon_noServer() { let zipFileName = "test_GMP.zip"; let zipURL = URL_HOST + ":0/" + zipFileName; let responseXML = '' + "" + " " + ' ' + " " + ""; overrideXHR(200, responseXML); let installManager = new GMPInstallManager(); let checkPromise = installManager.checkForAddons(); checkPromise.then( res => { Assert.equal(res.addons.length, 1); let gmpAddon = res.addons[0]; GMPInstallManager.overrideLeaveDownloadedZip = true; let installPromise = installManager.installAddon(gmpAddon); installPromise.then( extractedPaths => { do_throw("No server for install should reject"); }, err => { Assert.ok(!!err); installManager.uninit(); run_next_test(); } ); }, () => { do_throw("check should not reject for install no server"); } ); }); /*** * Tests GMPExtractor (an internal component of GMPInstallManager) to ensure * it handles paths with certain characters. */ add_task(async function test_GMPExtractor_paths() { let GMPExtractor = GMPScope.GMPExtractor; registerCleanupFunction(function() { // Must stop holding on to the zip file using the JAR cache: let zipFile = new FileUtils.File( OS.Path.join(tempDir.path, "dummy_gmp.zip") ); Services.obs.notifyObservers(zipFile, "flush-cache-entry"); extractedDir.remove(/* recursive */ true); tempDir.remove(/* recursive */ true); }); // Create a dir with the following in the name // - # -- this is used to delimit URI fragments and tests that // we escape any internal URIs appropriately. // - 猫 -- ensure we handle non-ascii characters appropriately. let tempDirName = "TmpDir#猫"; let tempDir = FileUtils.getDir("TmpD", [tempDirName], true); let zipPath = OS.Path.join(tempDir.path, "dummy_gmp.zip"); await OS.File.copy("zips/dummy_gmp.zip", zipPath, { noOverwrite: false }); // The path inside the profile dir we'll extract to. Make sure we handle // the characters there too. let relativeExtractPath = "extracted#猫"; let extractor = new GMPExtractor(zipPath, relativeExtractPath); let extractedPaths = await extractor.install(); // extractedPaths should contain the files extracted. In this case we // should have a single file extracted to our profile dir -- the zip // contains two files, but one should be skipped by the extraction logic. Assert.equal(extractedPaths.length, 1, "One file should be extracted"); Assert.ok( extractedPaths[0].includes("dummy_file.txt"), "dummy_file.txt should be on extracted path" ); Assert.ok( !extractedPaths[0].includes("verified_contents.json"), "verified_contents.json should not be on extracted path" ); let extractedDir = FileUtils.getDir("ProfD", [relativeExtractPath], false); Assert.ok( extractedDir.exists(), "Extraction should have created a directory" ); let extractedFile = FileUtils.getDir( "ProfD", [relativeExtractPath, "dummy_file.txt"], false ); Assert.ok( extractedFile.exists(), "Extraction should have created dummy_file.txt" ); let unextractedFile = FileUtils.getDir( "ProfD", [relativeExtractPath, "verified_contents.json"], false ); Assert.ok( !unextractedFile.exists(), "Extraction should not have created verified_contents.json" ); }); /** * Returns the read stream into a string */ function readStringFromInputStream(inputStream) { let sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance( Ci.nsIScriptableInputStream ); sis.init(inputStream); let text = sis.read(sis.available()); sis.close(); return text; } /** * Reads a string of text from a file. * This function only works with ASCII text. */ function readStringFromFile(file) { if (!file.exists()) { info("readStringFromFile - file doesn't exist: " + file.path); return null; } let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( Ci.nsIFileInputStream ); fis.init(file, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); return readStringFromInputStream(fis); } /** * Bare bones XMLHttpRequest implementation for testing onprogress, onerror, * and onload nsIDomEventListener handleEvent. */ function makeHandler(aVal) { if (typeof aVal == "function") { return { handleEvent: aVal }; } return aVal; } /** * Constructs a mock xhr which is used for testing different aspects * of responses. */ function xhr(inputStatus, inputResponse, options) { this.inputStatus = inputStatus; this.inputResponse = inputResponse; this.status = 0; this.responseXML = null; this._aborted = false; this._onabort = null; this._onprogress = null; this._onerror = null; this._onload = null; this._onloadend = null; this._ontimeout = null; this._url = null; this._method = null; this._timeout = 0; this._notified = false; this._options = options || {}; } xhr.prototype = { overrideMimeType(aMimetype) {}, setRequestHeader(aHeader, aValue) {}, status: null, channel: { set notificationCallbacks(aVal) {} }, open(aMethod, aUrl) { this.channel.originalURI = Services.io.newURI(aUrl); this._method = aMethod; this._url = aUrl; }, abort() { this._dropRequest = true; this._notify(["abort", "loadend"]); }, responseXML: null, responseText: null, send(aBody) { executeSoon(() => { try { if (this._options.dropRequest) { if (this._timeout > 0 && this._options.timeout) { this._notify(["timeout", "loadend"]); } return; } this.status = this.inputStatus; this.responseText = this.inputResponse; try { let parser = new DOMParser(); this.responseXML = parser.parseFromString( this.inputResponse, "application/xml" ); } catch (e) { this.responseXML = null; } if (this.inputStatus === 200) { this._notify(["load", "loadend"]); } else { this._notify(["error", "loadend"]); } } catch (ex) { do_throw(ex); } }); }, set onabort(aValue) { this._onabort = makeHandler(aValue); }, get onabort() { return this._onabort; }, set onprogress(aValue) { this._onprogress = makeHandler(aValue); }, get onprogress() { return this._onprogress; }, set onerror(aValue) { this._onerror = makeHandler(aValue); }, get onerror() { return this._onerror; }, set onload(aValue) { this._onload = makeHandler(aValue); }, get onload() { return this._onload; }, set onloadend(aValue) { this._onloadend = makeHandler(aValue); }, get onloadend() { return this._onloadend; }, set ontimeout(aValue) { this._ontimeout = makeHandler(aValue); }, get ontimeout() { return this._ontimeout; }, set timeout(aValue) { this._timeout = aValue; }, _notify(events) { if (this._notified) { return; } this._notified = true; for (let item of events) { let k = "on" + item; if (this[k]) { info("Notifying " + item); let e = { target: this, type: item, }; this[k](e); } else { info("Notifying " + item + ", but there are no listeners"); } } }, addEventListener(aEvent, aValue, aCapturing) { // eslint-disable-next-line no-eval eval("this._on" + aEvent + " = aValue"); }, get wrappedJSObject() { return this; }, }; /** * Helper used to overrideXHR requests (no matter to what URL) with the * specified status and response. * @param status The status you want to get back when an XHR request is made * @param response The response you want to get back when an XHR request is made */ function overrideXHR(status, response, options) { overrideXHR.myxhr = new xhr(status, response, options); ProductAddonCheckerScope.CreateXHR = function() { return overrideXHR.myxhr; }; return overrideXHR.myxhr; } /** * Creates a new zip file containing a file with the specified data * @param zipName The name of the zip file * @param data The data to go inside the zip for the filename entry1.info */ function createNewZipFile(zipName, data) { // Create a zip file which will be used for extracting let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance( Ci.nsIStringInputStream ); stream.setData(data, data.length); let zipWriter = Cc["@mozilla.org/zipwriter;1"].createInstance( Ci.nsIZipWriter ); let zipFile = FileUtils.getFile("TmpD", [zipName]); if (zipFile.exists()) { zipFile.remove(false); } // From prio.h const PR_RDWR = 0x04; const PR_CREATE_FILE = 0x08; const PR_TRUNCATE = 0x20; zipWriter.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); zipWriter.addEntryStream( "entry1.info", Date.now() * PR_USEC_PER_MSEC, Ci.nsIZipWriter.COMPRESSION_BEST, stream, false ); zipWriter.close(); stream.close(); info("zip file created on disk at: " + zipFile.path); return zipFile; }