зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1134073 - Part 3: Show network request cause and stacktrace in netmonitor - mochitests r=ochameau
MozReview-Commit-ID: Bjkl2XB3sFs
This commit is contained in:
Родитель
2276274acd
Коммит
45e8d66845
|
@ -4,6 +4,7 @@ subsuite = devtools
|
|||
support-files =
|
||||
dropmarker.svg
|
||||
head.js
|
||||
html_cause-test-page.html
|
||||
html_content-type-test-page.html
|
||||
html_content-type-without-cache-test-page.html
|
||||
html_cors-test-page.html
|
||||
|
@ -33,6 +34,7 @@ support-files =
|
|||
sjs_content-type-test-server.sjs
|
||||
sjs_cors-test-server.sjs
|
||||
sjs_https-redirect-test-server.sjs
|
||||
sjs_hsts-test-server.sjs
|
||||
sjs_simple-test-server.sjs
|
||||
sjs_sorting-test-server.sjs
|
||||
sjs_status-codes-test-server.sjs
|
||||
|
@ -47,6 +49,8 @@ skip-if = (toolkit == "cocoa" && e10s) # bug 1252254
|
|||
[browser_net_api-calls.js]
|
||||
[browser_net_autoscroll.js]
|
||||
[browser_net_cached-status.js]
|
||||
[browser_net_cause.js]
|
||||
[browser_net_cause_redirect.js]
|
||||
[browser_net_service-worker-status.js]
|
||||
[browser_net_charts-01.js]
|
||||
[browser_net_charts-02.js]
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if request cause is reported correctly.
|
||||
*/
|
||||
|
||||
const CAUSE_FILE_NAME = "html_cause-test-page.html";
|
||||
const CAUSE_URL = EXAMPLE_URL + CAUSE_FILE_NAME;
|
||||
|
||||
const EXPECTED_REQUESTS = [
|
||||
{
|
||||
method: "GET",
|
||||
url: CAUSE_URL,
|
||||
causeType: "document",
|
||||
causeUri: "",
|
||||
// The document load is from JS function in e10s, native in non-e10s
|
||||
hasStack: !gMultiProcessBrowser
|
||||
},
|
||||
{
|
||||
method: "GET",
|
||||
url: EXAMPLE_URL + "stylesheet_request",
|
||||
causeType: "stylesheet",
|
||||
causeUri: CAUSE_URL,
|
||||
hasStack: false
|
||||
},
|
||||
{
|
||||
method: "GET",
|
||||
url: EXAMPLE_URL + "img_request",
|
||||
causeType: "img",
|
||||
causeUri: CAUSE_URL,
|
||||
hasStack: false
|
||||
},
|
||||
{
|
||||
method: "GET",
|
||||
url: EXAMPLE_URL + "xhr_request",
|
||||
causeType: "xhr",
|
||||
causeUri: CAUSE_URL,
|
||||
hasStack: { fn: "performXhrRequest", file: CAUSE_FILE_NAME, line: 22 }
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
url: EXAMPLE_URL + "beacon_request",
|
||||
causeType: "beacon",
|
||||
causeUri: CAUSE_URL,
|
||||
hasStack: { fn: "performBeaconRequest", file: CAUSE_FILE_NAME, line: 26 }
|
||||
},
|
||||
];
|
||||
|
||||
var test = Task.async(function* () {
|
||||
// the initNetMonitor function clears the network request list after the
|
||||
// page is loaded. That's why we first load a bogus page from SIMPLE_URL,
|
||||
// and only then load the real thing from CAUSE_URL - we want to catch
|
||||
// all the requests the page is making, not only the XHRs.
|
||||
// We can't use about:blank here, because initNetMonitor checks that the
|
||||
// page has actually made at least one request.
|
||||
let [, debuggee, monitor] = yield initNetMonitor(SIMPLE_URL);
|
||||
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
debuggee.location = CAUSE_URL;
|
||||
|
||||
yield waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
|
||||
|
||||
is(RequestsMenu.itemCount, EXPECTED_REQUESTS.length,
|
||||
"All the page events should be recorded.");
|
||||
|
||||
EXPECTED_REQUESTS.forEach((spec, i) => {
|
||||
let { method, url, causeType, causeUri, hasStack } = spec;
|
||||
|
||||
let requestItem = RequestsMenu.getItemAtIndex(i);
|
||||
verifyRequestItemTarget(requestItem,
|
||||
method, url, { cause: { type: causeType, loadingDocumentUri: causeUri } }
|
||||
);
|
||||
|
||||
let { stacktrace } = requestItem.attachment.cause;
|
||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||
|
||||
if (hasStack) {
|
||||
ok(stacktrace, `Request #${i} has a stacktrace`);
|
||||
ok(stackLen > 0,
|
||||
`Request #${i} (${causeType}) has a stacktrace with ${stackLen} items`);
|
||||
|
||||
// if "hasStack" is object, check the details about the top stack frame
|
||||
if (typeof hasStack === "object") {
|
||||
is(stacktrace[0].functionName, hasStack.fn,
|
||||
`Request #${i} has the correct function on top of the JS stack`);
|
||||
is(stacktrace[0].filename.split("/").pop(), hasStack.file,
|
||||
`Request #${i} has the correct file on top of the JS stack`);
|
||||
is(stacktrace[0].lineNumber, hasStack.line,
|
||||
`Request #${i} has the correct line number on top of the JS stack`);
|
||||
}
|
||||
} else {
|
||||
is(stackLen, 0, `Request #${i} (${causeType}) has an empty stacktrace`);
|
||||
}
|
||||
});
|
||||
|
||||
yield teardown(monitor);
|
||||
finish();
|
||||
});
|
|
@ -0,0 +1,50 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if request JS stack is property reported if the request is internally
|
||||
* redirected without hitting the network (HSTS is one of such cases)
|
||||
*/
|
||||
|
||||
var test = Task.async(function* () {
|
||||
const EXPECTED_REQUESTS = [
|
||||
// Request to HTTP URL, redirects to HTTPS, has callstack
|
||||
{ status: 302, hasStack: true },
|
||||
// Serves HTTPS, sets the Strict-Transport-Security header, no stack
|
||||
{ status: 200, hasStack: false },
|
||||
// Second request to HTTP redirects to HTTPS internally
|
||||
{ status: 200, hasStack: true },
|
||||
];
|
||||
|
||||
let [, debuggee, monitor] = yield initNetMonitor(CUSTOM_GET_URL);
|
||||
let { RequestsMenu } = monitor.panelWin.NetMonitorView;
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
debuggee.performRequests(2, HSTS_SJS);
|
||||
yield waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
|
||||
|
||||
EXPECTED_REQUESTS.forEach(({status, hasStack}, i) => {
|
||||
let { attachment } = RequestsMenu.getItemAtIndex(i);
|
||||
|
||||
is(attachment.status, status, `Request #${i} has the expected status`);
|
||||
|
||||
let { stacktrace } = attachment.cause;
|
||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||
|
||||
if (hasStack) {
|
||||
ok(stacktrace, `Request #${i} has a stacktrace`);
|
||||
ok(stackLen > 0, `Request #${i} has a stacktrace with ${stackLen} items`);
|
||||
} else {
|
||||
is(stackLen, 0, `Request #${i} has an empty stacktrace`);
|
||||
}
|
||||
});
|
||||
|
||||
// Send a request to reset the HSTS policy to state before the test
|
||||
debuggee.performRequests(1, HSTS_SJS + "?reset");
|
||||
yield waitForNetworkEvents(monitor, 1);
|
||||
|
||||
yield teardown(monitor);
|
||||
finish();
|
||||
});
|
|
@ -23,7 +23,7 @@ add_task(function* test() {
|
|||
yield onThumbnail;
|
||||
|
||||
info("Checking the image thumbnail after a few requests were made...");
|
||||
yield showTooltipAndVerify(RequestsMenu.items[5]);
|
||||
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[5]);
|
||||
|
||||
// 7 XHRs as before + 1 extra document reload
|
||||
onEvents = waitForNetworkEvents(monitor, 8);
|
||||
|
@ -36,7 +36,7 @@ add_task(function* test() {
|
|||
yield onThumbnail;
|
||||
|
||||
info("Checking the image thumbnail after a reload.");
|
||||
yield showTooltipAndVerify(RequestsMenu.items[6]);
|
||||
yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[6]);
|
||||
|
||||
yield teardown(monitor);
|
||||
finish();
|
||||
|
@ -45,10 +45,7 @@ add_task(function* test() {
|
|||
* Show a tooltip on the {requestItem} and verify that it was displayed
|
||||
* with the expected content.
|
||||
*/
|
||||
function* showTooltipAndVerify(requestItem) {
|
||||
let { tooltip } = requestItem.attachment;
|
||||
ok(tooltip, "There should be a tooltip instance for the image request.");
|
||||
|
||||
function* showTooltipAndVerify(tooltip, requestItem) {
|
||||
let anchor = $(".requests-menu-file", requestItem.target);
|
||||
yield showTooltipOn(tooltip, anchor);
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@ const URL = EXAMPLE_URL.replace("http:", "https:");
|
|||
const TEST_URL = URL + "service-workers/status-codes.html";
|
||||
|
||||
var test = Task.async(function* () {
|
||||
let [tab, debuggee, monitor] = yield initNetMonitor(TEST_URL, null, true);
|
||||
let [, debuggee, monitor] = yield initNetMonitor(TEST_URL, null, true);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, L10N, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu, NetworkDetails } = NetMonitorView;
|
||||
let { NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
const REQUEST_DATA = [
|
||||
{
|
||||
|
@ -29,7 +29,8 @@ var test = Task.async(function* () {
|
|||
displayedStatus: "service worker",
|
||||
type: "plain",
|
||||
fullMimeType: "text/plain; charset=UTF-8"
|
||||
}
|
||||
},
|
||||
stackFunctions: ["doXHR", "performRequests"]
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -44,12 +45,27 @@ var test = Task.async(function* () {
|
|||
for (let request of REQUEST_DATA) {
|
||||
let item = RequestsMenu.getItemAtIndex(index);
|
||||
|
||||
info("Verifying request #" + index);
|
||||
info(`Verifying request #${index}`);
|
||||
yield verifyRequestItemTarget(item, request.method, request.uri, request.details);
|
||||
|
||||
let { stacktrace } = item.attachment.cause;
|
||||
let stackLen = stacktrace ? stacktrace.length : 0;
|
||||
|
||||
ok(stacktrace, `Request #${index} has a stacktrace`);
|
||||
ok(stackLen >= request.stackFunctions.length,
|
||||
`Request #${index} has a stacktrace with enough (${stackLen}) items`);
|
||||
|
||||
request.stackFunctions.forEach((functionName, j) => {
|
||||
is(stacktrace[j].functionName, functionName,
|
||||
`Request #${index} has the correct function at position #${j} on the stack`);
|
||||
});
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
info("Unregistering the service worker...");
|
||||
yield debuggee.unregisterServiceWorker();
|
||||
|
||||
yield teardown(monitor);
|
||||
finish();
|
||||
});
|
||||
|
|
|
@ -50,6 +50,10 @@ const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
|
|||
const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
|
||||
const HTTPS_REDIRECT_SJS = EXAMPLE_URL + "sjs_https-redirect-test-server.sjs";
|
||||
const CORS_SJS_PATH = "/browser/devtools/client/netmonitor/test/sjs_cors-test-server.sjs";
|
||||
const HSTS_SJS = EXAMPLE_URL + "sjs_hsts-test-server.sjs";
|
||||
|
||||
const HSTS_BASE_URL = EXAMPLE_URL;
|
||||
const HSTS_PAGE_URL = CUSTOM_GET_URL;
|
||||
|
||||
const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
|
||||
const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
|
||||
|
@ -284,7 +288,7 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
|
|||
info("Widget index of item: " + widgetIndex);
|
||||
info("Visible index of item: " + visibleIndex);
|
||||
|
||||
let { fuzzyUrl, status, statusText, type, fullMimeType,
|
||||
let { fuzzyUrl, status, statusText, cause, type, fullMimeType,
|
||||
transferred, size, time, displayedStatus } = aData;
|
||||
let { attachment, target } = aRequestItem;
|
||||
|
||||
|
@ -336,6 +340,15 @@ function verifyRequestItemTarget(aRequestItem, aMethod, aUrl, aData = {}) {
|
|||
is(codeValue, status, "The displayed status code is correct.");
|
||||
is(tooltip, status + " " + statusText, "The tooltip status is correct.");
|
||||
}
|
||||
if (cause !== undefined) {
|
||||
let causeLabel = target.querySelector(".requests-menu-cause-label");
|
||||
let value = causeLabel.getAttribute("value");
|
||||
let tooltip = causeLabel.getAttribute("tooltiptext");
|
||||
info("Displayed cause: " + value);
|
||||
info("Tooltip cause: " + tooltip);
|
||||
is(value, cause.type, "The displayed cause is correct.");
|
||||
is(tooltip, cause.loadingDocumentUri, "The tooltip cause is correct.")
|
||||
}
|
||||
if (type !== undefined) {
|
||||
let value = target.querySelector(".requests-menu-type").getAttribute("value");
|
||||
let tooltip = target.querySelector(".requests-menu-type").getAttribute("tooltiptext");
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<title>Network Monitor test page</title>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet_request" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>Request cause test</p>
|
||||
<img src="img_request" />
|
||||
<script type="text/javascript">
|
||||
function performXhrRequest() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "xhr_request", true);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function performBeaconRequest() {
|
||||
navigator.sendBeacon("beacon_request");
|
||||
}
|
||||
|
||||
performXhrRequest();
|
||||
performBeaconRequest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -2,7 +2,14 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
addEventListener("fetch", function (event) {
|
||||
"use strict";
|
||||
|
||||
self.addEventListener("activate", event => {
|
||||
// start controlling the already loaded page
|
||||
event.waitUntil(self.clients.claim());
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", event => {
|
||||
let response = new Response("Service worker response");
|
||||
event.respondWith(response);
|
||||
});
|
||||
|
|
|
@ -15,24 +15,44 @@
|
|||
<p>Status codes test</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
function get(url) {
|
||||
return new Promise(done => {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("src", url);
|
||||
document.documentElement.appendChild(iframe);
|
||||
iframe.contentWindow.onload = done;
|
||||
});
|
||||
}
|
||||
let swRegistration;
|
||||
|
||||
function registerServiceWorker() {
|
||||
return navigator.serviceWorker.register("status-codes-service-worker.js")
|
||||
.then(() => navigator.serviceWorker.ready);
|
||||
let sw = navigator.serviceWorker;
|
||||
return sw.register("status-codes-service-worker.js")
|
||||
.then(registration => {
|
||||
swRegistration = registration;
|
||||
console.log("Registered, scope is:", registration.scope);
|
||||
return sw.ready;
|
||||
}).then(() => {
|
||||
// wait until the page is controlled
|
||||
return new Promise(resolve => {
|
||||
if (sw.controller) {
|
||||
resolve();
|
||||
} else {
|
||||
sw.addEventListener('controllerchange', function onControllerChange() {
|
||||
sw.removeEventListener('controllerchange', onControllerChange);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error("Registration failed");
|
||||
});
|
||||
}
|
||||
|
||||
function unregisterServiceWorker() {
|
||||
return swRegistration.unregister();
|
||||
}
|
||||
|
||||
function performRequests() {
|
||||
return get("test/200");
|
||||
return new Promise(function doXHR(done) {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "test/200", true);
|
||||
xhr.onreadystatechange = done;
|
||||
xhr.send(null);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
|
||||
if (request.queryString === "reset") {
|
||||
// Reset the HSTS policy, prevent influencing other tests
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Strict-Transport-Security", "max-age=0");
|
||||
response.write("Resetting HSTS");
|
||||
} else if (request.scheme === "http") {
|
||||
response.setStatusLine(request.httpVersion, 302, "Found");
|
||||
response.setHeader("Location", "https://" + request.host + request.path);
|
||||
} else {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Strict-Transport-Security", "max-age=100");
|
||||
response.write("Page was accessed over HTTPS!");
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче