Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/terminal/lib/support.ts
Views: 687
/*1Some mocking and other funtionality that is very useful for unit testing.23The code below does not use Primus *at all* to implement anything -- it's just4a lightweight mocking of the same thing in process for unit testing purposes.5*/67import type { PrimusWithChannels } from "./types";8import { EventEmitter } from "events";9import { callback, delay } from "awaiting";10import type { Spark } from "primus";11import { uuid } from "@cocalc/util/misc";12import { exec } from "child_process";13import { once } from "@cocalc/util/async-utils";1415import debug from "debug";16const logger = debug("cocalc:test:terminal");1718const exec1 = (cmd: string, cb) => {19exec(cmd, (_err, stdout, stderr) => {20cb(undefined, { stdout, stderr });21});22};2324export const isPidRunning = async (pid: number) => {25const { stdout } = await callback(exec1, `ps -p ${pid} -o pid=`);26return stdout.trim() != "";27};2829export const getCommandLine = async (pid) => {30const { stdout } = await callback(exec1, `ps -p ${pid} -o comm=`);31return stdout;32};3334export const waitForPidToChange = async (terminal, pid) => {35let i = 1;36while (true) {37const newPid = terminal.getPid();38if (newPid != null && newPid != pid) {39return newPid;40}41await delay(5 * i);42i += 1;43}44};4546class PrimusSparkMock extends EventEmitter {47id: string = uuid();48address: { ip: string };49data: string = "";50messages: object[] = [];5152constructor(ip: string) {53super();54this.address = { ip };55}5657write = (data) => {58if (this.messages == null) return;59logger("spark write", data);60if (typeof data == "object") {61this.messages.push(data);62} else {63this.data += data;64}65this.emit("write");66};6768end = () => {69this.emit("end");70this.removeAllListeners();71const t = this as any;72delete t.id;73delete t.address;74delete t.data;75delete t.messages;76};7778waitForMessage = async () => {79while (true) {80if (this.messages.length > 0) {81return this.messages.shift();82}83await once(this, "write");84}85};8687waitForData = async (x: number | string) => {88let data = "";89const isDone = () => {90if (typeof x == "number") {91return data.length >= x;92} else {93return data.includes(x);94}95};96while (!isDone()) {97if (this.data.length > 0) {98data += this.data;99// console.log("so far", { data });100this.data = "";101}102if (!isDone()) {103await once(this, "write");104}105}106return data;107};108}109110class PrimusChannelMock extends EventEmitter {111name: string;112sparks: { [id: string]: Spark } = {};113114constructor(name) {115super();116this.name = name;117}118119write = (data) => {120if (this.sparks == null) return;121for (const spark of Object.values(this.sparks)) {122spark.write(data);123}124};125126createSpark = (address) => {127const spark = new PrimusSparkMock(address) as unknown as Spark;128this.sparks[spark.id] = spark;129this.emit("connection", spark);130this.on("end", () => {131delete this.sparks[spark.id];132});133return spark;134};135136destroy = () => {137this.removeAllListeners();138if (this.sparks != null) {139for (const spark of Object.values(this.sparks)) {140spark.end();141}142}143const t = this as any;144delete t.name;145delete t.sparks;146};147}148149class PrimusMock {150channels: { [name: string]: PrimusChannelMock } = {};151152channel = (name) => {153if (this.channels[name] == null) {154this.channels[name] = new PrimusChannelMock(name);155}156return this.channels[name];157};158}159160export function getPrimusMock(): PrimusWithChannels {161const primus = new PrimusMock();162return primus as unknown as PrimusWithChannels;163}164165export function getOpts() {166const name = uuid();167const path = `.${name}.term-0.term`;168const options = {169path: `${name}.term`,170};171return { path, options };172}173174175