Bug 1223831 - SpecialPowers API to create files in an e10s-compatible way. r=jmaher,baku

This commit is contained in:
Andrew McCreight 2015-11-13 09:29:17 -08:00
parent 826cd3d4e3
commit 79d5d6cd4d
5 changed files with 171 additions and 0 deletions

View File

@ -3,6 +3,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g'
[test_TestsRunningAfterSimpleTestFinish.html]
skip-if = true #depends on fix for bug 1048446
[test_add_task.html]
[test_createFiles.html]
[test_sanity.html]
[test_sanityException.html]
[test_sanityException2.html]

View File

@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for SpecialPowers.createFiles</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="content" class="testbody">
<script type="text/javascript">
// Creating one file, followed by failing to create a file.
function test1() {
let fdata = "this is same data for a file";
SpecialPowers.createFiles([{name: "test1.txt", data:fdata}],
function (files) {
is(files.length, 1, "Created 1 file");
let f = files[0];
is("[object File]", f.toString(), "first thing in array is a file");
is(f.size, fdata.length, "test1 size of first file should be length of its data");
is("test1.txt", f.name, "test1 test file should have the right name");
test2();
},
function (msg) { ok(false, "Should be able to create a file without an error"); test2(); }
);
}
// Failing to create a file, followed by creating a file.
function test2() {
function test3Check(passed) {
ok(passed, "Should trigger the error handler for a bad file name.");
test3();
};
SpecialPowers.createFiles([{name: "/\/\/\/\/\/\/\/\/\/\/\invalidname",}],
function () { test3Check(false); },
function (msg) { test3Check(true); }
);
}
// Creating two files at the same time.
function test3() {
let f1data = "hello";
SpecialPowers.createFiles([{name: "test3_file.txt", data:f1data}, {name: "emptyfile.txt"}],
function (files) {
is(files.length, 2, "Expected two files to be created");
let f1 = files[0];
let f2 = files[1];
is("[object File]", f1.toString(), "first thing in array is a file");
is("[object File]", f2.toString(), "second thing in array is a file");
is("test3_file.txt", f1.name, "first test3 test file should have the right name");
is("emptyfile.txt", f2.name, "second test3 test file should have the right name");
is(f1.size, f1data.length, "size of first file should be length of its data");
is(f2.size, 0, "size of second file should be 0");
SimpleTest.finish();
},
function (msg) {
ok(false, "Failed to create files: " + msg);
SimpleTest.finish();
}
);
};
SimpleTest.waitForExplicitFinish();
test1();
</script>
</div>
</body>
</html>

View File

@ -1025,6 +1025,8 @@ SimpleTest.finish = function() {
}
var afterCleanup = function() {
SpecialPowers.removeFiles();
if (SpecialPowers.DOMWindowUtils.isTestControllingRefreshes) {
SimpleTest.ok(false, "test left refresh driver under test control");
SpecialPowers.DOMWindowUtils.restoreNormalRefresh();

View File

@ -11,6 +11,7 @@
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.importGlobalProperties(['File']);
if (typeof(Cc) == "undefined") {
const Cc = Components.classes;
@ -81,6 +82,8 @@ SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
this._messageManager.addMessageListener("SPPingService", this);
this._messageManager.addMessageListener("SpecialPowers.Quit", this);
this._messageManager.addMessageListener("SpecialPowers.Focus", this);
this._messageManager.addMessageListener("SpecialPowers.CreateFiles", this);
this._messageManager.addMessageListener("SpecialPowers.RemoveFiles", this);
this._messageManager.addMessageListener("SPPermissionManager", this);
this._messageManager.addMessageListener("SPWebAppService", this);
this._messageManager.addMessageListener("SPObserverService", this);
@ -98,6 +101,7 @@ SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
this._messageManager.loadFrameScript(CHILD_SCRIPT_API, true);
this._messageManager.loadFrameScript(CHILD_SCRIPT, true);
this._isFrameScriptLoaded = true;
this._createdFiles = null;
}
};
@ -161,6 +165,8 @@ SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
this._messageManager.removeMessageListener("SPPingService", this);
this._messageManager.removeMessageListener("SpecialPowers.Quit", this);
this._messageManager.removeMessageListener("SpecialPowers.Focus", this);
this._messageManager.removeMessageListener("SpecialPowers.CreateFiles", this);
this._messageManager.removeMessageListener("SpecialPowers.RemoveFiles", this);
this._messageManager.removeMessageListener("SPPermissionManager", this);
this._messageManager.removeMessageListener("SPWebAppService", this);
this._messageManager.removeMessageListener("SPObserverService", this);
@ -265,6 +271,50 @@ SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
case "SpecialPowers.Focus":
aMessage.target.focus();
break;
case "SpecialPowers.CreateFiles":
let filePaths = new Array;
if (!this.createdFiles) {
this._createdFiles = new Array;
}
let createdFiles = this._createdFiles;
try {
aMessage.data.forEach(function(request) {
let testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
testFile.append(request.name);
let outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE
0666, 0);
if (request.data) {
outStream.write(request.data, request.data.length);
outStream.close();
}
filePaths.push(new File(testFile.path));
createdFiles.push(testFile);
});
aMessage.target
.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader
.messageManager
.sendAsyncMessage("SpecialPowers.FilesCreated", filePaths);
} catch (e) {
aMessage.target
.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader
.messageManager
.sendAsyncMessage("SpecialPowers.FilesError", e.toString());
}
break;
case "SpecialPowers.RemoveFiles":
if (this._createdFiles) {
this._createdFiles.forEach(function (testFile) {
try {
testFile.remove(false);
} catch (e) {}
});
this._createdFiles = null;
}
break;
default:
return this._receiveMessage(aMessage);
}

