diff options
Diffstat (limited to 'toolkit/components/normandy/test/unit/utils.js')
-rw-r--r-- | toolkit/components/normandy/test/unit/utils.js | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/toolkit/components/normandy/test/unit/utils.js b/toolkit/components/normandy/test/unit/utils.js new file mode 100644 index 0000000000..cffe634c91 --- /dev/null +++ b/toolkit/components/normandy/test/unit/utils.js @@ -0,0 +1,135 @@ +"use strict"; +/* eslint-disable no-unused-vars */ + +// Loaded into the same scope as head_xpc.js +/* import-globals-from head_xpc.js */ + +const { Preferences } = ChromeUtils.importESModule( + "resource://gre/modules/Preferences.sys.mjs" +); +const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js"); + +const { NormandyApi } = ChromeUtils.importESModule( + "resource://normandy/lib/NormandyApi.sys.mjs" +); +const { NormandyTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/NormandyTestUtils.sys.mjs" +); + +const CryptoHash = Components.Constructor( + "@mozilla.org/security/hash;1", + "nsICryptoHash", + "initWithString" +); +const FileInputStream = Components.Constructor( + "@mozilla.org/network/file-input-stream;1", + "nsIFileInputStream", + "init" +); + +class MockResponse { + constructor(content) { + this.content = content; + } + + async text() { + return this.content; + } + + async json() { + return JSON.parse(this.content); + } +} + +function withServer(server) { + return function (testFunction) { + return NormandyTestUtils.decorate( + NormandyTestUtils.withMockPreferences(), + async function inner({ mockPreferences, ...args }) { + const serverUrl = `http://localhost:${server.identity.primaryPort}`; + mockPreferences.set("app.normandy.api_url", `${serverUrl}/api/v1`); + NormandyApi.clearIndexCache(); + + try { + await testFunction({ ...args, serverUrl, mockPreferences, server }); + } finally { + await new Promise(resolve => server.stop(resolve)); + } + } + ); + }; +} + +function makeScriptServer(scriptPath) { + const server = new HttpServer(); + server.registerContentType("sjs", "sjs"); + server.registerFile("/", do_get_file(scriptPath)); + server.start(-1); + return server; +} + +function withScriptServer(scriptPath) { + return withServer(makeScriptServer(scriptPath)); +} + +function makeMockApiServer(directory) { + const server = new HttpServer(); + server.registerDirectory("/", directory); + + server.setIndexHandler(async function (request, response) { + response.processAsync(); + const dir = request.getProperty("directory"); + const index = dir.clone(); + index.append("index.json"); + + if (!index.exists()) { + response.setStatusLine("1.1", 404, "Not Found"); + response.write(`Cannot find path ${index.path}`); + response.finish(); + return; + } + + try { + const contents = await IOUtils.readUTF8(index.path); + response.write(contents); + } catch (e) { + response.setStatusLine("1.1", 500, "Server error"); + response.write(e.toString()); + } finally { + response.finish(); + } + }); + + server.start(-1); + return server; +} + +function withMockApiServer(apiName = "mock_api") { + return withServer(makeMockApiServer(do_get_file(apiName))); +} + +const CryptoUtils = { + _getHashStringForCrypto(aCrypto) { + // return the two-digit hexadecimal code for a byte + let toHexString = charCode => ("0" + charCode.toString(16)).slice(-2); + + // convert the binary hash data to a hex string. + let binary = aCrypto.finish(false); + let hash = Array.from(binary, c => toHexString(c.charCodeAt(0))); + return hash.join("").toLowerCase(); + }, + + /** + * Get the computed hash for a given file + * @param {nsIFile} file The file to be hashed + * @param {string} [algorithm] The hashing algorithm to use + */ + getFileHash(file, algorithm = "sha256") { + const crypto = CryptoHash(algorithm); + const fis = new FileInputStream(file, -1, -1, false); + crypto.updateFromStream(fis, file.fileSize); + const hash = this._getHashStringForCrypto(crypto); + fis.close(); + return hash; + }, +}; |