head_helpers.js (6637B)
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 file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* import-globals-from head_global.js */ 6 7 var { Log } = ChromeUtils.importESModule("resource://gre/modules/Log.sys.mjs"); 8 var { CommonUtils } = ChromeUtils.importESModule( 9 "resource://services-common/utils.sys.mjs" 10 ); 11 var { 12 HTTP_400, 13 HTTP_401, 14 HTTP_402, 15 HTTP_403, 16 HTTP_404, 17 HTTP_405, 18 HTTP_406, 19 HTTP_407, 20 HTTP_408, 21 HTTP_409, 22 HTTP_410, 23 HTTP_411, 24 HTTP_412, 25 HTTP_413, 26 HTTP_414, 27 HTTP_415, 28 HTTP_417, 29 HTTP_500, 30 HTTP_501, 31 HTTP_502, 32 HTTP_503, 33 HTTP_504, 34 HTTP_505, 35 HttpError, 36 HttpServer, 37 } = ChromeUtils.importESModule("resource://testing-common/httpd.sys.mjs"); 38 var { getTestLogger, initTestLogging } = ChromeUtils.importESModule( 39 "resource://testing-common/services/common/logging.sys.mjs" 40 ); 41 var { MockRegistrar } = ChromeUtils.importESModule( 42 "resource://testing-common/MockRegistrar.sys.mjs" 43 ); 44 var { NetUtil } = ChromeUtils.importESModule( 45 "resource://gre/modules/NetUtil.sys.mjs" 46 ); 47 48 function do_check_empty(obj) { 49 do_check_attribute_count(obj, 0); 50 } 51 52 function do_check_attribute_count(obj, c) { 53 Assert.equal(c, Object.keys(obj).length); 54 } 55 56 function do_check_throws(aFunc, aResult) { 57 try { 58 aFunc(); 59 } catch (e) { 60 Assert.equal(e.result, aResult); 61 return; 62 } 63 do_throw("Expected result " + aResult + ", none thrown."); 64 } 65 66 /** 67 * Test whether specified function throws exception with expected 68 * result. 69 * 70 * @param func 71 * Function to be tested. 72 * @param message 73 * Message of expected exception. <code>null</code> for no throws. 74 */ 75 function do_check_throws_message(aFunc, aResult) { 76 try { 77 aFunc(); 78 } catch (e) { 79 Assert.equal(e.message, aResult); 80 return; 81 } 82 do_throw("Expected an error, none thrown."); 83 } 84 85 /** 86 * Print some debug message to the console. All arguments will be printed, 87 * separated by spaces. 88 * 89 * @param [arg0, arg1, arg2, ...] 90 * Any number of arguments to print out 91 * @example 92 * _("Hello World") -> prints "Hello World" 93 * _(1, 2, 3) -> prints "1 2 3" 94 */ 95 var _ = function () { 96 print(Array.from(arguments).join(" ")); 97 }; 98 99 function httpd_setup(handlers, port = -1) { 100 let server = new HttpServer(); 101 for (let path in handlers) { 102 server.registerPathHandler(path, handlers[path]); 103 } 104 try { 105 server.start(port); 106 } catch (ex) { 107 _("=========================================="); 108 _("Got exception starting HTTP server on port " + port); 109 _("Error: " + Log.exceptionStr(ex)); 110 _("Is there a process already listening on port " + port + "?"); 111 _("=========================================="); 112 do_throw(ex); 113 } 114 115 // Set the base URI for convenience. 116 let i = server.identity; 117 server.baseURI = 118 i.primaryScheme + "://" + i.primaryHost + ":" + i.primaryPort; 119 120 return server; 121 } 122 123 function httpd_handler(statusCode, status, body) { 124 return function handler(request, response) { 125 _("Processing request"); 126 // Allow test functions to inspect the request. 127 request.body = readBytesFromInputStream(request.bodyInputStream); 128 handler.request = request; 129 130 response.setStatusLine(request.httpVersion, statusCode, status); 131 if (body) { 132 response.bodyOutputStream.write(body, body.length); 133 } 134 }; 135 } 136 137 function promiseStopServer(server) { 138 return new Promise(resolve => server.stop(resolve)); 139 } 140 141 /* 142 * Read bytes string from an nsIInputStream. If 'count' is omitted, 143 * all available input is read. 144 */ 145 function readBytesFromInputStream(inputStream, count) { 146 if (!count) { 147 count = inputStream.available(); 148 } 149 if (!count) { 150 return ""; 151 } 152 return NetUtil.readInputStreamToString(inputStream, count, { 153 charset: "UTF-8", 154 }); 155 } 156 157 function writeBytesToOutputStream(outputStream, string) { 158 if (!string) { 159 return; 160 } 161 let converter = Cc[ 162 "@mozilla.org/intl/converter-output-stream;1" 163 ].createInstance(Ci.nsIConverterOutputStream); 164 converter.init(outputStream, "UTF-8"); 165 converter.writeString(string); 166 converter.close(); 167 } 168 169 /* 170 * Ensure exceptions from inside callbacks leads to test failures. 171 */ 172 function ensureThrows(func) { 173 return function () { 174 try { 175 func.apply(this, arguments); 176 } catch (ex) { 177 do_throw(ex); 178 } 179 }; 180 } 181 182 /** 183 * Proxy auth helpers. 184 */ 185 186 /** 187 * Fake a PAC to prompt a channel replacement. 188 */ 189 var PACSystemSettings = { 190 QueryInterface: ChromeUtils.generateQI(["nsISystemProxySettings"]), 191 192 // Replace this URI for each test to avoid caching. We want to ensure that 193 // each test gets a completely fresh setup. 194 mainThreadOnly: true, 195 PACURI: null, 196 getProxyForURI: function getProxyForURI() { 197 throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED); 198 }, 199 }; 200 201 var fakePACCID; 202 function installFakePAC() { 203 _("Installing fake PAC."); 204 fakePACCID = MockRegistrar.register( 205 "@mozilla.org/system-proxy-settings;1", 206 PACSystemSettings 207 ); 208 } 209 210 function uninstallFakePAC() { 211 _("Uninstalling fake PAC."); 212 MockRegistrar.unregister(fakePACCID); 213 } 214 215 function getUptakeTelemetrySnapshot(component, source) { 216 const TELEMETRY_CATEGORY_ID = "uptake.remotecontent.result"; 217 const snapshot = Services.telemetry.snapshotEvents( 218 Ci.nsITelemetry.DATASET_ALL_CHANNELS, 219 true 220 ); 221 const parentEvents = snapshot.parent || []; 222 return ( 223 parentEvents 224 // Transform raw event data to objects. 225 .map(([, category, method, object, value, extras]) => { 226 return { category, method, object, value, extras }; 227 }) 228 // Keep only for the specified component and source. 229 .filter( 230 e => 231 e.category == TELEMETRY_CATEGORY_ID && 232 e.object == component && 233 e.extras.source == source 234 ) 235 // Return total number of events received by status, to mimic histograms snapshots. 236 .reduce((acc, e) => { 237 acc[e.value] = (acc[e.value] || 0) + 1; 238 return acc; 239 }, {}) 240 ); 241 } 242 243 function checkUptakeTelemetry(snapshot1, snapshot2, expectedIncrements) { 244 const { UptakeTelemetry } = ChromeUtils.importESModule( 245 "resource://services-common/uptake-telemetry.sys.mjs" 246 ); 247 const STATUSES = Object.values(UptakeTelemetry.STATUS); 248 for (const status of STATUSES) { 249 const expected = expectedIncrements[status] || 0; 250 const previous = snapshot1[status] || 0; 251 const current = snapshot2[status] || previous; 252 Assert.equal(expected, current - previous, `check events for ${status}`); 253 } 254 } 255 256 function arrayEqual(a, b) { 257 return JSON.stringify(a) == JSON.stringify(b); 258 }