View File

@ -24,6 +24,8 @@ function SpecialPowers(window) {
this._pongHandlers = [];
this._messageListener = this._messageReceived.bind(this);
this._grandChildFrameMM = null;
this._createFilesOnError = null;
this._createFilesOnSuccess = null;
this.SP_SYNC_MESSAGES = ["SPChromeScriptMessage",
"SPLoadChromeScript",
"SPObserverService",
@ -36,6 +38,8 @@ function SpecialPowers(window) {
this.SP_ASYNC_MESSAGES = ["SpecialPowers.Focus",
"SpecialPowers.Quit",
"SpecialPowers.CreateFiles",
"SpecialPowers.RemoveFiles",
"SPPingService",
"SPQuotaManager",
"SPLoadExtension",
@ -43,6 +47,8 @@ function SpecialPowers(window) {
"SPUnloadExtension",
"SPExtensionMessage"];
addMessageListener("SPPingService", this._messageListener);
addMessageListener("SpecialPowers.FilesCreated", this._messageListener);
addMessageListener("SpecialPowers.FilesError", this._messageListener);
let self = this;
Services.obs.addObserver(function onInnerWindowDestroyed(subject, topic, data) {
var id = subject.QueryInterface(Components.interfaces.nsISupportsPRUint64).data;
@ -50,6 +56,8 @@ function SpecialPowers(window) {
Services.obs.removeObserver(onInnerWindowDestroyed, "inner-window-destroyed");
try {
removeMessageListener("SPPingService", self._messageListener);
removeMessageListener("SpecialPowers.FilesCreated", self._messageListener);
removeMessageListener("SpecialPowers.FilesError", self._messageListener);
} catch (e if e.result == Components.results.NS_ERROR_ILLEGAL_VALUE) {
// Ignore the exception which the message manager has been destroyed.
;
@ -122,7 +130,26 @@ SpecialPowers.prototype._messageReceived = function(aMessage) {
}
}
break;
case "SpecialPowers.FilesCreated":
var handler = this._createFilesOnSuccess;
this._createFilesOnSuccess = null;
this._createFilesOnError = null;
if (handler) {
handler(aMessage.data);
}
break;
case "SpecialPowers.FilesError":
var handler = this._createFilesOnError;
this._createFilesOnSuccess = null;
this._createFilesOnError = null;
if (handler) {
handler(aMessage.data);
}
break;
}
return true;
};
@ -130,6 +157,27 @@ SpecialPowers.prototype.quit = function() {
sendAsyncMessage("SpecialPowers.Quit", {});
};
// fileRequests is an array of file requests. Each file request is an object.
// A request must have a field |name|, which gives the base of the name of the
// file to be created in the profile directory. If the request has a |data| field
// then that data will be written to the file.
SpecialPowers.prototype.createFiles = function(fileRequests, onCreation, onError) {
if (this._createFilesOnSuccess || this._createFilesOnError) {
onError("Already waiting for SpecialPowers.createFiles() to finish.");
return;
}
this._createFilesOnSuccess = onCreation;
this._createFilesOnError = onError;
sendAsyncMessage("SpecialPowers.CreateFiles", fileRequests);
};
// Remove the files that were created using |SpecialPowers.createFiles()|.
// This will be automatically called by |SimpleTest.finish()|.
SpecialPowers.prototype.removeFiles = function() {
sendAsyncMessage("SpecialPowers.RemoveFiles", {});
};
SpecialPowers.prototype.executeAfterFlushingMessageQueue = function(aCallback) {
this._pongHandlers.push(aCallback);
sendAsyncMessage("SPPingService", { op: "ping" });