Backed out changeset 941fd40d73de (bug 1251175) for causing perma time out failures in browser_ManifestObtainer_obtain.js
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 07 Jun 2016 14:15:30 +0200
changeset 300889 c1a5cf90a1eea8743ca7a1aafed3ff50a7c79529
parent 300888 18d08e0c6d2d2cda4e352f49826d7c425f9119a3
child 300890 1526b47e25e446cbbbaee357ed3d643fef45eb2a
push id19599
push usercbook@mozilla.com
push dateWed, 08 Jun 2016 10:16:21 +0000
treeherderfx-team@81f4cc3f6f4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1251175
milestone50.0a1
backs out941fd40d73de36e08efb0590a1ad1900602d1d37
Backed out changeset 941fd40d73de (bug 1251175) for causing perma time out failures in browser_ManifestObtainer_obtain.js
dom/manifest/test/browser.ini
dom/manifest/test/browser_ManifestFinder_browserHasManifestLink.js
dom/manifest/test/browser_ManifestObtainer_obtain.js
dom/manifest/test/resource.sjs
--- a/dom/manifest/test/browser.ini
+++ b/dom/manifest/test/browser.ini
@@ -1,9 +1,8 @@
 [DEFAULT]
 support-files =
+  manifestLoader.html
   file_reg_install_event.html
   file_testserver.sjs
-  manifestLoader.html
-  resource.sjs
 [browser_ManifestFinder_browserHasManifestLink.js]
 [browser_ManifestObtainer_obtain.js]
 [browser_fire_install_event.js]
\ No newline at end of file
--- a/dom/manifest/test/browser_ManifestFinder_browserHasManifestLink.js
+++ b/dom/manifest/test/browser_ManifestFinder_browserHasManifestLink.js
@@ -1,84 +1,114 @@
 //Used by JSHint:
-/*global Cu, BrowserTestUtils, ok, add_task, gBrowser */
+/*global Cu, BrowserTestUtils, is, ok, add_task, gBrowser, ManifestFinder */
 "use strict";
-const { ManifestFinder } = Cu.import("resource://gre/modules/ManifestFinder.jsm", {});
-const defaultURL = new URL("http://example.org/browser/dom/manifest/test/resource.sjs");
-defaultURL.searchParams.set("Content-Type", "text/html; charset=utf-8");
+Cu.import("resource://gre/modules/ManifestFinder.jsm", this);  // jshint ignore:line
 
