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 256979 78a61d56adaeb9a8beb4583026463f1dc6945197
parent 256978 ca1510a96cc66300e01798b376da2884d1ddca6f
child 256980 618c213ed8dbc3af0dd20145b999ae877ba97391
push id14559
push userphilringnalda@gmail.com
push dateSun, 09 Aug 2015 23:41:14 +0000
treeherderfx-team@0e269a1f1beb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs1187159
milestone42.0a1
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;
+  }
+}