Backed out 5 changesets (bug 1688669) for mochitest failures on browser_test_marker_network_redirect.js CLOSED TREE

Backed out changeset fab4be0d51b3 (bug 1688669)
Backed out changeset 83f79ed54c65 (bug 1688669)
Backed out changeset 923ed7912d59 (bug 1688669)
Backed out changeset c435c2d7badc (bug 1688669)
Backed out changeset 374be66fa3db (bug 1688669)
This commit is contained in:
Bogdan Tara 2021-02-15 20:39:04 +02:00
Родитель 2c06b9c5fa
Коммит 6852f28961
17 изменённых файлов: 15 добавлений и 1047 удалений

Просмотреть файл

@ -3,38 +3,16 @@ skip-if = tsan # TSan times out on pretty much all of these tests
support-files =
../shared-head.js
head.js
[browser_test_feature_ipcmessages.js]
support-files = simple.html
[browser_test_feature_jsallocations.js]
support-files = do_work_500ms.html
[browser_test_feature_nostacksampling.js]
support-files = do_work_500ms.html
[browser_test_feature_preferencereads.js]
support-files = fixed_height.html
[browser_test_markers_parent_process.js]
[browser_test_profile_single_frame_page_info.js]
support-files = single_frame.html
[browser_test_profile_multi_frame_page_info.js]
support-files =
do_work_500ms.html
fixed_height.html
multi_frame.html
simple.html
single_frame.html
[browser_test_marker_network_simple.js]
support-files = simple.html
[browser_test_marker_network_redirect.js]
support-files =
redirect.sjs
simple.html
page_with_resources.html
firefox-logo-nightly.svg
[browser_test_marker_network_serviceworker.js]
support-files =
serviceworkers/*
[browser_test_feature_ipcmessages.js]
[browser_test_feature_jsallocations.js]
[browser_test_feature_nostacksampling.js]
[browser_test_feature_preferencereads.js]
[browser_test_markers_parent_process.js]
[browser_test_profile_single_frame_page_info.js]
[browser_test_profile_multi_frame_page_info.js]

Просмотреть файл

@ -1,304 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Test that we emit network markers accordingly.
* In this file we'll test the redirect cases.
*/
add_task(async function test_network_markers_redirect_simple() {
// In this test, we request an HTML page that gets redirected. This is a
// top-level navigation.
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
startProfilerForMarkerTests();
const targetFileNameWithCacheBust = "simple.html?cacheBust=" + Math.random();
const url =
BASE_URL +
"redirect.sjs?" +
encodeURIComponent(targetFileNameWithCacheBust);
const targetUrl = BASE_URL + targetFileNameWithCacheBust;
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
const { parentThread, contentThread } = await stopProfilerNowAndGetThreads(
contentPid
);
const parentNetworkMarkers = getInflatedNetworkMarkers(parentThread);
const contentNetworkMarkers = getInflatedNetworkMarkers(contentThread);
info(JSON.stringify(parentNetworkMarkers, null, 2));
info(JSON.stringify(contentNetworkMarkers, null, 2));
Assert.equal(
parentNetworkMarkers.length,
4,
`We should get 2 pairs of network markers in the parent thread.`
);
/* It looks like that for a redirection for the top level navigation, the
* content thread sees the markers for the second request only.
* See Bug 1692879. */
Assert.equal(
contentNetworkMarkers.length,
2,
`We should get one pair of network markers in the content thread.`
);
const parentRedirectMarker = parentNetworkMarkers[1];
const parentStopMarker = parentNetworkMarkers[3];
const contentStopMarker = contentNetworkMarkers[1];
Assert.objectContains(parentRedirectMarker, {
name: Expect.stringMatches(`Load \\d+:.*${escapeStringRegexp(url)}`),
data: Expect.objectContains({
status: "STATUS_REDIRECT",
URI: url,
RedirectURI: targetUrl,
requestMethod: "GET",
contentType: null,
startTime: Expect.number(),
endTime: Expect.number(),
domainLookupStart: Expect.number(),
domainLookupEnd: Expect.number(),
connectStart: Expect.number(),
tcpConnectEnd: Expect.number(),
connectEnd: Expect.number(),
requestStart: Expect.number(),
responseStart: Expect.number(),
responseEnd: Expect.number(),
id: Expect.number(),
pri: Expect.number(),
}),
});
const expectedProperties = {
name: Expect.stringMatches(
`Load \\d+:.*${escapeStringRegexp(targetUrl)}`
),
data: Expect.objectContains({
status: "STATUS_STOP",
URI: targetUrl,
requestMethod: "GET",
contentType: "text/html",
startTime: Expect.number(),
endTime: Expect.number(),
domainLookupStart: Expect.number(),
domainLookupEnd: Expect.number(),
connectStart: Expect.number(),
tcpConnectEnd: Expect.number(),
connectEnd: Expect.number(),
requestStart: Expect.number(),
responseStart: Expect.number(),
responseEnd: Expect.number(),
id: Expect.number(),
count: Expect.number(),
pri: Expect.number(),
}),
};
Assert.objectContains(parentStopMarker, expectedProperties);
// The cache information is missing from the content marker, it's only part
// of the parent marker. See Bug 1544821.
Assert.objectContains(parentStopMarker.data, {
// Because the request races with the cache, these 2 values are valid:
// "Missed" when the cache answered before we get a result from the network.
// "Unresolved" when we got a response from the network before the cache subsystem.
cache: Expect.stringMatches(/^(Missed|Unresolved)$/),
});
Assert.objectContains(contentStopMarker, expectedProperties);
});
});
add_task(async function test_network_markers_redirect_resources() {
// In this test we request an HTML file that itself contains resources that
// are redirected.
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
startProfilerForMarkerTests();
const url = BASE_URL + "page_with_resources.html?cacheBust=" + Math.random();
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
const { parentThread, contentThread } = await stopProfilerNowAndGetThreads(
contentPid
);
const parentNetworkMarkers = getInflatedNetworkMarkers(parentThread);
const contentNetworkMarkers = getInflatedNetworkMarkers(contentThread);
info(JSON.stringify(parentNetworkMarkers, null, 2));
info(JSON.stringify(contentNetworkMarkers, null, 2));
Assert.equal(
parentNetworkMarkers.length,
8,
`We should get 4 pairs of network markers in the parent thread.`
// 1 - The main page
// 2 - The SVG
// 3 - The redirected request for the second SVG request.
// 4 - The SVG, again
);
/* In this second test, the top level navigation request isn't redirected.
* Contrary to Bug 1692879 we get all network markers for redirected
* resources. */
Assert.equal(
contentNetworkMarkers.length,
8,
`We should get 4 pairs of network markers in the content thread.`
);
// The same resource firefox-logo-nightly.svg is requested twice, but the
// second time it is redirected.
// We're not interested in the main page, as we test that in other files.
// In this page we're only interested in the marker for requested resources.
const parentPairs = getPairsOfNetworkMarkers(parentNetworkMarkers);
const contentPairs = getPairsOfNetworkMarkers(contentNetworkMarkers);
// First, make sure we properly matched all start with stop markers. This
// means that both arrays should contain only arrays of 2 elements.
parentPairs.forEach(pair =>
Assert.equal(
pair.length,
2,
`For the URL ${pair[0].data.URI} we should get 2 markers in the parent process.`
)
);
contentPairs.forEach(pair =>
Assert.equal(
pair.length,
2,
`For the URL ${pair[0].data.URI} we should get 2 markers in the content process.`
)
);
const parentFirstStopMarker = parentPairs[1][1];
const parentRedirectMarker = parentPairs[2][1];
const parentSecondStopMarker = parentPairs[3][1];
const contentFirstStopMarker = contentPairs[1][1];
const contentRedirectMarker = contentPairs[2][1];
const contentSecondStopMarker = contentPairs[3][1];
const expectedCommonProperties = {
requestMethod: "GET",
startTime: Expect.number(),
endTime: Expect.number(),
id: Expect.number(),
pri: Expect.number(),
};
const expectedPropertiesForFirstMarker = {
name: Expect.stringMatches(/Load \d+:.*firefox-logo-nightly\.svg/),
data: Expect.objectContains({
...expectedCommonProperties,
status: "STATUS_STOP",
URI: Expect.stringContains("/firefox-logo-nightly.svg"),
contentType: "image/svg+xml",
domainLookupStart: Expect.number(),
domainLookupEnd: Expect.number(),
connectStart: Expect.number(),
tcpConnectEnd: Expect.number(),
connectEnd: Expect.number(),
requestStart: Expect.number(),
responseStart: Expect.number(),
responseEnd: Expect.number(),
}),
};
const expectedPropertiesForRedirectMarker = {
name: Expect.stringMatches(
/Load \d+:.*redirect.sjs\?firefox-logo-nightly\.svg/
),
data: Expect.objectContains({
...expectedCommonProperties,
status: "STATUS_REDIRECT",
URI: Expect.stringContains("/redirect.sjs?firefox-logo-nightly.svg"),
RedirectURI: Expect.stringContains("/firefox-logo-nightly.svg"),
contentType: null,
domainLookupStart: Expect.number(),
domainLookupEnd: Expect.number(),
connectStart: Expect.number(),
tcpConnectEnd: Expect.number(),
connectEnd: Expect.number(),
requestStart: Expect.number(),
responseStart: Expect.number(),
responseEnd: Expect.number(),
}),
};
const expectedPropertiesForSecondMarker = {
name: Expect.stringMatches(/Load \d+:.*firefox-logo-nightly\.svg/),
data: Expect.objectContains({
...expectedCommonProperties,
status: "STATUS_STOP",
URI: Expect.stringContains("/firefox-logo-nightly.svg"),
contentType: "image/svg+xml",
}),
};
Assert.objectContains(
parentFirstStopMarker,
expectedPropertiesForFirstMarker
);
Assert.objectContains(
contentFirstStopMarker,
expectedPropertiesForFirstMarker
);
Assert.objectContains(
parentRedirectMarker,
expectedPropertiesForRedirectMarker
);
Assert.objectContains(
contentRedirectMarker,
expectedPropertiesForRedirectMarker
);
Assert.objectContains(
parentSecondStopMarker,
expectedPropertiesForSecondMarker
);
Assert.objectContains(
contentSecondStopMarker,
expectedPropertiesForSecondMarker
);
// The cache information is missing from the content marker, it's only part
// of the parent marker. See Bug 1544821.
// Also, because the request races with the cache, these 2 values are valid:
// "Missed" when the cache answered before we get a result from the network.
// "Unresolved" when we got a response from the network before the cache subsystem.
Assert.objectContains(parentFirstStopMarker.data, {
cache: Expect.stringMatches(/^(Missed|Unresolved)$/),
});
Assert.objectContains(parentRedirectMarker.data, {
cache: Expect.stringMatches(/^(Missed|Unresolved)$/),
});
// The second request to the SVG file is already in the cache, though.
Assert.objectContains(parentSecondStopMarker.data, {
cache: "Hit",
});
});
});

