Bug 1187159 - Add mochitest for loading packaged apps (iframe+fetch+mozapp) r=jduell
authorValentin Gosu <valentin.gosu@gmail.com>
Sat, 08 Aug 2015 07:11:58 +0200
changeset 288610 78a61d56adaeb9a8beb4583026463f1dc6945197
parent 288609 ca1510a96cc66300e01798b376da2884d1ddca6f
child 288611 618c213ed8dbc3af0dd20145b999ae877ba97391
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs1187159
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1187159 - Add mochitest for loading packaged apps (iframe+fetch+mozapp) r=jduell
netwerk/test/mochitests/mochitest.ini
netwerk/test/mochitests/test_web_packaged_app.html
netwerk/test/mochitests/web_packaged_app.sjs
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -5,22 +5,24 @@ support-files =
   method.sjs
   partial_content.sjs
   rel_preconnect.sjs
   user_agent.sjs
   user_agent_update.sjs
   redirect_idn.html^headers^
   redirect_idn.html
   empty.html
+  web_packaged_app.sjs
 
 [test_arraybufferinputstream.html]
 [test_partially_cached_content.html]
 [test_rel_preconnect.html]
 skip-if = e10s
 [test_uri_scheme.html]
 [test_user_agent_overrides.html]
 skip-if = e10s
 [test_user_agent_updates.html]
 skip-if = e10s
 [test_user_agent_updates_reset.html]
 [test_xhr_method_case.html]
 skip-if = e10s
 [test_idn_redirect.html]
