run-service.test.ts 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import { expect } from "bun:test"
  2. import { Effect, Layer, Context } from "effect"
  3. import { InstanceRef } from "../../src/effect/instance-ref"
  4. import { makeRuntime } from "../../src/effect/run-service"
  5. import { ProjectV2 } from "@kirincode-ai/core/project"
  6. import { it } from "../lib/effect"
  7. class Shared extends Context.Service<Shared, { readonly id: number }>()("@test/Shared") {}
  8. const testDirectory = "/tmp/opencode-test"
  9. it.live("makeRuntime shares dependent layers through the shared memo map", () =>
  10. Effect.gen(function* () {
  11. let n = 0
  12. const shared = Layer.effect(
  13. Shared,
  14. Effect.sync(() => {
  15. n += 1
  16. return Shared.of({ id: n })
  17. }),
  18. )
  19. class One extends Context.Service<One, { readonly get: () => Effect.Effect<number> }>()("@test/One") {}
  20. const one = Layer.effect(
  21. One,
  22. Effect.gen(function* () {
  23. const svc = yield* Shared
  24. return One.of({
  25. get: Effect.fn("One.get")(() => Effect.succeed(svc.id)),
  26. })
  27. }),
  28. ).pipe(Layer.provide(shared))
  29. class Two extends Context.Service<Two, { readonly get: () => Effect.Effect<number> }>()("@test/Two") {}
  30. const two = Layer.effect(
  31. Two,
  32. Effect.gen(function* () {
  33. const svc = yield* Shared
  34. return Two.of({
  35. get: Effect.fn("Two.get")(() => Effect.succeed(svc.id)),
  36. })
  37. }),
  38. ).pipe(Layer.provide(shared))
  39. const { runPromise: runOne } = makeRuntime(One, one)
  40. const { runPromise: runTwo } = makeRuntime(Two, two)
  41. expect(yield* Effect.promise(() => runOne((svc) => svc.get()))).toBe(1)
  42. expect(yield* Effect.promise(() => runTwo((svc) => svc.get()))).toBe(1)
  43. expect(n).toBe(1)
  44. }),
  45. )
  46. it.live("makeRuntime inherits InstanceRef from the current fiber", () =>
  47. Effect.gen(function* () {
  48. class NeedsInstance extends Context.Service<
  49. NeedsInstance,
  50. { readonly directory: () => Effect.Effect<string | undefined> }
  51. >()("@test/NeedsInstance") {}
  52. const runtime = makeRuntime(
  53. NeedsInstance,
  54. Layer.succeed(
  55. NeedsInstance,
  56. NeedsInstance.of({
  57. directory: () =>
  58. Effect.gen(function* () {
  59. return (yield* InstanceRef)?.directory
  60. }),
  61. }),
  62. ),
  63. )
  64. const actual = yield* Effect.promise(() => runtime.runPromise((svc) => svc.directory()))
  65. expect(actual).toBe(testDirectory)
  66. }).pipe(
  67. Effect.provideService(InstanceRef, {
  68. directory: testDirectory,
  69. worktree: testDirectory,
  70. project: {
  71. id: ProjectV2.ID.global,
  72. worktree: testDirectory,
  73. time: { created: 0, updated: 0 },
  74. sandboxes: [],
  75. },
  76. }),
  77. ),
  78. )