/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ const { StructuredLogger } = ChromeUtils.importESModule( "resource://testing-common/StructuredLog.sys.mjs" ); const { ProfilerTestUtils } = ChromeUtils.importESModule( "resource://testing-common/ProfilerTestUtils.sys.mjs" ); add_task(async function test_testStatus_adds_profiler_markers() { if (!Services.profiler) { Assert.ok(true, "Profiler not available, skipping test"); return; } await ProfilerTestUtils.startProfilerForMarkerTests(); let buffer = []; let appendBuffer = function (msg) { buffer.push(JSON.stringify(msg)); }; let logger = new StructuredLogger("test_markers", appendBuffer); // Add some test status events logger.testStatus("test1.html", null, "PASS", "PASS", "test passed"); logger.testStatus("test2.html", "subtest1", "FAIL", "PASS", "test failed"); logger.testStatus("test3.html", null, "ERROR", "PASS", "test error"); logger.testStatus("test4.html", null, "FAIL", "FAIL", "known fail"); logger.testStatus("test5.html", null, "PASS", "FAIL", "unexpected pass"); // Stop profiler and get profile const profile = await ProfilerTestUtils.stopNowAndGetProfile(); // Find markers const mainThread = profile.threads.find(({ name }) => name === "GeckoMain"); Assert.ok(mainThread, "Found main thread"); const markers = ProfilerTestUtils.getInflatedMarkerData(mainThread); const testMarkers = markers.filter(m => m.name.startsWith("TEST-")); // Find specific markers and verify them const passMarker = testMarkers.find(m => m.name === "TEST-PASS"); const failMarker = testMarkers.find(m => m.name === "TEST-UNEXPECTED-FAIL"); const errorMarker = testMarkers.find(m => m.name === "TEST-UNEXPECTED-ERROR"); const knownFailMarker = testMarkers.find(m => m.name === "TEST-KNOWN-FAIL"); const unexpectedPassMarker = testMarkers.find( m => m.name === "TEST-UNEXPECTED-PASS" ); Assert.ok(passMarker, "Found TEST-PASS marker"); Assert.equal( passMarker.data.type, "TestStatus", "TEST-PASS has TestStatus type" ); Assert.equal(passMarker.data.test, "test1.html", "TEST-PASS has test field"); Assert.ok( !passMarker.data.hasOwnProperty("subtest"), "TEST-PASS has no subtest field" ); Assert.equal(passMarker.data.status, "PASS", "TEST-PASS has status PASS"); Assert.equal(passMarker.data.expected, "PASS", "TEST-PASS has expected PASS"); Assert.equal(passMarker.data.color, "green", "TEST-PASS is green"); Assert.ok(failMarker, "Found TEST-UNEXPECTED-FAIL marker"); Assert.equal( failMarker.data.type, "TestStatus", "TEST-UNEXPECTED-FAIL has TestStatus type" ); Assert.equal( failMarker.data.test, "test2.html", "TEST-UNEXPECTED-FAIL has test field" ); Assert.equal( failMarker.data.subtest, "subtest1", "TEST-UNEXPECTED-FAIL has subtest field" ); Assert.equal( failMarker.data.status, "FAIL", "TEST-UNEXPECTED-FAIL has status FAIL" ); Assert.equal( failMarker.data.expected, "PASS", "TEST-UNEXPECTED-FAIL has expected PASS" ); Assert.equal( failMarker.data.color, "orange", "TEST-UNEXPECTED-FAIL is orange" ); Assert.ok(failMarker.data.stack, "TEST-UNEXPECTED-FAIL has captured stack"); Assert.ok(errorMarker, "Found TEST-UNEXPECTED-ERROR marker"); Assert.equal( errorMarker.data.type, "TestStatus", "TEST-UNEXPECTED-ERROR has TestStatus type" ); Assert.equal( errorMarker.data.test, "test3.html", "TEST-UNEXPECTED-ERROR has test field" ); Assert.ok( !errorMarker.data.hasOwnProperty("subtest"), "TEST-UNEXPECTED-ERROR has no subtest field" ); Assert.equal( errorMarker.data.status, "ERROR", "TEST-UNEXPECTED-ERROR has status ERROR" ); Assert.equal( errorMarker.data.expected, "PASS", "TEST-UNEXPECTED-ERROR has expected PASS" ); Assert.equal(errorMarker.data.color, "red", "TEST-UNEXPECTED-ERROR is red"); Assert.ok(errorMarker.data.stack, "TEST-UNEXPECTED-ERROR has captured stack"); Assert.ok(knownFailMarker, "Found TEST-KNOWN-FAIL marker"); Assert.equal( knownFailMarker.data.type, "TestStatus", "TEST-KNOWN-FAIL has TestStatus type" ); Assert.equal( knownFailMarker.data.test, "test4.html", "TEST-KNOWN-FAIL has test field" ); Assert.ok( !knownFailMarker.data.hasOwnProperty("subtest"), "TEST-KNOWN-FAIL has no subtest field" ); Assert.equal( knownFailMarker.data.status, "FAIL", "TEST-KNOWN-FAIL has status FAIL" ); Assert.equal( knownFailMarker.data.expected, "FAIL", "TEST-KNOWN-FAIL has expected FAIL" ); Assert.equal(knownFailMarker.data.color, "green", "TEST-KNOWN-FAIL is green"); Assert.ok(knownFailMarker.data.stack, "TEST-KNOWN-FAIL has captured stack"); Assert.ok(unexpectedPassMarker, "Found TEST-UNEXPECTED-PASS marker"); Assert.equal( unexpectedPassMarker.data.type, "TestStatus", "TEST-UNEXPECTED-PASS has TestStatus type" ); Assert.equal( unexpectedPassMarker.data.test, "test5.html", "TEST-UNEXPECTED-PASS has test field" ); Assert.ok( !unexpectedPassMarker.data.hasOwnProperty("subtest"), "TEST-UNEXPECTED-PASS has no subtest field" ); Assert.equal( unexpectedPassMarker.data.status, "PASS", "TEST-UNEXPECTED-PASS has status PASS" ); Assert.equal( unexpectedPassMarker.data.expected, "FAIL", "TEST-UNEXPECTED-PASS has expected FAIL" ); Assert.equal( unexpectedPassMarker.data.color, "orange", "TEST-UNEXPECTED-PASS is orange" ); }); add_task(async function test_testEnd_adds_profiler_markers() { if (!Services.profiler) { Assert.ok(true, "Profiler not available, skipping test"); return; } await ProfilerTestUtils.startProfilerForMarkerTests(); let buffer = []; let appendBuffer = function (msg) { buffer.push(JSON.stringify(msg)); }; let logger = new StructuredLogger("test_markers", appendBuffer); // Add test start/end pairs logger.testStart("browser/base/content/test1.html"); logger.testEnd("browser/base/content/test1.html", "PASS", "PASS"); logger.testStart("browser/base/content/test2.html"); logger.testEnd( "browser/base/content/test2.html", "FAIL", "PASS", "test failed" ); logger.testStart("browser/base/content/test3.html"); logger.testEnd( "browser/base/content/test3.html", "ERROR", "PASS", "test error" ); logger.testStart("browser/base/content/test4.html"); logger.testEnd( "browser/base/content/test4.html", "FAIL", "FAIL", "expected fail" ); // Stop profiler and get profile const profile = await ProfilerTestUtils.stopNowAndGetProfile(); // Find markers const mainThread = profile.threads.find(({ name }) => name === "GeckoMain"); Assert.ok(mainThread, "Found main thread"); const markers = ProfilerTestUtils.getInflatedMarkerData(mainThread); const testMarkers = markers.filter(m => m.name === "test"); Assert.equal(testMarkers.length, 4, "Found 4 test duration markers"); // Find specific test markers const passTestMarker = testMarkers.find( m => m.data.test === "browser/base/content/test1.html" ); const failTestMarker = testMarkers.find( m => m.data.test === "browser/base/content/test2.html" ); const errorTestMarker = testMarkers.find( m => m.data.test === "browser/base/content/test3.html" ); const expectedFailTestMarker = testMarkers.find( m => m.data.test === "browser/base/content/test4.html" ); Assert.ok(passTestMarker, "Found test1.html marker"); Assert.equal(passTestMarker.data.type, "Test", "PASS test has Test type"); Assert.equal( passTestMarker.data.test, "browser/base/content/test1.html", "PASS test has correct test" ); Assert.equal( passTestMarker.data.name, "test1.html", "PASS test has correct name" ); Assert.equal(passTestMarker.data.color, "green", "PASS test is green"); Assert.equal( passTestMarker.data.status, "PASS", "PASS test has correct status" ); Assert.ok( !passTestMarker.data.hasOwnProperty("expected"), "PASS test has no expected field" ); Assert.greater( passTestMarker.endTime, passTestMarker.startTime, "PASS test has duration" ); Assert.ok(failTestMarker, "Found test2.html marker"); Assert.equal(failTestMarker.data.type, "Test", "FAIL test has Test type"); Assert.equal( failTestMarker.data.test, "browser/base/content/test2.html", "FAIL test has correct test" ); Assert.equal( failTestMarker.data.name, "test2.html", "FAIL test has correct name" ); Assert.equal(failTestMarker.data.color, "orange", "FAIL test is orange"); Assert.equal( failTestMarker.data.status, "FAIL", "FAIL test has correct status" ); Assert.equal( failTestMarker.data.expected, "PASS", "FAIL test has expected field" ); Assert.greater( failTestMarker.endTime, failTestMarker.startTime, "FAIL test has duration" ); Assert.ok(errorTestMarker, "Found test3.html marker"); Assert.equal(errorTestMarker.data.type, "Test", "ERROR test has Test type"); Assert.equal( errorTestMarker.data.test, "browser/base/content/test3.html", "ERROR test has correct test" ); Assert.equal( errorTestMarker.data.name, "test3.html", "ERROR test has correct name" ); Assert.equal(errorTestMarker.data.color, "red", "ERROR test is red"); Assert.equal( errorTestMarker.data.status, "ERROR", "ERROR test has correct status" ); Assert.equal( errorTestMarker.data.expected, "PASS", "ERROR test has expected field" ); Assert.greater( errorTestMarker.endTime, errorTestMarker.startTime, "ERROR test has duration" ); Assert.ok(expectedFailTestMarker, "Found test4.html marker"); Assert.equal( expectedFailTestMarker.data.type, "Test", "Expected FAIL test has Test type" ); Assert.equal( expectedFailTestMarker.data.test, "browser/base/content/test4.html", "Expected FAIL test has correct test" ); Assert.equal( expectedFailTestMarker.data.name, "test4.html", "Expected FAIL test has correct name" ); Assert.equal( expectedFailTestMarker.data.color, "green", "Expected FAIL test is green" ); Assert.equal( expectedFailTestMarker.data.status, "FAIL", "Expected FAIL test has correct status" ); Assert.ok( !expectedFailTestMarker.data.hasOwnProperty("expected"), "Expected FAIL test has no expected field" ); Assert.greater( expectedFailTestMarker.endTime, expectedFailTestMarker.startTime, "Expected FAIL test has duration" ); }); add_task(async function test_log_adds_profiler_markers() { if (!Services.profiler) { Assert.ok(true, "Profiler not available, skipping test"); return; } await ProfilerTestUtils.startProfilerForMarkerTests(); let buffer = []; let appendBuffer = function (msg) { buffer.push(JSON.stringify(msg)); }; let logger = new StructuredLogger("test_markers", appendBuffer); // Add log messages at different levels logger.info("info message", { test: "test1.html", subtest: "subtest1" }); logger.warning("warning message"); logger.error("error message"); logger.debug("debug message"); // Stop profiler and get profile const profile = await ProfilerTestUtils.stopNowAndGetProfile(); // Find markers const mainThread = profile.threads.find(({ name }) => name === "GeckoMain"); Assert.ok(mainThread, "Found main thread"); const markers = ProfilerTestUtils.getInflatedMarkerData(mainThread); const logMarkers = markers.filter(m => ["INFO", "WARNING", "ERROR", "DEBUG"].includes(m.name) ); Assert.equal(logMarkers.length, 4, "Found 4 log markers"); // Find specific markers const infoMarker = logMarkers.find(m => m.name === "INFO"); const warningMarker = logMarkers.find(m => m.name === "WARNING"); const errorMarker = logMarkers.find(m => m.name === "ERROR"); const debugMarker = logMarkers.find(m => m.name === "DEBUG"); Assert.ok(infoMarker, "Found INFO marker"); Assert.ok(warningMarker, "Found WARNING marker"); Assert.ok(errorMarker, "Found ERROR marker"); Assert.ok(debugMarker, "Found DEBUG marker"); // Verify marker data Assert.equal(infoMarker.data.type, "Log", "INFO marker has Log type"); Assert.equal(infoMarker.data.test, "test1.html", "INFO marker has test name"); Assert.equal( infoMarker.data.subtest, "subtest1", "INFO marker has subtest name" ); Assert.ok(!infoMarker.data.color, "INFO marker has no color (default blue)"); Assert.equal(warningMarker.data.type, "Log", "WARNING marker has Log type"); Assert.equal(warningMarker.data.color, "orange", "WARNING marker is orange"); Assert.equal(errorMarker.data.type, "Log", "ERROR marker has Log type"); Assert.equal(errorMarker.data.color, "red", "ERROR marker is red"); Assert.equal(debugMarker.data.type, "Log", "DEBUG marker has Log type"); Assert.equal(debugMarker.data.color, "grey", "DEBUG marker is grey"); }); add_task(async function test_test_path_normalization() { if (!Services.profiler) { Assert.ok(true, "Profiler not available, skipping test"); return; } await ProfilerTestUtils.startProfilerForMarkerTests(); let buffer = []; let appendBuffer = function (msg) { buffer.push(JSON.stringify(msg)); }; let logger = new StructuredLogger("test_markers", appendBuffer); // Test various path formats that should be normalized // These match the test cases in testing/mochitest/tests/python/test_message_logger.py logger.testStatus( "chrome://mochitests/content/a11y/accessible/tests/browser/test_foo.html", null, "PASS", "PASS" ); logger.testStatus( "chrome://mochitests/content/browser/browser/base/content/test_foo.html", null, "PASS", "PASS" ); logger.testStatus( "http://mochi.test:8888/tests/dom/test_foo.html", null, "PASS", "PASS" ); logger.testStatus( "https://example.org:443/tests/netwerk/test/test_foo.html", null, "PASS", "PASS" ); // Test with testEnd logger.testStart("chrome://mochitests/content/browser/toolkit/test_bar.html"); logger.testEnd( "chrome://mochitests/content/browser/toolkit/test_bar.html", "PASS", "PASS" ); // Test with log markers logger.info("info message", { test: "chrome://mochitests/content/chrome/toolkit/test_baz.html", }); const profile = await ProfilerTestUtils.stopNowAndGetProfile(); const mainThread = profile.threads.find(({ name }) => name === "GeckoMain"); Assert.ok(mainThread, "Found main thread"); const markers = ProfilerTestUtils.getInflatedMarkerData(mainThread); const testStatusMarkers = markers.filter(m => m.name === "TEST-PASS"); const testEndMarkers = markers.filter(m => m.name === "test"); const infoMarkers = markers.filter(m => m.name === "INFO"); // Verify testStatus markers have normalized paths const a11yMarker = testStatusMarkers.find( m => m.data.test === "accessible/tests/browser/test_foo.html" ); Assert.ok(a11yMarker, "Found a11y marker with normalized path"); const browserMarker = testStatusMarkers.find( m => m.data.test === "browser/base/content/test_foo.html" ); Assert.ok(browserMarker, "Found browser marker with normalized path"); const domMarker = testStatusMarkers.find( m => m.data.test === "dom/test_foo.html" ); Assert.ok(domMarker, "Found dom marker with normalized path"); const netwerkMarker = testStatusMarkers.find( m => m.data.test === "netwerk/test/test_foo.html" ); Assert.ok(netwerkMarker, "Found netwerk marker with normalized path"); // Verify testEnd marker has normalized path const testEndMarker = testEndMarkers.find( m => m.data.test === "toolkit/test_bar.html" ); Assert.ok(testEndMarker, "Found testEnd marker with normalized path"); Assert.equal( testEndMarker.data.name, "test_bar.html", "testEnd marker has correct name" ); // Verify info marker has normalized path const infoMarker = infoMarkers.find( m => m.data.test === "toolkit/test_baz.html" ); Assert.ok(infoMarker, "Found info marker with normalized path"); });