Просмотреть файл

@ -1,136 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Test that we emit network markers accordingly.
* In this file we'll test a few service worker cases.
*/
registerCleanupFunction(() => SpecialPowers.removeAllServiceWorkerData());
add_task(async function test_network_markers_service_worker_register() {
// In this first step, we request an HTML page that will register a service
// worker. We'll wait until the service worker is fully installed before
// checking various things.
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
startProfilerForMarkerTests();
const url =
BASE_URL_HTTPS +
"serviceworkers/serviceworker_register.html?cacheBust=" +
Math.random();
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
await SpecialPowers.spawn(contentBrowser, [], async function() {
await content.wrappedJSObject.registerServiceWorkerAndWait();
});
const { parentThread, contentThread } = await stopProfilerNowAndGetThreads(
contentPid
);
const parentNetworkMarkers = getInflatedNetworkMarkers(parentThread);
const contentNetworkMarkers = getInflatedNetworkMarkers(contentThread);
info(JSON.stringify(parentNetworkMarkers, null, 2));
info(JSON.stringify(contentNetworkMarkers, null, 2));
const parentPairs = getPairsOfNetworkMarkers(parentNetworkMarkers);
const contentPairs = getPairsOfNetworkMarkers(contentNetworkMarkers);
// First, make sure we properly matched all start with stop markers. This
// means that both arrays should contain only arrays of 2 elements.
parentPairs.forEach(pair =>
Assert.equal(
pair.length,
2,
`For the URL ${pair[0].data.URI} we should get 2 markers in the parent process.`
)
);
contentPairs.forEach(pair =>
Assert.equal(
pair.length,
2,
`For the URL ${pair[0].data.URI} we should get 2 markers in the content process.`
)
);
// Let's make sure we actually have a registered service workers, to prevent
// stupid mistakes.
const workers = await SpecialPowers.registeredServiceWorkers();
Assert.equal(
workers.length,
1,
"One service worker should be properly registered."
);
});
});
add_task(async function test_network_markers_service_worker_use() {
// In this test we request an HTML file that itself contains resources that
// are redirected.
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
startProfilerForMarkerTests();
const url =
BASE_URL_HTTPS +
"serviceworkers/serviceworker_page.html?cacheBust=" +
Math.random();
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
const { parentThread, contentThread } = await stopProfilerNowAndGetThreads(
contentPid
);
const parentNetworkMarkers = getInflatedNetworkMarkers(parentThread);
const contentNetworkMarkers = getInflatedNetworkMarkers(contentThread);
info(JSON.stringify(parentNetworkMarkers, null, 2));
info(JSON.stringify(contentNetworkMarkers, null, 2));
// const parentPairs = getPairsOfNetworkMarkers(parentNetworkMarkers);
const contentPairs = getPairsOfNetworkMarkers(contentNetworkMarkers);
// First, make sure we properly matched all start with stop markers. This
// means that both arrays should contain only arrays of 2 elements.
/* This test fails for now, see Bug 1567222.
parentPairs.forEach(pair =>
Assert.equal(
pair.length,
2,
`For the URL ${pair[0].data.URI} we should get 2 markers in the parent process.`
)
);
*/
contentPairs.forEach(pair =>
Assert.equal(
pair.length,
2,
`For the URL ${pair[0].data.URI} we should get 2 markers in the content process.`
)
);
});
});

