Files
anomalyco_opencode/packages/server/test/workspace-modal-graph.test.ts
T
2026-08-05 21:43:07 -04:00

90 lines
4.1 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { existsSync, mkdtempSync } from "fs"
import { homedir, tmpdir } from "os"
import path from "path"
import { Effect, Layer } from "effect"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { Bus } from "@opencode-ai/core/bus"
import { Database } from "@opencode-ai/core/database/database"
import { FileMutation } from "@opencode-ai/core/file-mutation"
import { FileSystem } from "@opencode-ai/core/filesystem"
import { Location } from "@opencode-ai/core/location"
import { LocationMutation } from "@opencode-ai/core/location-mutation"
import { LocationServiceMap } from "@opencode-ai/core/location-service-map"
import { Project } from "@opencode-ai/core/project"
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
import { Shell } from "@opencode-ai/core/shell"
import { Workspace } from "@opencode-ai/core/workspace"
import { WorkspaceDriver } from "@opencode-ai/core/workspace/driver"
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
import { ServerWorkspaceDrivers } from "../src/workspace/drivers"
import { ModalDriver } from "../src/workspace/modal"
const hasCredentials = process.env.MODAL_TOKEN_ID !== undefined || existsSync(path.join(homedir(), ".modal.toml"))
const databaseFile = path.join(mkdtempSync(path.join(tmpdir(), "opencode-modal-graph-")), "graph.db")
const layer = AppNodeBuilder.build(
LayerNode.group([Database.node, Bus.node, Workspace.node, LocationServiceMap.node]),
[
[Database.node, Database.configured({ path: databaseFile })],
[WorkspaceDriver.registryNode, ServerWorkspaceDrivers.node],
],
)
// The complete hosted stack against real Modal: workspace creation, the full
// Location graph, file mutation, real bash in the sandbox, eviction, reconnect.
describe.skipIf(!hasCredentials)("hosted location graph on modal (live)", () => {
test(
"runs the location graph against a modal sandbox",
async () => {
await Effect.gen(function* () {
const workspaces = yield* Workspace.Service
const created = yield* workspaces.create({ provider: "modal" })
const driver = yield* ModalDriver.make
const found = yield* workspaces.binding(created.id)
yield* Effect.addFinalizer(() => Effect.ignore(driver.destroy(found.binding)))
const locations = yield* LocationServiceMap.Service
const ref = Location.Ref.make({
directory: AbsolutePath.make(created.root),
workspaceID: created.id,
})
yield* Effect.gen(function* () {
const location = yield* Location.Service
expect(location.project.id).toBe(Project.ID.global)
const mutation = yield* LocationMutation.Service
const mutations = yield* FileMutation.Service
const target = yield* mutation.resolve({ path: "hello.txt" })
yield* mutations.write({ target, content: "hello from opencode\n" })
const shell = yield* Shell.Service
const command = yield* shell.create({
command: "cat hello.txt && printf 'bash-made' > bash.txt",
timeout: 60_000,
})
const finished = yield* shell.wait(command.id)
expect(finished.status).toBe("exited")
const output = yield* shell.output(command.id)
expect(output.output).toContain("hello from opencode")
const filesystem = yield* FileSystem.Service
const fromBash = yield* filesystem.read({ path: RelativePath.make("bash.txt") })
expect(new TextDecoder().decode(fromBash.content)).toBe("bash-made")
}).pipe(Effect.provide(locations.get(ref)))
yield* locations.invalidate(ref)
yield* Effect.gen(function* () {
const filesystem = yield* FileSystem.Service
const hello = yield* filesystem.read({ path: RelativePath.make("hello.txt") })
expect(new TextDecoder().decode(hello.content)).toBe("hello from opencode\n")
}).pipe(Effect.provide(locations.get(ref)))
}).pipe(Effect.scoped, Effect.provide(layer), Effect.runPromise)
},
{ timeout: 600_000 },
)
})