From 3685e6555c795762169300ddb108d6e2d7af3bbc Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 19 Feb 2019 15:30:56 -0600 Subject: [PATCH] Move and refactor child_process tests --- packages/ide/src/fill/child_process.ts | 16 +++-- packages/ide/test/child_process.test.ts | 74 +++++++++++++++++++++++ packages/{protocol => ide}/test/forker.js | 2 +- packages/package.json | 1 + packages/vscode/src/fill/node-pty.ts | 6 +- packages/vscode/src/fill/spdlog.ts | 26 ++++---- 6 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 packages/ide/test/child_process.test.ts rename packages/{protocol => ide}/test/forker.js (93%) mode change 100755 => 100644 diff --git a/packages/ide/src/fill/child_process.ts b/packages/ide/src/fill/child_process.ts index f99d0ac4..c11cc18a 100644 --- a/packages/ide/src/fill/child_process.ts +++ b/packages/ide/src/fill/child_process.ts @@ -60,9 +60,9 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess { } 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("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.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("message", (message) => ae.emit("message", message)); - bindWritable(createUniqueEval(ae, "stdin"), childProcess.stdin); - bindReadable(createUniqueEval(ae, "stdout"), childProcess.stdout); - bindReadable(createUniqueEval(ae, "stderr"), childProcess.stderr); + if (childProcess.stdin) { + bindWritable(createUniqueEval(ae, "stdin"), childProcess.stdin); + } + if (childProcess.stdout) { + bindReadable(createUniqueEval(ae, "stdout"), childProcess.stdout); + } + if (childProcess.stderr) { + bindReadable(createUniqueEval(ae, "stderr"), childProcess.stderr); + } return { onDidDispose: (cb): cp.ChildProcess => childProcess.on("close", cb), diff --git a/packages/ide/test/child_process.test.ts b/packages/ide/test/child_process.test.ts new file mode 100644 index 00000000..57ce9998 --- /dev/null +++ b/packages/ide/test/child_process.test.ts @@ -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 => { + 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)); + }); + }); +}); diff --git a/packages/protocol/test/forker.js b/packages/ide/test/forker.js old mode 100755 new mode 100644 similarity index 93% rename from packages/protocol/test/forker.js rename to packages/ide/test/forker.js index 6f8b9593..f676683e --- a/packages/protocol/test/forker.js +++ b/packages/ide/test/forker.js @@ -1,3 +1,3 @@ process.on("message", (data) => { process.send(data); -}); \ No newline at end of file +}); diff --git a/packages/package.json b/packages/package.json index 8fdcb413..dbdeedf3 100644 --- a/packages/package.json +++ b/packages/package.json @@ -23,6 +23,7 @@ ], "moduleNameMapper": { "^.+\\.(s?css|png|svg)$": "/../scripts/dummy.js", + "@coder/ide/src/fill/evaluation": "/ide/src/fill/evaluation", "@coder/(.*)/test": "/$1/test", "@coder/(.*)": "/$1/src" }, diff --git a/packages/vscode/src/fill/node-pty.ts b/packages/vscode/src/fill/node-pty.ts index 8f39287c..ee3a1eff 100644 --- a/packages/vscode/src/fill/node-pty.ts +++ b/packages/vscode/src/fill/node-pty.ts @@ -42,9 +42,9 @@ class Pty implements nodePty.IPty { ptyProc.on("data", (data) => ae.emit("data", data)); - ae.on("resize", (cols, rows) => ptyProc.resize(cols, rows)); - ae.on("write", (data) => ptyProc.write(data)); - ae.on("kill", (signal) => ptyProc.kill(signal)); + ae.on("resize", (cols: number, rows: number) => ptyProc.resize(cols, rows)); + ae.on("write", (data: string) => ptyProc.write(data)); + ae.on("kill", (signal: string) => ptyProc.kill(signal)); return { onDidDispose: (cb): void => ptyProc.on("exit", cb), diff --git a/packages/vscode/src/fill/spdlog.ts b/packages/vscode/src/fill/spdlog.ts index caed24db..4be1f750 100644 --- a/packages/vscode/src/fill/spdlog.ts +++ b/packages/vscode/src/fill/spdlog.ts @@ -9,22 +9,22 @@ const ae = client.run((ae) => { const spdlog = __non_webpack_require__("spdlog") as typeof import("spdlog"); const loggers = new Map(); - 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); loggers.set(id, logger); }); - ae.on("clearFormatters", (id) => loggers.get(id)!.clearFormatters()); - ae.on("critical", (id, message) => loggers.get(id)!.critical(message)); - ae.on("debug", (id, message) => loggers.get(id)!.debug(message)); - ae.on("drop", (id) => loggers.get(id)!.drop()); - ae.on("errorLog", (id, message) => loggers.get(id)!.error(message)); - ae.on("flush", (id) => loggers.get(id)!.flush()); - ae.on("info", (id, message) => loggers.get(id)!.info(message)); - ae.on("setAsyncMode", (bufferSize, flushInterval) => spdlog.setAsyncMode(bufferSize, flushInterval)); - ae.on("setLevel", (id, level) => loggers.get(id)!.setLevel(level)); - ae.on("trace", (id, message) => loggers.get(id)!.trace(message)); - ae.on("warn", (id, message) => loggers.get(id)!.warn(message)); + ae.on("clearFormatters", (id: number) => loggers.get(id)!.clearFormatters()); + ae.on("critical", (id: number, message: string) => loggers.get(id)!.critical(message)); + ae.on("debug", (id: number, message: string) => loggers.get(id)!.debug(message)); + ae.on("drop", (id: number) => loggers.get(id)!.drop()); + ae.on("errorLog", (id: number, message: string) => loggers.get(id)!.error(message)); + ae.on("flush", (id: number) => loggers.get(id)!.flush()); + ae.on("info", (id: number, message: string) => loggers.get(id)!.info(message)); + ae.on("setAsyncMode", (bufferSize: number, flushInterval: number) => spdlog.setAsyncMode(bufferSize, flushInterval)); + ae.on("setLevel", (id: number, level: number) => loggers.get(id)!.setLevel(level)); + ae.on("trace", (id: number, message: string) => loggers.get(id)!.trace(message)); + ae.on("warn", (id: number, message: string) => loggers.get(id)!.warn(message)); const disposeCallbacks = void>>[]; @@ -40,7 +40,7 @@ const ae = client.run((ae) => { const spdLogger = logger.named("spdlog"); 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; export class RotatingLogger implements NodeRotatingLogger {