mirror of
https://github.com/servo/servo.git
synced 2025-08-22 13:55:34 +01:00
Update web-platform-tests to revision 5e3ea8f49fee68c327388bfd1dd1375a8ce12a0e.
This commit is contained in:
parent
12195a5c4a
commit
bfb96b9448
1166 changed files with 35123 additions and 900 deletions
360
tests/wpt/web-platform-tests/mixed-content/generic/common.js
Normal file
360
tests/wpt/web-platform-tests/mixed-content/generic/common.js
Normal file
|
@ -0,0 +1,360 @@
|
|||
/**
|
||||
* @fileoverview Utilities for mixed-content in Web Platform Tests.
|
||||
* @author burnik@google.com (Kristijan Burnik)
|
||||
* Disclaimer: Some methods of other authors are annotated in the corresponding
|
||||
* method's JSDoc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Normalizes the target port for use in a URL. For default ports, this is the
|
||||
* empty string (omitted port), otherwise it's a colon followed by the port
|
||||
* number. Ports 80, 443 and an empty string are regarded as default ports.
|
||||
* @param {number} targetPort The port to use
|
||||
* @return {string} The port portion for using as part of a URL.
|
||||
*/
|
||||
function getNormalizedPort(targetPort) {
|
||||
return ([80, 443, ""].indexOf(targetPort) >= 0) ? "" : ":" + targetPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a GUID.
|
||||
* See: https://en.wikipedia.org/wiki/Globally_unique_identifier
|
||||
* Original author: broofa (http://www.broofa.com/)
|
||||
* Sourced from: http://stackoverflow.com/a/2117523/4949715
|
||||
* @return {string} A pseudo-random GUID.
|
||||
*/
|
||||
function guid() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a new XHR via GET.
|
||||
* @param {string} url The endpoint URL for the XHR.
|
||||
* @param {string} responseType Optional - how should the response be parsed.
|
||||
* Default is "json".
|
||||
* See: https://xhr.spec.whatwg.org/#dom-xmlhttprequest-responsetype
|
||||
* @return {Promise} A promise wrapping the success and error events.
|
||||
*/
|
||||
function xhrRequest(url, responseType) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = responseType || "json";
|
||||
|
||||
xhr.addEventListener("error", function() {
|
||||
reject(Error("Network Error"));
|
||||
});
|
||||
|
||||
xhr.addEventListener("load", function() {
|
||||
if (xhr.status != 200)
|
||||
return reject(Error(xhr.statusText));
|
||||
|
||||
resolve(xhr.response);
|
||||
});
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets attributes on a given DOM element.
|
||||
* @param {DOMElement} element The element on which to set the attributes.
|
||||
* @param {object} An object with keys (serving as attribute names) and values.
|
||||
*/
|
||||
function setAttributes(el, attrs) {
|
||||
attrs = attrs || {}
|
||||
for (var attr in attrs)
|
||||
el.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Binds to success and error events of an object wrapping them into a promise
|
||||
* available through {@code element.eventPromise}. The success event
|
||||
* resolves and error event rejects.
|
||||
* @param {object} element An object supporting events on which to bind the
|
||||
* promise.
|
||||
* @param {string} resolveEventName [="load"] The event name to bind resolve to.
|
||||
* @param {string} rejectEventName [="error"] The event name to bind reject to.
|
||||
*/
|
||||
function bindEvents(element, resolveEventName, rejectEventName) {
|
||||
element.eventPromise = new Promise(function(resolve, reject) {
|
||||
element.addEventListener(resolveEventName || "load", resolve);
|
||||
element.addEventListener(rejectEventName || "error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DOM element.
|
||||
* @param {string} tagName The type of the DOM element.
|
||||
* @param {object} attrs A JSON with attributes to apply to the element.
|
||||
* @param {DOMElement} parent Optional - an existing DOM element to append to
|
||||
* If not provided, the returned element will remain orphaned.
|
||||
* @param {boolean} doBindEvents Optional - Whether to bind to load and error
|
||||
* events and provide the promise wrapping the events via the element's
|
||||
* {@code eventPromise} property. Default value evaluates to false.
|
||||
* @return {DOMElement} The newly created DOM element.
|
||||
*/
|
||||
function createElement(tagName, attrs, parent, doBindEvents) {
|
||||
var element = document.createElement(tagName);
|
||||
|
||||
if (doBindEvents)
|
||||
bindEvents(element);
|
||||
|
||||
// We set the attributes after binding to events to catch any
|
||||
// event-triggering attribute changes. E.g. form submission.
|
||||
setAttributes(element, attrs);
|
||||
|
||||
if (parent)
|
||||
parent.appendChild(element);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function createRequestViaElement(tagName, attrs, parent) {
|
||||
return createElement(tagName, attrs, parent, true).eventPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty iframe and appends it to {@code document.body} .
|
||||
* @param {string} name The name and ID of the new iframe.
|
||||
* @param {boolean} doBindEvents Whether to bind load and error events.
|
||||
* @return {DOMElement} The newly created iframe.
|
||||
*/
|
||||
function createHelperIframe(name, doBindEvents) {
|
||||
return createElement("iframe",
|
||||
{"name": name, "id": name},
|
||||
document.body,
|
||||
doBindEvents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new iframe, binds load and error events, sets the src attribute and
|
||||
* appends it to {@code document.body} .
|
||||
* @param {string} url The src for the iframe.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaIframe(url) {
|
||||
return createRequestViaElement("iframe", {"src": url}, document.body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new image, binds load and error events, sets the src attribute and
|
||||
* appends it to {@code document.body} .
|
||||
* @param {string} url The src for the image.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaImage(url) {
|
||||
return createRequestViaElement("img", {"src": url}, document.body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a new XHR GET request to provided URL.
|
||||
* @param {string} url The endpoint URL for the XHR.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaXhr(url) {
|
||||
return xhrRequest(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a new GET request to provided URL via the Fetch API.
|
||||
* @param {string} url The endpoint URL for the Fetch.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaFetch(url) {
|
||||
return fetch(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Worker, binds message and error events wrapping them into.
|
||||
* {@code worker.eventPromise} and posts an empty string message to start
|
||||
* the worker.
|
||||
* @param {string} url The endpoint URL for the worker script.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaWorker(url) {
|
||||
var worker = new Worker(url);
|
||||
bindEvents(worker, "message", "error");
|
||||
worker.postMessage('');
|
||||
|
||||
return worker.eventPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the href attribute on a navigable DOM element and performs a navigation
|
||||
* by clicking it. To avoid navigating away from the current execution
|
||||
* context, a target attribute is set to point to a new helper iframe.
|
||||
* @param {DOMElement} navigableElement The navigable DOMElement
|
||||
* @param {string} url The href for the navigable element.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaNavigable(navigableElement, url) {
|
||||
var iframe = createHelperIframe(guid(), true);
|
||||
setAttributes(navigableElement,
|
||||
{"href": url,
|
||||
"target": iframe.name});
|
||||
navigableElement.click();
|
||||
|
||||
return iframe.eventPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new anchor element, appends it to {@code document.body} and
|
||||
* performs the navigation.
|
||||
* @param {string} url The URL to navigate to.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaAnchor(url) {
|
||||
var a = createElement("a", {"innerHTML": "Link to resource"}, document.body);
|
||||
|
||||
return requestViaNavigable(a, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new area element, appends it to {@code document.body} and performs
|
||||
* the navigation.
|
||||
* @param {string} url The URL to navigate to.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaArea(url) {
|
||||
var area = createElement("area", {}, document.body);
|
||||
|
||||
return requestViaNavigable(area, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new script element, sets the src to url, and appends it to
|
||||
* {@code document.body}.
|
||||
* @param {string} url The src URL.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaScript(url) {
|
||||
return createRequestViaElement("script", {"src": url}, document.body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new form element, sets attributes, appends it to
|
||||
* {@code document.body} and submits the form.
|
||||
* @param {string} url The URL to submit to.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaForm(url) {
|
||||
var iframe = createHelperIframe(guid());
|
||||
var form = createElement("form",
|
||||
{"action": url,
|
||||
"method": "POST",
|
||||
"target": iframe.name},
|
||||
document.body);
|
||||
bindEvents(iframe);
|
||||
form.submit();
|
||||
|
||||
return iframe.eventPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new link element for a stylesheet, binds load and error events,
|
||||
* sets the href to url and appends it to {@code document.head}.
|
||||
* @param {string} url The URL for a stylesheet.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaLinkStylesheet(url) {
|
||||
return createRequestViaElement("link",
|
||||
{"rel": "stylesheet", "href": url},
|
||||
document.head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new link element for a prefetch, binds load and error events, sets
|
||||
* the href to url and appends it to {@code document.head}.
|
||||
* @param {string} url The URL of a resource to prefetch.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaLinkPrefetch(url) {
|
||||
// TODO(kristijanburnik): Check if prefetch should support load and error
|
||||
// events. For now we assume it's not specified.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ
|
||||
return createRequestViaElement("link",
|
||||
{"rel": "prefetch", "href": url},
|
||||
document.head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new media element with a child source element, binds loadeddata and
|
||||
* error events, sets attributes and appends to document.body.
|
||||
* @param {string} type The type of the media element (audio/video/picture).
|
||||
* @param {object} media_attrs The attributes for the media element.
|
||||
* @param {object} source_attrs The attributes for the child source element.
|
||||
* @return {DOMElement} The newly created media element.
|
||||
*/
|
||||
function createMediaElement(type, media_attrs, source_attrs) {
|
||||
var mediaElement = createElement(type, {});
|
||||
var sourceElement = createElement("source", {}, mediaElement);
|
||||
|
||||
mediaElement.eventPromise = new Promise(function(resolve, reject) {
|
||||
mediaElement.addEventListener("loadeddata", resolve);
|
||||
// Notice that the source element will raise the error.
|
||||
sourceElement.addEventListener("error", reject);
|
||||
});
|
||||
|
||||
setAttributes(mediaElement, media_attrs);
|
||||
setAttributes(sourceElement, source_attrs);
|
||||
document.body.appendChild(mediaElement);
|
||||
|
||||
return mediaElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new video element, binds loadeddata and error events, sets
|
||||
* attributes and source URL and appends to {@code document.body}.
|
||||
* @param {string} url The URL of the video.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaVideo(url) {
|
||||
return createMediaElement("video",
|
||||
{},
|
||||
{type: "video/mp4", src: url}).eventPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new audio element, binds loadeddata and error events, sets
|
||||
* attributes and source URL and appends to {@code document.body}.
|
||||
* @param {string} url The URL of the audio.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaAudio(url) {
|
||||
return createMediaElement("audio",
|
||||
{},
|
||||
{type: "audio/mpeg", src: url}).eventPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new picture element, binds loadeddata and error events, sets
|
||||
* attributes and source URL and appends to {@code document.body}. Also
|
||||
* creates new image element appending it to the picture
|
||||
* @param {string} url The URL of the image for the source and image elements.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaPicture(url) {
|
||||
var picture = createMediaElement("picture", {}, {"srcset": url,
|
||||
"type": "image/png"});
|
||||
return createRequestViaElement("img", {"src": url}, picture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object element, binds load and error events, sets the data to
|
||||
* url, and appends it to {@code document.body}.
|
||||
* @param {string} url The data URL.
|
||||
* @return {Promise} The promise for success/error events.
|
||||
*/
|
||||
function requestViaObject(url) {
|
||||
return createRequestViaElement("object", {"data": url}, document.body);
|
||||
}
|
||||
|
||||
// SanityChecker does nothing in release mode. See sanity-checker.js for debug
|
||||
// mode.
|
||||
function SanityChecker() {}
|
||||
SanityChecker.prototype.checkScenario = function() {};
|
101
tests/wpt/web-platform-tests/mixed-content/generic/expect.py
Normal file
101
tests/wpt/web-platform-tests/mixed-content/generic/expect.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
import json, os, urllib, urlparse
|
||||
|
||||
def redirect(url, response):
|
||||
response.add_required_headers = False
|
||||
response.writer.write_status(301)
|
||||
response.writer.write_header("access-control-allow-origin", "*")
|
||||
response.writer.write_header("location", url)
|
||||
response.writer.end_headers()
|
||||
response.writer.write("")
|
||||
|
||||
def create_redirect_url(request, swap_scheme = False):
|
||||
parsed = urlparse.urlsplit(request.url)
|
||||
destination_netloc = parsed.netloc
|
||||
scheme = parsed.scheme
|
||||
|
||||
if swap_scheme:
|
||||
scheme = "http" if parsed.scheme == "https" else "https"
|
||||
hostname = parsed.netloc.split(':')[0]
|
||||
port = request.server.config["ports"][scheme][0]
|
||||
destination_netloc = ":".join([hostname, str(port)])
|
||||
|
||||
# Remove "redirection" from query to avoid redirect loops.
|
||||
parsed_query = dict(urlparse.parse_qsl(parsed.query))
|
||||
assert "redirection" in parsed_query
|
||||
del parsed_query["redirection"]
|
||||
|
||||
destination_url = urlparse.urlunsplit(urlparse.SplitResult(
|
||||
scheme = scheme,
|
||||
netloc = destination_netloc,
|
||||
path = parsed.path,
|
||||
query = urllib.urlencode(parsed_query),
|
||||
fragment = None))
|
||||
|
||||
return destination_url
|
||||
|
||||
def main(request, response):
|
||||
if "redirection" in request.GET:
|
||||
redirection = request.GET["redirection"]
|
||||
if redirection == "no-redirect":
|
||||
pass
|
||||
elif redirection == "keep-scheme-redirect":
|
||||
redirect(create_redirect_url(request, swap_scheme=False), response)
|
||||
return
|
||||
elif redirection == "swap-scheme-redirect":
|
||||
redirect(create_redirect_url(request, swap_scheme=True), response)
|
||||
return
|
||||
else:
|
||||
raise ValueError ("Invalid redirect type: %s" % redirection)
|
||||
|
||||
content_type = "text/plain"
|
||||
response_data = ""
|
||||
|
||||
if "action" in request.GET:
|
||||
action = request.GET["action"]
|
||||
|
||||
if "content_type" in request.GET:
|
||||
content_type = request.GET["content_type"]
|
||||
|
||||
key = request.GET["key"]
|
||||
stash = request.server.stash
|
||||
|
||||
if action == "put":
|
||||
value = request.GET["value"]
|
||||
stash.take(key=key)
|
||||
stash.put(key=key, value=value)
|
||||
response_data = json.dumps({"status": "success", "result": key})
|
||||
elif action == "purge":
|
||||
value = stash.take(key=key)
|
||||
if content_type == "image/png":
|
||||
response_data = open(os.path.join(request.doc_root,
|
||||
"images",
|
||||
"smiley.png")).read()
|
||||
elif content_type == "audio/mpeg":
|
||||
response_data = open(os.path.join(request.doc_root,
|
||||
"media",
|
||||
"sound_5.oga")).read()
|
||||
elif content_type == "video/mp4":
|
||||
response_data = open(os.path.join(request.doc_root,
|
||||
"media",
|
||||
"movie_5.mp4")).read()
|
||||
elif content_type == "application/javascript":
|
||||
response_data = open(os.path.join(request.doc_root,
|
||||
"mixed-content",
|
||||
"generic",
|
||||
"worker.js")).read()
|
||||
else:
|
||||
response_data = "/* purged */"
|
||||
elif action == "take":
|
||||
value = stash.take(key=key)
|
||||
if value is None:
|
||||
status = "allowed"
|
||||
else:
|
||||
status = "blocked"
|
||||
response_data = json.dumps({"status": status, "result": value})
|
||||
|
||||
response.add_required_headers = False
|
||||
response.writer.write_status(200)
|
||||
response.writer.write_header("content-type", content_type)
|
||||
response.writer.write_header("cache-control", "no-cache; must-revalidate")
|
||||
response.writer.end_headers()
|
||||
response.writer.write(response_data)
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* @fileoverview Test case for mixed-content in Web Platform Tests.
|
||||
* @author burnik@google.com (Kristijan Burnik)
|
||||
*/
|
||||
|
||||
/**
|
||||
* MixedContentTestCase exercises all the tests for checking browser behavior
|
||||
* when resources regarded as mixed-content are requested. A single run covers
|
||||
* only a single scenario.
|
||||
* @param {object} scenario A JSON describing the test arrangement and
|
||||
* expectation(s). Refer to /mixed-content/spec.src.json for details.
|
||||
* @param {string} description The test scenario verbose description.
|
||||
* @param {SanityChecker} sanityChecker Instance of an object used to check the
|
||||
* running scenario. Useful in debug mode. See ./sanity-checker.js.
|
||||
* Run {@code ./tools/generate.py -h} for info on test generating modes.
|
||||
* @return {object} Object wrapping the start method used to run the test.
|
||||
*/
|
||||
function MixedContentTestCase(scenario, description, sanityChecker) {
|
||||
var insecureProtocol = "http";
|
||||
var secureProtocol = "https";
|
||||
|
||||
var sameOriginHost = location.hostname;
|
||||
var crossOriginHost = "{{domains[www1]}}";
|
||||
|
||||
// These values can evaluate to either empty strings or a ":port" string.
|
||||
var insecurePort = getNormalizedPort(parseInt("{{ports[http][0]}}", 10));
|
||||
var securePort = getNormalizedPort(parseInt("{{ports[https][0]}}", 10));
|
||||
|
||||
var resourcePath = "/mixed-content/generic/expect.py";
|
||||
|
||||
// Map all endpoints to scenario for use in the test.
|
||||
var endpoint = {
|
||||
"same-origin":
|
||||
location.origin + resourcePath,
|
||||
"same-host-https":
|
||||
secureProtocol + "://" + sameOriginHost + securePort + resourcePath,
|
||||
"same-host-http":
|
||||
insecureProtocol + "://" + sameOriginHost + insecurePort + resourcePath,
|
||||
"cross-origin-https":
|
||||
secureProtocol + "://" + crossOriginHost + securePort + resourcePath,
|
||||
"cross-origin-http":
|
||||
insecureProtocol + "://" + crossOriginHost + insecurePort + resourcePath
|
||||
};
|
||||
|
||||
// Mapping all the resource requesting methods to the scenario.
|
||||
var resourceMap = {
|
||||
"a-tag": requestViaAnchor,
|
||||
"area-tag": requestViaArea,
|
||||
"fetch-request": requestViaFetch,
|
||||
"form-tag": requestViaForm,
|
||||
"iframe-tag": requestViaIframe,
|
||||
"img-tag": requestViaImage,
|
||||
"script-tag": requestViaScript,
|
||||
"worker-request": requestViaWorker,
|
||||
"xhr-request": requestViaXhr,
|
||||
"audio-tag": requestViaAudio,
|
||||
"video-tag": requestViaVideo,
|
||||
"picture-tag": requestViaPicture,
|
||||
"object-tag": requestViaObject,
|
||||
"link-css-tag": requestViaLinkStylesheet,
|
||||
"link-prefetch-tag": requestViaLinkPrefetch
|
||||
};
|
||||
|
||||
sanityChecker.checkScenario(scenario, resourceMap);
|
||||
|
||||
// Mapping all expected MIME types to the scenario.
|
||||
var contentType = {
|
||||
"a-tag": "text/html",
|
||||
"area-tag": "text/html",
|
||||
"fetch-request": "application/json",
|
||||
"form-tag": "text/html",
|
||||
"iframe-tag": "text/html",
|
||||
"img-tag": "image/png",
|
||||
"script-tag": "text/javascript",
|
||||
"worker-request": "application/javascript",
|
||||
"xhr-request": "application/json",
|
||||
"audio-tag": "audio/mpeg",
|
||||
"video-tag": "video/mp4",
|
||||
"picture-tag": "image/png",
|
||||
"object-tag": "text/html",
|
||||
"link-css-tag": "text/css",
|
||||
"link-prefetch-tag": "text/html"
|
||||
};
|
||||
|
||||
var mixed_content_test = async_test(description);
|
||||
|
||||
function runTest() {
|
||||
var testCompleted = false;
|
||||
|
||||
// Due to missing implementations, tests time out, so we fail them early.
|
||||
// TODO(kristijanburnik): Once WPT rolled in:
|
||||
// https://github.com/w3c/testharness.js/pull/127
|
||||
// Refactor to make use of step_timeout.
|
||||
setTimeout(function() {
|
||||
mixed_content_test.step(function() {
|
||||
assert_true(testCompleted, "Expected test to complete.");
|
||||
mixed_content_test.done();
|
||||
})
|
||||
}, 1000);
|
||||
|
||||
var key = guid();
|
||||
var value = guid();
|
||||
var announceResourceRequestUrl = endpoint['same-origin'] +
|
||||
"?action=put&key=" + key +
|
||||
"&value=" + value;
|
||||
var assertResourceRequestUrl = endpoint['same-origin'] +
|
||||
"?action=take&key=" + key;
|
||||
var resourceRequestUrl = endpoint[scenario.origin] + "?redirection=" +
|
||||
scenario.redirection + "&action=purge&key=" +
|
||||
key + "&content_type=" +
|
||||
contentType[scenario.subresource];
|
||||
|
||||
xhrRequest(announceResourceRequestUrl)
|
||||
.then(function(response) {
|
||||
// Send out the real resource request.
|
||||
// This should tear down the key if it's not blocked.
|
||||
return resourceMap[scenario.subresource](resourceRequestUrl);
|
||||
})
|
||||
.then(function() {
|
||||
mixed_content_test.step(function() {
|
||||
assert_equals("allowed", scenario.expectation,
|
||||
"The triggered event should match '" +
|
||||
scenario.expectation + "'.");
|
||||
}, "Check if success event was triggered.");
|
||||
|
||||
// Send request to check if the key has been torn down.
|
||||
return xhrRequest(assertResourceRequestUrl);
|
||||
}, function(error) {
|
||||
mixed_content_test.step(function() {
|
||||
assert_equals("blocked", scenario.expectation,
|
||||
"The triggered event should match '" +
|
||||
scenario.expectation + "'.");
|
||||
// TODO(kristijanburnik): param "error" can be an event or error.
|
||||
// Map assertion by resource.
|
||||
// e.g.: assert_equals(e.type, "error");
|
||||
}, "Check if error event was triggered.");
|
||||
|
||||
// When requestResource fails, we also check the key state.
|
||||
return xhrRequest(assertResourceRequestUrl);
|
||||
})
|
||||
.then(function(response) {
|
||||
// Now check if the value has been torn down. If it's still there,
|
||||
// we have blocked the request to mixed-content.
|
||||
mixed_content_test.step(function() {
|
||||
assert_equals(response.status, scenario.expectation,
|
||||
"The resource request should be '" + scenario.expectation +
|
||||
"'.");
|
||||
}, "Check if request was sent.");
|
||||
mixed_content_test.done();
|
||||
testCompleted = true;
|
||||
});
|
||||
|
||||
} // runTest
|
||||
|
||||
return {start: runTest};
|
||||
} // MixedContentTestCase
|
|
@ -0,0 +1,38 @@
|
|||
// The SanityChecker is used in debug mode to identify problems with the
|
||||
// structure of the testsuite. In release mode it is mocked out to do nothing.
|
||||
|
||||
function SanityChecker() {}
|
||||
|
||||
SanityChecker.prototype.checkScenario = function(scenario, resourceInvoker) {
|
||||
// Check if scenario is valid.
|
||||
test(function() {
|
||||
var expectedFields = SPEC_JSON["test_expansion_schema"];
|
||||
|
||||
for (var field in expectedFields) {
|
||||
if (field == "expansion")
|
||||
continue
|
||||
|
||||
assert_own_property(scenario, field,
|
||||
"The scenario should contain field '" + field + "'.")
|
||||
|
||||
var expectedFieldList = expectedFields[field];
|
||||
if (!expectedFieldList.hasOwnProperty('length')) {
|
||||
var expectedFieldList = [];
|
||||
for (var key in expectedFields[field]) {
|
||||
expectedFieldList = expectedFieldList.concat(expectedFields[field][key])
|
||||
}
|
||||
}
|
||||
assert_in_array(scenario[field], expectedFieldList,
|
||||
"Scenario's " + field + " is one of: " +
|
||||
expectedFieldList.join(", ")) + "."
|
||||
}
|
||||
|
||||
// Check if the protocol is matched.
|
||||
assert_equals(scenario["source_scheme"] + ":", location.protocol,
|
||||
"Protocol of the test page should match the scenario.")
|
||||
|
||||
assert_own_property(resourceInvoker, scenario.subresource,
|
||||
"Subresource should be supported");
|
||||
|
||||
}, "[MixedContentTestCase] The test scenario should be valid.");
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<!-- DO NOT EDIT! Generated by %(generating_script_filename)s using %(html_template_filename)s. -->
|
|
@ -0,0 +1 @@
|
|||
var SPEC_JSON = %(spec_json)s;
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
%(generated_disclaimer)s
|
||||
<html>
|
||||
<head>
|
||||
<title>Mixed-Content: %(spec_title)s</title>
|
||||
<meta charset='utf-8'>
|
||||
<meta name="description" content="%(spec_description)s">
|
||||
<meta name="assert" content="%(test_description)s">%(meta_opt_in)s
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<!-- Common global functions for mixed-content tests. -->
|
||||
<script src="/mixed-content/generic/common.js"></script>
|
||||
<!-- The original specification JSON for validating the scenario. -->
|
||||
<script src="/mixed-content/spec_json.js"></script>
|
||||
<!-- Internal checking of the tests -->
|
||||
<script src="/mixed-content/generic/sanity-checker.js"></script>
|
||||
<!-- Simple wrapper API for all mixed-content test cases. -->
|
||||
<script src="/mixed-content/generic/mixed-content-test-case.js?pipe=sub"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>%(spec_title)s</h1>
|
||||
<h2>%(spec_description)s</h2>
|
||||
<pre>%(test_description)s</pre>
|
||||
|
||||
<p>See <a href="%(spec_specification_url)s" target="_blank">specification</a>
|
||||
details for this test.</p>
|
||||
|
||||
<div id="log"></div>
|
||||
<script>%(test_js)s</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
MixedContentTestCase(
|
||||
{
|
||||
"opt_in_method": "%(opt_in_method)s",
|
||||
"origin": "%(origin)s",
|
||||
"source_scheme": "%(source_scheme)s",
|
||||
"context_nesting": "%(context_nesting)s",
|
||||
"redirection": "%(redirection)s",
|
||||
"subresource": "%(subresource)s",
|
||||
"expectation": "%(expectation)s"
|
||||
},
|
||||
document.querySelector("meta[name=assert]").content,
|
||||
new SanityChecker()
|
||||
).start();
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
%(generated_disclaimer)s
|
||||
<html>
|
||||
<head>
|
||||
<title>Mixed-Content: %(spec_title)s</title>
|
||||
<meta charset='utf-8'>
|
||||
<meta name="description" content="%(spec_description)s">
|
||||
<link rel="author" title="Kristijan Burnik" href="burnik@chromium.org">
|
||||
<link rel="help" href="%(spec_specification_url)s">
|
||||
<meta name="assert" content="%(test_description)s">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/mixed-content/generic/common.js"></script>
|
||||
<script src="/mixed-content/generic/mixed-content-test-case.js?pipe=sub"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>%(test_js)s</script>
|
||||
<div id="log"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
opt_in_method: %(opt_in_method)s
|
||||
origin: %(origin)s
|
||||
source_scheme: %(source_scheme)s
|
||||
context_nesting: %(context_nesting)s
|
||||
redirection: %(redirection)s
|
||||
subresource: %(subresource)s
|
||||
expectation: %(expectation)s
|
35
tests/wpt/web-platform-tests/mixed-content/generic/tools/clean.py
Executable file
35
tests/wpt/web-platform-tests/mixed-content/generic/tools/clean.py
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, json
|
||||
from common_paths import *
|
||||
import spec_validator
|
||||
|
||||
def rmtree(top):
|
||||
top = os.path.abspath(top)
|
||||
assert top != os.path.expanduser("~")
|
||||
assert len(top) > len(os.path.expanduser("~"))
|
||||
assert "web-platform-tests" in top
|
||||
assert "mixed-content" in top
|
||||
|
||||
for root, dirs, files in os.walk(top, topdown=False):
|
||||
for name in files:
|
||||
os.remove(os.path.join(root, name))
|
||||
for name in dirs:
|
||||
os.rmdir(os.path.join(root, name))
|
||||
|
||||
os.rmdir(top)
|
||||
|
||||
def main():
|
||||
spec_json = load_spec_json();
|
||||
spec_validator.assert_valid_spec_json(spec_json)
|
||||
|
||||
for spec in spec_json['specification']:
|
||||
generated_dir = os.path.join(spec_directory, spec["name"])
|
||||
if (os.path.isdir(generated_dir)):
|
||||
rmtree(generated_dir)
|
||||
|
||||
if (os.path.isfile(generated_spec_json_filename)):
|
||||
os.remove(generated_spec_json_filename)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,58 @@
|
|||
import os, sys, json, re
|
||||
|
||||
script_directory = os.path.dirname(os.path.abspath(__file__))
|
||||
generic_directory = os.path.abspath(os.path.join(script_directory, '..'))
|
||||
|
||||
template_directory = os.path.abspath(os.path.join(script_directory,
|
||||
'..',
|
||||
'template'))
|
||||
spec_directory = os.path.abspath(os.path.join(script_directory, '..', '..'))
|
||||
test_root_directory = os.path.abspath(os.path.join(script_directory,
|
||||
'..', '..', '..'))
|
||||
|
||||
spec_filename = os.path.join(spec_directory, "spec.src.json")
|
||||
generated_spec_json_filename = os.path.join(spec_directory, "spec_json.js")
|
||||
|
||||
selection_pattern = '%(opt_in_method)s/' + \
|
||||
'%(origin)s/' + \
|
||||
'%(subresource)s/' + \
|
||||
'%(context_nesting)s/' + \
|
||||
'%(redirection)s/'
|
||||
|
||||
test_file_path_pattern = '%(spec_name)s/' + selection_pattern + \
|
||||
'%(name)s.%(source_scheme)s.html'
|
||||
|
||||
|
||||
def get_template(basename):
|
||||
with open(os.path.join(template_directory, basename)) as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def write_file(filename, contents):
|
||||
with open(filename, "w") as f:
|
||||
f.write(contents)
|
||||
|
||||
|
||||
def read_nth_line(fp, line_number):
|
||||
fp.seek(0)
|
||||
for i, line in enumerate(fp):
|
||||
if (i + 1) == line_number:
|
||||
return line
|
||||
|
||||
|
||||
def load_spec_json(path_to_spec = None):
|
||||
if path_to_spec is None:
|
||||
path_to_spec = spec_filename
|
||||
|
||||
re_error_location = re.compile('line ([0-9]+) column ([0-9]+)')
|
||||
with open(path_to_spec) as f:
|
||||
try:
|
||||
return json.load(f)
|
||||
except ValueError, ex:
|
||||
print ex.message
|
||||
match = re_error_location.search(ex.message)
|
||||
if match:
|
||||
line_number, column = int(match.group(1)), int(match.group(2))
|
||||
print read_nth_line(f, line_number).rstrip()
|
||||
print " " * (column - 1) + "^"
|
||||
sys.exit(1)
|
157
tests/wpt/web-platform-tests/mixed-content/generic/tools/generate.py
Executable file
157
tests/wpt/web-platform-tests/mixed-content/generic/tools/generate.py
Executable file
|
@ -0,0 +1,157 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os, sys, json
|
||||
from common_paths import *
|
||||
import spec_validator
|
||||
import argparse
|
||||
|
||||
|
||||
def expand_pattern(expansion_pattern, test_expansion_schema):
|
||||
expansion = {}
|
||||
for artifact_key in expansion_pattern:
|
||||
artifact_value = expansion_pattern[artifact_key]
|
||||
if artifact_value == '*':
|
||||
expansion[artifact_key] = test_expansion_schema[artifact_key]
|
||||
elif isinstance(artifact_value, list):
|
||||
expansion[artifact_key] = artifact_value
|
||||
elif isinstance(artifact_value, dict):
|
||||
# Flattened expansion.
|
||||
expansion[artifact_key] = []
|
||||
values_dict = expand_pattern(artifact_value,
|
||||
test_expansion_schema[artifact_key])
|
||||
for sub_key in values_dict.keys():
|
||||
expansion[artifact_key] += values_dict[sub_key]
|
||||
else:
|
||||
expansion[artifact_key] = [artifact_value]
|
||||
|
||||
return expansion
|
||||
|
||||
|
||||
def permute_expansion(expansion, artifact_order, selection = {}, artifact_index = 0):
|
||||
assert isinstance(artifact_order, list), "artifact_order should be a list"
|
||||
|
||||
if artifact_index >= len(artifact_order):
|
||||
yield selection
|
||||
return
|
||||
|
||||
artifact_key = artifact_order[artifact_index]
|
||||
|
||||
for artifact_value in expansion[artifact_key]:
|
||||
selection[artifact_key] = artifact_value
|
||||
for next_selection in permute_expansion(expansion,
|
||||
artifact_order,
|
||||
selection,
|
||||
artifact_index + 1):
|
||||
yield next_selection
|
||||
|
||||
|
||||
def generate_selection(selection, spec, test_html_template_basename):
|
||||
selection['spec_name'] = spec['name']
|
||||
selection['spec_title'] = spec['title']
|
||||
selection['spec_description'] = spec['description']
|
||||
selection['spec_specification_url'] = spec['specification_url']
|
||||
|
||||
test_filename = test_file_path_pattern % selection
|
||||
test_headers_filename = test_filename + ".headers"
|
||||
test_directory = os.path.dirname(test_filename)
|
||||
full_path = os.path.join(spec_directory, test_directory)
|
||||
|
||||
test_html_template = get_template(test_html_template_basename)
|
||||
test_js_template = get_template("test.js.template")
|
||||
disclaimer_template = get_template('disclaimer.template')
|
||||
test_description_template = get_template("test_description.template")
|
||||
|
||||
html_template_filename = os.path.join(template_directory,
|
||||
test_html_template_basename)
|
||||
generated_disclaimer = disclaimer_template \
|
||||
% {'generating_script_filename': os.path.relpath(__file__,
|
||||
test_root_directory),
|
||||
'html_template_filename': os.path.relpath(html_template_filename,
|
||||
test_root_directory)}
|
||||
|
||||
selection['generated_disclaimer'] = generated_disclaimer.rstrip()
|
||||
test_description_template = \
|
||||
test_description_template.rstrip().replace("\n", "\n" + " " * 33)
|
||||
selection['test_description'] = test_description_template % selection
|
||||
|
||||
# Adjust the template for the test invoking JS. Indent it to look nice.
|
||||
indent = "\n" + " " * 6;
|
||||
test_js_template = indent + test_js_template.replace("\n", indent);
|
||||
selection['test_js'] = test_js_template % selection
|
||||
|
||||
# Directory for the test files.
|
||||
try:
|
||||
os.makedirs(full_path)
|
||||
except:
|
||||
pass
|
||||
|
||||
# TODO(kristijanburnik): Implement the opt-in-method here.
|
||||
opt_in_method = selection['opt_in_method']
|
||||
selection['meta_opt_in'] = ''
|
||||
if opt_in_method == 'meta-csp':
|
||||
selection['meta_opt_in'] = '<meta http-equiv="Content-Security-Policy" ' + \
|
||||
'content="block-all-mixed-content">'
|
||||
elif opt_in_method == 'http-csp':
|
||||
opt_in_headers = "Content-Security-Policy: block-all-mixed-content\n"
|
||||
write_file(test_headers_filename, opt_in_headers)
|
||||
elif opt_in_method == 'no-opt-in':
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Invalid opt_in_method %s" % opt_in_method)
|
||||
|
||||
# Write out the generated HTML file.
|
||||
write_file(test_filename, test_html_template % selection)
|
||||
|
||||
def generate_test_source_files(spec_json, target):
|
||||
test_expansion_schema = spec_json['test_expansion_schema']
|
||||
specification = spec_json['specification']
|
||||
|
||||
spec_json_js_template = get_template('spec_json.js.template')
|
||||
write_file(generated_spec_json_filename,
|
||||
spec_json_js_template % {'spec_json': json.dumps(spec_json)})
|
||||
|
||||
# Choose a debug/release template depending on the target.
|
||||
html_template = "test.%s.html.template" % target
|
||||
|
||||
artifact_order = test_expansion_schema.keys() + ['name']
|
||||
|
||||
# Create list of excluded tests.
|
||||
exclusion_dict = {}
|
||||
for excluded_pattern in spec_json['excluded_tests']:
|
||||
excluded_expansion = \
|
||||
expand_pattern(excluded_pattern,
|
||||
test_expansion_schema)
|
||||
for excluded_selection in permute_expansion(excluded_expansion, artifact_order):
|
||||
excluded_selection_path = selection_pattern % excluded_selection
|
||||
exclusion_dict[excluded_selection_path] = True
|
||||
|
||||
for spec in specification:
|
||||
for expansion_pattern in spec['test_expansion']:
|
||||
expansion = expand_pattern(expansion_pattern,
|
||||
test_expansion_schema)
|
||||
for selection in permute_expansion(expansion, artifact_order):
|
||||
selection_path = selection_pattern % selection
|
||||
if not selection_path in exclusion_dict:
|
||||
generate_selection(selection,
|
||||
spec,
|
||||
html_template)
|
||||
else:
|
||||
print 'Excluding selection:', selection_path
|
||||
|
||||
|
||||
def main(target, spec_filename):
|
||||
spec_json = load_spec_json(spec_filename);
|
||||
spec_validator.assert_valid_spec_json(spec_json)
|
||||
generate_test_source_files(spec_json, target)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Test suite generator utility')
|
||||
parser.add_argument('-t', '--target', type = str,
|
||||
choices = ("release", "debug"), default = "release",
|
||||
help = 'Sets the appropriate template for generating tests')
|
||||
parser.add_argument('-s', '--spec', type = str, default = None,
|
||||
help = 'Specify a file used for describing and generating the tests')
|
||||
# TODO(kristijanburnik): Add option for the spec_json file.
|
||||
args = parser.parse_args()
|
||||
main(args.target, args.spec)
|
3
tests/wpt/web-platform-tests/mixed-content/generic/tools/regenerate
Executable file
3
tests/wpt/web-platform-tests/mixed-content/generic/tools/regenerate
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
python $DIR/clean.py && python $DIR/generate.py
|
159
tests/wpt/web-platform-tests/mixed-content/generic/tools/spec_validator.py
Executable file
159
tests/wpt/web-platform-tests/mixed-content/generic/tools/spec_validator.py
Executable file
|
@ -0,0 +1,159 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import json, sys
|
||||
from common_paths import *
|
||||
|
||||
def assert_non_empty_string(obj, field):
|
||||
assert field in obj, 'Missing field "%s"' % field
|
||||
assert isinstance(obj[field], basestring), \
|
||||
'Field "%s" must be a string' % field
|
||||
assert len(obj[field]) > 0, 'Field "%s" must not be empty' % field
|
||||
|
||||
|
||||
def assert_non_empty_list(obj, field):
|
||||
assert isinstance(obj[field], list), \
|
||||
'%s must be a list' % field
|
||||
assert len(obj[field]) > 0, \
|
||||
'%s list must not be empty' % field
|
||||
|
||||
|
||||
def assert_non_empty_dict(obj, field):
|
||||
assert isinstance(obj[field], dict), \
|
||||
'%s must be a dict' % field
|
||||
assert len(obj[field]) > 0, \
|
||||
'%s dict must not be empty' % field
|
||||
|
||||
|
||||
def assert_contains(obj, field):
|
||||
assert field in obj, 'Must contain field "%s"' % field
|
||||
|
||||
|
||||
def assert_string_from(obj, field, items):
|
||||
assert obj[field] in items, \
|
||||
'Field "%s" must be from: %s' % (field, str(items))
|
||||
|
||||
|
||||
def assert_string_or_list_items_from(obj, field, items):
|
||||
if isinstance(obj[field], basestring):
|
||||
assert_string_from(obj, field, items)
|
||||
return
|
||||
|
||||
assert isinstance(obj[field], list), "%s must be a list!" % field
|
||||
for allowed_value in obj[field]:
|
||||
assert allowed_value != '*', "Wildcard is not supported for lists!"
|
||||
assert allowed_value in items, \
|
||||
'Field "%s" must be from: %s' % (field, str(items))
|
||||
|
||||
|
||||
def assert_contains_only_fields(obj, expected_fields):
|
||||
for expected_field in expected_fields:
|
||||
assert_contains(obj, expected_field)
|
||||
|
||||
for actual_field in obj:
|
||||
assert actual_field in expected_fields, \
|
||||
'Unexpected field "%s".' % actual_field
|
||||
|
||||
|
||||
def assert_value_unique_in(value, used_values):
|
||||
assert value not in used_values, 'Duplicate value "%s"!' % str(value)
|
||||
used_values[value] = True
|
||||
|
||||
|
||||
def assert_valid_artifact(exp_pattern, artifact_key, schema):
|
||||
if isinstance(schema, list):
|
||||
assert_string_or_list_items_from(exp_pattern, artifact_key,
|
||||
["*"] + schema)
|
||||
return
|
||||
|
||||
for sub_artifact_key, sub_schema in schema.iteritems():
|
||||
assert_valid_artifact(exp_pattern[artifact_key], sub_artifact_key,
|
||||
sub_schema)
|
||||
|
||||
def validate(spec_json, details):
|
||||
""" Validates the json specification for generating tests. """
|
||||
|
||||
details['object'] = spec_json
|
||||
assert_contains_only_fields(spec_json, ["specification",
|
||||
"test_expansion_schema",
|
||||
"excluded_tests"])
|
||||
assert_non_empty_list(spec_json, "specification")
|
||||
assert_non_empty_dict(spec_json, "test_expansion_schema")
|
||||
assert_non_empty_list(spec_json, "excluded_tests")
|
||||
|
||||
specification = spec_json['specification']
|
||||
test_expansion_schema = spec_json['test_expansion_schema']
|
||||
excluded_tests = spec_json['excluded_tests']
|
||||
|
||||
valid_test_expansion_fields = ['name'] + test_expansion_schema.keys()
|
||||
|
||||
# Validate each single spec.
|
||||
for spec in specification:
|
||||
details['object'] = spec
|
||||
|
||||
# Validate required fields for a single spec.
|
||||
assert_contains_only_fields(spec, ['name',
|
||||
'title',
|
||||
'description',
|
||||
'specification_url',
|
||||
'test_expansion'])
|
||||
assert_non_empty_string(spec, 'name')
|
||||
assert_non_empty_string(spec, 'title')
|
||||
assert_non_empty_string(spec, 'description')
|
||||
assert_non_empty_string(spec, 'specification_url')
|
||||
assert_non_empty_list(spec, 'test_expansion')
|
||||
|
||||
# Validate spec's test expansion.
|
||||
used_spec_names = {}
|
||||
|
||||
for spec_exp in spec['test_expansion']:
|
||||
details['object'] = spec_exp
|
||||
assert_non_empty_string(spec_exp, 'name')
|
||||
# The name is unique in same expansion group.
|
||||
assert_value_unique_in((spec_exp['expansion'], spec_exp['name']),
|
||||
used_spec_names)
|
||||
assert_contains_only_fields(spec_exp, valid_test_expansion_fields)
|
||||
|
||||
for artifact in test_expansion_schema:
|
||||
details['test_expansion_field'] = artifact
|
||||
assert_valid_artifact(spec_exp, artifact,
|
||||
test_expansion_schema[artifact])
|
||||
del details['test_expansion_field']
|
||||
|
||||
# Validate the test_expansion schema members.
|
||||
details['object'] = test_expansion_schema
|
||||
assert_contains_only_fields(test_expansion_schema, ['expansion',
|
||||
'source_scheme',
|
||||
'opt_in_method',
|
||||
'context_nesting',
|
||||
'redirection',
|
||||
'subresource',
|
||||
'origin',
|
||||
'expectation'])
|
||||
# Validate excluded tests.
|
||||
details['object'] = excluded_tests
|
||||
for excluded_test_expansion in excluded_tests:
|
||||
assert_contains_only_fields(excluded_test_expansion,
|
||||
valid_test_expansion_fields)
|
||||
|
||||
|
||||
del details['object']
|
||||
|
||||
|
||||
def assert_valid_spec_json(spec_json):
|
||||
error_details = {}
|
||||
try:
|
||||
validate(spec_json, error_details)
|
||||
except AssertionError, err:
|
||||
print 'ERROR:', err.message
|
||||
print json.dumps(error_details, indent=4)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
spec_json = load_spec_json();
|
||||
assert_valid_spec_json(spec_json)
|
||||
print "Spec JSON is valid."
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1 @@
|
|||
postMessage('done');
|
Loading…
Add table
Add a link
Reference in a new issue