summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit/test_failover_retry.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_failover_retry.js')
-rw-r--r--toolkit/components/telemetry/tests/unit/test_failover_retry.js263
1 files changed, 263 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..01305a10b1
--- /dev/null
+++ b/toolkit/components/telemetry/tests/unit/test_failover_retry.js
@@ -0,0 +1,263 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+const { HttpServer } = ChromeUtils.importESModule(
+ "resource://testing-common/httpd.sys.mjs"
+);
+
+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();
+});