Bug 1048526 - Create a Loop test server for querying OAuth URL parameters to use. r=ckarlof,vladikoff,jaws
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Fri, 15 Aug 2014 16:51:55 -0700
changeset 199887 4068cffc03fcc48aa87a75b06d4d681de3b88b30
parent 199886 563f7421eeaa97538294aba91be72eebb07803ce
child 199888 e9ae608b82e896cf4ce444e694a1ff66e009a2a6
push id27324
push userryanvm@gmail.com
push dateSat, 16 Aug 2014 21:18:56 +0000
treeherdermozilla-central@9a2152d29d8a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckarlof, vladikoff, jaws
bugs1048526
milestone34.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 1048526 - Create a Loop test server for querying OAuth URL parameters to use. r=ckarlof,vladikoff,jaws
browser/components/loop/test/mochitest/browser.ini
browser/components/loop/test/mochitest/browser_loop_fxa_server.js
browser/components/loop/test/mochitest/head.js
browser/components/loop/test/mochitest/loop_fxa.sjs
--- a/browser/components/loop/test/mochitest/browser.ini
+++ b/browser/components/loop/test/mochitest/browser.ini
@@ -1,8 +1,10 @@
 [DEFAULT]
 support-files =
     head.js
+    loop_fxa.sjs
 
+[browser_loop_fxa_server.js]
 [browser_mozLoop_appVersionInfo.js]
 [browser_mozLoop_prefs.js]
 [browser_mozLoop_doNotDisturb.js]
 skip-if = buildapp == 'mulet'
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/test/mochitest/browser_loop_fxa_server.js
@@ -0,0 +1,72 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test the server mocking FxA integration endpoints on the Loop server.
+ */
+
+"use strict";
+
+const BASE_URL = "http://mochi.test:8888/browser/browser/components/loop/test/mochitest/loop_fxa.sjs?";
+
+registerCleanupFunction(function* () {
+  yield promiseDeletedOAuthParams(BASE_URL);
+});
+
+add_task(function* required_setup_params() {
+  let params = {
+    client_id: "my_client_id",
+    content_uri: "https://example.com/content/",
+    oauth_uri: "https://example.com/oauth/",
+    profile_uri: "https://example.com/profile/",
+    state: "my_state",
+  };
+  let request = yield promiseOAuthParamsSetup(BASE_URL, params);
+  is(request.status, 200, "Check /setup_params status");
+  request = yield promiseParams();
+  is(request.status, 200, "Check /fxa-oauth/params status");
+  for (let param of Object.keys(params)) {
+    is(request.response[param], params[param], "Check /fxa-oauth/params " + param);
+  }
+});
+
+add_task(function* optional_setup_params() {
+  let params = {
+    action: "signin",
+    client_id: "my_client_id",
+    content_uri: "https://example.com/content/",
+    oauth_uri: "https://example.com/oauth/",
+    profile_uri: "https://example.com/profile/",
+    scope: "profile",
+    state: "my_state",
+  };
+  let request = yield promiseOAuthParamsSetup(BASE_URL, params);
+  is(request.status, 200, "Check /setup_params status");
+  request = yield promiseParams();
+  is(request.status, 200, "Check /fxa-oauth/params status");
+  for (let param of Object.keys(params)) {
+    is(request.response[param], params[param], "Check /fxa-oauth/params " + param);
+  }
+});
+
+add_task(function* delete_setup_params() {
+  yield promiseDeletedOAuthParams(BASE_URL);
+  let request = yield promiseParams();
+  is(Object.keys(request.response).length, 0, "Params should have been deleted");
+});
+
+function promiseParams() {
+  let deferred = Promise.defer();
+  let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
+              createInstance(Ci.nsIXMLHttpRequest);
+  xhr.open("POST", BASE_URL + "/fxa-oauth/params", true);
+  xhr.responseType = "json";
+  xhr.addEventListener("load", () => {
+    info("/fxa-oauth/params response:\n" + JSON.stringify(xhr.response, null, 4));
+    deferred.resolve(xhr);
+  });
+  xhr.addEventListener("error", error => deferred.reject(error));
+  xhr.send();
+
+  return deferred.promise;
+}
--- a/browser/components/loop/test/mochitest/head.js
+++ b/browser/components/loop/test/mochitest/head.js
@@ -64,8 +64,33 @@ function loadLoopPanel() {
 
   // Turn off animations to make tests quicker.
   let loopPanel = document.getElementById("loop-notification-panel");
   loopPanel.setAttribute("animate", "false");
 
   // Now get the actual API.
   yield promiseGetMozLoopAPI();
 }
