Move and refactor child_process tests

This commit is contained in:
Asher 2019-02-19 15:30:56 -06:00
parent d80f82ab98
commit 3685e6555c
No known key found for this signature in database
GPG Key ID: 7BB4BA9C783D2BBC
6 changed files with 103 additions and 22 deletions

View File

@ -60,9 +60,9 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
} }
ae.on("disconnect", () => childProcess.disconnect()); ae.on("disconnect", () => childProcess.disconnect());
ae.on("kill", (signal) => childProcess.kill(signal)); ae.on("kill", (signal: string) => childProcess.kill(signal));
ae.on("ref", () => childProcess.ref()); ae.on("ref", () => childProcess.ref());
ae.on("send", (message, callbackId) => childProcess.send(message, maybeCallback(ae, callbackId))); ae.on("send", (message: string, callbackId: number) => childProcess.send(message, maybeCallback(ae, callbackId)));
ae.on("unref", () => childProcess.unref()); ae.on("unref", () => childProcess.unref());
ae.emit("pid", childProcess.pid); ae.emit("pid", childProcess.pid);
@ -72,9 +72,15 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
childProcess.on("exit", (code, signal) => ae.emit("exit", code, signal)); childProcess.on("exit", (code, signal) => ae.emit("exit", code, signal));
childProcess.on("message", (message) => ae.emit("message", message)); childProcess.on("message", (message) => ae.emit("message", message));
bindWritable(createUniqueEval(ae, "stdin"), childProcess.stdin); if (childProcess.stdin) {
bindReadable(createUniqueEval(ae, "stdout"), childProcess.stdout); bindWritable(createUniqueEval(ae, "stdin"), childProcess.stdin);
bindReadable(createUniqueEval(ae, "stderr"), childProcess.stderr); }
if (childProcess.stdout) {
bindReadable(createUniqueEval(ae, "stdout"), childProcess.stdout);
}
if (childProcess.stderr) {
bindReadable(createUniqueEval(ae, "stderr"), childProcess.stderr);
}
return { return {
onDidDispose: (cb): cp.ChildProcess => childProcess.on("close", cb), onDidDispose: (cb): cp.ChildProcess => childProcess.on("close", cb),

View File

@ -0,0 +1,74 @@
import { ChildProcess } from "child_process";
import * as path from "path";
import { Readable } from "stream";
import * as util from "util";
import { createClient } from "@coder/protocol/test";
const client = createClient();
jest.mock("../src/fill/client", () => ({ client }));
const cp = require("../src/fill/child_process") as typeof import("child_process");
describe("child_process", () => {
const getStdout = async (proc: ChildProcess): Promise<string> => {
return new Promise((r): Readable => proc.stdout.on("data", r))
.then((s) => s.toString());
};
describe("exec", () => {
it("should get exec stdout", async () => {
await expect(util.promisify(cp.exec)("echo test", { encoding: "utf8" }))
.resolves.toEqual({
stdout: "test\n",
stderr: "",
});
});
});
describe("spawn", () => {
it("should get spawn stdout", async () => {
const proc = cp.spawn("echo", ["test"]);
await expect(Promise.all([
getStdout(proc),
new Promise((r): ChildProcess => proc.on("exit", r)),
]).then((values) => values[0])).resolves.toEqual("test\n");
});
it("should cat", async () => {
const proc = cp.spawn("cat", []);
expect(proc.pid).toBe(-1);
proc.stdin.write("banana");
await expect(getStdout(proc)).resolves.toBe("banana");
proc.stdin.end();
proc.kill();
expect(proc.pid).toBeGreaterThan(-1);
await new Promise((r): ChildProcess => proc.on("exit", r));
});
it("should print env", async () => {
const proc = cp.spawn("env", [], {
env: { hi: "donkey" },
});
await expect(getStdout(proc)).resolves.toContain("hi=donkey\n");
});
});
describe("fork", () => {
it("should echo messages", async () => {
const proc = cp.fork(path.join(__dirname, "forker.js"));
proc.send({ bananas: true });
await expect(new Promise((r): ChildProcess => proc.on("message", r)))
.resolves.toMatchObject({
bananas: true,
});
proc.kill();
await new Promise((r): ChildProcess => proc.on("exit", r));
});
});
});

View File

@ -1,3 +1,3 @@
process.on("message", (data) => { process.on("message", (data) => {
process.send(data); process.send(data);
}); });

View File

@ -23,6 +23,7 @@
], ],
"moduleNameMapper": { "moduleNameMapper": {
"^.+\\.(s?css|png|svg)$": "<rootDir>/../scripts/dummy.js", "^.+\\.(s?css|png|svg)$": "<rootDir>/../scripts/dummy.js",
"@coder/ide/src/fill/evaluation": "<rootDir>/ide/src/fill/evaluation",
"@coder/(.*)/test": "<rootDir>/$1/test", "@coder/(.*)/test": "<rootDir>/$1/test",
"@coder/(.*)": "<rootDir>/$1/src" "@coder/(.*)": "<rootDir>/$1/src"
}, },

