|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 Cu.import("resource://gre/modules/Services.jsm"); |
|
6 |
|
7 const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs"; |
|
8 const gTestRoot = getRootDirectory(gTestPath); |
|
9 var gTestBrowser = null; |
|
10 |
|
11 // Test that plugin crash submissions still work properly after |
|
12 // click-to-play activation. |
|
13 |
|
14 function test() { |
|
15 // Crashing the plugin takes up a lot of time, so extend the test timeout. |
|
16 requestLongerTimeout(2); |
|
17 waitForExplicitFinish(); |
|
18 setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY); |
|
19 |
|
20 // The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin |
|
21 // crash reports. This test needs them enabled. The test also needs a mock |
|
22 // report server, and fortunately one is already set up by toolkit/ |
|
23 // crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL, |
|
24 // which CrashSubmit.jsm uses as a server override. |
|
25 let env = Cc["@mozilla.org/process/environment;1"]. |
|
26 getService(Components.interfaces.nsIEnvironment); |
|
27 let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT"); |
|
28 let serverURL = env.get("MOZ_CRASHREPORTER_URL"); |
|
29 env.set("MOZ_CRASHREPORTER_NO_REPORT", ""); |
|
30 env.set("MOZ_CRASHREPORTER_URL", SERVER_URL); |
|
31 |
|
32 let tab = gBrowser.loadOneTab("about:blank", { inBackground: false }); |
|
33 gTestBrowser = gBrowser.getBrowserForTab(tab); |
|
34 gTestBrowser.addEventListener("PluginCrashed", onCrash, false); |
|
35 gTestBrowser.addEventListener("load", onPageLoad, true); |
|
36 Services.obs.addObserver(onSubmitStatus, "crash-report-status", false); |
|
37 |
|
38 registerCleanupFunction(function cleanUp() { |
|
39 env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport); |
|
40 env.set("MOZ_CRASHREPORTER_URL", serverURL); |
|
41 gTestBrowser.removeEventListener("PluginCrashed", onCrash, false); |
|
42 gTestBrowser.removeEventListener("load", onPageLoad, true); |
|
43 Services.obs.removeObserver(onSubmitStatus, "crash-report-status"); |
|
44 gBrowser.removeCurrentTab(); |
|
45 }); |
|
46 |
|
47 gTestBrowser.contentWindow.location = gTestRoot + "plugin_big.html"; |
|
48 } |
|
49 function onPageLoad() { |
|
50 // Force the plugins binding to attach as layout is async. |
|
51 let plugin = gTestBrowser.contentDocument.getElementById("test"); |
|
52 plugin.clientTop; |
|
53 executeSoon(afterBindingAttached); |
|
54 } |
|
55 |
|
56 function afterBindingAttached() { |
|
57 let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); |
|
58 ok(popupNotification, "Should have a click-to-play notification"); |
|
59 |
|
60 let plugin = gTestBrowser.contentDocument.getElementById("test"); |
|
61 let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); |
|
62 ok(!objLoadingContent.activated, "Plugin should not be activated"); |
|
63 |
|
64 // Simulate clicking the "Allow Always" button. |
|
65 popupNotification.reshow(); |
|
66 PopupNotifications.panel.firstChild._primaryButton.click(); |
|
67 |
|
68 let condition = function() objLoadingContent.activated; |
|
69 waitForCondition(condition, pluginActivated, "Waited too long for plugin to activate"); |
|
70 } |
|
71 |
|
72 function pluginActivated() { |
|
73 let plugin = gTestBrowser.contentDocument.getElementById("test"); |
|
74 try { |
|
75 plugin.crash(); |
|
76 } catch (e) { |
|
77 // The plugin crashed in the above call, an exception is expected. |
|
78 } |
|
79 } |
|
80 |
|
81 function onCrash() { |
|
82 try { |
|
83 let plugin = gBrowser.contentDocument.getElementById("test"); |
|
84 let elt = gPluginHandler.getPluginUI.bind(gPluginHandler, plugin); |
|
85 let style = |
|
86 gBrowser.contentWindow.getComputedStyle(elt("pleaseSubmit")); |
|
87 is(style.display, "block", "Submission UI visibility should be correct"); |
|
88 |
|
89 elt("submitComment").value = "a test comment"; |
|
90 is(elt("submitURLOptIn").checked, true, "URL opt-in should default to true"); |
|
91 EventUtils.synthesizeMouseAtCenter(elt("submitURLOptIn"), {}, gTestBrowser.contentWindow); |
|
92 EventUtils.synthesizeMouseAtCenter(elt("submitButton"), {}, gTestBrowser.contentWindow); |
|
93 // And now wait for the submission status notification. |
|
94 } |
|
95 catch (err) { |
|
96 failWithException(err); |
|
97 } |
|
98 } |
|
99 |
|
100 function onSubmitStatus(subj, topic, data) { |
|
101 try { |
|
102 // Wait for success or failed, doesn't matter which. |
|
103 if (data != "success" && data != "failed") |
|
104 return; |
|
105 |
|
106 let extra = getPropertyBagValue(subj.QueryInterface(Ci.nsIPropertyBag), |
|
107 "extra"); |
|
108 ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag"); |
|
109 |
|
110 let val = getPropertyBagValue(extra, "PluginUserComment"); |
|
111 is(val, "a test comment", |
|
112 "Comment in extra data should match comment in textbox"); |
|
113 |
|
114 val = getPropertyBagValue(extra, "PluginContentURL"); |
|
115 ok(val === undefined, |
|
116 "URL should be absent from extra data when opt-in not checked"); |
|
117 } |
|
118 catch (err) { |
|
119 failWithException(err); |
|
120 } |
|
121 finish(); |
|
122 } |
|
123 |
|
124 function getPropertyBagValue(bag, key) { |
|
125 try { |
|
126 var val = bag.getProperty(key); |
|
127 } |
|
128 catch (e if e.result == Cr.NS_ERROR_FAILURE) {} |
|
129 return val; |
|
130 } |
|
131 |
|
132 function failWithException(err) { |
|
133 ok(false, "Uncaught exception: " + err + "\n" + err.stack); |
|
134 } |