68 lines
2.2 KiB
TypeScript
68 lines
2.2 KiB
TypeScript
import fs from "node:fs"
|
|
import os from "node:os"
|
|
import path from "node:path"
|
|
import { afterAll, expect, test } from "bun:test"
|
|
import { Effect } from "effect"
|
|
import { ChildProcess } from "effect/unstable/process"
|
|
import { Failed, makeFiles } from "@opencode-ai/core/environment"
|
|
import { environmentConformance } from "@opencode-ai/core/testing/environment-conformance"
|
|
import { createModalSandbox } from "../src/workspace/modal"
|
|
|
|
const enabled =
|
|
!!process.env.OPENCODE_TEST_MODAL &&
|
|
((!!process.env.MODAL_TOKEN_ID && !!process.env.MODAL_TOKEN_SECRET) ||
|
|
fs.existsSync(path.join(os.homedir(), ".modal.toml")))
|
|
const modalTest = enabled ? test : test.skip
|
|
const root = `/tmp/opencode-environment-${crypto.randomUUID()}`
|
|
const sandbox = enabled
|
|
? createModalSandbox({
|
|
app: "opencode-environment-tests",
|
|
sandbox: { timeoutMs: 10 * 60 * 1000 },
|
|
})
|
|
: undefined
|
|
|
|
modalTest(
|
|
"kills a running modal process",
|
|
async () => {
|
|
const value = await sandbox!
|
|
const started = performance.now()
|
|
const exitCode = await Effect.runPromise(
|
|
Effect.scoped(
|
|
Effect.gen(function* () {
|
|
const handle = yield* value.driver.spawner.spawn(ChildProcess.make("sleep", ["300"]))
|
|
yield* handle.kill()
|
|
return yield* handle.exitCode
|
|
}),
|
|
).pipe(Effect.timeout("10 seconds")),
|
|
)
|
|
expect(exitCode).not.toBe(0)
|
|
expect(performance.now() - started).toBeLessThan(10_000)
|
|
},
|
|
15_000,
|
|
)
|
|
|
|
environmentConformance(
|
|
"modal environment",
|
|
() =>
|
|
Effect.promise(async () => {
|
|
const value = await sandbox!
|
|
return {
|
|
files: makeFiles(value.driver),
|
|
root,
|
|
symlink: (target, link) =>
|
|
Effect.scoped(value.driver.spawner.exitCode(ChildProcess.make("ln", ["-s", "--", target, link]))).pipe(
|
|
Effect.flatMap((code) =>
|
|
code === 0 ? Effect.void : Effect.fail(new Failed({ path: link, cause: new Error(`ln exited ${code}`) })),
|
|
),
|
|
Effect.mapError((cause) => (cause instanceof Failed ? cause : new Failed({ path: link, cause }))),
|
|
),
|
|
}
|
|
}),
|
|
!enabled,
|
|
)
|
|
|
|
afterAll(async () => {
|
|
if (!sandbox) return
|
|
await (await sandbox).terminate()
|
|
})
|