View File

@ -42,9 +42,9 @@ class Pty implements nodePty.IPty {
ptyProc.on("data", (data) => ae.emit("data", data)); ptyProc.on("data", (data) => ae.emit("data", data));
ae.on("resize", (cols, rows) => ptyProc.resize(cols, rows)); ae.on("resize", (cols: number, rows: number) => ptyProc.resize(cols, rows));
ae.on("write", (data) => ptyProc.write(data)); ae.on("write", (data: string) => ptyProc.write(data));
ae.on("kill", (signal) => ptyProc.kill(signal)); ae.on("kill", (signal: string) => ptyProc.kill(signal));
return { return {
onDidDispose: (cb): void => ptyProc.on("exit", cb), onDidDispose: (cb): void => ptyProc.on("exit", cb),

View File

@ -9,22 +9,22 @@ const ae = client.run((ae) => {
const spdlog = __non_webpack_require__("spdlog") as typeof import("spdlog"); const spdlog = __non_webpack_require__("spdlog") as typeof import("spdlog");
const loggers = new Map<number, NodeRotatingLogger>(); const loggers = new Map<number, NodeRotatingLogger>();
ae.on("new", (id, name, filePath, fileSize, fileCount) => { ae.on("new", (id: number, name: string, filePath: string, fileSize: number, fileCount: number) => {
const logger = new spdlog.RotatingLogger(name, filePath, fileSize, fileCount); const logger = new spdlog.RotatingLogger(name, filePath, fileSize, fileCount);
loggers.set(id, logger); loggers.set(id, logger);
}); });
ae.on("clearFormatters", (id) => loggers.get(id)!.clearFormatters()); ae.on("clearFormatters", (id: number) => loggers.get(id)!.clearFormatters());
ae.on("critical", (id, message) => loggers.get(id)!.critical(message)); ae.on("critical", (id: number, message: string) => loggers.get(id)!.critical(message));
ae.on("debug", (id, message) => loggers.get(id)!.debug(message)); ae.on("debug", (id: number, message: string) => loggers.get(id)!.debug(message));
ae.on("drop", (id) => loggers.get(id)!.drop()); ae.on("drop", (id: number) => loggers.get(id)!.drop());
ae.on("errorLog", (id, message) => loggers.get(id)!.error(message)); ae.on("errorLog", (id: number, message: string) => loggers.get(id)!.error(message));
ae.on("flush", (id) => loggers.get(id)!.flush()); ae.on("flush", (id: number) => loggers.get(id)!.flush());
ae.on("info", (id, message) => loggers.get(id)!.info(message)); ae.on("info", (id: number, message: string) => loggers.get(id)!.info(message));
ae.on("setAsyncMode", (bufferSize, flushInterval) => spdlog.setAsyncMode(bufferSize, flushInterval)); ae.on("setAsyncMode", (bufferSize: number, flushInterval: number) => spdlog.setAsyncMode(bufferSize, flushInterval));
ae.on("setLevel", (id, level) => loggers.get(id)!.setLevel(level)); ae.on("setLevel", (id: number, level: number) => loggers.get(id)!.setLevel(level));
ae.on("trace", (id, message) => loggers.get(id)!.trace(message)); ae.on("trace", (id: number, message: string) => loggers.get(id)!.trace(message));
ae.on("warn", (id, message) => loggers.get(id)!.warn(message)); ae.on("warn", (id: number, message: string) => loggers.get(id)!.warn(message));
const disposeCallbacks = <Array<() => void>>[]; const disposeCallbacks = <Array<() => void>>[];
@ -40,7 +40,7 @@ const ae = client.run((ae) => {
const spdLogger = logger.named("spdlog"); const spdLogger = logger.named("spdlog");
ae.on("close", () => spdLogger.error("session closed prematurely")); ae.on("close", () => spdLogger.error("session closed prematurely"));
ae.on("error", (error) => spdLogger.error(error.message)); ae.on("error", (error: Error) => spdLogger.error(error.message));
let id = 0; let id = 0;
export class RotatingLogger implements NodeRotatingLogger { export class RotatingLogger implements NodeRotatingLogger {