+
+function promiseOAuthParamsSetup(baseURL, params) {
+  let deferred = Promise.defer();
+  let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
+              createInstance(Ci.nsIXMLHttpRequest);
+  xhr.open("POST", baseURL + "/setup_params", true);
+  xhr.setRequestHeader("X-Params", JSON.stringify(params));
+  xhr.addEventListener("load", () => deferred.resolve(xhr));
+  xhr.addEventListener("error", error => deferred.reject(error));
+  xhr.send();
+
+  return deferred.promise;
+}
+
+function promiseDeletedOAuthParams(baseURL) {
+  let deferred = Promise.defer();
+  let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
+              createInstance(Ci.nsIXMLHttpRequest);
+  xhr.open("DELETE", baseURL + "/setup_params", true);
+  xhr.addEventListener("load", () => deferred.resolve(xhr));
+  xhr.addEventListener("error", error => deferred.reject(error));
+  xhr.send();
+
+  return deferred.promise;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/loop/test/mochitest/loop_fxa.sjs
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * This is a mock server that implements the FxA endpoints on the Loop server.
+ */
+
+"use strict";
+
+const REQUIRED_PARAMS = ["client_id", "content_uri", "oauth_uri", "profile_uri", "state"];
+
+/**
+ * Entry point for HTTP requests.
+ */
+function handleRequest(request, response) {
+  switch (request.queryString) {
+    case "/setup_params":
+      setup_params(request, response);
+      return;
+    case "/fxa-oauth/params":
+      params(request, response);
+      return;
+  }
+  response.setStatusLine(request.httpVersion, 404, "Not Found");
+}
+
+/**
+ * POST /setup_params
+ * DELETE /setup_params
+ *
+ * Test-only endpoint to setup the /fxa-oauth/params response.
+ *
+ * For a POST the X-Params header should contain a JSON object with keys to set for /fxa-oauth/params.
+ * A DELETE request will delete the stored parameters and should be run in a cleanup function to
+ * avoid interfering with subsequen tests.
+ */
+function setup_params(request, response) {
+  response.setHeader("Content-Type", "text/plain", false);
+  if (request.method == "DELETE") {
+    setSharedState("/fxa-oauth/params", "");
+    response.write("Params deleted");
+    return;
+  }
+  let params = JSON.parse(request.getHeader("X-Params"));
+  if (!params) {
+    response.setStatusLine(request.httpVersion, 400, "Bad Request");
+    return;
+  }
+  setSharedState("/fxa-oauth/params", JSON.stringify(params));
+  response.write("Params updated");
+}
+
+/**
+ * POST /fxa-oauth/params endpoint
+ *
+ * Fetch OAuth parameters used to start the OAuth flow in the browser.
+ * Parameters: None
+ * Response: JSON containing an object of oauth parameters.
+ */
+function params(request, response) {
+  if (request.method != "POST") {
+    response.setStatusLine(request.httpVersion, 405, "Method Not Allowed");
+    response.setHeader("Allow", "POST", false);
+
+    // Add a button to make a POST request to make this endpoint easier to debug in the browser.
+    response.write("<form method=POST><button type=submit>POST</button></form>");
+    return;
+  }
+
+  let origin = request.scheme + "://" + request.host + ":" + request.port;
+
+  let params = JSON.parse(getSharedState("/fxa-oauth/params") || "{}");
+
+  // Warn if required parameters are missing.
+  for (let paramName of REQUIRED_PARAMS) {
+    if (!(paramName in params)) {
+      dump("Warning: " + paramName + " is a required parameter\n");
+    }
+  }
+
+  // Save the result so we have the effective `state` value.
+  setSharedState("/fxa-oauth/params", JSON.stringify(params));
+  response.setHeader("Content-Type", "application/json; charset=utf-8", false);
+  response.write(JSON.stringify(params, null, 2));
+}