зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1272522 Handle stderr of native app r=kmag
MozReview-Commit-ID: 5qGw83uTYTu --HG-- extra : rebase_source : 8cefe9f2661782b45000ff704db2ea7aaa46ac68
This commit is contained in:
Родитель
b5739bf710
Коммит
5b775d5271
|
@ -202,6 +202,7 @@ this.NativeApp = class extends EventEmitter {
|
||||||
command: command,
|
command: command,
|
||||||
arguments: [hostInfo.path],
|
arguments: [hostInfo.path],
|
||||||
workdir: OS.Path.dirname(command),
|
workdir: OS.Path.dirname(command),
|
||||||
|
stderr: "pipe",
|
||||||
};
|
};
|
||||||
return Subprocess.call(subprocessOpts);
|
return Subprocess.call(subprocessOpts);
|
||||||
}).then(proc => {
|
}).then(proc => {
|
||||||
|
@ -209,6 +210,7 @@ this.NativeApp = class extends EventEmitter {
|
||||||
this.proc = proc;
|
this.proc = proc;
|
||||||
this._startRead();
|
this._startRead();
|
||||||
this._startWrite();
|
this._startWrite();
|
||||||
|
this._startStderrRead();
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
this.startupPromise = null;
|
this.startupPromise = null;
|
||||||
Cu.reportError(err.message);
|
Cu.reportError(err.message);
|
||||||
|
@ -268,6 +270,32 @@ this.NativeApp = class extends EventEmitter {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_startStderrRead() {
|
||||||
|
let proc = this.proc;
|
||||||
|
let app = this.name;
|
||||||
|
Task.spawn(function* () {
|
||||||
|
let partial = "";
|
||||||
|
while (true) {
|
||||||
|
let data = yield proc.stderr.readString();
|
||||||
|
if (data.length == 0) {
|
||||||
|
// We have hit EOF, just stop reading
|
||||||
|
if (partial) {
|
||||||
|
Services.console.logStringMessage(`stderr output from native app ${app}: ${partial}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lines = data.split(/\r?\n/);
|
||||||
|
lines[0] = partial + lines[0];
|
||||||
|
partial = lines.pop();
|
||||||
|
|
||||||
|
for (let line of lines) {
|
||||||
|
Services.console.logStringMessage(`stderr output from native app ${app}: ${line}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
send(msg) {
|
send(msg) {
|
||||||
if (this._isDisconnected) {
|
if (this._isDisconnected) {
|
||||||
throw new this.context.cloneScope.Error("Attempt to postMessage on disconnected port");
|
throw new this.context.cloneScope.Error("Attempt to postMessage on disconnected port");
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"sendAsyncMessage": false,
|
"sendAsyncMessage": false,
|
||||||
|
|
||||||
"waitForLoad": true,
|
"waitForLoad": true,
|
||||||
|
"promiseConsoleOutput": true,
|
||||||
|
|
||||||
"ExtensionTestUtils": false,
|
"ExtensionTestUtils": false,
|
||||||
"NetUtil": true,
|
"NetUtil": true,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
|
head.js
|
||||||
file_download.html
|
file_download.html
|
||||||
file_download.txt
|
file_download.txt
|
||||||
interruptible.sjs
|
interruptible.sjs
|
||||||
|
|
|
@ -10,3 +10,4 @@ function waitForLoad(win) {
|
||||||
}, true);
|
}, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
<script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||||
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
<script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||||
<script type="text/javascript" src="head.js"></script>
|
<script type="text/javascript" src="head.js"></script>
|
||||||
<script type="text/javascript" src="test_constants.js"></script>
|
|
||||||
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -23,11 +22,40 @@ Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/osfile.jsm");
|
Cu.import("resource://gre/modules/osfile.jsm");
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
let {Subprocess, SubprocessImpl} = Cu.import("resource://gre/modules/Subprocess.jsm");
|
let {Subprocess, SubprocessImpl} = Cu.import("resource://gre/modules/Subprocess.jsm");
|
||||||
|
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||||
|
|
||||||
if (AppConstants.platform == "win") {
|
if (AppConstants.platform == "win") {
|
||||||
Cu.import("resource://testing-common/MockRegistry.jsm");
|
Cu.import("resource://testing-common/MockRegistry.jsm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var promiseConsoleOutput = Task.async(function* (task) {
|
||||||
|
const DONE = "=== extension test console listener done ===";
|
||||||
|
|
||||||
|
let listener;
|
||||||
|
let messages = [];
|
||||||
|
let awaitListener = new Promise(resolve => {
|
||||||
|
listener = msg => {
|
||||||
|
if (msg == DONE) {
|
||||||
|
resolve();
|
||||||
|
} else if (msg instanceof Ci.nsIConsoleMessage) {
|
||||||
|
messages.push(msg.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
Services.console.registerListener(listener);
|
||||||
|
try {
|
||||||
|
let result = yield task();
|
||||||
|
|
||||||
|
Services.console.logStringMessage(DONE);
|
||||||
|
yield awaitListener;
|
||||||
|
|
||||||
|
return {messages, result};
|
||||||
|
} finally {
|
||||||
|
Services.console.unregisterListener(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const PREF_MAX_READ = "webextensions.native-messaging.max-input-message-bytes";
|
const PREF_MAX_READ = "webextensions.native-messaging.max-input-message-bytes";
|
||||||
const PREF_MAX_WRITE = "webextensions.native-messaging.max-output-message-bytes";
|
const PREF_MAX_WRITE = "webextensions.native-messaging.max-output-message-bytes";
|
||||||
|
|
||||||
|
@ -96,6 +124,21 @@ while True:
|
||||||
sys.stdout.write(msg)
|
sys.stdout.write(msg)
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const STDERR_LINES = ["hello stderr", "this should be a separate line"];
|
||||||
|
let STDERR_MSG = STDERR_LINES.join("\\n");
|
||||||
|
|
||||||
|
// Python apparently line-buffers stderr even with the -u arg on
|
||||||
|
// Windows 7. Dealing with that is more hassle than its worth but
|
||||||
|
// on other platforms, we want to keep testing partial lines.
|
||||||
|
if (AppConstants.isPlatformAndVersionAtMost("win", "7")) {
|
||||||
|
STDERR_MSG += "\\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
const STDERR_BODY = String.raw`
|
||||||
|
import sys
|
||||||
|
sys.stderr.write("${STDERR_MSG}")
|
||||||
|
`;
|
||||||
|
|
||||||
const SCRIPTS = [
|
const SCRIPTS = [
|
||||||
{
|
{
|
||||||
name: "echo",
|
name: "echo",
|
||||||
|
@ -112,6 +155,11 @@ const SCRIPTS = [
|
||||||
description: "a native app that does not exit when stdin closes or on SIGTERM",
|
description: "a native app that does not exit when stdin closes or on SIGTERM",
|
||||||
script: WONTDIE_BODY,
|
script: WONTDIE_BODY,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "stderr",
|
||||||
|
description: "a native app that writes to stderr and then exits",
|
||||||
|
script: STDERR_BODY,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
add_task(function* setup() {
|
add_task(function* setup() {
|
||||||
|
@ -610,6 +658,35 @@ add_task(function* test_unresponsive_native_app() {
|
||||||
is(procCount, 0, "subprocess was succesfully killed");
|
is(procCount, 0, "subprocess was succesfully killed");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add_task(function* test_stderr() {
|
||||||
|
function background() {
|
||||||
|
let port = browser.runtime.connectNative("stderr");
|
||||||
|
port.onDisconnect.addListener(() => {
|
||||||
|
browser.test.sendMessage("finished");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let {messages} = yield promiseConsoleOutput(function* () {
|
||||||
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
|
background: `(${background})()`,
|
||||||
|
manifest: {
|
||||||
|
permissions: ["nativeMessaging"],
|
||||||
|
},
|
||||||
|
}, ID);
|
||||||
|
|
||||||
|
yield extension.startup();
|
||||||
|
yield extension.awaitMessage("finished");
|
||||||
|
yield extension.unload();
|
||||||
|
});
|
||||||
|
|
||||||
|
let lines = STDERR_LINES.map(line => messages.findIndex(msg => msg.includes(line)));
|
||||||
|
isnot(lines[0], -1, "Saw first line of stderr output on the console");
|
||||||
|
isnot(lines[1], -1, "Saw second line of stderr output on the console");
|
||||||
|
isnot(lines[0], lines[1], "Stderr output lines are separated in the console");
|
||||||
|
|
||||||
|
yield waitForSubprocessExit();
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче