service.test.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { NodeFileSystem } from "@effect/platform-node"
  2. import { expect, test } from "bun:test"
  3. import { Effect } from "effect"
  4. import fs from "node:fs/promises"
  5. import os from "node:os"
  6. import path from "node:path"
  7. import { Service } from "../src/effect/index"
  8. test("service status distinguishes registration and health states", async () => {
  9. const root = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-service-inspection-"))
  10. const file = path.join(root, "service.json")
  11. const expectedVersion = "0.0.0-client"
  12. let response = Response.json({ healthy: true, version: expectedVersion, pid: process.pid })
  13. const server = Bun.serve({ hostname: "127.0.0.1", port: 0, fetch: () => response.clone() })
  14. const inspect = (version: string | null = expectedVersion) =>
  15. Effect.runPromise(
  16. Service.status({ file, ...(version === null ? {} : { version }) }).pipe(Effect.provide(NodeFileSystem.layer)),
  17. )
  18. const discover = (version: string | null) =>
  19. Effect.runPromise(
  20. Service.discover({ file, ...(version === null ? {} : { version }) }).pipe(Effect.provide(NodeFileSystem.layer)),
  21. )
  22. const registration = (input: { url?: string; pid?: number; version?: string } = {}) => ({
  23. url: input.url ?? server.url.toString(),
  24. pid: input.pid ?? process.pid,
  25. version: input.version ?? expectedVersion,
  26. })
  27. const register = (input?: Parameters<typeof registration>[0]) => Bun.write(file, JSON.stringify(registration(input)))
  28. try {
  29. expect(await inspect()).toEqual({ status: "stopped" })
  30. await Bun.write(file, "{")
  31. expect(await inspect()).toEqual({ status: "invalid", reason: "malformed" })
  32. await fs.rm(file)
  33. await fs.mkdir(file)
  34. expect(await inspect()).toEqual({ status: "invalid", reason: "unreadable" })
  35. await fs.rm(file, { recursive: true })
  36. await register({ url: "http://127.0.0.1:1" })
  37. expect(await inspect()).toEqual({
  38. status: "unhealthy",
  39. reason: "unreachable",
  40. registration: registration({ url: "http://127.0.0.1:1" }),
  41. })
  42. await register()
  43. response = new Response("Unavailable", { status: 503 })
  44. expect(await inspect()).toEqual({
  45. status: "unhealthy",
  46. reason: "http-error",
  47. registration: registration(),
  48. statusCode: 503,
  49. })
  50. response = new Response("not json")
  51. expect(await inspect()).toEqual({
  52. status: "unhealthy",
  53. reason: "invalid-response",
  54. registration: registration(),
  55. })
  56. response = Response.json({ healthy: true })
  57. expect(await inspect()).toEqual({ status: "legacy", registration: registration() })
  58. response = Response.json({ healthy: true, version: "0.0.0-server", pid: process.pid + 1 })
  59. expect(await inspect()).toEqual({
  60. status: "inconsistent",
  61. fields: ["pid", "version"],
  62. registration: registration(),
  63. health: { pid: process.pid + 1, version: "0.0.0-server" },
  64. })
  65. response = Response.json({ healthy: true, version: "0.0.0-server", pid: process.pid })
  66. await register({ version: "0.0.0-server" })
  67. expect(await inspect()).toEqual({
  68. status: "running",
  69. url: server.url.toString(),
  70. pid: process.pid,
  71. version: "0.0.0-server",
  72. compatible: false,
  73. })
  74. expect(await inspect("0.0.0-server")).toEqual({
  75. status: "running",
  76. url: server.url.toString(),
  77. pid: process.pid,
  78. version: "0.0.0-server",
  79. compatible: true,
  80. })
  81. expect(await inspect(null)).toEqual({
  82. status: "running",
  83. url: server.url.toString(),
  84. pid: process.pid,
  85. version: "0.0.0-server",
  86. })
  87. expect(await discover(expectedVersion)).toBeUndefined()
  88. expect((await discover("0.0.0-server"))?.url).toBe(server.url.toString())
  89. expect((await discover(null))?.url).toBe(server.url.toString())
  90. } finally {
  91. server.stop(true)
  92. await fs.rm(root, { recursive: true, force: true })
  93. }
  94. })