diff options
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_failover_retry.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_failover_retry.js | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_failover_retry.js b/toolkit/components/telemetry/tests/unit/test_failover_retry.js new file mode 100644 index 0000000000..c66cb64aea --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_failover_retry.js @@ -0,0 +1,261 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js"); + +const { TelemetryUtils } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryUtils.sys.mjs" +); + +// Enable the collection (during test) for all products so even products +// that don't collect the data will be able to run the test without failure. +Services.prefs.setBoolPref( + "toolkit.telemetry.testing.overrideProductsCheck", + true +); + +Services.prefs.setBoolPref("network.dns.native-is-localhost", true); + +// Trigger a proper telemetry init. +do_get_profile(true); + +AddonTestUtils.init(this); +AddonTestUtils.overrideCertDB(); +AddonTestUtils.createAppInfo( + "xpcshell@tests.mozilla.org", + "XPCShell", + "42", + "42" +); + +// setup and configure a proxy server that will just deny connections. +const proxy = AddonTestUtils.createHttpServer(); +proxy.registerPrefixHandler("/", (request, response) => { + response.setStatusLine(request.httpVersion, 504, "hello proxy user"); + response.write("ok!"); +}); + +// Register a proxy to be used by TCPSocket connections later. +let proxy_info; + +function getBadProxyPort() { + let server = new HttpServer(); + server.start(-1); + const badPort = server.identity.primaryPort; + server.stop(); + return badPort; +} + +function registerProxy() { + let pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService( + Ci.nsIProtocolProxyService + ); + + const proxyFilter = { + applyFilter(uri, defaultProxyInfo, callback) { + if ( + proxy_info && + uri.host == PingServer.host && + uri.port == PingServer.port + ) { + let proxyInfo = pps.newProxyInfo( + proxy_info.type, + proxy_info.host, + proxy_info.port, + "", + "", + 0, + 4096, + null + ); + proxyInfo.sourceId = proxy_info.sourceId; + callback.onProxyFilterResult(proxyInfo); + } else { + callback.onProxyFilterResult(defaultProxyInfo); + } + }, + }; + + pps.registerFilter(proxyFilter, 0); + registerCleanupFunction(() => { + pps.unregisterFilter(proxyFilter); + }); +} + +add_task(async function setup() { + fakeIntlReady(); + + // Make sure we don't generate unexpected pings due to pref changes. + await setEmptyPrefWatchlist(); + Services.prefs.setBoolPref( + TelemetryUtils.Preferences.HealthPingEnabled, + false + ); + TelemetryStopwatch.setTestModeEnabled(true); + + registerProxy(); + + PingServer.start(); + + // accept proxy connections for PingServer + proxy.identity.add("http", PingServer.host, PingServer.port); + + await TelemetrySend.setup(true); + TelemetrySend.setTestModeEnabled(true); + TelemetrySend.setServer(`http://localhost:${PingServer.port}`); +}); + +function checkEvent() { + // ServiceRequest should have recorded an event for this. + let expected = [ + "service_request", + "bypass", + "proxy_info", + "telemetry.send", + { + source: proxy_info.sourceId, + type: "api", + }, + ]; + let snapshot = Telemetry.snapshotEvents( + Ci.nsITelemetry.DATASET_ALL_CHANNELS, + false + ); + + let received = snapshot.parent[0]; + received.shift(); + Assert.deepEqual( + expected, + received, + `retry telemetry data matched ${JSON.stringify(received)}` + ); + Telemetry.clearEvents(); +} + +async function submitPingWithDate(date, expected) { + fakeNow(new Date(date)); + let pingId = await TelemetryController.submitExternalPing( + "test-send-date-header", + {} + ); + let req = await PingServer.promiseNextRequest(); + let ping = decodeRequestPayload(req); + Assert.equal( + req.getHeader("Date"), + expected, + "Telemetry should send the correct Date header with requests." + ); + Assert.equal(ping.id, pingId, "Should have received the correct ping id."); +} + +// While there is no specific indiction, this test causes the +// telemetrySend doPing onload handler to be invoked. +add_task(async function test_failed_server() { + proxy_info = { + type: "http", + host: proxy.identity.primaryHost, + port: proxy.identity.primaryPort, + sourceId: "failed_server_test", + }; + + await TelemetrySend.reset(); + await submitPingWithDate( + Date.UTC(2011, 1, 1, 11, 0, 0), + "Tue, 01 Feb 2011 11:00:00 GMT" + ); + checkEvent(); +}); + +// While there is no specific indiction, this test causes the +// telemetrySend doPing error handler to be invoked. +add_task(async function test_no_server() { + // Make sure the underlying proxy failover is disabled to easily force + // telemetry to retry the request. + Services.prefs.setBoolPref("network.proxy.failover_direct", false); + + proxy_info = { + type: "http", + host: "localhost", + port: getBadProxyPort(), + sourceId: "no_server_test", + }; + + await TelemetrySend.reset(); + await submitPingWithDate( + Date.UTC(2012, 1, 1, 11, 0, 0), + "Wed, 01 Feb 2012 11:00:00 GMT" + ); + checkEvent(); +}); + +// Mock out the send timer activity. +function waitForTimer() { + return new Promise(resolve => { + fakePingSendTimer( + (callback, timeout) => { + resolve([callback, timeout]); + }, + () => {} + ); + }); +} + +add_task(async function test_no_bypass() { + // Make sure the underlying proxy failover is disabled to easily force + // telemetry to retry the request. + Services.prefs.setBoolPref("network.proxy.failover_direct", false); + // Disable the retry and submit again. + Services.prefs.setBoolPref("network.proxy.allow_bypass", false); + + proxy_info = { + type: "http", + host: "localhost", + port: getBadProxyPort(), + sourceId: "no_server_test", + }; + + await TelemetrySend.reset(); + + fakeNow(new Date(Date.UTC(2013, 1, 1, 11, 0, 0))); + + let timerPromise = waitForTimer(); + let pingId = await TelemetryController.submitExternalPing( + "test-send-date-header", + {} + ); + let [pingSendTimerCallback] = await timerPromise; + Assert.ok(!!pingSendTimerCallback, "Should have a timer callback"); + + Assert.equal( + TelemetrySend.pendingPingCount, + 1, + "Should have correct pending ping count" + ); + + // Reset the proxy, trigger the next tick - we should receive the ping. + proxy_info = null; + pingSendTimerCallback(); + let req = await PingServer.promiseNextRequest(); + let ping = decodeRequestPayload(req); + + // PingServer finished before telemetry, so make sure it's done. + await TelemetrySend.testWaitOnOutgoingPings(); + + Assert.equal( + req.getHeader("Date"), + "Fri, 01 Feb 2013 11:00:00 GMT", + "Telemetry should send the correct Date header with requests." + ); + Assert.equal(ping.id, pingId, "Should have received the correct ping id."); + + // reset to save any pending pings + Assert.equal( + TelemetrySend.pendingPingCount, + 0, + "Should not have any pending pings" + ); + + await TelemetrySend.reset(); + PingServer.stop(); +}); |