session-remove.test.ts 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import { describe, expect } from "bun:test"
  2. import { Effect, Layer } from "effect"
  3. import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
  4. import { LayerNode } from "@opencode-ai/util/effect/layer-node"
  5. import { Database } from "@opencode-ai/core/database/database"
  6. import { Bus } from "@opencode-ai/core/bus"
  7. import { Location } from "@opencode-ai/core/location"
  8. import { Project } from "@opencode-ai/core/project"
  9. import { AbsolutePath } from "@opencode-ai/core/schema"
  10. import { Session } from "@opencode-ai/core/session"
  11. import { SessionExecution } from "@opencode-ai/core/session/execution"
  12. import { SessionModelTransport } from "@opencode-ai/core/session/model-transport"
  13. import { SessionProjector } from "@opencode-ai/core/session/projector"
  14. import { SessionStore } from "@opencode-ai/core/session/store"
  15. import { LocationServiceMap } from "@opencode-ai/core/location-services"
  16. import { testEffect } from "./lib/effect"
  17. import { globalProjectLayer } from "./lib/project"
  18. const closed: Session.ID[] = []
  19. const transport = Layer.succeed(
  20. SessionModelTransport.Service,
  21. SessionModelTransport.Service.of({
  22. bind: () => ({ execute: () => Effect.die("Unexpected WebSocket execution") }),
  23. close: (sessionID) => Effect.sync(() => closed.push(sessionID)),
  24. closeAll: Effect.void,
  25. }),
  26. )
  27. const it = testEffect(
  28. AppNodeBuilder.build(
  29. LayerNode.group([
  30. Database.node,
  31. Bus.node,
  32. SessionProjector.node,
  33. SessionStore.node,
  34. Session.node,
  35. LocationServiceMap.node,
  36. ]),
  37. [
  38. [Project.node, globalProjectLayer],
  39. [SessionExecution.node, SessionExecution.noopLayer],
  40. [SessionModelTransport.node, transport],
  41. ],
  42. ),
  43. )
  44. const location = Location.Ref.make({ directory: AbsolutePath.make(import.meta.dir) })
  45. describe("Session.remove", () => {
  46. it.effect("removes a session and its children", () =>
  47. Effect.gen(function* () {
  48. const session = yield* Session.Service
  49. const parent = yield* session.create({ location })
  50. const child = yield* session.create({ parentID: parent.id })
  51. yield* (yield* LocationServiceMap.Service).contextEffect(location)
  52. closed.length = 0
  53. yield* session.remove(parent.id)
  54. expect((yield* session.list()).data).toEqual([])
  55. expect(closed).toEqual([parent.id, child.id])
  56. expect(yield* Effect.result(session.get(parent.id))).toMatchObject({ _tag: "Failure" })
  57. expect(yield* Effect.result(session.get(child.id))).toMatchObject({ _tag: "Failure" })
  58. }),
  59. )
  60. it.effect("fails when the session does not exist", () =>
  61. Effect.gen(function* () {
  62. const session = yield* Session.Service
  63. const sessionID = Session.ID.make("ses_missing")
  64. expect(yield* Effect.result(session.remove(sessionID))).toMatchObject({
  65. _tag: "Failure",
  66. failure: { _tag: "Session.NotFoundError", sessionID },
  67. })
  68. }),
  69. )
  70. })