diff options
Diffstat (limited to 'devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_telemetry_connection_attempt.js')
-rw-r--r-- | devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_telemetry_connection_attempt.js | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_telemetry_connection_attempt.js b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_telemetry_connection_attempt.js new file mode 100644 index 0000000000..a5836ad50a --- /dev/null +++ b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_telemetry_connection_attempt.js @@ -0,0 +1,274 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* import-globals-from helper-telemetry.js */ +Services.scriptloader.loadSubScript( + CHROME_URL_ROOT + "helper-telemetry.js", + this +); + +const USB_RUNTIME = { + id: "runtime-id-1", + deviceName: "Device A", + name: "Runtime 1", + shortName: "R1", +}; + +/** + * Check that telemetry events for connection attempts are correctly recorded in various + * scenarios: + * - successful connection + * - successful connection after showing the timeout warning + * - failed connection + * - connection timeout + */ +add_task(async function testSuccessfulConnectionAttempt() { + const { doc, mocks, runtimeId, sessionId, tab } = + await setupConnectionAttemptTest(); + + await connectToRuntime(USB_RUNTIME.deviceName, doc); + + const connectionEvents = checkTelemetryEvents( + [ + { method: "runtime_connected", extras: { runtime_id: runtimeId } }, + { + method: "connection_attempt", + extras: getEventExtras("start", runtimeId), + }, + { + method: "connection_attempt", + extras: getEventExtras("success", runtimeId), + }, + ], + sessionId + ).filter(({ method }) => method === "connection_attempt"); + + checkConnectionId(connectionEvents); + + await removeUsbRuntime(USB_RUNTIME, mocks, doc); + await removeTab(tab); +}); + +add_task(async function testFailedConnectionAttempt() { + const { doc, mocks, runtimeId, sessionId, tab } = + await setupConnectionAttemptTest(); + mocks.runtimeClientFactoryMock.createClientForRuntime = async runtime => { + throw new Error("failed"); + }; + + info( + "Try to connect to the runtime and wait for the connection error message" + ); + const usbRuntimeSidebarItem = findSidebarItemByText( + USB_RUNTIME.deviceName, + doc + ); + const connectButton = + usbRuntimeSidebarItem.querySelector(".qa-connect-button"); + connectButton.click(); + await waitUntil(() => + usbRuntimeSidebarItem.querySelector(".qa-connection-error") + ); + + const connectionEvents = checkTelemetryEvents( + [ + { + method: "connection_attempt", + extras: getEventExtras("start", runtimeId), + }, + { + method: "connection_attempt", + extras: getEventExtras("failed", runtimeId), + }, + ], + sessionId + ).filter(({ method }) => method === "connection_attempt"); + + checkConnectionId(connectionEvents); + + await removeUsbRuntime(USB_RUNTIME, mocks, doc); + await removeTab(tab); +}); + +add_task(async function testPendingConnectionAttempt() { + info("Set timeout preferences to avoid cancelling the connection"); + await pushPref( + "devtools.aboutdebugging.test-connection-timing-out-delay", + 100 + ); + await pushPref( + "devtools.aboutdebugging.test-connection-cancel-delay", + 100000 + ); + + const { doc, mocks, runtimeId, sessionId, tab } = + await setupConnectionAttemptTest(); + + info("Simulate a pending connection"); + let resumeConnection; + const resumeConnectionPromise = new Promise(r => { + resumeConnection = r; + }); + mocks.runtimeClientFactoryMock.createClientForRuntime = async runtime => { + await resumeConnectionPromise; + return mocks._clients[runtime.type][runtime.id]; + }; + + info("Click on the connect button and wait for the warning message"); + const usbRuntimeSidebarItem = findSidebarItemByText( + USB_RUNTIME.deviceName, + doc + ); + const connectButton = + usbRuntimeSidebarItem.querySelector(".qa-connect-button"); + connectButton.click(); + await waitUntil(() => doc.querySelector(".qa-connection-not-responding")); + + info("Resume the connection and wait for the connection to succeed"); + resumeConnection(); + await waitUntil( + () => !usbRuntimeSidebarItem.querySelector(".qa-connect-button") + ); + + const connectionEvents = checkTelemetryEvents( + [ + { method: "runtime_connected", extras: { runtime_id: runtimeId } }, + { + method: "connection_attempt", + extras: getEventExtras("start", runtimeId), + }, + { + method: "connection_attempt", + extras: getEventExtras("not responding", runtimeId), + }, + { + method: "connection_attempt", + extras: getEventExtras("success", runtimeId), + }, + ], + sessionId + ).filter(({ method }) => method === "connection_attempt"); + checkConnectionId(connectionEvents); + + await removeUsbRuntime(USB_RUNTIME, mocks, doc); + await removeTab(tab); +}); + +add_task(async function testCancelledConnectionAttempt() { + info("Set timeout preferences to quickly cancel the connection"); + await pushPref( + "devtools.aboutdebugging.test-connection-timing-out-delay", + 100 + ); + await pushPref("devtools.aboutdebugging.test-connection-cancel-delay", 1000); + + const { doc, mocks, runtimeId, sessionId, tab } = + await setupConnectionAttemptTest(); + + info("Simulate a connection timeout"); + mocks.runtimeClientFactoryMock.createClientForRuntime = async runtime => { + await new Promise(r => {}); + }; + + info("Click on the connect button and wait for the error message"); + const usbRuntimeSidebarItem = findSidebarItemByText( + USB_RUNTIME.deviceName, + doc + ); + const connectButton = + usbRuntimeSidebarItem.querySelector(".qa-connect-button"); + connectButton.click(); + await waitUntil(() => + usbRuntimeSidebarItem.querySelector(".qa-connection-timeout") + ); + + const connectionEvents = checkTelemetryEvents( + [ + { + method: "connection_attempt", + extras: getEventExtras("start", runtimeId), + }, + { + method: "connection_attempt", + extras: getEventExtras("not responding", runtimeId), + }, + { + method: "connection_attempt", + extras: getEventExtras("cancelled", runtimeId), + }, + ], + sessionId + ).filter(({ method }) => method === "connection_attempt"); + checkConnectionId(connectionEvents); + + await removeUsbRuntime(USB_RUNTIME, mocks, doc); + await removeTab(tab); +}); + +function checkConnectionId(connectionEvents) { + const connectionId = connectionEvents[0].extras.connection_id; + ok( + !!connectionId, + "Found a valid connection id in the first connection_attempt event" + ); + for (const evt of connectionEvents) { + is( + evt.extras.connection_id, + connectionId, + "All connection_attempt events share the same connection id" + ); + } +} + +// Small helper to create the expected event extras object for connection_attempt events +function getEventExtras(status, runtimeId) { + return { + connection_type: "usb", + runtime_id: runtimeId, + status, + }; +} + +// Open about:debugging, setup telemetry, mocks and create a mocked USB runtime. +async function setupConnectionAttemptTest() { + const mocks = new Mocks(); + setupTelemetryTest(); + + const { tab, document } = await openAboutDebugging(); + + const sessionId = getOpenEventSessionId(); + ok(!isNaN(sessionId), "Open event has a valid session id"); + + mocks.createUSBRuntime(USB_RUNTIME.id, { + deviceName: USB_RUNTIME.deviceName, + name: USB_RUNTIME.name, + shortName: USB_RUNTIME.shortName, + }); + mocks.emitUSBUpdate(); + + info("Wait for the runtime to appear in the sidebar"); + await waitUntil(() => findSidebarItemByText(USB_RUNTIME.shortName, document)); + const evts = checkTelemetryEvents( + [ + { method: "device_added", extras: {} }, + { method: "runtime_added", extras: {} }, + ], + sessionId + ); + + const runtimeId = evts.filter(e => e.method === "runtime_added")[0].extras + .runtime_id; + return { doc: document, mocks, runtimeId, sessionId, tab }; +} + +async function removeUsbRuntime(runtime, mocks, doc) { + mocks.removeRuntime(runtime.id); + mocks.emitUSBUpdate(); + await waitUntil( + () => + !findSidebarItemByText(runtime.name, doc) && + !findSidebarItemByText(runtime.shortName, doc) + ); +} |