httpapi-file.test.ts 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { afterEach, describe, expect, test } from "bun:test"
  2. import { Context, Effect } from "effect"
  3. import path from "path"
  4. import { HttpApiApp } from "../../src/server/routes/instance/httpapi/server"
  5. import { FilePaths } from "../../src/server/routes/instance/httpapi/groups/file"
  6. import { resetDatabase } from "../fixture/db"
  7. import { disposeAllInstances, tmpdir } from "../fixture/fixture"
  8. import { pollWithTimeout } from "../lib/effect"
  9. const context = Context.empty() as Context.Context<unknown>
  10. function request(route: string, directory: string, query?: Record<string, string>) {
  11. const url = new URL(`http://localhost${route}`)
  12. for (const [key, value] of Object.entries(query ?? {})) {
  13. url.searchParams.set(key, value)
  14. }
  15. return HttpApiApp.webHandler().handler(
  16. new Request(url, {
  17. headers: {
  18. "x-opencode-directory": directory,
  19. },
  20. }),
  21. context,
  22. )
  23. }
  24. afterEach(async () => {
  25. await disposeAllInstances()
  26. await resetDatabase()
  27. })
  28. describe("file HttpApi", () => {
  29. test("serves read endpoints", async () => {
  30. await using tmp = await tmpdir({ git: true })
  31. await Bun.write(path.join(tmp.path, "hello.txt"), "hello")
  32. const [list, content, status] = await Promise.all([
  33. request(FilePaths.list, tmp.path, { path: "." }),
  34. request(FilePaths.content, tmp.path, { path: "hello.txt" }),
  35. request(FilePaths.status, tmp.path),
  36. ])
  37. expect(list.status).toBe(200)
  38. expect(await list.json()).toContainEqual(
  39. expect.objectContaining({ name: "hello.txt", path: "hello.txt", type: "file" }),
  40. )
  41. expect(content.status).toBe(200)
  42. expect(await content.json()).toMatchObject({ type: "text", content: "hello" })
  43. expect(status.status).toBe(200)
  44. expect(await status.json()).toEqual([])
  45. })
  46. test("serves search endpoints", async () => {
  47. await using tmp = await tmpdir({ git: true })
  48. await Bun.write(path.join(tmp.path, "hello.txt"), "needle")
  49. const [text, symbols] = await Promise.all([
  50. request(FilePaths.findText, tmp.path, { pattern: "needle" }),
  51. request(FilePaths.findSymbol, tmp.path, { query: "hello" }),
  52. ])
  53. const files = await Effect.runPromise(
  54. pollWithTimeout(
  55. Effect.promise(async () => {
  56. const response = await request(FilePaths.findFile, tmp.path, { query: "hello", type: "file" })
  57. const body = await response.json()
  58. return body.includes("hello.txt") ? { response, body } : undefined
  59. }),
  60. "file search index was not ready",
  61. ),
  62. )
  63. expect(text.status).toBe(200)
  64. expect(await text.json()).toContainEqual(expect.objectContaining({ line_number: 1 }))
  65. expect(files.response.status).toBe(200)
  66. expect(files.body).toContain("hello.txt")
  67. expect(symbols.status).toBe(200)
  68. expect(await symbols.json()).toEqual([])
  69. })
  70. })