Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"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 () => {
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 () => {
await new Promise(() => {});
};
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)
);
}