From 56b0ccf0ff8307851c34d492584497424f794202 Mon Sep 17 00:00:00 2001 From: Kristijan Burnik Date: Fri, 22 May 2015 13:29:38 +0200 Subject: [PATCH] Referrer-Policy: Debug/Release mode for test templates and sanity checks. --- referrer-policy/README.md | 23 +++++++- referrer-policy/generic/common.js | 40 +++++++------- .../generic/referrer-policy-test-case.js | 51 +++--------------- referrer-policy/generic/sanity-checker.js | 52 +++++++++++++++++++ .../generic/template/document.html.template | 6 --- .../generic/template/script.js.template | 1 - ...html.template => test.debug.html.template} | 37 ++++++------- .../generic/template/test.js.template | 14 +++++ .../template/test.release.html.template | 23 ++++++++ referrer-policy/generic/tools/generate.py | 38 +++++++++++--- 10 files changed, 183 insertions(+), 102 deletions(-) create mode 100644 referrer-policy/generic/sanity-checker.js rename referrer-policy/generic/template/{test.html.template => test.debug.html.template} (58%) create mode 100644 referrer-policy/generic/template/test.js.template create mode 100644 referrer-policy/generic/template/test.release.html.template diff --git a/referrer-policy/README.md b/referrer-policy/README.md index 373f259c6d0f55..eb85de96e4301b 100644 --- a/referrer-policy/README.md +++ b/referrer-policy/README.md @@ -27,12 +27,16 @@ The ```spec.src.json``` defines all the test scenarios for the referrer policy. Invoking ```./generic/tools/generate.py``` will parse the spec JSON and determine which tests to generate (or skip) while using templates. + The spec can be validated by running ```./generic/tools/spec_validator.py```. This is specially important when you're making changes to ```spec.src.json```. Make sure it's a valid JSON (no comments or trailing commas). The validator should be informative and very specific on any issues. For details about the spec JSON, see **Overview of the spec JSON** below. -## Generating the tests +## Generating and running the tests + +The repository already contains generated tests, so if you're making changes, +see the **Removing all generated tests** section below, on how to remove them before you start generating tests which include your changes. Start from the command line: @@ -58,6 +62,18 @@ Run tests under path: ```/referrer-policy```. Click start. + +## Options for generating tests + +The generator script ```./generic/tools/generate.py``` has two targets: ```release``` and ```debug```. + +* Using **release** for the target will produce tests using a template for optimizing size and performance. The release template is intended for the official web-platform-tests and possibly other test suites. No sanity checking is done in release mode. Use this option whenever you're checking into web-platform-tests. + +* When generating for ```debug```, the produced tests will contain more verbosity and sanity checks. Use this target to identify problems with the test suite when making changes locally. Make sure you don't check in tests generated with the debug target. + +Note that **release** is the default target when invoking ```generate.py```. + + ## Removing all generated tests ```bash @@ -77,6 +93,7 @@ git add * && git commit -m "Remove generated tests" **Important:** The ```./generic/tools/clean.py``` utility will only work if there is a valid ```spec.src.json``` and previously generated directories match the specification requirement names. So make sure you run ```clean.py``` before you alter the specification section of the spec JSON. + ## Updating the tests The main test logic lives in ```./generic/referrer-policy-test-case.js``` with helper functions defined in ```./generic/common.js``` so you should probably start there. @@ -124,6 +141,7 @@ git add * && git commit -m "Update generated tests" ``` + ## Overview of the spec JSON **Main sections:** @@ -152,6 +170,7 @@ git add * && git commit -m "Update generated tests" A 1:1 mapping of a **subresource type** to the URL path of the sub-resource. When adding a new sub-resource, a path to an existing file for it also must be specified. + ### Test Expansion Patterns Each field in a test expansion can be in one of the following formats: @@ -206,6 +225,7 @@ var scenario = { "source_protocol": "http", "target_protocol": "http", "subresource": "iframe-tag", + "subresource_path": "/referrer-policy/generic/subresource/document.py", "referrer_url": "origin" }; ``` @@ -219,4 +239,3 @@ Taking the spec JSON, the generator follows this algorithm: * For each specification requirement: Expand the ```test_expansion``` pattern into selections and check each against the blacklist, if not marked as suppresed, generate the test resources for the selection - diff --git a/referrer-policy/generic/common.js b/referrer-policy/generic/common.js index f8164da88dd6d7..788ef67fba9c29 100644 --- a/referrer-policy/generic/common.js +++ b/referrer-policy/generic/common.js @@ -38,25 +38,25 @@ function loadImage(src, callback) { } function decodeImageData(rgba) { - // Remove alpha component. - var data = new Uint8ClampedArray(rgba.length); - var x = 0; - for (var i in rgba) { - if (i > 0 && i%4 == 3 || rgba[i] == 0) + var rgb = new Uint8ClampedArray(rgba.length); + + // RGBA -> RGB. + var rgb_length = 0; + for (var i = 0; i < rgba.length; ++i) { + // Skip alpha component. + if (i % 4 == 3) continue; - data[x++] = rgba[i]; - } + // Zero is the string terminator. + if (rgba[i] == 0) + break; - // Remove trailing nulls from data. - var length = rgba.length; - - for (var i = rgba.length - 1; data[i] == 0 && i > 0; i--) { - length--; + rgb[rgb_length++] = rgba[i]; } - data = data.subarray(0, length); - var string_data = (new TextDecoder("ascii")).decode(data); + // Remove trailing nulls from data. + rgb = rgb.subarray(0, rgb_length); + var string_data = (new TextDecoder("ascii")).decode(rgb); return JSON.parse(string_data); } @@ -74,6 +74,7 @@ function decodeImage(url, callback) { function normalizePort(targetPort) { var defaultPorts = [80, 443]; var isDefaultPortForProtocol = (defaultPorts.indexOf(targetPort) >= 0); + return (targetPort == "" || isDefaultPortForProtocol) ? "" : ":" + targetPort; } @@ -109,15 +110,12 @@ function queryImage(url, callback) { function queryXhr(url, callback) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); - console.log(url); - xhr.onreadystatechange = function(e) { if (this.readyState == 4 && this.status == 200) { var headers = JSON.parse(this.responseText); callback(wrapResult(url, headers)); } }; - xhr.send(); } @@ -175,9 +173,6 @@ function queryLink(url, callback, referrer_policy) { function queryAreaLink(url, callback, referrer_policy) { var area = document.createElement("area"); - area.shape="rect" - area.coords="0,0,10,10" - // TODO(kristijanburnik): Append to map and add image. document.body.appendChild(area); queryNavigable(area, url, callback, referrer_policy) @@ -196,3 +191,8 @@ function queryScript(url, callback) { document.body.appendChild(script); } + + // SanityChecker does nothing in release mode. +function SanityChecker() {} +SanityChecker.prototype.checkScenario = function() {}; +SanityChecker.prototype.checkSubresourceResult = function() {}; diff --git a/referrer-policy/generic/referrer-policy-test-case.js b/referrer-policy/generic/referrer-policy-test-case.js index 0da5133f5629c8..99205d89141313 100644 --- a/referrer-policy/generic/referrer-policy-test-case.js +++ b/referrer-policy/generic/referrer-policy-test-case.js @@ -1,4 +1,4 @@ -var ReferrerPolicyTestCase = function(scenario, testDescription) { +function ReferrerPolicyTestCase(scenario, testDescription, sanityChecker) { // Pass and skip rest of the test if browser does not support fetch. if (scenario.subresource == "fetch-request" && !window.fetch) { // TODO(kristijanburnik): This should be refactored. @@ -10,28 +10,8 @@ var ReferrerPolicyTestCase = function(scenario, testDescription) { }; } - // Check if scenario is valid. - // TODO(kristijanburnik): Move to a sanity-checks.js for debug mode only. - test(function() { - - // We extend the exsiting test_expansion_schema not to kill performance by - // copying. - var expectedFields = SPEC_JSON["test_expansion_schema"]; - expectedFields["referrer_policy"] = SPEC_JSON["referrer_policy_schema"]; - - for (var field in expectedFields) { - assert_own_property(scenario, field, - "The scenario contains field " + field) - assert_in_array(scenario[field], expectedFields[field], - "Scenario's " + field + " is one of: " + - expectedFields[field].join(", ")) + "." - } - - // Check if the protocol is matched. - assert_equals(scenario["source_protocol"] + ":", location.protocol, - "Protocol of the test page should match the scenario.") - - }, "[ReferrerPolicyTestCase] The test scenario is valid."); + // This check is A NOOP in release. + sanityChecker.checkScenario(scenario); var subresourceInvoker = { "a-tag": queryLink, @@ -44,8 +24,6 @@ var ReferrerPolicyTestCase = function(scenario, testDescription) { "xhr-request": queryXhr }; - var pathForSubresource = SPEC_JSON["subresource_path"]; - var referrerUrlResolver = { "omitted": function() { return undefined; @@ -85,7 +63,7 @@ var ReferrerPolicyTestCase = function(scenario, testDescription) { t._subresourceUrl = t._scenario.target_protocol + "://" + domainForOrigin[t._scenario.origin] + normalizePort(targetPort) + - pathForSubresource[t._scenario.subresource]; + t._scenario["subresource_path"]; }, _constructExpectedReferrerUrl: function() { @@ -121,29 +99,16 @@ var ReferrerPolicyTestCase = function(scenario, testDescription) { var test = async_test(t._testDescription); t._invokeSubresource(function(result) { - // Check if the result is in valid format. - test.step(function() { - assert_equals(Object.keys(result).length, 3); - assert_own_property(result, "location"); - assert_own_property(result, "referrer"); - assert_own_property(result, "headers"); - - // Skip location check for scripts. - if (t._scenario.subresource == "script-tag") - return; - - // Sanity check: location of sub-resource matches reported location. - assert_equals(result.location, t._subresourceUrl, - "Subresource reported location."); - }, "Running a valid test scenario."); + // Check if the result is in valid format. NOOP in release. + sanityChecker.checkSubresourceResult( + test, t._scenario, t._subresourceUrl, result); // Check the reported URL. test.step(function() { assert_equals(result.referrer, t._expectedReferrerUrl, "Reported Referrer URL is '" + - t._scenario.referrer_url + - "'."); + t._scenario.referrer_url + "'."); assert_equals(result.headers.referer, t._expectedReferrerUrl, "Reported Referrer URL from HTTP header is '" + diff --git a/referrer-policy/generic/sanity-checker.js b/referrer-policy/generic/sanity-checker.js new file mode 100644 index 00000000000000..e0714885ffcc9d --- /dev/null +++ b/referrer-policy/generic/sanity-checker.js @@ -0,0 +1,52 @@ +// 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) { + // Check if scenario is valid. + // TODO(kristijanburnik): Move to a sanity-checks.js for debug mode only. + test(function() { + + // We extend the exsiting test_expansion_schema not to kill performance by + // copying. + var expectedFields = SPEC_JSON["test_expansion_schema"]; + expectedFields["referrer_policy"] = SPEC_JSON["referrer_policy_schema"]; + + assert_own_property(scenario, "subresource_path", + "Scenario has the path to the subresource."); + + for (var field in expectedFields) { + assert_own_property(scenario, field, + "The scenario contains field " + field) + assert_in_array(scenario[field], expectedFields[field], + "Scenario's " + field + " is one of: " + + expectedFields[field].join(", ")) + "." + } + + // Check if the protocol is matched. + assert_equals(scenario["source_protocol"] + ":", location.protocol, + "Protocol of the test page should match the scenario.") + + }, "[ReferrerPolicyTestCase] The test scenario is valid."); +} + +SanityChecker.prototype.checkSubresourceResult = function(test, + scenario, + subresourceUrl, + result) { + test.step(function() { + assert_equals(Object.keys(result).length, 3); + assert_own_property(result, "location"); + assert_own_property(result, "referrer"); + assert_own_property(result, "headers"); + + // Skip location check for scripts. + if (scenario.subresource == "script-tag") + return; + + // Sanity check: location of sub-resource matches reported location. + assert_equals(result.location, subresourceUrl, + "Subresource reported location."); + }, "Running a valid test scenario."); +}; diff --git a/referrer-policy/generic/template/document.html.template b/referrer-policy/generic/template/document.html.template index 6a38c9a12ae7de..c375b74121d343 100644 --- a/referrer-policy/generic/template/document.html.template +++ b/referrer-policy/generic/template/document.html.template @@ -2,13 +2,8 @@ This page reports back it's request details to the parent frame - - -