+const defaultURL =
+  "http://example.org/tests/dom/manifest/test/resource.sjs";
 const tests = [{
-  body: `
-    <link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>
-    <link rel="foo bar manifest bar test" href='${defaultURL}?body={"name":"value"}'>
-    <link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>
-  `,
+  expected: "Document has a web manifest.",
+  get tabURL() {
+    let query = [
+      `body=<h1>${this.expected}</h1>`,
+      "Content-Type=text/html; charset=utf-8",
+    ];
+    const URL = `${defaultURL}?${query.join("&")}`;
+    return URL;
+  },
   run(result) {
-    ok(result, "Document has a web manifest.");
+    is(result, true, this.expected);
   },
+  testData: `
+      <link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>
+      <link rel="foo bar manifest bar test" href='${defaultURL}?body={"name":"value"}'>
+      <link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
 }, {
-  body: `
-    <link rel="amanifista" href='${defaultURL}?body={"name":"fail"}'>
-    <link rel="foo bar manifesto bar test" href='${defaultURL}?body={"name":"pass-1"}'>
-    <link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>`,
+  expected: "Document does not have a web manifest.",
+  get tabURL() {
+    let query = [
+      `body=<h1>${this.expected}</h1>`,
+      "Content-Type=text/html; charset=utf-8",
+    ];
+    const URL = `${defaultURL}?${query.join("&")}`;
+    return URL;
+  },
   run(result) {
-    ok(!result, "Document does not have a web manifest.");
+    is(result, false, this.expected);
   },
+  testData: `
+      <link rel="amanifista" href='${defaultURL}?body={"name":"fail"}'>
+      <link rel="foo bar manifesto bar test" href='${defaultURL}?body={"name":"pass-1"}'>
+      <link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>`
 }, {
-  body: `
-    <link rel="manifest" href="">
-    <link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`,
+  expected: "Manifest link is has empty href.",
+  get tabURL() {
+    let query = [
+      `body=<h1>${this.expected}</h1>`,
+      "Content-Type=text/html; charset=utf-8",
+    ];
+    const URL = `${defaultURL}?${query.join("&")}`;
+    return URL;
+  },
   run(result) {
-    ok(!result, "Manifest link is has empty href.");
+    is(result, false, this.expected);
   },
+  testData: `
+  <link rel="manifest" href="">
+  <link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
 }, {
-  body: `
+  expected: "Manifest link is missing.",
+  get tabURL() {
+    let query = [
+      `body=<h1>${this.expected}</h1>`,
+      "Content-Type=text/html; charset=utf-8",
+    ];
+    const URL = `${defaultURL}?${query.join("&")}`;
+    return URL;
+  },
+  run(result) {
+    is(result, false, this.expected);
+  },
+  testData: `
     <link rel="manifest">
-    <link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`,
-  run(result) {
-    ok(!result, "Manifest link is missing.");
-  },
+    <link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
 }];
 
-function makeTestURL({ body }) {
-  const url = new URL(defaultURL);
-  url.searchParams.set("body", encodeURIComponent(body));
-  return url.href;
-}
-
 /**
  * Test basic API error conditions
  */
-add_task(function*() {
-  const expected = "Invalid types should throw a TypeError.";
+add_task(function* () {
+  let expected = "Invalid types should throw a TypeError.";
   for (let invalidValue of [undefined, null, 1, {}, "test"]) {
     try {
       yield ManifestFinder.contentManifestLink(invalidValue);
       ok(false, expected);
     } catch (e) {
       is(e.name, "TypeError", expected);
     }
     try {
       yield ManifestFinder.browserManifestLink(invalidValue);
       ok(false, expected);
     } catch (e) {
       is(e.name, "TypeError", expected);
     }
   }
 });
 
-add_task(function*() {
-  const runningTests = tests
-    .map(
-      test => ({
-        gBrowser,
-        test,
-        url: makeTestURL(test),
-      })
-    )
-    .map(
-      tabOptions => BrowserTestUtils.withNewTab(tabOptions, function*(browser) {
-        const result = yield ManifestFinder.browserHasManifestLink(browser);
-        tabOptions.test.run(result);
-      })
+add_task(function* () {
+  for (let test of tests) {
+    let tabOptions = {
+      gBrowser: gBrowser,
+      url: test.tabURL,
+    };
+    yield BrowserTestUtils.withNewTab(
+      tabOptions,
+      browser => testHasManifest(browser, test)
     );
-  yield Promise.all(runningTests);
+  }
+
+  function* testHasManifest(aBrowser, aTest) {
+    aBrowser.contentWindowAsCPOW.document.head.innerHTML = aTest.testData;
+    const result = yield ManifestFinder.browserHasManifestLink(aBrowser);
+    aTest.run(result);
+  }
 });
--- a/dom/manifest/test/browser_ManifestObtainer_obtain.js
+++ b/dom/manifest/test/browser_ManifestObtainer_obtain.js
@@ -1,175 +1,249 @@
 //Used by JSHint:
-/*global is, Cu, BrowserTestUtils, add_task, gBrowser, makeTestURL*/
-'use strict';
-const { ManifestObtainer } = Cu.import('resource://gre/modules/ManifestObtainer.jsm', {});
-const remoteURL = 'http://mochi.test:8888/browser/dom/manifest/test/resource.sjs';
-const defaultURL = new URL('http://example.org/browser/dom/manifest/test/resource.sjs');
-defaultURL.searchParams.set('Content-Type', 'text/html; charset=utf-8');
+/*global requestLongerTimeout, Cu, BrowserTestUtils, add_task, SpecialPowers, gBrowser, Assert*/ 'use strict';
+const {
+  ManifestObtainer
+} = Cu.import('resource://gre/modules/ManifestObtainer.jsm', {});
 
+requestLongerTimeout(4); // e10s tests take time.
+const defaultURL =
+  'http://example.org/tests/dom/manifest/test/resource.sjs';
+const remoteURL =
+  'http://mochi.test:8888/tests/dom/manifest/test/resource.sjs';
 const tests = [
   // Fetch tests.
   {
-    body: `
-      <link rel="manifesto" href='resource.sjs?body={"name":"fail"}'>
-      <link rel="foo bar manifest bar test" href='resource.sjs?body={"name":"pass-1"}'>
-      <link rel="manifest" href='resource.sjs?body={"name":"fail"}'>`,
+    expected: 'Manifest is first `link` where @rel contains token manifest.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
     run(manifest) {
-      is(manifest.name, 'pass-1', 'Manifest is first `link` where @rel contains token manifest.');
-    }
+      Assert.strictEqual(manifest.name, 'pass-1', this.expected);
+    },
+    testData: `
+      <link rel="manifesto" href='${defaultURL}?body={"name":"fail"}'>
+      <link rel="foo bar manifest bar test" href='${defaultURL}?body={"name":"pass-1"}'>
+      <link rel="manifest" href='${defaultURL}?body={"name":"fail"}'>`
   }, {
-    body: `
+    expected: 'Manifest is first `link` where @rel contains token manifest.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
+    run(manifest) {
+      Assert.strictEqual(manifest.name, 'pass-2', this.expected);
+    },
+    testData: `
       <link rel="foo bar manifest bar test" href='resource.sjs?body={"name":"pass-2"}'>
       <link rel="manifest" href='resource.sjs?body={"name":"fail"}'>
-      <link rel="manifest foo bar test" href='resource.sjs?body={"name":"fail"}'>`,
-    run(manifest) {
-      is(manifest.name, 'pass-2', 'Manifest is first `link` where @rel contains token manifest.');
-    },
+      <link rel="manifest foo bar test" href='resource.sjs?body={"name":"fail"}'>`
   }, {
-    body: `<link rel="manifest" href='${remoteURL}?body={"name":"pass-3"}'>`,
+    expected: 'By default, manifest cannot load cross-origin.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
     run(err) {
-      is(err.name, 'TypeError', 'By default, manifest cannot load cross-origin.');
+      Assert.strictEqual(err.name, 'TypeError', this.expected);
     },
+    testData: `<link rel="manifest" href='${remoteURL}?body={"name":"pass-3"}'>`
   },
   // CORS Tests.
   {
-    get body() {
+    expected: 'CORS enabled, manifest must be fetched.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
+    run(manifest) {
+      Assert.strictEqual(manifest.name, 'pass-4', this.expected);
+    },
+    get testData() {
       const body = 'body={"name": "pass-4"}';
       const CORS =
-        `Access-Control-Allow-Origin=${defaultURL.origin}`;
+        `Access-Control-Allow-Origin=${new URL(this.tabURL).origin}`;
       const link =
         `<link
         crossorigin=anonymous
         rel="manifest"
         href='${remoteURL}?${body}&${CORS}'>`;
       return link;
+    }
+  }, {
+    expected: 'Fetch blocked by CORS - origin does not match.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
     },
-    run(manifest) {
-      is(manifest.name, 'pass-4', 'CORS enabled, manifest must be fetched.');
+    run(err) {
+      Assert.strictEqual(err.name, 'TypeError', this.expected);
     },
-  }, {
-    get body() {
+    get testData() {
       const body = 'body={"name": "fail"}';
       const CORS = 'Access-Control-Allow-Origin=http://not-here';
       const link =
         `<link
         crossorigin
         rel="manifest"
         href='${remoteURL}?${body}&${CORS}'>`;
       return link;
+    }
+  },{
+    expected: 'Trying to load from about:whatever is a TypeError.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
     },
     run(err) {
-      is(err.name, 'TypeError', 'Fetch blocked by CORS - origin does not match.');
+      Assert.strictEqual(err.name, 'TypeError', this.expected);
     },
-  }, {
-    body: `<link rel="manifest" href='about:whatever'>`,
+    testData: `<link rel="manifest" href='about:whatever'>`
+  },
+  {
+    expected: 'Trying to load from file://whatever is a TypeError.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
     run(err) {
-      is(err.name, 'TypeError', 'Trying to load from about:whatever is TypeError.');
+      Assert.strictEqual(err.name, 'TypeError', this.expected);
     },
-  }, {
-    body: `<link rel="manifest" href='file://manifest'>`,
-    run(err) {
-      is(err.name, 'TypeError', 'Trying to load from file://whatever is a TypeError.');
-    },
+    testData: `<link rel="manifest" href='file://manifest'>`
   },
   //URL parsing tests
   {
-    body: `<link rel="manifest" href='http://[12.1212.21.21.12.21.12]'>`,
+    expected: 'Trying to load invalid URL is a TypeError.',
+    get tabURL() {
+      let query = [
+        `body=<h1>${this.expected}</h1>`,
+        'Content-Type=text/html; charset=utf-8',
+      ];
+      const URL = `${defaultURL}?${query.join('&')}`;
+      return URL;
+    },
     run(err) {
-      is(err.name, 'TypeError', 'Trying to load invalid URL is a TypeError.');
+      Assert.strictEqual(err.name, 'TypeError', this.expected);
     },
+    testData: `<link rel="manifest" href='http://[12.1212.21.21.12.21.12]'>`
   },
 ];
 
-function makeTestURL({ body }) {
-  const url = new URL(defaultURL);
-  url.searchParams.set("body", encodeURIComponent(body));
-  return url.href;
-}
+add_task(function*() {
+  yield new Promise(resolve => {
+    SpecialPowers.pushPrefEnv({
+      'set': [
+        ['dom.fetch.enabled', true]
+      ]
+    }, resolve);
+  });
+  for (let test of tests) {
+    let tabOptions = {
+      gBrowser: gBrowser,
+      url: test.tabURL,
+    };
+    yield BrowserTestUtils.withNewTab(
+      tabOptions,
+      browser => testObtainingManifest(browser, test)
+    );
+  }
 
-add_task(function*() {
-  const promises = tests
-    .map(test => ({
-      gBrowser,
-      testRunner: testObtainingManifest(test),
-      url: makeTestURL(test)
-    }))
-    .reduce((collector, tabOpts) => {
-      const promise = BrowserTestUtils.withNewTab(tabOpts, tabOpts.testRunner);
-      collector.push(promise);
-      return collector;
-    }, []);
-
-  const results = yield Promise.all(promises);
-
-  function testObtainingManifest(aTest) {
-    return function*(aBrowser) {
-      try {
-        const manifest = yield ManifestObtainer.browserObtainManifest(aBrowser);
-        aTest.run(manifest);
-      } catch (e) {
-        aTest.run(e);
-      }
-    };
+  function* testObtainingManifest(aBrowser, aTest) {
+    aBrowser.contentWindowAsCPOW.document.head.innerHTML = aTest.testData;
+    try {
+      const manifest = yield ManifestObtainer.browserObtainManifest(aBrowser);
+      aTest.run(manifest);
+    } catch (e) {
+      aTest.run(e);
+    }
   }
 });
 
 /*
  * e10s race condition tests
  * Open a bunch of tabs and load manifests
  * in each tab. They should all return pass.
  */
 add_task(function*() {
-  const defaultPath = '/browser/dom/manifest/test/manifestLoader.html';
+  const defaultPath = '/tests/dom/manifest/test/manifestLoader.html';
   const tabURLs = [
-    `http://example.com:80${defaultPath}`,
-    `http://example.org:80${defaultPath}`,
-    `http://example.org:8000${defaultPath}`,
+    `http://test:80${defaultPath}`,
     `http://mochi.test:8888${defaultPath}`,
-    `http://sub1.test1.example.com:80${defaultPath}`,
-    `http://sub1.test1.example.org:80${defaultPath}`,
-    `http://sub1.test1.example.org:8000${defaultPath}`,
+    `http://test1.mochi.test:8888${defaultPath}`,
     `http://sub1.test1.mochi.test:8888${defaultPath}`,
-    `http://sub1.test2.example.com:80${defaultPath}`,
+    `http://sub2.xn--lt-uia.mochi.test:8888${defaultPath}`,
+    `http://test2.mochi.test:8888${defaultPath}`,
+    `http://example.org:80${defaultPath}`,
+    `http://test1.example.org:80${defaultPath}`,
+    `http://test2.example.org:80${defaultPath}`,
+    `http://sub1.test1.example.org:80${defaultPath}`,
     `http://sub1.test2.example.org:80${defaultPath}`,
-    `http://sub1.test2.example.org:8000${defaultPath}`,
-    `http://sub2.test1.example.com:80${defaultPath}`,
     `http://sub2.test1.example.org:80${defaultPath}`,
-    `http://sub2.test1.example.org:8000${defaultPath}`,
-    `http://sub2.test2.example.com:80${defaultPath}`,
     `http://sub2.test2.example.org:80${defaultPath}`,
-    `http://sub2.test2.example.org:8000${defaultPath}`,
-    `http://sub2.xn--lt-uia.mochi.test:8888${defaultPath}`,
-    `http://test1.example.com:80${defaultPath}`,
-    `http://test1.example.org:80${defaultPath}`,
+    `http://example.org:8000${defaultPath}`,
     `http://test1.example.org:8000${defaultPath}`,
-    `http://test1.mochi.test:8888${defaultPath}`,
+    `http://test2.example.org:8000${defaultPath}`,
+    `http://sub1.test1.example.org:8000${defaultPath}`,
+    `http://sub1.test2.example.org:8000${defaultPath}`,
+    `http://sub2.test1.example.org:8000${defaultPath}`,
+    `http://sub2.test2.example.org:8000${defaultPath}`,
+    `http://example.com:80${defaultPath}`,
+    `http://www.example.com:80${defaultPath}`,
+    `http://test1.example.com:80${defaultPath}`,
     `http://test2.example.com:80${defaultPath}`,
-    `http://test2.example.org:80${defaultPath}`,
-    `http://test2.example.org:8000${defaultPath}`,
-    `http://test2.mochi.test:8888${defaultPath}`,
-    `http://test:80${defaultPath}`,
-    `http://www.example.com:80${defaultPath}`,
+    `http://sub1.test1.example.com:80${defaultPath}`,
+    `http://sub1.test2.example.com:80${defaultPath}`,
+    `http://sub2.test1.example.com:80${defaultPath}`,
+    `http://sub2.test2.example.com:80${defaultPath}`,
   ];
   // Open tabs an collect corresponding browsers
   let browsers = [
     for (url of tabURLs) gBrowser.addTab(url).linkedBrowser
   ];
   // Once all the pages have loaded, run a bunch of tests in "parallel".
   yield Promise.all((
     for (browser of browsers) BrowserTestUtils.browserLoaded(browser)
   ));
   // Flood random browsers with requests. Once promises settle, check that
   // responses all pass.
   const results = yield Promise.all((
     for (browser of randBrowsers(browsers, 100)) ManifestObtainer.browserObtainManifest(browser)
   ));
+  const expected = 'Expect every manifest to have name equal to `pass`.';
   const pass = results.every(manifest => manifest.name === 'pass');
-  ok(pass, 'Expect every manifest to have name equal to `pass`.');
+  Assert.ok(pass, expected);
   //cleanup
   browsers
     .map(browser => gBrowser.getTabForBrowser(browser))
     .forEach(tab => gBrowser.removeTab(tab));
 
   //Helper generator, spits out random browsers
   function* randBrowsers(aBrowsers, aMax) {
     for (let i = 0; i < aMax; i++) {
--- a/dom/manifest/test/resource.sjs
+++ b/dom/manifest/test/resource.sjs
@@ -15,17 +15,16 @@
  * Outputs:
  * HTTP/1.1 200 OK
  * Content-Type: text/html
  * Hello: hi
  * <h1>hello</h1>
  */
 //global handleRequest
 'use strict';
-Components.utils.importGlobalProperties(["URLSearchParams"]);
 const HTTPStatus = new Map([
   [100, 'Continue'],
   [101, 'Switching Protocol'],
   [200, 'OK'],
   [201, 'Created'],
   [202, 'Accepted'],
   [203, 'Non-Authoritative Information'],
   [204, 'No Content'],
@@ -62,24 +61,33 @@ const HTTPStatus = new Map([
   [501, 'Not Implemented'],
   [502, 'Bad Gateway'],
   [503, 'Service Unavailable'],
   [504, 'Gateway Timeout'],
   [505, 'HTTP Version Not Supported']
 ]);
 
 function handleRequest(request, response) {
-  const queryMap = new URLSearchParams(request.queryString);
+  const queryMap = createQueryMap(request);
   if (queryMap.has('statusCode')) {
     let statusCode = parseInt(queryMap.get('statusCode'));
     let statusText = HTTPStatus.get(statusCode);
     queryMap.delete('statusCode');
     response.setStatusLine('1.1', statusCode, statusText);
   }
   if (queryMap.has('body')) {
     let body = queryMap.get('body') || '';
     queryMap.delete('body');
-    response.write(decodeURIComponent(body));
+    response.write(body);
   }
-  for (let [key, value] of queryMap.entries()) {
+  for (let [key, value] of queryMap) {
     response.setHeader(key, value);
   }
+
+  function createQueryMap(request) {
+    const queryMap = new Map();
+    request.queryString.split('&')
+      //split on first "="
+      .map((component) => component.split(/=(.+)?/))
+      .forEach(pair => queryMap.set(pair[0], decodeURIComponent(pair[1])));
+    return queryMap;
+  }
 }