summaryrefslogtreecommitdiffstats
path: root/dom/ipc/tests
diff options
context:
space:
mode:
Diffstat (limited to 'dom/ipc/tests')
-rw-r--r--dom/ipc/tests/blob_verify.sjs20
-rw-r--r--dom/ipc/tests/browser.ini6
-rw-r--r--dom/ipc/tests/browser_domainPolicy.js240
-rw-r--r--dom/ipc/tests/chrome.ini8
-rw-r--r--dom/ipc/tests/file_bug1086684.html16
-rw-r--r--dom/ipc/tests/file_disableScript.html11
-rw-r--r--dom/ipc/tests/file_domainPolicy_base.html8
-rw-r--r--dom/ipc/tests/mochitest.ini22
-rw-r--r--dom/ipc/tests/process_error.xul58
-rw-r--r--dom/ipc/tests/process_error_contentscript.js7
-rw-r--r--dom/ipc/tests/test_CrashService_crash.html95
-rw-r--r--dom/ipc/tests/test_blob_sliced_from_child_process.html185
-rw-r--r--dom/ipc/tests/test_blob_sliced_from_parent_process.html213
-rw-r--r--dom/ipc/tests/test_bug1086684.html107
-rw-r--r--dom/ipc/tests/test_child_docshell.html86
-rw-r--r--dom/ipc/tests/test_cpow_cookies.html90
-rw-r--r--dom/ipc/tests/test_process_error.xul22
-rw-r--r--dom/ipc/tests/test_temporaryfile_stream.html80
18 files changed, 1274 insertions, 0 deletions
diff --git a/dom/ipc/tests/blob_verify.sjs b/dom/ipc/tests/blob_verify.sjs
new file mode 100644
index 000000000..62b82359e
--- /dev/null
+++ b/dom/ipc/tests/blob_verify.sjs
@@ -0,0 +1,20 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream");
+const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
+ "nsIBinaryOutputStream",
+ "setOutputStream");
+
+function handleRequest(request, response) {
+ var bodyStream = new BinaryInputStream(request.bodyInputStream);
+ var bodyBytes = [];
+ while ((bodyAvail = bodyStream.available()) > 0)
+ Array.prototype.push.apply(bodyBytes, bodyStream.readByteArray(bodyAvail));
+
+ var bos = new BinaryOutputStream(response.bodyOutputStream);
+
+ response.processAsync();
+ bos.writeByteArray(bodyBytes, bodyBytes.length);
+ response.finish();
+}
diff --git a/dom/ipc/tests/browser.ini b/dom/ipc/tests/browser.ini
new file mode 100644
index 000000000..f3d8ce140
--- /dev/null
+++ b/dom/ipc/tests/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+support-files =
+ file_disableScript.html
+ file_domainPolicy_base.html
+
+[browser_domainPolicy.js]
diff --git a/dom/ipc/tests/browser_domainPolicy.js b/dom/ipc/tests/browser_domainPolicy.js
new file mode 100644
index 000000000..df06b8bc0
--- /dev/null
+++ b/dom/ipc/tests/browser_domainPolicy.js
@@ -0,0 +1,240 @@
+var policy; // To make sure we never leave up an activated domain policy after a failed test, let's make this global.
+function activateDomainPolicy() {
+ const ssm = Services.scriptSecurityManager;
+ policy = ssm.activateDomainPolicy();
+}
+
+function deactivateDomainPolicy() {
+ if (policy) {
+ policy.deactivate();
+ policy = null;
+ }
+}
+
+function* test_domainPolicy() {
+
+ XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
+ let deferred = Promise.defer();
+ let currentTask = deferred.promise;
+ SpecialPowers.pushPrefEnv(
+ {set: [["dom.ipc.browser_frames.oop_by_default", false],
+ ["browser.pagethumbnails.capturing_disabled", false],
+ ["dom.mozBrowserFramesEnabled", false]]},
+ () => { return deferred.resolve()});
+ yield currentTask;
+
+ // Create tab
+ let tab;
+
+ // Init test
+ function initProcess() {
+ tab = gBrowser.addTab();
+ gBrowser.selectedTab = tab;
+
+ let initPromise = ContentTask.spawn(tab.linkedBrowser, null, function() {
+ Cu.import("resource://gre/modules/PromiseUtils.jsm");
+ function loadBase() {
+ let deferred = PromiseUtils.defer();
+ let listener = (event) => {
+ removeEventListener("DOMDocElementInserted", listener, true);
+ let listener2 = (event) => {
+ content.removeEventListener('load', listener2);
+ deferred.resolve();
+ }
+ content.addEventListener('load', listener2);
+ };
+ addEventListener("DOMDocElementInserted", listener, true);
+ return deferred.promise;
+ }
+
+ return loadBase();
+ });
+ tab.linkedBrowser.loadURI("http://mochi.test:8888/browser/dom/ipc/tests/file_domainPolicy_base.html");
+ return initPromise;
+ }
+
+ // We use ContentTask for the tests, but we also want to pass some data and some helper functions too.
+ // To do that, we serialize an input object via JSON |ipcArgs| and some shared helper functions |initUtils|
+ // and eval them in the content process.
+ var ipcArgs = {};
+ function initUtils(obj) {
+ obj.checkScriptEnabled = function(win, expectEnabled) {
+ win.wrappedJSObject.gFiredOnclick = false;
+ win.document.body.dispatchEvent(new win.Event('click'));
+ return { passed: win.wrappedJSObject.gFiredOnclick == expectEnabled,
+ msg: `Checking script-enabled for ${win.name} (${win.location})`};
+ }
+
+ obj.navigateFrame = function(ifr, src) {
+ let deferred = PromiseUtils.defer();
+ function onload() {
+ ifr.removeEventListener('load', onload);
+ deferred.resolve();
+ }
+ ifr.addEventListener('load', onload, false);
+ ifr.setAttribute('src', src);
+ return deferred.promise;
+ }
+ };
+
+ function runTest(test) {
+ return ContentTask.spawn(tab.linkedBrowser,
+ 'ipcArgs = ' + JSON.stringify(ipcArgs) + '; (' + initUtils.toSource() + ')(utils)', test);
+ }
+
+ function checkAndCleanup(result) {
+ result = [].concat(result);
+ for (var i in result)
+ ok(result[i].passed, result[i].msg);
+ gBrowser.removeTab(tab);
+ deactivateDomainPolicy();
+ ipcArgs = {};
+ }
+
+ function testDomain(domain) {
+ ipcArgs.domain = domain;
+ return (aUtils) => {
+ Cu.import("resource://gre/modules/PromiseUtils.jsm");
+ var ipcArgs;
+ var utils = {};
+ eval(aUtils);
+
+ let path = '/browser/dom/ipc/tests/file_disableScript.html';
+ let deferred = PromiseUtils.defer();
+ var rootFrame = content.document.getElementById('root');
+ utils.navigateFrame(rootFrame, ipcArgs.domain + path).then(() => {
+ deferred.resolve(utils.checkScriptEnabled(rootFrame.contentWindow, false));
+ });
+ return deferred.promise;
+ }
+ }
+
+ info("Testing simple blacklist policy");
+
+ info("Creating child process first, activating domainPolicy after");
+ currentTask = initProcess();
+ yield currentTask;
+ activateDomainPolicy();
+ var bl = policy.blacklist;
+ bl.add(Services.io.newURI('http://example.com', null, null));
+ currentTask = runTest(testDomain("http://example.com"));
+ checkAndCleanup(yield currentTask);
+
+ info("Activating domainPolicy first, creating child process after");
+ activateDomainPolicy();
+ var bl = policy.blacklist;
+ bl.add(Services.io.newURI('http://example.com', null, null));
+ currentTask = initProcess();
+ yield currentTask;
+ currentTask = runTest(testDomain("http://example.com"));
+ checkAndCleanup(yield currentTask);
+
+ function testList(expectEnabled, list) {
+ ipcArgs.expectEnabled = expectEnabled;
+ ipcArgs.list = list;
+ return (aUtils) => {
+ Cu.import("resource://gre/modules/PromiseUtils.jsm");
+ var ipcArgs;
+ var utils = {};
+ eval(aUtils);
+
+ var results = [];
+ var testListInternal = function(expectEnabled, list, idx) {
+ idx = idx || 0;
+ let deferred = PromiseUtils.defer();
+ let path = '/browser/dom/ipc/tests/file_disableScript.html';
+ let target = list[idx] + path;
+ var rootFrame = content.document.getElementById('root');
+ utils.navigateFrame(rootFrame, target).then(function() {
+ results.push(utils.checkScriptEnabled(rootFrame.contentWindow, expectEnabled));
+ if (idx == list.length - 1)
+ deferred.resolve(results);
+ else
+ testListInternal(expectEnabled, list, idx + 1).then(function(retArg) { deferred.resolve(retArg); });
+ });
+ return deferred.promise;
+ }
+ return testListInternal(ipcArgs.expectEnabled, ipcArgs.list);
+ }
+ }
+
+ let testPolicy = {
+ exceptions: ['http://test1.example.com', 'http://example.com'],
+ superExceptions: ['http://test2.example.org', 'https://test1.example.com'],
+ exempt: ['http://test1.example.com', 'http://example.com',
+ 'http://test2.example.org', 'http://sub1.test2.example.org',
+ 'https://sub1.test1.example.com'],
+ notExempt: ['http://test2.example.com', 'http://sub1.test1.example.com',
+ 'http://www.example.com', 'https://test2.example.com',
+ 'https://example.com', 'http://test1.example.org'],
+ };
+
+ function activate(isBlack, exceptions, superExceptions) {
+ activateDomainPolicy();
+ let set = isBlack ? policy.blacklist : policy.whitelist;
+ let superSet = isBlack ? policy.superBlacklist : policy.superWhitelist;
+ for (var e of exceptions)
+ set.add(makeURI(e));
+ for (var e of superExceptions)
+ superSet.add(makeURI(e));
+ };
+
+ info("Testing Blacklist-style Domain Policy");
+ info("Activating domainPolicy first, creating child process after");
+ activate(true, testPolicy.exceptions, testPolicy.superExceptions);
+ currentTask = initProcess();
+ yield currentTask;
+ let results = [];
+ currentTask = runTest(testList(true, testPolicy.notExempt));
+ results = results.concat(yield currentTask);
+ currentTask = runTest(testList(false, testPolicy.exempt));
+ results = results.concat(yield currentTask);
+ checkAndCleanup(results);
+
+ info("Creating child process first, activating domainPolicy after");
+ currentTask = initProcess();
+ yield currentTask;
+ activate(true, testPolicy.exceptions, testPolicy.superExceptions);
+ results = [];
+ currentTask = runTest(testList(true, testPolicy.notExempt));
+ results = results.concat(yield currentTask);
+ currentTask = runTest(testList(false, testPolicy.exempt));
+ results = results.concat(yield currentTask);
+ checkAndCleanup(results);
+
+ info("Testing Whitelist-style Domain Policy");
+ deferred = Promise.defer();
+ currentTask = deferred.promise;
+ SpecialPowers.pushPrefEnv({set:[["javascript.enabled", false]]}, () => { return deferred.resolve()});
+ yield currentTask;
+
+ info("Activating domainPolicy first, creating child process after");
+ activate(false, testPolicy.exceptions, testPolicy.superExceptions);
+ currentTask = initProcess();
+ yield currentTask;
+ results = [];
+ currentTask = runTest(testList(false, testPolicy.notExempt));
+ results = results.concat(yield currentTask);
+ currentTask = runTest(testList(true, testPolicy.exempt));
+ results = results.concat(yield currentTask);
+ checkAndCleanup(results);
+
+ info("Creating child process first, activating domainPolicy after");
+ currentTask = initProcess();
+ yield currentTask;
+ activate(false, testPolicy.exceptions, testPolicy.superExceptions);
+ results = [];
+ currentTask = runTest(testList(false, testPolicy.notExempt));
+ results = results.concat(yield currentTask);
+ currentTask = runTest(testList(true, testPolicy.exempt));
+ results = results.concat(yield currentTask);
+ checkAndCleanup(results);
+ finish();
+}
+
+
+add_task(test_domainPolicy);
+
+registerCleanupFunction(()=>{
+ deactivateDomainPolicy();
+}) \ No newline at end of file
diff --git a/dom/ipc/tests/chrome.ini b/dom/ipc/tests/chrome.ini
new file mode 100644
index 000000000..b6e3d4801
--- /dev/null
+++ b/dom/ipc/tests/chrome.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+skip-if = os == 'android'
+support-files =
+ process_error.xul
+ process_error_contentscript.js
+
+[test_process_error.xul]
+skip-if = !crashreporter
diff --git a/dom/ipc/tests/file_bug1086684.html b/dom/ipc/tests/file_bug1086684.html
new file mode 100644
index 000000000..95db6f387
--- /dev/null
+++ b/dom/ipc/tests/file_bug1086684.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1086684
+-->
+<head>
+ <title>Test for Bug 1086684</title>
+ <meta charset="UTF-8">
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1086684">Mozilla Bug 1086684</a>
+<div id="content">
+ <input type="file" id="f">
+</div>
+</body>
+</html>
diff --git a/dom/ipc/tests/file_disableScript.html b/dom/ipc/tests/file_disableScript.html
new file mode 100644
index 000000000..f4888cd58
--- /dev/null
+++ b/dom/ipc/tests/file_disableScript.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+var gFiredOnload = false;
+var gFiredOnclick = false;
+</script>
+</head>
+<body onload="gFiredOnload = true;" onclick="gFiredOnclick = true;">
+</body>
+</html>
diff --git a/dom/ipc/tests/file_domainPolicy_base.html b/dom/ipc/tests/file_domainPolicy_base.html
new file mode 100644
index 000000000..6e3ec7aec
--- /dev/null
+++ b/dom/ipc/tests/file_domainPolicy_base.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+<iframe id="root" name="root"/>
+</body>
+</html>
diff --git a/dom/ipc/tests/mochitest.ini b/dom/ipc/tests/mochitest.ini
new file mode 100644
index 000000000..cf2a20d5b
--- /dev/null
+++ b/dom/ipc/tests/mochitest.ini
@@ -0,0 +1,22 @@
+[DEFAULT]
+support-files =
+ file_bug1086684.html
+
+[test_blob_sliced_from_child_process.html]
+# This test is only supposed to run in the main process.
+skip-if = e10s
+[test_blob_sliced_from_parent_process.html]
+# This test is only supposed to run in the main process.
+skip-if = e10s
+[test_bug1086684.html]
+# This test is only supposed to run in the main process
+skip-if = e10s || toolkit == 'android'
+[test_cpow_cookies.html]
+[test_child_docshell.html]
+skip-if = toolkit == 'cocoa' # disabled due to hangs, see changeset 6852e7c47edf
+[test_CrashService_crash.html]
+skip-if = !(crashreporter && !e10s && (toolkit == 'gtk2' || toolkit == 'gtk3' || toolkit == 'cocoa' || toolkit == 'windows'))
+[test_temporaryfile_stream.html]
+support-files =
+ blob_verify.sjs
+ !/dom/canvas/test/captureStream_common.js
diff --git a/dom/ipc/tests/process_error.xul b/dom/ipc/tests/process_error.xul
new file mode 100644
index 000000000..62d3d9724
--- /dev/null
+++ b/dom/ipc/tests/process_error.xul
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ orient="vertical">
+
+ <browser id="thebrowser" type="content" remote="true" />
+ <script type="application/javascript"><![CDATA[
+ Components.utils.import("resource://gre/modules/Services.jsm");
+
+ const ok = window.opener.wrappedJSObject.ok;
+ const is = window.opener.wrappedJSObject.is;
+ const done = window.opener.wrappedJSObject.done;
+ const SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+
+ function getMinidumpDirectory() {
+ var dir = Services.dirsvc.get('ProfD', Components.interfaces.nsIFile);
+ dir.append("minidumps");
+ return dir;
+ }
+
+ function removeFile(directory, filename) {
+ var file = directory.clone();
+ file.append(filename);
+ if (file.exists()) {
+ file.remove(false);
+ }
+ }
+
+ function crashObserver(subject, topic, data) {
+ is(topic, 'ipc:content-shutdown', 'Received correct observer topic.');
+ ok(subject instanceof Components.interfaces.nsIPropertyBag2,
+ 'Subject implements nsIPropertyBag2.');
+
+ var dumpID;
+ if ('nsICrashReporter' in Components.interfaces) {
+ dumpID = subject.getPropertyAsAString('dumpID');
+ ok(dumpID, "dumpID is present and not an empty string");
+ }
+
+ if (dumpID) {
+ var minidumpDirectory = getMinidumpDirectory();
+ removeFile(minidumpDirectory, dumpID + '.dmp');
+ removeFile(minidumpDirectory, dumpID + '.extra');
+ }
+
+ Services.obs.removeObserver(crashObserver, 'ipc:content-shutdown');
+ done();
+ }
+ Services.obs.addObserver(crashObserver, 'ipc:content-shutdown', false);
+
+ document.getElementById('thebrowser')
+ .QueryInterface(Components.interfaces.nsIFrameLoaderOwner)
+ .frameLoader.messageManager
+ .loadFrameScript('chrome://mochitests/content/chrome/dom/ipc/tests/process_error_contentscript.js', true);
+ ]]></script>
+
+</window>
diff --git a/dom/ipc/tests/process_error_contentscript.js b/dom/ipc/tests/process_error_contentscript.js
new file mode 100644
index 000000000..789b8a37f
--- /dev/null
+++ b/dom/ipc/tests/process_error_contentscript.js
@@ -0,0 +1,7 @@
+Components.utils.import("resource://gre/modules/ctypes.jsm");
+
+privateNoteIntentionalCrash();
+
+var zero = new ctypes.intptr_t(8);
+var badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
+var crash = badptr.contents;
diff --git a/dom/ipc/tests/test_CrashService_crash.html b/dom/ipc/tests/test_CrashService_crash.html
new file mode 100644
index 000000000..a1d9b938d
--- /dev/null
+++ b/dom/ipc/tests/test_CrashService_crash.html
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Ensures that content crashes are reported to the crash service
+(nsICrashService and CrashManager.jsm).
+-->
+<head>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+SpecialPowers.addPermission("browser", true, document);
+SpecialPowers.pushPrefEnv({'set':[
+ ["dom.mozBrowserFramesEnabled", true],
+ ["network.disable.ipc.security", true],
+ ["dom.ipc.tabs.disabled", false]
+]}, function () {
+
+ var iframe = document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
+ iframe.setAttribute("remote", "true");
+ SpecialPowers.wrap(iframe).mozbrowser = true;
+ document.documentElement.appendChild(iframe);
+
+ SimpleTest.expectChildProcessCrash();
+
+ var crashMan =
+ SpecialPowers.Cu.import("resource://gre/modules/Services.jsm").
+ Services.crashmanager;
+
+ // First, clear the crash record store.
+ info("Waiting for pruneOldCrashes");
+ var future = new Date(Date.now() + 1000 * 60 * 60 * 24);
+ crashMan.pruneOldCrashes(future).then(function () {
+
+ var crashDateMS = Date.now();
+
+ // Inject a frame script that crashes the content process.
+ var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+ mm.loadFrameScript('data:,new ' + function ContentScriptScope() {
+ let Cu = Components.utils;
+ Cu.import("resource://gre/modules/ctypes.jsm");
+ let crash = function() {
+ let zero = new ctypes.intptr_t(8);
+ let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
+ badptr.contents;
+ };
+ privateNoteIntentionalCrash();
+ crash();
+ }, false);
+
+ // Finally, poll for the new crash record.
+ function tryGetCrash() {
+ info("Waiting for getCrashes");
+ crashMan.getCrashes().then(SpecialPowers.wrapCallback(function (crashes) {
+ if (crashes.length) {
+ is(crashes.length, 1, "There should be only one record");
+ var crash = crashes[0];
+ ok(crash.isOfType(crashMan.PROCESS_TYPE_CONTENT,
+ crashMan.CRASH_TYPE_CRASH),
+ "Record should be a content crash");
+ ok(!!crash.id, "Record should have an ID");
+ ok(!!crash.crashDate, "Record should have a crash date");
+ var dateMS = crash.crashDate.valueOf();
+ var twoMin = 1000 * 60 * 2;
+ ok(crashDateMS - twoMin <= dateMS &&
+ dateMS <= crashDateMS + twoMin,
+ "Record's crash date should be nowish: " +
+ "now=" + crashDateMS + " recordDate=" + dateMS);
+ SimpleTest.finish();
+ }
+ else {
+ setTimeout(tryGetCrash, 1000);
+ }
+ }), function (err) {
+ ok(false, "Error getting crashes: " + err);
+ SimpleTest.finish();
+ });
+ }
+ setTimeout(tryGetCrash, 1000);
+
+ }, function () {
+ ok(false, "pruneOldCrashes error");
+ SimpleTest.finish();
+ });
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/ipc/tests/test_blob_sliced_from_child_process.html b/dom/ipc/tests/test_blob_sliced_from_child_process.html
new file mode 100644
index 000000000..0dec1d84c
--- /dev/null
+++ b/dom/ipc/tests/test_blob_sliced_from_child_process.html
@@ -0,0 +1,185 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Test for slicing blobs that originated in a child process</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+ <body onload="setup();">
+ <script type="application/javascript;version=1.7">
+"use strict";
+
+function childFrameScript() {
+ "use strict";
+
+ Components.utils.importGlobalProperties(["Blob"]);
+
+ const messageName = "test:blob-slice-test";
+ const blobData = ["So", " ", "many", " ", "blobs!"];
+ const blobText = blobData.join("");
+ const blobType = "text/plain";
+
+ let blob = new Blob(blobData, { type: blobType });
+
+ let sliceText = blobData[2][1] + blobData[2][2];
+ let sliceIndex = blobText.indexOf(sliceText);
+
+ let firstSliceStart = blobData[0].length + blobData[1].length;
+ let firstSliceEnd = firstSliceStart + blobData[2].length;
+
+ let slice = blob.slice(firstSliceStart, firstSliceEnd, blobType);
+
+ let secondSliceStart = blobData[2].indexOf("a");
+ let secondSliceEnd = secondSliceStart + 2;
+
+ slice = slice.slice(secondSliceStart, secondSliceEnd, blobType);
+
+ sendAsyncMessage(messageName, { blob: blob });
+ sendAsyncMessage(messageName, { slice: slice });
+}
+
+function parentFrameScript(mm) {
+ const messageName = "test:blob-slice-test";
+ const blobData = ["So", " ", "many", " ", "blobs!"];
+ const blobText = blobData.join("");
+ const blobType = "text/plain";
+
+ const sliceText = "an";
+
+ let receivedBlob = false;
+ let receivedSlice = false;
+
+ let finishedTestingBlob = false;
+ let finishedTestingSlice = false;
+
+ mm.addMessageListener(messageName, function(message) {
+ if ("blob" in message.data) {
+ is(receivedBlob, false, "Have not yet received Blob");
+ is(receivedSlice, false, "Have not yet received Slice");
+ is(finishedTestingBlob, false, "Have not yet finished testing Blob");
+ is(finishedTestingSlice, false, "Have not yet finished testing Slice");
+
+ receivedBlob = true;
+
+ let blob = message.data.blob;
+
+ ok(blob instanceof Blob, "Received a Blob");
+ is(blob.size, blobText.length, "Blob has correct size");
+ is(blob.type, blobType, "Blob has correct type");
+
+ let slice = blob.slice(blobText.length -
+ blobData[blobData.length - 1].length,
+ blob.size,
+ blobType);
+
+ ok(slice instanceof Blob, "Slice returned a Blob");
+ is(slice.size,
+ blobData[blobData.length - 1].length,
+ "Slice has correct size");
+ is(slice.type, blobType, "Slice has correct type");
+
+ let reader = new FileReader();
+ reader.onload = function() {
+ is(reader.result,
+ blobData[blobData.length - 1],
+ "Slice has correct data");
+
+ finishedTestingBlob = true;
+
+ if (finishedTestingSlice) {
+ SimpleTest.finish();
+ }
+ };
+ reader.readAsText(slice);
+
+ return;
+ }
+
+ if ("slice" in message.data) {
+ is(receivedBlob, true, "Already received Blob");
+ is(receivedSlice, false, "Have not yet received Slice");
+ is(finishedTestingSlice, false, "Have not yet finished testing Slice");
+
+ receivedSlice = true;
+
+ let slice = message.data.slice;
+
+ ok(slice instanceof Blob, "Received a Blob for slice");
+ is(slice.size, sliceText.length, "Slice has correct size");
+ is(slice.type, blobType, "Slice has correct type");
+
+ let reader = new FileReader();
+ reader.onload = function() {
+ is(reader.result, sliceText, "Slice has correct data");
+
+ let slice2 = slice.slice(1, 2, blobType);
+
+ ok(slice2 instanceof Blob, "Slice returned a Blob");
+ is(slice2.size, 1, "Slice has correct size");
+ is(slice2.type, blobType, "Slice has correct type");
+
+ let reader2 = new FileReader();
+ reader2.onload = function() {
+ is(reader2.result, sliceText[1], "Slice has correct data");
+
+ finishedTestingSlice = true;
+
+ if (finishedTestingBlob) {
+ SimpleTest.finish();
+ }
+ };
+ reader2.readAsText(slice2);
+ };
+ reader.readAsText(slice);
+
+ return;
+ }
+
+ ok(false, "Received a bad message: " + JSON.stringify(message.data));
+ });
+
+ mm.loadFrameScript("data:,(" + childFrameScript.toString() + ")();",
+ false);
+}
+
+function setup() {
+ info("Got load event");
+
+ SpecialPowers.pushPrefEnv(
+ { set: [ ["dom.ipc.browser_frames.oop_by_default", true],
+ ["dom.mozBrowserFramesEnabled", true],
+ ["network.disable.ipc.security", true],
+ ["browser.pagethumbnails.capturing_disabled", true] ] },
+ function() {
+ info("Prefs set");
+
+ SpecialPowers.pushPermissions(
+ [ { type: "browser", allow: true, context: document } ],
+ function() {
+ info("Permissions set");
+
+ let iframe = document.createElement("iframe");
+ SpecialPowers.wrap(iframe).mozbrowser = true;
+ iframe.id = "iframe";
+ iframe.src =
+ "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
+
+ iframe.addEventListener("mozbrowserloadend", function() {
+ info("Starting tests");
+
+ let mm = SpecialPowers.getBrowserFrameMessageManager(iframe)
+ parentFrameScript(mm);
+ });
+
+ document.body.appendChild(iframe);
+ }
+ );
+ }
+ );
+}
+
+SimpleTest.waitForExplicitFinish();
+ </script>
+ </body>
+</html>
diff --git a/dom/ipc/tests/test_blob_sliced_from_parent_process.html b/dom/ipc/tests/test_blob_sliced_from_parent_process.html
new file mode 100644
index 000000000..7d8a1665f
--- /dev/null
+++ b/dom/ipc/tests/test_blob_sliced_from_parent_process.html
@@ -0,0 +1,213 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Test for slicing blobs that originated in a parent process</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+ <body onload="setup();">
+ <script type="application/javascript;version=1.7">
+"use strict";
+
+function childFrameScript() {
+ "use strict";
+
+ const { classes: Cc, interfaces: Ci } = Components;
+
+ const messageName = "test:blob-slice-test";
+ const blobData = ["So", " ", "many", " ", "blobs!"];
+ const blobText = blobData.join("");
+ const blobType = "text/plain";
+
+ const sliceText = "an";
+
+ function info(msg) {
+ sendAsyncMessage(messageName, { op: "info", msg: msg });
+ }
+
+ function ok(condition, name, diag) {
+ sendAsyncMessage(messageName,
+ { op: "ok",
+ condition: condition,
+ name: name,
+ diag: diag });
+ }
+
+ function is(a, b, name) {
+ let pass = a == b;
+ let diag = pass ? "" : "got " + a + ", expected " + b;
+ ok(pass, name, diag);
+ }
+
+ function finish(result) {
+ sendAsyncMessage(messageName, { op: "done", result: result });
+ }
+
+ function grabAndContinue(arg) {
+ testGenerator.send(arg);
+ }
+
+ function testSteps() {
+ addMessageListener(messageName, grabAndContinue);
+ let message = yield undefined;
+
+ let blob = message.data;
+
+ ok(blob instanceof Ci.nsIDOMBlob, "Received a Blob");
+ is(blob.size, blobText.length, "Blob has correct length");
+ is(blob.type, blobType, "Blob has correct type");
+
+ info("Reading blob");
+
+ let reader = new FileReader();
+ reader.addEventListener("load", grabAndContinue);
+ reader.readAsText(blob);
+
+ yield undefined;
+
+ is(reader.result, blobText, "Blob has correct data");
+
+ let firstSliceStart = blobData[0].length + blobData[1].length;
+ let firstSliceEnd = firstSliceStart + blobData[2].length;
+
+ let slice = blob.slice(firstSliceStart, firstSliceEnd, blobType);
+
+ ok(slice instanceof Ci.nsIDOMBlob, "Slice returned a Blob");
+ is(slice.size, blobData[2].length, "Slice has correct length");
+ is(slice.type, blobType, "Slice has correct type");
+
+ info("Reading slice");
+
+ reader = new FileReader();
+ reader.addEventListener("load", grabAndContinue);
+ reader.readAsText(slice);
+
+ yield undefined;
+
+ is(reader.result, blobData[2], "Slice has correct data");
+
+ let secondSliceStart = blobData[2].indexOf("a");
+ let secondSliceEnd = secondSliceStart + sliceText.length;
+
+ slice = slice.slice(secondSliceStart, secondSliceEnd, blobType);
+
+ ok(slice instanceof Ci.nsIDOMBlob, "Second slice returned a Blob");
+ is(slice.size, sliceText.length, "Second slice has correct length");
+ is(slice.type, blobType, "Second slice has correct type");
+
+ info("Sending second slice");
+ finish(slice);
+
+ yield undefined;
+ }
+
+ let testGenerator = testSteps();
+ testGenerator.next();
+}
+
+function parentFrameScript(mm) {
+ const messageName = "test:blob-slice-test";
+ const blobData = ["So", " ", "many", " ", "blobs!"];
+ const blobText = blobData.join("");
+ const blobType = "text/plain";
+
+ const sliceText = "an";
+
+ function grabAndContinue(arg) {
+ testGenerator.send(arg);
+ }
+
+ function testSteps() {
+ let slice = yield undefined;
+
+ ok(slice instanceof Blob, "Received a Blob");
+ is(slice.size, sliceText.length, "Slice has correct size");
+ is(slice.type, blobType, "Slice has correct type");
+
+ let reader = new FileReader();
+ reader.onload = grabAndContinue;
+ reader.readAsText(slice);
+ yield undefined;
+
+ is(reader.result, sliceText, "Slice has correct data");
+ SimpleTest.finish();
+
+ yield undefined;
+ }
+
+ let testGenerator = testSteps();
+ testGenerator.next();
+
+ mm.addMessageListener(messageName, function(message) {
+ let data = message.data;
+ switch (data.op) {
+ case "info": {
+ info(data.msg);
+ break;
+ }
+
+ case "ok": {
+ ok(data.condition, data.name, data.diag);
+ break;
+ }
+
+ case "done": {
+ testGenerator.send(data.result);
+ break;
+ }
+
+ default: {
+ ok(false, "Unknown op: " + data.op);
+ SimpleTest.finish();
+ }
+ }
+ });
+
+ mm.loadFrameScript("data:,(" + childFrameScript.toString() + ")();",
+ false);
+
+ let blob = new Blob(blobData, { type: blobType });
+ mm.sendAsyncMessage(messageName, blob);
+}
+
+function setup() {
+ info("Got load event");
+
+ SpecialPowers.pushPrefEnv(
+ { set: [ ["dom.ipc.browser_frames.oop_by_default", true],
+ ["dom.mozBrowserFramesEnabled", true],
+ ["network.disable.ipc.security", true],
+ ["browser.pagethumbnails.capturing_disabled", true] ] },
+ function() {
+ info("Prefs set");
+
+ SpecialPowers.pushPermissions(
+ [ { type: "browser", allow: true, context: document } ],
+ function() {
+ info("Permissions set");
+
+ let iframe = document.createElement("iframe");
+ SpecialPowers.wrap(iframe).mozbrowser = true;
+ iframe.id = "iframe";
+ iframe.src =
+ "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
+
+ iframe.addEventListener("mozbrowserloadend", function() {
+ info("Starting tests");
+
+ let mm = SpecialPowers.getBrowserFrameMessageManager(iframe)
+ parentFrameScript(mm);
+ });
+
+ document.body.appendChild(iframe);
+ }
+ );
+ }
+ );
+}
+
+SimpleTest.waitForExplicitFinish();
+ </script>
+ </body>
+</html>
diff --git a/dom/ipc/tests/test_bug1086684.html b/dom/ipc/tests/test_bug1086684.html
new file mode 100644
index 000000000..962826ec6
--- /dev/null
+++ b/dom/ipc/tests/test_bug1086684.html
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for recursive CPOW-getting-cookie bug</title>
+ <script type="application/javascript"
+ src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+ <script type="application/javascript;version=1.8">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+
+ const childFrameURL =
+ "http://mochi.test:8888/tests/dom/ipc/tests/file_bug1086684.html";
+
+ function childFrameScript() {
+ "use strict";
+
+ let { MockFilePicker } =
+ Components.utils.import("chrome://specialpowers/content/MockFilePicker.jsm", {});
+
+ function parentReady(message) {
+ MockFilePicker.init(content);
+ MockFilePicker.returnFiles = [message.data.file];
+ MockFilePicker.returnValue = MockFilePicker.returnOK;
+
+ let input = content.document.getElementById("f");
+ input.addEventListener("change", () => {
+ MockFilePicker.cleanup();
+ let value = input.value;
+ message.target.sendAsyncMessage("testBug1086684:childDone", { value });
+ });
+
+ input.focus();
+ input.click();
+ }
+
+ addMessageListener("testBug1086684:parentReady", function(message) {
+ parentReady(message);
+ });
+ }
+
+ let test;
+ function* testStructure(mm) {
+ let value;
+
+ function testDone(msg) {
+ test.next(msg.data.value);
+ }
+
+ mm.addMessageListener("testBug1086684:childDone", testDone);
+
+ let blob = new Blob([]);
+ let file = new File([blob], "helloworld.txt", { type: "text/plain" });
+
+ mm.sendAsyncMessage("testBug1086684:parentReady", { file });
+ value = yield;
+
+ // Note that the "helloworld.txt" passed in above doesn't affect the
+ // 'value' getter. Because we're mocking a file using a blob, we ask the
+ // blob for its path, which is the empty string.
+ is(value, "", "got the right answer and didn't crash");
+
+ SimpleTest.finish();
+ }
+
+ function runTests() {
+ info("Browser prefs set.");
+
+ let iframe = document.createElement("iframe");
+ SpecialPowers.wrap(iframe).mozbrowser = true;
+ iframe.id = "iframe";
+ iframe.src = childFrameURL;
+
+ iframe.addEventListener("mozbrowserloadend", function() {
+ info("Got iframe load event.");
+ let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+ mm.loadFrameScript("data:,(" + encodeURI(childFrameScript.toString()) + ")();",
+ false);
+
+ test = testStructure(mm);
+ test.next();
+ });
+
+ document.body.appendChild(iframe);
+ }
+
+ addEventListener("load", function() {
+ info("Got load event.");
+
+ SpecialPowers.addPermission("browser", true, document);
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["dom.ipc.browser_frames.oop_by_default", true],
+ ["dom.mozBrowserFramesEnabled", true],
+ ["network.disable.ipc.security", true],
+ ["browser.pagethumbnails.capturing_disabled", true]
+ ]
+ }, runTests);
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/ipc/tests/test_child_docshell.html b/dom/ipc/tests/test_child_docshell.html
new file mode 100644
index 000000000..5855569e8
--- /dev/null
+++ b/dom/ipc/tests/test_child_docshell.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.addPermission("browser", true, document);
+SpecialPowers.pushPrefEnv({'set':[
+ ["dom.mozBrowserFramesEnabled", true],
+ ["network.disable.ipc.security", true],
+ ["dom.ipc.tabs.disabled", false]
+]}, function () {
+
+ var iframe = document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
+ iframe.setAttribute("remote", "true");
+ SpecialPowers.wrap(iframe).mozbrowser = true;
+ document.documentElement.appendChild(iframe);
+
+ var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+ mm.addMessageListener("chromeEventHandler", function (msg) {
+ msg = SpecialPowers.wrap(msg);
+ var result = msg.json;
+ is(result.processType, SpecialPowers.Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT,
+ "The frame script is running in a real distinct child process");
+ ok(result.hasCorrectInterface,
+ "docshell.chromeEventHandler has nsIDOMEventTarget interface");
+ });
+
+
+ mm.addMessageListener("DOMWindowCreatedReceived", function (msg) {
+ msg = SpecialPowers.wrap(msg);
+ ok(true, "the chrome event handler looks functional");
+ var result = msg.json;
+ ok(result.stableChromeEventHandler, "docShell.chromeEventHandler is stable");
+ ok(result.iframeHasNewDocShell, "iframe spawns a new docShell");
+ ok(result.iframeHasSameChromeEventHandler, "but iframe has the same chrome event handler");
+ SimpleTest.finish();
+ });
+ // Inject a frame script in the child process:
+ mm.loadFrameScript('data:,new ' + function ContentScriptScope() {
+ var processType = Components.classes["@mozilla.org/xre/runtime;1"]
+ .getService(Components.interfaces.nsIXULRuntime)
+ .processType;
+ var chromeEventHandler = docShell.chromeEventHandler;
+ sendAsyncMessage("chromeEventHandler", {
+ processType: Services.appinfo.processType,
+ hasCorrectInterface: chromeEventHandler instanceof Components.interfaces.nsIDOMEventTarget
+ });
+
+ /*
+ Ensure that this chromeEventHandler actually works,
+ by creating a new window and listening for its DOMWindowCreated event
+ */
+ chromeEventHandler.addEventListener("DOMWindowCreated", function listener(evt) {
+ if (evt.target == content.document) {
+ return;
+ }
+ chromeEventHandler.removeEventListener("DOMWindowCreated", listener);
+ let new_win = evt.target.defaultView;
+ let new_docShell = new_win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell);
+ sendAsyncMessage("DOMWindowCreatedReceived", {
+ stableChromeEventHandler: chromeEventHandler === docShell.chromeEventHandler,
+ iframeHasNewDocShell: new_docShell !== docShell,
+ iframeHasSameChromeEventHandler: new_docShell.chromeEventHandler === chromeEventHandler
+ });
+ });
+
+ let i = content.document.createElement("iframe");
+ i.setAttribute("src", "data:text/html,foo");
+ content.document.documentElement.appendChild(i);
+ }, false);
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/ipc/tests/test_cpow_cookies.html b/dom/ipc/tests/test_cpow_cookies.html
new file mode 100644
index 000000000..1e55d3878
--- /dev/null
+++ b/dom/ipc/tests/test_cpow_cookies.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for recursive CPOW-getting-cookie bug</title>
+ <script type="application/javascript"
+ src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+ <script type="application/javascript;version=1.8">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+
+ const childFrameURL =
+ "data:text/html,<!DOCTYPE HTML><html><body></body></html>";
+
+ function childFrameScript() {
+ "use strict";
+
+ const Ci = Components.interfaces;
+
+ function test1(message) {
+ // NB: This is a no-op because we're a data: document with a null
+ // principal.
+ content.document.cookie = "a=b";
+ message.target.sendAsyncMessage("testCPOWCookies:test1Finished", { pass: true });
+ }
+
+ addMessageListener("testCPOWCookies:test1", function(message) {
+ test1(message);
+ });
+ }
+
+ let test;
+ function* testStructure(mm) {
+ let lastResult;
+
+ function testDone(msg) {
+ test.next(msg.data);
+ }
+
+ mm.addMessageListener("testCPOWCookies:test1Finished", testDone);
+
+ mm.sendAsyncMessage("testCPOWCookies:test1", {});
+ lastResult = yield;
+ ok(lastResult.pass, "got the right answer and didn't crash");
+
+ SimpleTest.finish();
+ }
+
+ function runTests() {
+ info("Browser prefs set.");
+
+ let iframe = document.createElement("iframe");
+ SpecialPowers.wrap(iframe).mozbrowser = true;
+ iframe.id = "iframe";
+ iframe.src = childFrameURL;
+
+ iframe.addEventListener("mozbrowserloadend", function() {
+ info("Got iframe load event.");
+ let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+ mm.loadFrameScript("data:,(" + encodeURI(childFrameScript.toString()) + ")();",
+ false);
+
+ test = testStructure(mm);
+ test.next();
+ });
+
+ document.body.appendChild(iframe);
+ }
+
+ addEventListener("load", function() {
+ info("Got load event.");
+
+ SpecialPowers.addPermission("browser", true, document);
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["dom.ipc.browser_frames.oop_by_default", true],
+ ["dom.mozBrowserFramesEnabled", true],
+ ["network.disable.ipc.security", true],
+ ["browser.pagethumbnails.capturing_disabled", true]
+ ]
+ }, runTests);
+ });
+ </script>
+</body>
+</html>
diff --git a/dom/ipc/tests/test_process_error.xul b/dom/ipc/tests/test_process_error.xul
new file mode 100644
index 000000000..72352fc88
--- /dev/null
+++ b/dom/ipc/tests/test_process_error.xul
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ var w = window.open('process_error.xul', '_blank', 'chrome,resizable=yes,width=400,height=600');
+
+ function done()
+ {
+ w.close();
+ SimpleTest.finish();
+ }
+ </script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;" />
+</window>
diff --git a/dom/ipc/tests/test_temporaryfile_stream.html b/dom/ipc/tests/test_temporaryfile_stream.html
new file mode 100644
index 000000000..e05accbdf
--- /dev/null
+++ b/dom/ipc/tests/test_temporaryfile_stream.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Send an nsTemporaryFileInputStream cross-process</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/dom/canvas/test/captureStream_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<div id="content">
+</div>
+<script class="testbody" type="text/javascript">
+function startTest() {
+ var canvas = document.createElement("canvas");
+ canvas.width = canvas.height = 100;
+ document.getElementById("content").appendChild(canvas);
+
+ var helper = new CaptureStreamTestHelper2D(100, 100);
+ helper.drawColor(canvas, helper.red);
+
+ var stream = canvas.captureStream(0);
+
+ var blob;
+
+ mediaRecorder = new MediaRecorder(stream);
+ is(mediaRecorder.stream, stream,
+ "Media recorder stream = canvas stream at the start of recording");
+
+ mediaRecorder.onwarning = () => ok(false, "warning unexpectedly fired");
+
+ mediaRecorder.onerror = () => ok(false, "Recording failed");
+
+ mediaRecorder.ondataavailable = ev => {
+ is(blob, undefined, "Should only get one dataavailable event");
+ blob = ev.data;
+ };
+
+ mediaRecorder.onstart = () => {
+ info("Got 'start' event");
+ // We just want one frame encoded, to see that the recorder produces something readable.
+ mediaRecorder.stop();
+ };
+
+ mediaRecorder.onstop = () => {
+ info("Got 'stop' event");
+ ok(blob, "Should have gotten a data blob");
+ var xhr = new XMLHttpRequest();
+ xhr.open('POST', 'blob_verify.sjs', true);
+ xhr.onload = () => {
+ var video = document.createElement("video");
+ video.id = "recorded-video";
+ video.src = URL.createObjectURL(xhr.response);
+ video.play();
+ video.onerror = err => {
+ ok(false, "Should be able to play the recording. Got error. code=" + video.error.code);
+ SimpleTest.finish();
+ };
+ document.getElementById("content").appendChild(video);
+ helper.waitForPixelColor(video, helper.red, 128, "Should become red")
+ .then(SimpleTest.finish);
+ };
+ xhr.onerror = () => {
+ ok(false, "XHR error");
+ SimpleTest.finish();
+ }
+ xhr.responseType = "blob";
+ xhr.send(blob);
+ };
+
+ mediaRecorder.start();
+ is(mediaRecorder.state, "recording", "Media recorder should be recording");
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({set:[["media.recorder.max_memory", 1]]}, startTest);
+</script>
+</pre>
+</body>
+</html>