This page reports back it's request details to the parent frame

-
%(headers)s
- - diff --git a/referrer-policy/generic/template/script.js.template b/referrer-policy/generic/template/script.js.template index e185d3b301323e..a562d959def4bb 100644 --- a/referrer-policy/generic/template/script.js.template +++ b/referrer-policy/generic/template/script.js.template @@ -1,3 +1,2 @@ var SERVER_REQUEST_HEADERS = %(headers)s; - postMessage(SERVER_REQUEST_HEADERS, '*'); diff --git a/referrer-policy/generic/template/test.html.template b/referrer-policy/generic/template/test.debug.html.template similarity index 58% rename from referrer-policy/generic/template/test.html.template rename to referrer-policy/generic/template/test.debug.html.template index fc668732fc1e4a..0ef2f5a463660b 100644 --- a/referrer-policy/generic/template/test.html.template +++ b/referrer-policy/generic/template/test.debug.html.template @@ -1,18 +1,21 @@ %(generated_disclaimer)s - - Referrer-Policy: %(spec_title)s - %(meta_delivery_method)s + Referrer-Policy: %(spec_title)s%(meta_delivery_method)s + + + + @@ -20,10 +23,12 @@ http://testthewebforward.org/docs/test-templates.html#script-test-with-metadata

%(spec_title)s

