Bug 1258360 - [webext] Mochitest plain runtime.onMessageExternal and runtime.onConnectExternal. r?kmag draft
authorLuca Greco <lgreco@mozilla.com>
Mon, 09 May 2016 15:48:01 +0200
changeset 364835 99488d71bc27c97591b43c469782da6159722427
parent 364834 c3b9caddf860947e80b6bbedc07e0f53971d9013
child 520396 9cf9d2c9e81a07d2ccce6f0caa564e59492c5370
push id17573
push userluca.greco@alcacoop.it
push dateMon, 09 May 2016 13:55:29 +0000
reviewerskmag
bugs1258360
milestone49.0a1
Bug 1258360 - [webext] Mochitest plain runtime.onMessageExternal and runtime.onConnectExternal. r?kmag MozReview-Commit-ID: 2VOZMRo90ZM
toolkit/components/extensions/test/mochitest/mochitest.ini
toolkit/components/extensions/test/mochitest/test_ext_runtime_cross_addons_messaging.html
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -51,16 +51,17 @@ skip-if = buildapp == 'b2g' # runat != d
 [test_ext_onmessage_removelistener.html]
 [test_ext_notifications.html]
 [test_ext_permission_xhr.html]
 skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE:
 [test_ext_runtime_connect.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
 [test_ext_runtime_connect2.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
+[test_ext_runtime_cross_addons_messaging.html]
 [test_ext_runtime_disconnect.html]
 [test_ext_runtime_getPlatformInfo.html]
 [test_ext_runtime_sendMessage.html]
 [test_ext_sandbox_var.html]
 [test_ext_sendmessage_reply.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
 [test_ext_sendmessage_reply2.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_cross_addons_messaging.html
@@ -0,0 +1,325 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>WebExtension test</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="text/javascript">
+"use strict";
+
+/**
+ *  This test file contains test cases related to cross addon messages exchange
+ *  based on `runtime.onMessageExternal` and `runtime.onConnectExternal`,
+ *  each test coordinates a message exchange between two extensions,
+ *  a sender and receiver, and makes assertions on the collected data
+ *  (messages, replies, ports and sender info).
+ *
+ *  - `test_onMessageExternal`: this test case coordinates a message
+ *    exchange based on `runtime.sendMessage` and `runtime.onMessageExternal`,
+ *    implemented in the following background scripts:
+ *
+ *    - `backgroundExternalMessageSender`
+ *    - `backgroundExternalMessageReceiver`
+ *
+ *  - `test_onConnectExternal`: this test case coordinates a message
+ *    exchange based on `runtime.connect` and `runtime.onConnectExternal`,
+ *    implemented in the following background scripts:
+ *
+ *    - `backgroundExternalConnectSender`
+ *    - `backgroundExternalConnectReceiver`
+ *
+ */
+function backgroundExternalMessageSender({type, targetAddonId, msgToSend}) {
+  browser.test.onMessage.addListener(msg => {
+    if (msg == "send-internal-message") {
+      browser.runtime.sendMessage("internal-send-message");
+    } else if (msg == "send-external-message") {
+      browser.runtime.sendMessage(targetAddonId, msgToSend, {}, response => {
+        browser.test.sendMessage(`${type}.got-reply`, {
+          msg_reply: response,
+        });
+      });
+      browser.test.log(`${browser.runtime.id} sent a message to ${targetAddonId}`);
+    }
+  });
+
+  browser.runtime.onMessage.addListener(msg => {
+    if (msg == "internal-send-message") {
+      browser.test.log(`Internal send message received from the internal listener as expected`);
+      browser.test.notifyPass("send-internal-message.done");
+    } else {
+      browser.test.fail(`runtime.onMessage received an unexpected internal message: "${msg}"`);
+      browser.test.notifyFail("send-internal-message.done");
+    }
+  });
+
+  // This `runtime.onMessageExternal` should not receive any message, if it does
+  // it means that the `MessageChannel.getHandlers` method is not filtering
+  // the `isExternal == false` handlers correctly.
+  browser.runtime.onMessageExternal.addListener(msg => {
+    browser.test.fail(`runtime.onMessageExternal received an unexpected message: "${msg}"`);
+    browser.test.notifyFail("send-internal-message.done");
+  });
+
+  browser.test.sendMessage(`${type}.ready`, {
+    id: browser.runtime.id,
+    uuid: String(window.location).match("://(.*)/")[1],
+    bgURL: String(window.location),
+  });
+}
+
+function backgroundExternalMessageReceiver({type}) {
+  // This `runtime.onMessage` should not receive any message, if it does
+  // it means that the `MessageChannel.getHandlers` method is not filtering
+  // the `isExternal == false` handlers correctly.
+  browser.runtime.onMessage.addListener((msg, sender, sendResponse) => {
+    browser.test.fail(`runtime.onMessage received an unexpected msg: ${msg}`);
+    browser.test.sendMessage(`${type}.got-message`, {
+      msg, sender,
+    });
+  });
+
+  browser.runtime.onMessageExternal.addListener((msg, sender, sendResponse) => {
+    browser.test.log(`${browser.runtime.id} received a message from ${sender.extensionId}`);
+    let msg_reply = `${type}.reply`;
+
+    sendResponse(msg_reply);
+
+    browser.test.sendMessage(`${type}.got-message`, {
+      msg, sender, msg_reply,
+    });
+  });
+
+  browser.test.sendMessage(`${type}.ready`, {
+    id: browser.runtime.id,
+    uuid: String(window.location).match("://(.*)/")[1],
+    bgURL: String(window.location),
+  });
+}
+
+function backgroundExternalConnectSender({type, targetAddonId}) {
+  browser.test.onMessage.addListener(msg => {
+    if (msg == "send-internal-connect") {
+      browser.runtime.onConnect.addListener(port => {
+        port.postMessage("internal-port-message");
+      });
+
+      let port = browser.runtime.connect();
+      port.onMessage.addListener(msg => {
+        if (msg == "internal-port-message") {
+          browser.test.log(`Got the expected internal message on the the internal listener`);
+          browser.test.notifyPass("send-internal-connect.done");
+        } else {
+          browser.test.fail(`port.onMessage received an unexpected internal message: "${msg}"`);
+          browser.test.notifyFail("send-internal-message.done");
+        }
+        port.disconnect();
+      });
+    } else if (msg == "send-external-connect") {
+      let port = browser.runtime.connect(targetAddonId);
+      browser.test.log(`${browser.runtime.id} connected to ${targetAddonId}`);
+
+      port.onMessage.addListener(msg => {
+        browser.test.log(`${browser.runtime.id} received a message from ${targetAddonId}`);
+
+        browser.test.sendMessage(`${type}.got-message`, {msg});
+      });
+    }
+  });
+
+  // This `runtime.onConnectExternal` should not receive any port, if it does
+  // it means that the `MessageChannel.getHandlers` method is not filtering
+  // the `isExternal == true` handlers correctly.
+  browser.runtime.onConnectExternal.addListener(port => {
+    browser.test.fail(`runtime.onConnectExternal received an unexpected port from: "${JSON.stringify(port.sender)}"`);
+    browser.test.notifyFail("send-internal-connect.done");
+  });
+
+  browser.test.sendMessage(`${type}.ready`, {
+    id: browser.runtime.id,
+    uuid: String(window.location).match("://(.*)/")[1],
+    bgURL: String(window.location),
+  });
+}
+
+function backgroundExternalConnectReceiver({type, msgToSend}) {
+  // This `runtime.onConnect` should not receive any port, if it does
+  // it means that the `MessageChannel.getHandlers` method is not filtering
+  // the `isExternal == false` handlers correctly.
+  browser.runtime.onConnect.addListener(port => {
+    let sender = port.sender || {};
+    browser.test.fail(`runtime.onConnect received an unexpected port from: ${JSON.stringify(sender)}`);
+    browser.test.sendMessage(`${type}.got-port`, {sender});
+  });
+
+  browser.runtime.onConnectExternal.addListener(port => {
+    let sender = port.sender || {};
+    browser.test.log(`${browser.runtime.id} received a connection from ${sender.extensionId}`);
+    browser.test.sendMessage(`${type}.got-port`, {sender});
+
+    port.postMessage(msgToSend);
+
+    browser.test.log(`${browser.runtime.id} sent a message to ${sender.extensionId}`);
+  });
+
+  browser.test.sendMessage(`${type}.ready`, {
+    id: browser.runtime.id,
+    uuid: String(window.location).match("://(.*)/")[1],
+    bgURL: String(window.location),
+  });
+}
+
+function makeExtension(params) {
+  let {type} = params;
+  let backgroundScript;
+  switch (type) {
+    case "external-message-sender":
+      backgroundScript = backgroundExternalMessageSender;
+      break;
+    case "external-message-receiver":
+      backgroundScript = backgroundExternalMessageReceiver;
+      break;
+    case "external-connect-sender":
+      backgroundScript = backgroundExternalConnectSender;
+      break;
+    case "external-connect-receiver":
+      backgroundScript = backgroundExternalConnectReceiver;
+      break;
+    default:
+      throw new Error("makeExtension - unknown extension of type '${type}'");
+  }
+
+  let extensionData = {
+    background: `(${backgroundScript})(${JSON.stringify(params)});`,
+  };
+  return extensionData;
+}
+
+add_task(function* test_onMessageExternal() {
+  let receiverExtension = ExtensionTestUtils.loadExtension(
+    makeExtension({
+      type: "external-message-receiver",
+    })
+  );
+
+  let senderExtension = ExtensionTestUtils.loadExtension(
+    makeExtension({
+      type: "external-message-sender",
+      targetAddonId: receiverExtension.id,
+      msgToSend: "cross-addons-msg",
+    })
+  );
+
+  yield Promise.all([senderExtension.startup(), receiverExtension.startup()]);
+
+  let [
+    senderInfo,
+    // NOTE: receiverInfo is currently unused
+  ] = yield Promise.all([
+    senderExtension.awaitMessage("external-message-sender.ready"),
+    receiverExtension.awaitMessage("external-message-receiver.ready"),
+  ]);
+
+  senderExtension.sendMessage("send-internal-message");
+  yield senderExtension.awaitFinish("send-internal-message.done");
+
+  senderExtension.sendMessage("send-external-message");
+
+  let [
+    finalReceiverInfo,
+    finalSenderInfo,
+  ] = yield Promise.all([
+    receiverExtension.awaitMessage("external-message-receiver.got-message"),
+    senderExtension.awaitMessage("external-message-sender.got-reply"),
+  ]);
+
+  ok(finalSenderInfo, "The sender extension has got a reply");
+  is(finalSenderInfo.msg_reply, finalReceiverInfo.msg_reply,
+     "The receiver has got the expected message");
+
+  ok(finalReceiverInfo, "The receiver extension has got a message");
+  is(finalReceiverInfo.msg, "cross-addons-msg", "The receiver has got the expected message");
+
+  is(finalReceiverInfo.sender && finalReceiverInfo.sender.url,
+     senderInfo.bgURL, "The receiver has got the expected sender.url");
+
+  // NOTE: sender.id should be probably equal to the sender addon id instead of its uuid,
+  // so that the received could be able to decide if he wants to receive messages from that
+  // particular addon. (current the sender addon id is in the sender as sender.extensionId)
+  is(finalReceiverInfo.sender && finalReceiverInfo.sender.id,
+     senderInfo.uuid, "The receiver has got the expected sender.id");
+  is(finalReceiverInfo.sender && finalReceiverInfo.sender.extensionId,
+     senderInfo.id, "The receiver has got the expected sender.extensionId");
+
+  yield senderExtension.unload();
+  yield receiverExtension.unload();
+});
+
+add_task(function* test_onConnectExternal() {
+  let receiverExtension = ExtensionTestUtils.loadExtension(
+    makeExtension({
+      type: "external-connect-receiver",
+      msgToSend: "cross-addons-msg",
+    })
+  );
+
+  let senderExtension = ExtensionTestUtils.loadExtension(
+    makeExtension({
+      type: "external-connect-sender",
+      targetAddonId: receiverExtension.id,
+    })
+  );
+
+  yield Promise.all([senderExtension.startup(), receiverExtension.startup()]);
+
+  let [
+    senderInfo,
+    // NOTE: receiverInfo is currently unused
+  ] = yield Promise.all([
+    senderExtension.awaitMessage("external-connect-sender.ready"),
+    receiverExtension.awaitMessage("external-connect-receiver.ready"),
+  ]);
+
+  senderExtension.sendMessage("send-internal-connect");
+  yield senderExtension.awaitFinish("send-internal-connect.done");
+
+  senderExtension.sendMessage("send-external-connect");
+
+  let [
+    finalSenderInfo,
+    finalReceiverInfo,
+  ] = yield Promise.all([
+    senderExtension.awaitMessage("external-connect-sender.got-message"),
+    receiverExtension.awaitMessage("external-connect-receiver.got-port"),
+  ]);
+
+  ok(finalReceiverInfo, "The receiver extension has got a port");
+  is(finalReceiverInfo.sender && finalReceiverInfo.sender.url,
+     senderInfo.bgURL, "The receiver has got the expected sender.url");
+
+  // NOTE: sender.id should be probably equal to the sender addon id instead of its uuid,
+  // so that the received could be able to decide if he wants to receive messages from that
+  // particular addon. (current the sender addon id is in the sender as sender.extensionId)
+  is(finalReceiverInfo.sender && finalReceiverInfo.sender.id,
+     senderInfo.uuid, "The receiver has got the expected sender.id");
+  is(finalReceiverInfo.sender && finalReceiverInfo.sender.extensionId,
+     senderInfo.id, "The receiver has got the expected sender.extensionId");
+
+  ok(finalSenderInfo, "The sender extension has got a message");
+  is(finalSenderInfo.msg, "cross-addons-msg", "The sender has got the expected message");
+
+  yield senderExtension.unload();
+  yield receiverExtension.unload();
+});
+
+
+</script>
+
+</body>
+</html>