Просмотреть файл

@ -1,84 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Test that we emit network markers accordingly
*/
add_task(async function test_network_markers() {
if (!AppConstants.MOZ_GECKO_PROFILER) {
return;
}
Assert.ok(
!Services.profiler.IsActive(),
"The profiler is not currently active"
);
startProfilerForMarkerTests();
const url = BASE_URL + "simple.html?cacheBust=" + Math.random();
await BrowserTestUtils.withNewTab(url, async contentBrowser => {
const contentPid = await SpecialPowers.spawn(
contentBrowser,
[],
() => Services.appinfo.processID
);
const { parentThread, contentThread } = await stopProfilerNowAndGetThreads(
contentPid
);
const parentNetworkMarkers = getInflatedNetworkMarkers(parentThread);
const contentNetworkMarkers = getInflatedNetworkMarkers(contentThread);
info(JSON.stringify(parentNetworkMarkers, null, 2));
info(JSON.stringify(contentNetworkMarkers, null, 2));
Assert.equal(
parentNetworkMarkers.length,
2,
`We should get a pair of network markers in the parent thread.`
);
Assert.equal(
contentNetworkMarkers.length,
2,
`We should get a pair of network markers in the content thread.`
);
const parentStopMarker = parentNetworkMarkers[1];
const contentStopMarker = contentNetworkMarkers[1];
const expectedProperties = {
name: Expect.stringMatches(`Load \\d+:.*${escapeStringRegexp(url)}`),
data: Expect.objectContains({
status: "STATUS_STOP",
URI: url,
requestMethod: "GET",
contentType: "text/html",
startTime: Expect.number(),
endTime: Expect.number(),
domainLookupStart: Expect.number(),
domainLookupEnd: Expect.number(),
connectStart: Expect.number(),
tcpConnectEnd: Expect.number(),
connectEnd: Expect.number(),
requestStart: Expect.number(),
responseStart: Expect.number(),
responseEnd: Expect.number(),
id: Expect.number(),
count: Expect.number(),
pri: Expect.number(),
}),
};
Assert.objectContains(parentStopMarker, expectedProperties);
// The cache information is missing from the content marker, it's only part
// of the parent marker. See Bug 1544821.
Assert.objectContains(parentStopMarker.data, {
// Because the request races with the cache, these 2 values are valid:
// "Missed" when the cache answered before we get a result from the network.
// "Unresolved" when we got a response from the network before the cache subsystem.
cache: Expect.stringMatches(/^(Missed|Unresolved)$/),
});
Assert.objectContains(contentStopMarker, expectedProperties);
});
});

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 19 KiB

