60 lines
2.3 KiB
TypeScript
60 lines
2.3 KiB
TypeScript
import { describe, expect } from "bun:test"
|
|
import { Effect, Layer, Stream } from "effect"
|
|
import { ChildProcess } from "effect/unstable/process"
|
|
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
|
|
import { InMemoryFs } from "just-bash"
|
|
import { SimulationFileSystem } from "../../../src/testing/simulation/filesystem"
|
|
import { SimulationSpawner } from "../../../src/testing/simulation/spawner"
|
|
import { testEffect } from "../../lib/effect"
|
|
|
|
const root = "/opencode"
|
|
const fs = new InMemoryFs()
|
|
const it = testEffect(
|
|
Layer.mergeAll(SimulationFileSystem.layer({ root, fs }), SimulationSpawner.layer({ root, fs })),
|
|
)
|
|
|
|
describe("SimulationSpawner", () => {
|
|
it.effect("runs shell commands through just-bash", () =>
|
|
Effect.gen(function* () {
|
|
const spawner = yield* ChildProcessSpawner
|
|
const handle = yield* spawner.spawn(
|
|
ChildProcess.make("printf 'hello' > file.txt && cat file.txt", [], { cwd: root, shell: "/bin/bash" }),
|
|
).pipe(Effect.scoped)
|
|
|
|
expect(yield* Stream.mkString(Stream.decodeText(handle.stdout))).toBe("hello")
|
|
expect(Number(yield* handle.exitCode)).toBe(0)
|
|
expect(yield* Effect.promise(() => fs.readFile("/opencode/file.txt"))).toBe("hello")
|
|
}),
|
|
)
|
|
|
|
it.effect("extracts shell command text from -lc", () =>
|
|
Effect.gen(function* () {
|
|
const spawner = yield* ChildProcessSpawner
|
|
const handle = yield* spawner.spawn(ChildProcess.make("bash", ["-lc", "printf ok"], { cwd: root })).pipe(Effect.scoped)
|
|
|
|
expect(yield* Stream.mkString(Stream.decodeText(handle.stdout))).toBe("ok")
|
|
expect(Number(yield* handle.exitCode)).toBe(0)
|
|
}),
|
|
)
|
|
|
|
it.effect("rejects non-shell commands", () =>
|
|
Effect.gen(function* () {
|
|
const spawner = yield* ChildProcessSpawner
|
|
const exit = yield* spawner.spawn(ChildProcess.make("git", ["status"], { cwd: root })).pipe(Effect.scoped, Effect.exit)
|
|
|
|
expect(exit._tag).toBe("Failure")
|
|
}),
|
|
)
|
|
|
|
it.effect("rejects shell commands outside the simulation root", () =>
|
|
Effect.gen(function* () {
|
|
const spawner = yield* ChildProcessSpawner
|
|
const exit = yield* spawner.spawn(ChildProcess.make("printf blocked", [], { cwd: "/tmp", shell: "/bin/bash" })).pipe(
|
|
Effect.scoped,
|
|
Effect.exit,
|
|
)
|
|
|
|
expect(exit._tag).toBe("Failure")
|
|
}),
|
|
)
|
|
})
|