+[test_web_packaged_app.html]
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/test_web_packaged_app.html
@@ -0,0 +1,210 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title> Web packaged app </title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+var Cu = SpecialPowers.Cu;
+var Cr = SpecialPowers.Cr;
+var LoadContextInfo = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {}).LoadContextInfo;
+var CommonUtils = Cu.import("resource://services-common/utils.js", {}).CommonUtils;
+
+function CacheCallback(expect) {
+  this.expect = expect || true;
+}
+
+CacheCallback.prototype = {
+  QueryInterface: function(iid) {
+    if (!iid.equals(Ci.nsISupports) &&
+        !iid.equals(Ci.nsICacheEntryOpenCallback)) {
+      throw Cr.NS_ERROR_NO_INTERFACE;
+    }
+    return this;
+  },
+  onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+  onCacheEntryAvailable: function(entry, isnew, applicationCache, status) {
+    is(status, this.expect ? Cr.NS_OK : Cr.NS_ERROR_CACHE_KEY_NOT_FOUND, "check status");
+    is(!!entry, this.expect, "check if entry exists");
+    SpecialPowers.executeSoon(continueTest);
+  }
+};
+
+function checkCacheEntry(url, exists, appId) {
+  var loadContext = appId ? LoadContextInfo.custom(false, false, appId, false) : LoadContextInfo.default;
+  var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+                     .getService(Ci.nsICacheStorageService);
+  var cache = cacheService.diskCacheStorage(loadContext, false);
+  cache.asyncOpenURI(CommonUtils.makeURI(url), "", 0, new CacheCallback(exists));
+}
+
+var gGenerator = runTest();
+
+addLoadEvent(go);
+function go() {
+  SpecialPowers.pushPermissions(
+    [
+     { "type": "webapps-manage", "allow": 1, "context": document },
+     { "type": "embed-apps", "allow": 1, "context": document },
+     { "type": "browser", "allow": 1, "context": document }
+    ],
+    function() {
+      SpecialPowers.pushPrefEnv({"set": [['network.http.enable-packaged-apps', true],
+        ["dom.mozBrowserFramesEnabled", true]]},
+        function() { gGenerator.next(); } );
+    });
+}
+
+function continueTest() {
+  try {
+    gGenerator.next();
+  } catch (e if e instanceof StopIteration) {
+    finish();
+  }
+}
+
+function finish() {
+  SimpleTest.finish();
+}
+
+function cbError(aEvent) {
+  ok(false, "Error callback invoked " +
+            aEvent.target.error.name + " " + aEvent.target.error.message);
+  finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+
+  // Install the app
+  SpecialPowers.setAllAppsLaunchable(true);
+  var manifestURL = "http://test/tests/dom/apps/tests/file_app.sjs?apptype=hosted&getmanifest=true";
+
+  SpecialPowers.autoConfirmAppInstall(continueTest);
+  yield undefined;
+
+  SpecialPowers.autoConfirmAppUninstall(continueTest);
+  yield undefined;
+
+  var request = navigator.mozApps.install(manifestURL, { });
+  request.onerror = cbError;
+  request.onsuccess = continueTest;
+  yield undefined;
+
+  var app = request.result;
+  ok(app, "App is non-null");
+  is(app.manifestURL, manifestURL, "App manifest url is correct.");
+
+  // Get the AppID
+  let appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
+  let appId = appsService.getAppLocalIdByManifestURL(manifestURL);
+
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs", false, appId);
+  yield undefined;
+
+  // Check that the entry does not exist
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs!//index.html", false, appId);
+  yield undefined;
+
+  // Run the app and load a resource from the package
+  runApp(app, continueTest);
+  yield undefined;
+
+  // Check that the cache entry exists after being loaded in the app
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs!//index.html", true, appId);
+  yield undefined;
+
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs", true, appId);
+  yield undefined;
+
+  request = navigator.mozApps.mgmt.uninstall(app);
+  request.onerror = cbError;
+  request.onsuccess = continueTest;
+  yield undefined;
+  is(request.result, manifestURL, "App uninstalled.");
+
+  // Check that the cache entry went away after uninstalling the app
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs!//index.html", false, appId);
+  yield undefined;
+
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs", false);
+  yield undefined;
+
+  // Check that the entry does not exist
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs!//scripts/app.js", false);
+  yield undefined;
+
+  // Test that we can load a file in an iframe, with default permissions
+  var iframe = document.createElement("iframe");
+  iframe.addEventListener("load", continueTest, false);
+  document.body.appendChild(iframe);
+  iframe.src = "http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs!//scripts/app.js";
+  yield undefined;
+  ok(iframe.contentWindow.document.body.innerHTML.includes("..."), "This is the right file");
+  document.body.removeChild(iframe);
+
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs", true);
+  yield undefined;
+
+  // Check that the entry now exists
+  checkCacheEntry("http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs!//scripts/app.js", true);
+  yield undefined;
+
+  // Test that a fetch works
+  fetch('http://mochi.test:8888/tests/netwerk/test/mochitests/web_packaged_app.sjs!//index.html')
+  .then(function(res) {
+    ok(res.ok, "completed fetch");
+    res.text().then(function(body) {
+      ok(body.includes("Web Packaged App Index"), "correct content");
+      continueTest();
+    }); }
+  , function(e) {
+    ok(false, "error in fetch");
+  });
+  yield undefined;
+
+}
+
+function runApp(aApp, aCallback) {
+  var ifr = document.createElement('iframe');
+  ifr.setAttribute('mozbrowser', 'true');
+  ifr.setAttribute('mozapp', aApp.manifestURL);
+  ifr.src = "web_packaged_app.sjs!//index.html";
+
+  ifr.addEventListener('mozbrowsershowmodalprompt', function onAlert(e) {
+    var message = e.detail.message;
+    info("Got message " + message);
+
+    if (message.startsWith("OK:")) {
+      ok(true, message.substring(3, message.length));
+    } else if (message.startsWith("ERROR:")) {
+      ok(false, message.substring(6, message.length));
+    } else if (message == "DONE") {
+      ok(true, "Done test");
+      ifr.removeEventListener('mozbrowsershowmodalprompt', onAlert, false);
+      document.body.removeChild(ifr);
+      continueTest();
+    }
+  }, false);
+
+  document.body.appendChild(ifr);
+}
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/web_packaged_app.sjs
@@ -0,0 +1,35 @@
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+function handleRequest(request, response)
+{
+  response.setHeader("Content-Type", "application/package", false);
+  response.write(octetStreamData.getData());
+  return;
+}
+
+// The package content
+// getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format
+var octetStreamData = {
+  content: [
+   { headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "<html>\r\n  <head>\r\n    <script> alert('OK: hello'); alert('DONE'); </script>\r\n</head>\r\n  Web Packaged App Index\r\n</html>\r\n", type: "text/html" },
+   { headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" },
+   { headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" }
+  ],
+  token : "gc0pJq0M:08jU534c0p",
+  getData: function() {
+    var str = "";
+    for (var i in this.content) {
+      str += "--" + this.token + "\r\n";
+      for (var j in this.content[i].headers) {
+        str += this.content[i].headers[j] + "\r\n";
+      }
+      str += "\r\n";
+      str += this.content[i].data + "\r\n";
+    }
+
+    str += "--" + this.token + "--";
+    return str;
+  }
+}