Просмотреть файл

@ -10,8 +10,6 @@ const { BrowserTestUtils } = ChromeUtils.import(
);
const BASE_URL = "http://example.com/browser/tools/profiler/tests/browser/";
const BASE_URL_HTTPS =
"https://example.com/browser/tools/profiler/tests/browser/";
registerCleanupFunction(() => {
if (Services.profiler.IsActive()) {
@ -23,8 +21,8 @@ registerCleanupFunction(() => {
});
/**
* This is a helper function that will stop the profiler and returns the main
* threads for the parent process and the content process with PID contentPid.
* This is a helper function that will stop the profiler of the browser running
* with PID contentPid.
* This happens immediately, without waiting for any sampling to happen or
* finish. Use stopProfilerAndGetThreads (without "Now") below instead to wait
* for samples before stopping.
@ -33,7 +31,6 @@ registerCleanupFunction(() => {
* @returns {Promise}
*/
async function stopProfilerNowAndGetThreads(contentPid) {
Services.profiler.Pause();
const profile = await Services.profiler.getProfileDataAsync();
Services.profiler.StopProfiler();
@ -58,8 +55,8 @@ async function stopProfilerNowAndGetThreads(contentPid) {
}
/**
* This is a helper function that will stop the profiler and returns the main
* threads for the parent process and the content process with PID contentPid.
* This is a helper function that will stop the profiler of the browser running
* with PID contentPid.
* As opposed to stopProfilerNowAndGetThreads (with "Now") above, the profiler
* in that PID will not stop until there is at least one periodic sample taken.
*

Просмотреть файл

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
</head>
<body>
Testing
<img src='firefox-logo-nightly.svg' width="24"/>
<img src='redirect.sjs?firefox-logo-nightly.svg' width="24"/>
</body>
</html>

Просмотреть файл

@ -1,4 +0,0 @@
function handleRequest(request, response) {
response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
response.setHeader("Location", decodeURIComponent(request.queryString), false);
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 19 KiB

Просмотреть файл

@ -1,9 +0,0 @@
async function registerServiceWorkerAndWait() {
console.log("Registering the serviceworker.");
await navigator.serviceWorker.register("./serviceworker_cache_first.js", {
scope: "./",
});
await navigator.serviceWorker.ready;
console.log("The service worker is ready.");
}

Просмотреть файл

@ -1,32 +0,0 @@
const files = ["serviceworker_page.html", "firefox-logo-nightly.svg"];
const cacheName = "v1";
self.addEventListener("install", event => {
console.log("[SW]:", "Install event");
event.waitUntil(cacheAssets);
});
async function cacheAssets() {
const cache = await caches.open(cacheName);
await cache.addAll(files);
}
self.addEventListener("fetch", event => {
console.log("Handling fetch event for", event.request.url);
event.respondWith(handleFetch(event.request));
});
async function handleFetch(request) {
const cachedResponse = await caches.match(request);
if (cachedResponse) {
console.log("Found response in cache:", cachedResponse);
return cachedResponse;
}
console.log("No response found in cache. About to fetch from network...");
const networkResponse = await fetch(request);
console.log("Response from network is:", networkResponse);
return networkResponse;
}

Просмотреть файл

@ -1,11 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='initial-scale=1'>
<script src='serviceworker-utils.js'></script>
</head>
<body>
<img src='firefox-logo-nightly.svg' width="24">
</body>
</html>

Просмотреть файл

@ -1,9 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<script src='serviceworker-utils.js'></script>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -2,8 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* globals Assert */
/**
* This file contains utilities that can be shared between xpcshell tests and mochitests.
*/
@ -42,10 +40,6 @@ function startProfiler(callersSettings) {
);
}
function startProfilerForMarkerTests() {
startProfiler({ features: ["threads", "nostacksampling"] });
}
/**
* This is a helper function be able to run `await wait(500)`. Unfortunately
* this is needed as the act of collecting functions relies on the periodic
@ -127,48 +121,6 @@ function getInflatedMarkerData(thread) {
});
}
/**
* Applies the marker schema to create individual objects for each marker, then
* keeps only the network markers that match the profiler tests.
*
* @param {Object} thread The thread from a profile.
* @return {InflatedMarker[]} The filtered network markers.
*/
function getInflatedNetworkMarkers(thread) {
const markers = getInflatedMarkerData(thread);
return markers.filter(
m =>
m.data &&
m.data.type === "Network" &&
// We filter out network markers that aren't related to the test, to
// avoid intermittents.
m.data.URI.includes("/browser/tools/profiler/")
);
}
/**
* From a list of network markers, this returns pairs of start/stop markers.
* If a stop marker can't be found for a start marker, this will return an array
* of only 1 element.
*
* @param {InflatedMarker[]} networkMarkers Network markers
* @return {InflatedMarker[][]} Pairs of network markers
*/
function getPairsOfNetworkMarkers(allNetworkMarkers) {
// For each 'start' marker we want to find the 'stop' or 'redirect' marker
// with the same id.
// Note: the algorithm we use here to match markers is very crude and would
// be too slow for the real product, but because it is very simple it's good
// for a test. Also the logic will be compatible with future marker sets.
// Because we only have a few markers the performance is good enough in this
// case.
return allNetworkMarkers
.filter(({ data }) => data.status === "STATUS_START")
.map(startMarker =>
allNetworkMarkers.filter(({ data }) => data.id === startMarker.data.id)
);
}
/**
* It can be helpful to force the profiler to collect a JavaScript sample. This
* function spins on a while loop until at least one more sample is collected.
@ -262,196 +214,3 @@ function getSchema(profile, name) {
}
throw new Error(`Could not find a schema for "${name}".`);
}
/**
* This escapes all characters that have a special meaning in RegExps.
* This was stolen from https://github.com/sindresorhus/escape-string-regexp and
* so it is licence MIT and:
* Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com).
* See the full license in https://raw.githubusercontent.com/sindresorhus/escape-string-regexp/main/license.
* @param {string} string The string to be escaped
* @returns {string} The result
*/
function escapeStringRegexp(string) {
if (typeof string !== "string") {
throw new TypeError("Expected a string");
}
// Escape characters with special meaning either inside or outside character
// sets. Use a simple backslash escape when its always valid, and a `\xnn`
// escape when the simpler form would be disallowed by Unicode patterns
// stricter grammar.
return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
}
/** ------ Assertions helper ------ */
/**
* This assert helper function makes it easy to check a lot of properties in an
* object. We augment Assert.jsm to make it easier to use.
*/
Object.assign(Assert, {
/*
* It checks if the properties on the right are all present in the object on
* the left. Note that the object might still have other properties (see
* objectContainsOnly below if you want the stricter form).
*
* The basic form does basic equality on each expected property:
*
* Assert.objectContains(fixture, {
* foo: "foo",
* bar: 1,
* baz: true,
* });
*
* But it also has a more powerful form with expectations. The available
* expectations are:
* - any(): this only checks for the existence of the property, not its value
* - number(), string(), boolean(), bigint(), function(), symbol(), object():
* this checks if the value is of this type
* - objectContains(expected): this applies Assert.objectContains()
* recursively on this property.
* - stringContains(needle): this checks if the expected value is included in
* the property value.
* - stringMatches(regexp): this checks if the property value matches this
* regexp. The regexp can be passed as a string, to be dynamically built.
*
* example:
*
* Assert.objectContains(fixture, {
* name: Expect.stringMatches(`Load \\d+:.*${url}`),
* data: Expect.objectContains({
* status: "STATUS_STOP",
* URI: Expect.stringContains("https://"),
* requestMethod: "GET",
* contentType: Expect.string(),
* startTime: Expect.number(),
* cached: Expect.boolean(),
* }),
* });
*
* Each expectation will translate into one or more Assert call. Therefore if
* one expectation fails, this will be clearly visible in the test output.
*
* Expectations can also be normal functions, for example:
*
* Assert.objectContains(fixture, {
* number: value => Assert.greater(value, 5)
* });
*
* Note that you'll need to use Assert inside this function.
*/
objectContains(object, properties) {
// Basic tests: we don't want to run other assertions if these tests fail.
if (typeof object !== "object") {
this.ok(
false,
`The first parameter should be an object, but found: ${object}.`
);
return;
}
if (typeof properties !== "object") {
this.ok(
false,
`The second parameter should be an object, but found: ${properties}.`
);
return;
}
for (const key of Object.keys(properties)) {
const expected = properties[key];
if (!(key in object)) {
this.ok(false, `The object should contain the property ${key}`);
continue;
}
if (typeof expected === "function") {
// This is a function, so let's call it.
expected(
object[key],
`The object should contain the property "${key}" with an expected value and type.`
);
} else {
// Otherwise, we check for equality.
this.equal(
object[key],
properties[key],
`The object should contain the property "${key}" with an expected value.`
);
}
}
},
/**
* This is very similar to the previous `objectContains`, but this also looks
* at the number of the objects' properties. Thus this will fail if the
* objects don't have the same properties exactly.
*/
objectContainsOnly(object, properties) {
// Basic tests: we don't want to run other assertions if these tests fail.
if (typeof object !== "object") {
this.ok(
false,
`The first parameter should be an object but found: ${object}.`
);
return;
}
if (typeof properties !== "object") {
this.ok(
false,
`The second parameter should be an object but found: ${properties}.`
);
return;
}
this.equal(
Object.keys(object).length,
Object.keys(properties).length,
"The 2 objects should have the same number of properties."
);
this.objectContains(object, properties);
},
});
const Expect = {
any: () => actual => {} /* We don't check anything more than the presence of this property. */,
};
/* These functions are part of the Assert object, and we want to reuse them. */
[
"stringContains",
"stringMatches",
"objectContains",
"objectContainsOnly",
].forEach(
assertChecker =>
(Expect[assertChecker] = expected => (actual, ...moreArgs) =>
Assert[assertChecker](actual, expected, ...moreArgs))
);
/* These functions will only check for the type. */
[
"number",
"string",
"boolean",
"bigint",
"symbol",
"object",
"function",
].forEach(type => (Expect[type] = makeTypeChecker(type)));
function makeTypeChecker(type) {
return (...unexpectedArgs) => {
if (unexpectedArgs.length) {
throw new Error(
"Type checkers expectations aren't expecting any argument."
);
}
return (actual, message) => {
const isCorrect = typeof actual === type;
Assert.report(!isCorrect, actual, type, message, "has type");
};
};
}
/* ------ End of assertion helper ------ */

Просмотреть файл

@ -85,7 +85,7 @@ add_task(async () => {
return;
}
startProfilerForMarkerTests();
startProfiler();
startTime = Cu.now();
while (Cu.now() < startTime + 1) {
// Busy wait for 1ms to ensure the intentionally set start time of markers

Просмотреть файл

@ -1,162 +0,0 @@
add_task(function setup() {
// With the default reporter, an assertion doesn't throw if it fails, it
// merely report the result to the reporter and then go on. But in this test
// we want that a failure really throws, so that we can actually assert that
// it throws in case of failures!
// That's why we disable the default repoter here.
// I noticed that this line needs to be in an add_task (or possibly run_test)
// function. If put outside this will crash the test.
Assert.setReporter(null);
});
add_task(function test_objectContains() {
const fixture = {
foo: "foo",
bar: "bar",
};
Assert.objectContains(fixture, { foo: "foo" }, "Matches one property value");
Assert.objectContains(
fixture,
{ foo: "foo", bar: "bar" },
"Matches both properties"
);
Assert.objectContainsOnly(
fixture,
{ foo: "foo", bar: "bar" },
"Matches both properties"
);
Assert.throws(
() => Assert.objectContainsOnly(fixture, { foo: "foo" }),
/AssertionError/,
"Fails if some properties are missing"
);
Assert.throws(
() => Assert.objectContains(fixture, { foo: "bar" }),
/AssertionError/,
"Fails if the value for a present property is wrong"
);
Assert.throws(
() => Assert.objectContains(fixture, { hello: "world" }),
/AssertionError/,
"Fails if an expected property is missing"
);
Assert.throws(
() => Assert.objectContains(fixture, { foo: "foo", hello: "world" }),
/AssertionError/,
"Fails if some properties are present but others are missing"
);
});
add_task(function test_objectContains_expectations() {
const fixture = {
foo: "foo",
bar: "bar",
num: 42,
nested: {
nestedFoo: "nestedFoo",
nestedBar: "nestedBar",
},
};
Assert.objectContains(
fixture,
{
foo: Expect.stringMatches(/^fo/),
bar: Expect.stringContains("ar"),
num: Expect.number(),
nested: Expect.objectContainsOnly({
nestedFoo: Expect.stringMatches(/[Ff]oo/),
nestedBar: Expect.stringMatches(/[Bb]ar/),
}),
},
"Supports expectations"
);
Assert.objectContainsOnly(
fixture,
{
foo: Expect.stringMatches(/^fo/),
bar: Expect.stringContains("ar"),
num: Expect.number(),
nested: Expect.objectContains({
nestedFoo: Expect.stringMatches(/[Ff]oo/),
}),
},
"Supports expectations"
);
Assert.objectContains(fixture, {
num: val => Assert.greater(val, 40),
});
// Failed expectations
Assert.throws(
() =>
Assert.objectContains(fixture, {
foo: Expect.stringMatches(/bar/),
}),
/AssertionError/,
"Expect.stringMatches shouldn't match when the value is unexpected"
);
Assert.throws(
() =>
Assert.objectContains(fixture, {
foo: Expect.stringContains("bar"),
}),
/AssertionError/,
"Expect.stringContains shouldn't match when the value is unexpected"
);
Assert.throws(
() =>
Assert.objectContains(fixture, {
foo: Expect.number(),
}),
/AssertionError/,
"Expect.number shouldn't match when the value isn't a number"
);
Assert.throws(
() =>
Assert.objectContains(fixture, {
nested: Expect.objectContains({
nestedFoo: "bar",
}),
}),
/AssertionError/,
"Expect.objectContains should throw when the value is unexpected"
);
Assert.throws(
() =>
Assert.objectContains(fixture, {
num: val => Assert.less(val, 40),
}),
/AssertionError/,
"Expect.objectContains should throw when a function assertion fails"
);
});
add_task(function test_type_expectations() {
const fixture = {
any: "foo",
string: "foo",
number: 42,
boolean: true,
bigint: 42n,
symbol: Symbol("foo"),
object: { foo: "foo" },
function1() {},
function2: () => {},
};
Assert.objectContains(fixture, {
any: Expect.any(),
string: Expect.string(),
number: Expect.number(),
boolean: Expect.boolean(),
bigint: Expect.bigint(),
symbol: Expect.symbol(),
object: Expect.object(),
function1: Expect.function(),
function2: Expect.function(),
});
});

Просмотреть файл

@ -51,5 +51,3 @@ skip-if = tsan # Times out on TSan, bug 1612707
# See the comment on test_feature_stackwalking.js
[test_merged_stacks.js]
skip-if = (os == "mac" && release_or_beta) || (os == "linux" && release_or_beta && !debug) || asan || tsan
[test_assertion_helper.js]