%(spec_description)s

-

The referrer URL is %(referrer_url)s when a document - served over %(source_protocol)s requires an %(target_protocol)s - sub-resource via %(subresource)s using the %(delivery_method)s delivery - method and when the target request is %(origin)s.

+

+ +

See specification details for this test.

@@ -53,19 +58,7 @@ http://testthewebforward.org/docs/test-templates.html#script-test-with-metadata - +
diff --git a/referrer-policy/generic/template/test.js.template b/referrer-policy/generic/template/test.js.template new file mode 100644 index 00000000000000..21ea8893417466 --- /dev/null +++ b/referrer-policy/generic/template/test.js.template @@ -0,0 +1,14 @@ +ReferrerPolicyTestCase( + { + "referrer_policy": %(referrer_policy_json)s, + "delivery_method": "%(delivery_method)s", + "origin": "%(origin)s", + "source_protocol": "%(source_protocol)s", + "target_protocol": "%(target_protocol)s", + "subresource": "%(subresource)s", + "subresource_path": "%(subresource_path)s", + "referrer_url": "%(referrer_url)s" + }, + document.querySelector("meta[name=assert]").content, + new SanityChecker() +).start(); diff --git a/referrer-policy/generic/template/test.release.html.template b/referrer-policy/generic/template/test.release.html.template new file mode 100644 index 00000000000000..42a110590e3f66 --- /dev/null +++ b/referrer-policy/generic/template/test.release.html.template @@ -0,0 +1,23 @@ + +%(generated_disclaimer)s + + + Referrer-Policy: %(spec_title)s + %(meta_delivery_method)s + + + + + + + + + + + +
+ + diff --git a/referrer-policy/generic/tools/generate.py b/referrer-policy/generic/tools/generate.py index 994e6daaf20552..484b34d8bfd91a 100755 --- a/referrer-policy/generic/tools/generate.py +++ b/referrer-policy/generic/tools/generate.py @@ -3,6 +3,8 @@ import os, sys, json from common_paths import * import spec_validator +import argparse + def expand_test_expansion_pattern(spec_test_expansion, test_expansion_schema): expansion = {} @@ -36,11 +38,13 @@ def permute_expansion(expansion, selection = {}, artifact_index = 0): yield next_selection -def generate_selection(selection, spec): +def generate_selection(selection, spec, subresource_path, + 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'] + selection['subresource_path'] = subresource_path # Oddball: it can be None, so in JS it's null. selection['referrer_policy_json'] = json.dumps(spec['referrer_policy']) @@ -48,9 +52,8 @@ def generate_selection(selection, spec): test_directory = os.path.dirname(test_filename) full_path = os.path.join(spec_directory, test_directory) - test_html_template_basename = 'test.html.template' - test_html_template = get_template(test_html_template_basename) + test_js_template = get_template("test.js.template") disclaimer_template = get_template('disclaimer.template') html_template_filename = os.path.join(template_directory, @@ -63,6 +66,11 @@ def generate_selection(selection, spec): selection['generated_disclaimer'] = generated_disclaimer.rstrip() + # 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) @@ -107,7 +115,7 @@ def generate_selection(selection, spec): f.write(test_html_template % selection) -def generate_test_source_files(spec_json): +def generate_test_source_files(spec_json, target): test_expansion_schema = spec_json['test_expansion_schema'] specification = spec_json['specification'] @@ -116,6 +124,9 @@ def generate_test_source_files(spec_json): f.write(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 + # Create list of excluded tests. exclusion_dict = {} for excluded_pattern in spec_json['excluded_tests']: @@ -133,16 +144,27 @@ def generate_test_source_files(spec_json): for selection in permute_expansion(expansion): selection_path = selection_pattern % selection if not selection_path in exclusion_dict: - generate_selection(selection, spec) + subresource_path = \ + spec_json["subresource_path"][selection["subresource"]] + generate_selection(selection, + spec, + subresource_path, + html_template) else: print 'Excluding selection:', selection_path -def main(): +def main(target): spec_json = load_spec_json(); spec_validator.assert_valid_spec_json(spec_json) - generate_test_source_files(spec_json) + generate_test_source_files(spec_json, target) if __name__ == '__main__': - 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') + # TODO(kristijanburnik): Add option for the spec_json file. + args = parser.parse_args() + main(args.target)