From 95bb1e548fb9bb3d39a90cffc489f60325fd3db5 Mon Sep 17 00:00:00 2001 From: Yury Date: Sat, 25 Aug 2012 17:18:44 -0400 Subject: [PATCH] Bug 776208 - Plugin preview overlay test. r=jaws --- browser/base/content/test/Makefile.in | 1 + .../test/browser_pluginnotification.js | 24 +- .../content/test/browser_pluginplaypreview.js | 311 ++++++++++++++++++ browser/base/content/test/head.js | 13 + 4 files changed, 331 insertions(+), 18 deletions(-) create mode 100644 browser/base/content/test/browser_pluginplaypreview.js diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index 46a5ef26493..c1ff516cd03 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -179,6 +179,7 @@ _BROWSER_FILES = \ browser_pinnedTabs.js \ browser_plainTextLinks.js \ browser_pluginnotification.js \ + browser_pluginplaypreview.js \ browser_relatedTabs.js \ browser_sanitize-passwordDisabledHosts.js \ browser_sanitize-sitepermissions.js \ diff --git a/browser/base/content/test/browser_pluginnotification.js b/browser/base/content/test/browser_pluginnotification.js index 18793c32710..b2dcffc9f44 100644 --- a/browser/base/content/test/browser_pluginnotification.js +++ b/browser/base/content/test/browser_pluginnotification.js @@ -7,18 +7,6 @@ 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. @@ -117,7 +105,7 @@ function test1() { 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; @@ -131,7 +119,7 @@ function test2() { 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"); @@ -162,7 +150,7 @@ function test4(tab, win) { } function prepareTest5() { - var plugin = get_test_plugin(); + var plugin = getTestPlugin(); plugin.disabled = false; plugin.blocklisted = true; prepareTest(test5, gTestRoot + "plugin_test.html"); @@ -205,7 +193,7 @@ function test7() { 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); @@ -461,7 +449,7 @@ function test14() { 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(); @@ -640,7 +628,7 @@ function test18c() { 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"); diff --git a/browser/base/content/test/browser_pluginplaypreview.js b/browser/base/content/test/browser_pluginplaypreview.js new file mode 100644 index 00000000000..b8462680b1b --- /dev/null +++ b/browser/base/content/test/browser_pluginplaypreview.js @@ -0,0 +1,311 @@ +/* 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 gNextTestSkip = 0; +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", 1); +} + +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 + + // iframe might triggers load event as well, making sure we skip some to let + // all iframes on the page be loaded as well + if (gNextTestSkip) { + gNextTestSkip--; + return; + } + executeSoon(gNextTest); +} + +function prepareTest(nextTest, url, skip) { + gNextTest = nextTest; + gNextTestSkip = skip; + 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", 1); +} + +// 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", 1); +} + +// 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(); +} + diff --git a/browser/base/content/test/head.js b/browser/base/content/test/head.js index 565d07b3160..e22bf9184ba 100644 --- a/browser/base/content/test/head.js +++ b/browser/base/content/test/head.js @@ -97,6 +97,19 @@ function ensureSocialUrlNotRemembered(url) { ok(!gh.isVisited(uri), "social URL " + url + " should not be in global history"); } +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;