Bug 776208 - Tests for plugin preview overlay. r=jaws
authorYury <async.processingjs@yahoo.com>
Fri, 24 Aug 2012 16:18:17 -0400
changeset 105380 4e2788b485d4ee18379a678ac2271bb228ed08a1
parent 105379 ed93b381d52ae402e79295cd342cf65bb87f21d0
child 105381 b3c861bd1e2fda67d732c0520c4c0eec997a7258
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersjaws
bugs776208
milestone17.0a1
Bug 776208 - Tests for plugin preview overlay. r=jaws
browser/base/content/test/Makefile.in
browser/base/content/test/browser_pluginnotification.js
browser/base/content/test/browser_pluginplaypreview.js
browser/base/content/test/head.js
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -177,16 +177,17 @@ endif
                  browser_hide_removing.js \
                  browser_overflowScroll.js \
                  browser_locationBarCommand.js \
                  browser_locationBarExternalLoad.js \
                  browser_page_style_menu.js \
                  browser_pinnedTabs.js \
                  browser_plainTextLinks.js \
                  browser_pluginnotification.js \
+                 browser_pluginplaypreview.js \
                  browser_relatedTabs.js \
                  browser_sanitize-passwordDisabledHosts.js \
                  browser_sanitize-sitepermissions.js \
                  browser_sanitize-timespans.js \
                  browser_clearplugindata.js \
                  browser_clearplugindata.html \
                  browser_clearplugindata_noage.html \
                  browser_popupUI.js \
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -2,28 +2,16 @@ var rootDir = getRootDirectory(gTestPath
 const gTestRoot = rootDir;
 const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
 
 var gTestBrowser = null;
 var gNextTest = null;
 var gClickToPlayPluginActualEvents = 0;
 var gClickToPlayPluginExpectedEvents = 5;
 
-function get_test_plugin() {
-  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
-  var tags = ph.getPluginTags();
-
-  // Find the test plugin
-  for (var i = 0; i < tags.length; i++) {
-    if (tags[i].name == "Test Plug-in")
-      return tags[i];
-  }
-  ok(false, "Unable to find plugin");
-}
-
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 // This listens for the next opened tab and checks it is of the right url.
 // opencallback is called when the new tab is fully loaded
 // closecallback is called when the tab is closed
 function TabOpenListener(url, opencallback, closecallback) {
   this.url = url;
   this.opencallback = opencallback;
@@ -112,31 +100,31 @@ function test1() {
   ok("application/x-unknown" in gTestBrowser.missingPlugins, "Test 1, Should know about application/x-unknown");
   ok(!("application/x-test" in gTestBrowser.missingPlugins), "Test 1, Should not know about application/x-test");
 
   var pluginNode = gTestBrowser.contentDocument.getElementById("unknown");
   ok(pluginNode, "Test 1, Found plugin in page");
   var objLoadingContent = pluginNode.QueryInterface(Ci.nsIObjectLoadingContent);
   is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED, "Test 1, plugin fallback type should be PLUGIN_UNSUPPORTED");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   ok(plugin, "Should have a test plugin");
   plugin.disabled = false;
   plugin.blocklisted = false;
   prepareTest(test2, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a working plugin in it.
 function test2() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 2, Should not have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 2, Should not have displayed the blocked plugin notification");
   ok(!gTestBrowser.missingPlugins, "Test 2, Should not be a missing plugin list");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   ok(plugin, "Should have a test plugin");
   plugin.disabled = true;
   prepareTest(test3, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a disabled plugin in it.
 function test3() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
@@ -157,17 +145,17 @@ function test3() {
 }
 
 function test4(tab, win) {
   is(win.wrappedJSObject.gViewController.currentViewId, "addons://list/plugin", "Test 4, Should have displayed the plugins pane");
   gBrowser.removeTab(tab);
 }
 
 function prepareTest5() {
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = true;
   prepareTest(test5, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a blocked plugin in it.
 function test5() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
@@ -200,17 +188,17 @@ function test6() {
 function test7() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(notificationBox.getNotificationWithValue("missing-plugins"), "Test 7, Should have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 7, Should not have displayed the blocked plugin notification");
   ok(gTestBrowser.missingPlugins, "Test 7, Should be a missing plugin list");
   ok("application/x-unknown" in gTestBrowser.missingPlugins, "Test 7, Should know about application/x-unknown");
   ok("application/x-test" in gTestBrowser.missingPlugins, "Test 7, Should know about application/x-test");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = false;
   Services.prefs.setBoolPref("plugins.click_to_play", true);
 
   prepareTest(test8, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a working plugin that is click-to-play
@@ -456,17 +444,17 @@ function test13c() {
 }
 
 // Tests that the plugin's "activated" property is true for working plugins with click-to-play disabled.
 function test14() {
   var plugin = gTestBrowser.contentDocument.getElementById("test1");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 14, Plugin should be activated");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = false;
   Services.perms.removeAll();
   Services.prefs.setBoolPref("plugins.click_to_play", true);
   prepareTest(test15, gTestRoot + "plugin_alternate_content.html");
 }
 
 // Tests that the overlay is shown instead of alternate content when
@@ -635,17 +623,17 @@ function test18c() {
   is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE, "Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
   ok(!objLoadingContent.activated, "Test 18c, Plugin should not be activated");
   var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
   ok(overlay.style.visibility != "hidden", "Test 18c, Plugin overlay should exist, not be hidden");
   var updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
   ok(updateLink.style.display != "block", "Test 18c, Plugin should not have an update link");
 
   unregisterFakeBlocklistService();
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.clicktoplay = false;
 
   prepareTest(test19a, gTestRoot + "plugin_test.html");
 }
 
 // Tests that clicking the icon of the overlay activates the plugin
 function test19a() {
   var doc = gTestBrowser.contentDocument;
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_pluginplaypreview.js
@@ -0,0 +1,309 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir;
+
+var gTestBrowser = null;
+var gNextTest = null;
+var gPlayPreviewPluginActualEvents = 0;
+var gPlayPreviewPluginExpectedEvents = 1;
+
+var gPlayPreviewRegistration = null;
+
+function registerPlayPreview(mimeType, targetUrl) {
+
+  function StreamConverterFactory() {}
+  StreamConverterFactory.prototype = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]),
+    _targetConstructor: null,
+
+    register: function register(targetConstructor) {
+      this._targetConstructor = targetConstructor;
+      var proto = targetConstructor.prototype;
+      var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+      registrar.registerFactory(proto.classID, proto.classDescription,
+                                proto.contractID, this);
+    },
+
+    unregister: function unregister() {
+      var proto = this._targetConstructor.prototype;
+      var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+      registrar.unregisterFactory(proto.classID, this);
+      this._targetConstructor = null;
+    },
+
+    // nsIFactory
+    createInstance: function createInstance(aOuter, iid) {
+      if (aOuter !== null)
+        throw Cr.NS_ERROR_NO_AGGREGATION;
+      return (new (this._targetConstructor)).QueryInterface(iid);
+    },
+
+    // nsIFactory
+    lockFactory: function lockFactory(lock) {
+      // No longer used as of gecko 1.7.
+      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  };
+
+  function OverlayStreamConverter() {}
+  OverlayStreamConverter.prototype = {
+    QueryInterface: XPCOMUtils.generateQI([
+        Ci.nsISupports,
+        Ci.nsIStreamConverter,
+        Ci.nsIStreamListener,
+        Ci.nsIRequestObserver
+    ]),
+
+    classID: Components.ID('{4c6030f7-e20a-264f-0f9b-ada3a9e97384}'),
+    classDescription: 'overlay-test-data Component',
+    contractID: '@mozilla.org/streamconv;1?from=application/x-moz-playpreview&to=*/*',
+
+    // nsIStreamConverter::convert
+    convert: function(aFromStream, aFromType, aToType, aCtxt) {
+      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+    },
+
+    // nsIStreamConverter::asyncConvertData
+    asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
+      var isValidRequest = false;
+      try {
+        var request = aCtxt;
+        request.QueryInterface(Ci.nsIChannel);
+        var spec = request.URI.spec;
+        var expectedSpec = 'data:application/x-moz-playpreview;,' + mimeType;
+        isValidRequest = (spec == expectedSpec);
+      } catch (e) { }
+      if (!isValidRequest)
+        throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+
+      // Store the listener passed to us
+      this.listener = aListener;
+    },
+
+    // nsIStreamListener::onDataAvailable
+    onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
+      // Do nothing since all the data loading is handled by the viewer.
+      ok(false, "onDataAvailable should not be called");
+    },
+
+    // nsIRequestObserver::onStartRequest
+    onStartRequest: function(aRequest, aContext) {
+
+      // Setup the request so we can use it below.
+      aRequest.QueryInterface(Ci.nsIChannel);
+      // Cancel the request so the viewer can handle it.
+      aRequest.cancel(Cr.NS_BINDING_ABORTED);
+
+      // Create a new channel that is viewer loaded as a resource.
+      var ioService = Services.io;
+      var channel = ioService.newChannel(targetUrl, null, null);
+      channel.asyncOpen(this.listener, aContext);
+    },
+
+    // nsIRequestObserver::onStopRequest
+    onStopRequest: function(aRequest, aContext, aStatusCode) {
+      // Do nothing.
+    }
+  };
+
+  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+  ph.registerPlayPreviewMimeType(mimeType);
+
+  var factory = new StreamConverterFactory();
+  factory.register(OverlayStreamConverter);
+
+  return (gPlayPreviewRegistration = {
+    unregister: function() {
+      ph.unregisterPlayPreviewMimeType(mimeType);
+      factory.unregister();
+      gPlayPreviewRegistration = null;
+    }
+  });
+}
+
+function unregisterPlayPreview() {
+  gPlayPreviewRegistration.unregister();
+}
+
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(function() {
+    if (gPlayPreviewRegistration)
+      gPlayPreviewRegistration.unregister();
+    Services.prefs.clearUserPref("plugins.click_to_play");
+  });
+
+  var newTab = gBrowser.addTab();
+  gBrowser.selectedTab = newTab;
+  gTestBrowser = gBrowser.selectedBrowser;
+  gTestBrowser.addEventListener("load", pageLoad, true);
+  gTestBrowser.addEventListener("PluginPlayPreview", handlePluginPlayPreview, true);
+
+  registerPlayPreview('application/x-test', 'about:');
+  prepareTest(test1a, gTestRoot + "plugin_test.html");
+}
+
+function finishTest() {
+  gTestBrowser.removeEventListener("load", pageLoad, true);
+  gTestBrowser.removeEventListener("PluginPlayPreview", handlePluginPlayPreview, true);
+  gBrowser.removeCurrentTab();
+  window.focus();
+  finish();
+}
+
+function handlePluginPlayPreview() {
+  gPlayPreviewPluginActualEvents++;
+}
+
+function pageLoad() {
+  // The plugin events are async dispatched and can come after the load event
+  // This just allows the events to fire before we then go on to test the states
+
+  // XXX overlay iframe might trigger load event as well, making sure we call the next test once
+  if (!gNextTest)
+    return;
+  var nextTest = gNextTest;
+  gNextTest = null;
+
+  executeSoon(nextTest);
+}
+
+function prepareTest(nextTest, url) {
+  gNextTest = nextTest;
+  gTestBrowser.contentWindow.location = url;
+}
+
+// Tests a page with normal play preview registration (1/2)
+function test1a() {
+  var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
+  ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 1a, Should not have displayed the missing plugin notification");
+  ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 1a, Should not have displayed the blocked plugin notification");
+
+  var pluginInfo = getTestPlugin();
+  ok(pluginInfo, "Should have a test plugin");
+
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 1a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 1a, the overlay div is expected");
+
+  var iframe = overlay.getElementsByClassName("previewPluginContentFrame")[0];
+  ok(iframe && iframe.localName == "iframe", "Test 1a, the overlay iframe is expected");
+  var iframeHref = iframe.contentWindow.location.href;
+  ok(iframeHref == "about:", "Test 1a, the overlay about: content is expected");
+
+  var rect = iframe.getBoundingClientRect();
+  ok(rect.width == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being replaced by actual plugin");
+  ok(rect.height == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being replaced by actual plugin");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, null);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin to stop play preview");
+}
+
+// Tests that activating via MozPlayPlugin through the notification works (part 2/2)
+function test1b() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");
+
+  is(gPlayPreviewPluginActualEvents, gPlayPreviewPluginExpectedEvents,
+     "There should be exactly one PluginPlayPreview event");
+
+  unregisterPlayPreview();
+
+  prepareTest(test2, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- the mime type was just unregistered.
+function test2() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 2, Plugin should be activated");
+
+  registerPlayPreview('application/x-unknown', 'about:');
+
+  prepareTest(test3, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- diffent play preview type is reserved.
+function test3() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 3, Plugin should be activated");
+
+  unregisterPlayPreview();
+
+  registerPlayPreview('application/x-test', 'about:');
+  Services.prefs.setBoolPref("plugins.click_to_play", true);
+  prepareTest(test4a, gTestRoot + "plugin_test.html");
+}
+
+// Test a fallback to the click-to-play
+function test4a() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 4a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 4a, the overlay div is expected");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, true);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY;
+  waitForCondition(condition, test4b, "Test 4a, Waited too long for plugin to stop play preview");
+}
+
+function test4b() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4b, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 4b, Plugin should not be activated");
+
+  prepareTest(test5a, gTestRoot + "plugin_test.html");
+}
+
+// Test a bypass of the click-to-play
+function test5a() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 5a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 5a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 5a, the overlay div is expected");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, false);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test5b, "Test 5a, Waited too long for plugin to stop play preview");
+}
+
+function test5b() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 5b, Plugin should be activated");
+
+  finishTest();
+}
+
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head.js
@@ -83,16 +83,29 @@ function waitForCondition(condition, nex
     if (condition()) {
       moveOn();
     }
     tries++;
   }, 100);
   var moveOn = function() { clearInterval(interval); nextTest(); };
 }
 
+function getTestPlugin() {
+  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+  var tags = ph.getPluginTags();
+
+  // Find the test plugin
+  for (var i = 0; i < tags.length; i++) {
+    if (tags[i].name == "Test Plug-in")
+      return tags[i];
+  }
+  ok(false, "Unable to find plugin");
+  return null;
+}
+
 function runSocialTestWithProvider(manifest, callback) {
   let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
 
   info("runSocialTestWithProvider: " + manifest.toSource());
 
   let oldProvider;
   SocialService.addProvider(manifest, function(provider) {
     info("runSocialTestWithProvider: provider added");