preload.ts 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // IMPORTANT: Set env vars BEFORE any imports from src/ directory
  2. // xdg-basedir reads env vars at import time, so we must set these first
  3. import os from "os"
  4. import path from "path"
  5. import fs from "fs/promises"
  6. import { setTimeout as sleep } from "node:timers/promises"
  7. import { afterAll } from "bun:test"
  8. // Set XDG env vars FIRST, before any src/ imports
  9. const dir = path.join(os.tmpdir(), "opencode-test-data-" + process.pid)
  10. await fs.mkdir(dir, { recursive: true })
  11. afterAll(async () => {
  12. const { AppRuntime } = await import("../src/effect/app-runtime")
  13. await AppRuntime.dispose()
  14. const busy = (error: unknown) =>
  15. typeof error === "object" && error !== null && "code" in error && error.code === "EBUSY"
  16. const rm = async (left: number): Promise<void> => {
  17. Bun.gc(true)
  18. await sleep(100)
  19. return fs.rm(dir, { recursive: true, force: true }).catch((error) => {
  20. if (!busy(error)) throw error
  21. if (left <= 1 && process.platform !== "win32") throw error
  22. if (left <= 1) return
  23. return rm(left - 1)
  24. })
  25. }
  26. // Windows can keep SQLite WAL handles alive until GC finalizers run, so we
  27. // force GC and retry teardown to avoid flaky EBUSY in test cleanup.
  28. await rm(30)
  29. })
  30. process.env["XDG_DATA_HOME"] = path.join(dir, "share")
  31. process.env["XDG_CACHE_HOME"] = path.join(dir, "cache")
  32. process.env["XDG_CONFIG_HOME"] = path.join(dir, "config")
  33. process.env["XDG_STATE_HOME"] = path.join(dir, "state")
  34. process.env["OPENCODE_MODELS_PATH"] = path.join(import.meta.dir, "tool", "fixtures", "models-api.json")
  35. process.env["OPENCODE_EXPERIMENTAL_EVENT_SYSTEM"] = "true"
  36. process.env["OPENCODE_EXPERIMENTAL_WORKSPACES"] = "true"
  37. // Set test home directory to isolate tests from user's actual home directory
  38. // This prevents tests from picking up real user configs/skills from ~/.claude/skills
  39. const testHome = path.join(dir, "home")
  40. await fs.mkdir(testHome, { recursive: true })
  41. process.env["OPENCODE_TEST_HOME"] = testHome
  42. // Set test managed config directory to isolate tests from system managed settings
  43. const testManagedConfigDir = path.join(dir, "managed")
  44. process.env["OPENCODE_TEST_MANAGED_CONFIG_DIR"] = testManagedConfigDir
  45. // Write the cache version file to prevent global/index.ts from clearing the cache
  46. const cacheDir = path.join(dir, "cache", "opencode")
  47. await fs.mkdir(cacheDir, { recursive: true })
  48. await fs.writeFile(path.join(cacheDir, "version"), "14")
  49. // Clear provider and server auth env vars to ensure clean test state
  50. delete process.env["ANTHROPIC_API_KEY"]
  51. delete process.env["OPENAI_API_KEY"]
  52. delete process.env["GOOGLE_API_KEY"]
  53. delete process.env["GOOGLE_GENERATIVE_AI_API_KEY"]
  54. delete process.env["AZURE_OPENAI_API_KEY"]
  55. delete process.env["AWS_ACCESS_KEY_ID"]
  56. delete process.env["AWS_PROFILE"]
  57. delete process.env["AWS_REGION"]
  58. delete process.env["AWS_BEARER_TOKEN_BEDROCK"]
  59. delete process.env["OPENROUTER_API_KEY"]
  60. delete process.env["LLM_GATEWAY_API_KEY"]
  61. delete process.env["GROQ_API_KEY"]
  62. delete process.env["MISTRAL_API_KEY"]
  63. delete process.env["PERPLEXITY_API_KEY"]
  64. delete process.env["TOGETHER_API_KEY"]
  65. delete process.env["XAI_API_KEY"]
  66. delete process.env["DEEPSEEK_API_KEY"]
  67. delete process.env["FIREWORKS_API_KEY"]
  68. delete process.env["CEREBRAS_API_KEY"]
  69. delete process.env["SAMBANOVA_API_KEY"]
  70. delete process.env["OPENCODE_SERVER_PASSWORD"]
  71. delete process.env["OPENCODE_SERVER_USERNAME"]
  72. delete process.env["OPENCODE_EXPERIMENTAL"]
  73. delete process.env["OPENCODE_ENABLE_EXPERIMENTAL_MODELS"]
  74. delete process.env["OTEL_EXPORTER_OTLP_ENDPOINT"]
  75. delete process.env["OTEL_EXPORTER_OTLP_HEADERS"]
  76. delete process.env["OTEL_RESOURCE_ATTRIBUTES"]
  77. // Use in-memory sqlite
  78. process.env["OPENCODE_DB"] = ":memory:"
  79. // Now safe to import from src/
  80. const { initProjectors } = await import("../src/server/projectors")
  81. initProjectors()