-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d775061
commit 7a9577d
Showing
12 changed files
with
602 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
workroot/ |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors | ||
|
||
import { beforeAll, describe, expect, it } from "@jest/globals"; | ||
import * as path from "node:path"; | ||
import { Workdir } from "../helpers/workdir"; | ||
import * as time from "../helpers/time"; | ||
import * as pepr from "../helpers/pepr"; | ||
|
||
const FILE = path.basename(__filename); | ||
const HERE = __dirname; | ||
|
||
describe("init", () => { | ||
const workdir = new Workdir(`${FILE}`, `${HERE}/../workroot/cli`); | ||
|
||
beforeAll(async () => { | ||
await workdir.recreate(); | ||
await pepr.prepWorkdir(workdir.path()); | ||
}); | ||
|
||
it( | ||
"init --help", | ||
async () => { | ||
const res = await pepr.cli(workdir.path(), { cmd: "pepr init --help" }); | ||
expect(res.exitcode).toBe(0); | ||
expect(res.stderr.join("").trim()).toBe(""); | ||
expect(res.stdout.at(0)).toMatch("Usage: pepr init"); | ||
}, | ||
time.toMs("2m"), | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { describe, expect, it } from "@jest/globals"; | ||
import { Cmd } from "./cmd"; | ||
|
||
describe("runRaw()", () => { | ||
it("returns stdout", async () => { | ||
const expected = "pong"; | ||
const { stdout } = await new Cmd({ cmd: `echo "${expected}"` }).runRaw(); | ||
expect(stdout.join("")).toBe(expected); | ||
}); | ||
|
||
it("returns exit code", async () => { | ||
const expected = 83; | ||
const { exitcode } = await new Cmd({ cmd: `exit ${expected}` }).runRaw(); | ||
expect(exitcode).toBe(expected); | ||
}); | ||
|
||
it("returns stderr", async () => { | ||
const expected = "oof"; | ||
const { stderr } = await new Cmd({ cmd: `>&2 echo "${expected}" ` }).runRaw(); | ||
expect(stderr.join("")).toBe(expected); | ||
}); | ||
|
||
it("caches last result", async () => { | ||
const cmd = new Cmd({ cmd: `echo "whatever"` }); | ||
const result = await cmd.runRaw(); | ||
expect(result).toBe(cmd.result); | ||
}); | ||
|
||
it("accepts working directory", async () => { | ||
const expected = "/tmp"; | ||
const { stdout } = await new Cmd({ cwd: expected, cmd: `pwd` }).runRaw(); | ||
expect(stdout.join("")).toBe(expected); | ||
}); | ||
|
||
it("accepts env var overrides", async () => { | ||
const [key, val] = ["TESTVAR", "testcontent"]; | ||
const { stdout } = await new Cmd({ env: { [key]: val }, cmd: `echo $${key}` }).runRaw(); | ||
expect(stdout.join("")).toBe(val); | ||
}); | ||
}); | ||
|
||
describe("run()", () => { | ||
it("on success, returns result", async () => { | ||
const expected = "pong"; | ||
const result = await new Cmd({ cmd: `echo "${expected}"` }).run(); | ||
expect(result.stdout.join("")).toBe(expected); | ||
expect(result.stderr.join("")).toBe(""); | ||
expect(result.exitcode).toBe(0); | ||
}); | ||
|
||
it("on failure, throws result", async () => { | ||
const expected = { exitcode: 1, stderr: [], stdout: [] }; | ||
const promise = new Cmd({ cmd: `exit ${expected.exitcode}` }).run(); | ||
expect(promise).rejects.toEqual(expected); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { spawn } from "child_process"; | ||
|
||
export interface Spec { | ||
cmd: string; | ||
stdin?: string[]; | ||
cwd?: string; | ||
env?: object; // object containing key-value pairs | ||
} | ||
|
||
export interface Result { | ||
stdout: string[]; | ||
stderr: string[]; | ||
exitcode: number; | ||
} | ||
|
||
export class Cmd { | ||
result?: Result; | ||
cmd: string; | ||
stdin: string[]; | ||
cwd: string; | ||
env: object; | ||
|
||
constructor(spec: Spec) { | ||
this.cmd = spec.cmd; | ||
this.stdin = spec.stdin || []; | ||
this.cwd = spec.cwd || process.cwd(); | ||
this.env = spec.env ? { ...process.env, ...spec.env } : process.env; | ||
} | ||
|
||
runRaw(): Promise<Result> { | ||
return new Promise((resolve, reject) => { | ||
const proc = spawn(this.cmd, [], { | ||
shell: true, | ||
cwd: this.cwd, | ||
env: this.env as NodeJS.ProcessEnv, | ||
}); | ||
|
||
this.stdin.forEach(line => proc.stdin.write(`${line}\n`)); | ||
proc.stdin.end(); | ||
|
||
let bufout: Buffer = Buffer.from(""); | ||
proc.stdout.on("data", buf => { | ||
bufout = Buffer.concat([bufout, buf]); | ||
}); | ||
|
||
let buferr: Buffer = Buffer.from(""); | ||
proc.stderr.on("data", buf => { | ||
buferr = Buffer.concat([buferr, buf]); | ||
}); | ||
|
||
proc.on("close", exitcode => { | ||
const stdout = bufout.toString("utf8") === "" ? [] : bufout.toString("utf8").split(/[\r\n]+/); | ||
|
||
const stderr = buferr.toString("utf8") === "" ? [] : buferr.toString("utf8").split(/[\r\n]+/); | ||
|
||
this.result = { stdout, stderr, exitcode: exitcode || 0 }; | ||
resolve(this.result); | ||
}); | ||
|
||
proc.on("error", err => { | ||
reject(err); | ||
}); | ||
}); | ||
} | ||
|
||
run(): Promise<Result> { | ||
return this.runRaw().then(result => { | ||
if (result.exitcode > 0) { | ||
throw result; | ||
} | ||
return result; | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors | ||
|
||
import { beforeAll, describe, expect, it } from "@jest/globals"; | ||
import * as fs from "node:fs/promises"; | ||
import * as path from "node:path"; | ||
import { Workdir } from "./workdir"; | ||
import * as time from "./time"; | ||
import * as sut from "./pepr"; | ||
|
||
const FILE = path.basename(__filename); | ||
const HERE = __dirname; | ||
|
||
describe("pepr", () => { | ||
describe("projectRoot", () => { | ||
it("returns pepr project root directory", async () => { | ||
const expected = path.resolve(HERE, "../.."); | ||
const actual = await sut.projectRoot(); | ||
expect(actual).toBe(expected); | ||
}); | ||
}); | ||
|
||
describe("prepWorkdir", () => { | ||
const workdir = new Workdir(`${FILE}-prepWorkdir`, `${HERE}/../workroot/helpers`); | ||
|
||
beforeAll(async () => await workdir.recreate()); | ||
|
||
it("builds pepr package and drops .tgz into given directory", async () => { | ||
await sut.prepWorkdir(workdir.path()); | ||
const files = await fs.readdir(workdir.path()); | ||
|
||
expect(files).toHaveLength(1); | ||
expect(files).toContain("pepr-0.0.0-development.tgz"); | ||
}); | ||
}); | ||
|
||
describe("cli", () => { | ||
const workdir = new Workdir(`${FILE}-cli`, `${HERE}/../workroot/helpers`); | ||
|
||
beforeAll(async () => { | ||
await workdir.recreate(); | ||
await sut.prepWorkdir(workdir.path()); | ||
}); | ||
|
||
it( | ||
"invokes pepr command via .tgz", | ||
async () => { | ||
const res = await sut.cli(workdir.path(), { cmd: "pepr --version" }); | ||
expect(res.exitcode).toBe(0); | ||
expect(res.stderr.join("").trim()).toBe(""); | ||
expect(res.stdout.join("").trim()).toBe("0.0.0-development"); | ||
}, | ||
time.toMs("2m"), | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { resolve, join } from "node:path"; | ||
import { copyFile } from "node:fs/promises"; | ||
import { Spec, Cmd, Result } from "./cmd"; | ||
import { clone } from "ramda"; | ||
|
||
const HERE = __dirname; | ||
|
||
export async function projectRoot(): Promise<string> { | ||
const cmd = new Cmd({ cmd: `npm root`, cwd: HERE }); | ||
const res = await cmd.run(); | ||
const npmroot = res.stdout.join("").trim(); | ||
return resolve(npmroot, ".."); | ||
} | ||
|
||
export async function prepWorkdir(workdir: string): Promise<void> { | ||
const rootdir = await projectRoot(); | ||
const tgz = "pepr-0.0.0-development.tgz"; | ||
const src = join(rootdir, tgz); | ||
const dst = join(workdir, tgz); | ||
await copyFile(src, dst); | ||
} | ||
|
||
export async function cli(workdir: string, spec: Spec): Promise<Result> { | ||
const tgz = "pepr-0.0.0-development.tgz"; | ||
|
||
const _spec = clone(spec); | ||
_spec.cwd = workdir; | ||
|
||
const _cmd = _spec.cmd.trim().replace(/^pepr /, `npx --yes file://./${tgz} `); | ||
_spec.cmd = _cmd; | ||
|
||
const cmd = new Cmd(_spec); | ||
return await cmd.runRaw(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors | ||
|
||
import { describe, it, expect } from "@jest/globals"; | ||
import * as sut from "./time"; | ||
|
||
describe("toHuman()", () => { | ||
it.each([ | ||
// simple | ||
[1, "1ms"], | ||
[1000, "1s"], | ||
[60000, "1m"], | ||
[3600000, "1h"], | ||
[86400000, "1d"], | ||
[604800000, "1w"], | ||
[2592000000, "1mo"], | ||
[31536000000, "1y"], | ||
|
||
// combined | ||
[34822861001, "1y1mo1w1d1h1m1s1ms"], | ||
])("given ms '%s', returns '%s' duration", (ms, human) => { | ||
const result = sut.toHuman(ms); | ||
expect(result).toBe(human); | ||
}); | ||
}); | ||
|
||
describe("toMs()", () => { | ||
it.each([ | ||
// simple | ||
["1ms", 1], | ||
["1s", 1000], | ||
["60s", 60000], | ||
["1m", 60000], | ||
["60m", 3600000], | ||
["1h", 3600000], | ||
["24h", 86400000], | ||
["1d", 86400000], | ||
["7d", 604800000], | ||
["1w", 604800000], | ||
["30d", 2592000000], | ||
["1mo", 2592000000], | ||
["365d", 31536000000], | ||
["1y", 31536000000], | ||
|
||
// weird | ||
["0001s", 1000], | ||
["1 s ", 1000], | ||
|
||
// combined | ||
["1y1mo1w1d1h1m1s1ms", 34822861001], | ||
["1ms1s1m1h1d1w1mo1y", 34822861001], | ||
])("given duration '%s', returns '%s' ms", (human, ms) => { | ||
const result = sut.toMs(human); | ||
expect(result).toBe(ms); | ||
}); | ||
|
||
it.each([ | ||
// bad | ||
["h1m1s", /Unrecognized number .* while parsing/], | ||
["1z", /Unrecognized unit .* while parsing/], | ||
])("given duration '%s', throws error matching '%s'", (human, err) => { | ||
expect(() => sut.toMs(human)).toThrow(err); | ||
}); | ||
}); |
Oops, something went wrong.