httpapi-config.test.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { afterEach, describe, expect } from "bun:test"
  2. import path from "path"
  3. import { Server } from "../../src/server/server"
  4. import * as Log from "@opencode-ai/core/util/log"
  5. import { Effect, Fiber } from "effect"
  6. import { resetDatabase } from "../fixture/db"
  7. import { disposeAllInstances, tmpdir } from "../fixture/fixture"
  8. import { it } from "../lib/effect"
  9. import { waitGlobalBusEvent } from "./global-bus"
  10. void Log.init({ print: false })
  11. function app() {
  12. return Server.Default().app
  13. }
  14. function waitDisposed(directory: string) {
  15. return waitGlobalBusEvent({
  16. message: "timed out waiting for instance disposal",
  17. predicate: (event) => event.payload.type === "server.instance.disposed" && event.directory === directory,
  18. })
  19. }
  20. const tmpdirEffect = (options: Parameters<typeof tmpdir>[0]) =>
  21. Effect.acquireRelease(
  22. Effect.promise(() => tmpdir(options)),
  23. (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
  24. )
  25. afterEach(async () => {
  26. await disposeAllInstances()
  27. await resetDatabase()
  28. })
  29. describe("config HttpApi", () => {
  30. it.live(
  31. "serves config update through the default server app",
  32. Effect.gen(function* () {
  33. const tmp = yield* tmpdirEffect({ config: { formatter: false, lsp: false } })
  34. const disposed = yield* waitDisposed(tmp.path).pipe(Effect.forkScoped)
  35. const response = yield* Effect.promise(() =>
  36. Promise.resolve(
  37. app().request("/config", {
  38. method: "PATCH",
  39. headers: {
  40. "content-type": "application/json",
  41. "x-opencode-directory": tmp.path,
  42. },
  43. body: JSON.stringify({ username: "patched-user", formatter: false, lsp: false }),
  44. }),
  45. ),
  46. )
  47. expect(response.status).toBe(200)
  48. expect(yield* Effect.promise(() => response.json())).toMatchObject({
  49. username: "patched-user",
  50. formatter: false,
  51. lsp: false,
  52. })
  53. yield* Fiber.join(disposed)
  54. expect(yield* Effect.promise(() => Bun.file(path.join(tmp.path, "config.json")).json())).toMatchObject({
  55. username: "patched-user",
  56. formatter: false,
  57. lsp: false,
  58. })
  59. }),
  60. )
  61. it.live(
  62. "serves config with active provider model status",
  63. Effect.gen(function* () {
  64. const tmp = yield* tmpdirEffect({
  65. config: {
  66. formatter: false,
  67. lsp: false,
  68. provider: {
  69. omniroute: {
  70. models: {
  71. "gpt-4o": {
  72. status: "active",
  73. },
  74. },
  75. },
  76. },
  77. },
  78. })
  79. const response = yield* Effect.promise(() =>
  80. Promise.resolve(
  81. app().request("/config", {
  82. headers: {
  83. "x-opencode-directory": tmp.path,
  84. },
  85. }),
  86. ),
  87. )
  88. expect(response.status).toBe(200)
  89. expect(yield* Effect.promise(() => response.json())).toMatchObject({
  90. provider: {
  91. omniroute: {
  92. models: {
  93. "gpt-4o": {
  94. status: "active",
  95. },
  96. },
  97. },
  98. },
  99. })
  100. }),
  101. )
  102. })