{"path":"oracle/src/__tests__/config.test.ts","size":8129,"locked":false,"binary":false,"truncated":false,"content":"import { describe, it, expect, vi, beforeEach, afterEach } from \"vitest\";\n\n// We test the config helper functions by re-importing the module with\n// controlled environment variables. The module calls dotenv.config() at import\n// time, so we mock dotenv to be a no-op.\n\nvi.mock(\"dotenv\", () => ({\n  config: vi.fn(),\n}));\n\ndescribe(\"config module\", () => {\n  const ORIGINAL_ENV = process.env;\n\n  beforeEach(() => {\n    vi.resetModules();\n    process.env = { ...ORIGINAL_ENV };\n  });\n\n  afterEach(() => {\n    process.env = ORIGINAL_ENV;\n  });\n\n  function setRequiredEnv(): void {\n    process.env.SOLANA_RPC_URL = \"http://localhost:8899\";\n    process.env.PROGRAM_ID = \"52yt1gCbPeiKP4JYjUVKmMJSgBMMcUx8xRGqozMKX2Mu\";\n    process.env.ORACLE_PRIVATE_KEY = \"fake-key\";\n    process.env.HELIUS_GRPC_ENDPOINT = \"http://fake-grpc\";\n    process.env.HELIUS_API_KEY = \"fake-helius\";\n    process.env.GEMINI_API_KEY = \"fake-gemini\";\n    process.env.ANTHROPIC_API_KEY = \"fake-anthropic\";\n  }\n\n  // ── required() ──────────────────────────────────────────────────────────\n\n  describe(\"required()\", () => {\n    it(\"throws when a required env var is missing\", async () => {\n      // Missing SOLANA_RPC_URL\n      process.env.PROGRAM_ID = \"test\";\n      process.env.ORACLE_PRIVATE_KEY = \"test\";\n      process.env.HELIUS_GRPC_ENDPOINT = \"test\";\n      process.env.HELIUS_API_KEY = \"test\";\n      process.env.GEMINI_API_KEY = \"test\";\n      process.env.ANTHROPIC_API_KEY = \"test\";\n\n      await expect(import(\"../config\")).rejects.toThrow(\n        \"Missing required environment variable: SOLANA_RPC_URL\"\n      );\n    });\n\n    it(\"throws when a required env var is empty string\", async () => {\n      setRequiredEnv();\n      process.env.SOLANA_RPC_URL = \"\";\n\n      await expect(import(\"../config\")).rejects.toThrow(\n        \"Missing required environment variable: SOLANA_RPC_URL\"\n      );\n    });\n\n    it(\"throws when a required env var is whitespace only\", async () => {\n      setRequiredEnv();\n      process.env.SOLANA_RPC_URL = \"   \";\n\n      await expect(import(\"../config\")).rejects.toThrow(\n        \"Missing required environment variable: SOLANA_RPC_URL\"\n      );\n    });\n\n    it(\"trims whitespace from required env vars\", async () => {\n      setRequiredEnv();\n      process.env.SOLANA_RPC_URL = \"  http://trimmed:8899  \";\n\n      const { config } = await import(\"../config\");\n      expect(config.solana.rpcUrl).toBe(\"http://trimmed:8899\");\n    });\n  });\n\n  // ── optional() ──────────────────────────────────────────────────────────\n\n  describe(\"optional()\", () => {\n    it(\"uses fallback when env var is not set\", async () => {\n      setRequiredEnv();\n      delete process.env.GEMINI_MODEL;\n\n      const { config } = await import(\"../config\");\n      expect(config.ai.geminiModel).toBe(\"gemini-3.5-flash\");\n    });\n\n    it(\"uses env value when set\", async () => {\n      setRequiredEnv();\n      process.env.GEMINI_MODEL = \"gemini-pro-custom\";\n\n      const { config } = await import(\"../config\");\n      expect(config.ai.geminiModel).toBe(\"gemini-pro-custom\");\n    });\n\n    it(\"uses fallback for anthropicModel when not set\", async () => {\n      setRequiredEnv();\n      delete process.env.ANTHROPIC_MODEL;\n\n      const { config } = await import(\"../config\");\n      expect(config.ai.anthropicModel).toBe(\"claude-sonnet-4-6\");\n    });\n  });\n\n  // ── optionalNumber() ────────────────────────────────────────────────────\n\n  describe(\"optionalNumber()\", () => {\n    it(\"uses default 0.80 for approvalThreshold when not set\", async () => {\n      setRequiredEnv();\n      delete process.env.APPROVAL_CONFIDENCE_THRESHOLD;\n\n      const { config } = await import(\"../config\");\n      expect(config.ai.approvalThreshold).toBe(0.80);\n    });\n\n    it(\"uses default 0.75 for rejectionThreshold when not set\", async () => {\n      setRequiredEnv();\n      delete process.env.REJECTION_CONFIDENCE_THRESHOLD;\n\n      const { config } = await import(\"../config\");\n      expect(config.ai.rejectionThreshold).toBe(0.75);\n    });\n\n    it(\"parses custom numeric threshold\", async () => {\n      setRequiredEnv();\n      process.env.APPROVAL_CONFIDENCE_THRESHOLD = \"0.90\";\n\n      const { config } = await import(\"../config\");\n      expect(config.ai.approvalThreshold).toBe(0.90);\n    });\n\n    it(\"throws when numeric env var is not a valid number\", async () => {\n      setRequiredEnv();\n      process.env.APPROVAL_CONFIDENCE_THRESHOLD = \"not-a-number\";\n\n      await expect(import(\"../config\")).rejects.toThrow(\n        \"APPROVAL_CONFIDENCE_THRESHOLD must be a valid number\"\n      );\n    });\n  });\n\n  // ── server.port ─────────────────────────────────────────────────────────\n\n  describe(\"server.port\", () => {\n    it(\"defaults to 3001\", async () => {\n      setRequiredEnv();\n      delete process.env.PORT;\n\n      const { config } = await import(\"../config\");\n      expect(config.server.port).toBe(3001);\n    });\n\n    it(\"uses custom PORT\", async () => {\n      setRequiredEnv();\n      process.env.PORT = \"4000\";\n\n      const { config } = await import(\"../config\");\n      expect(config.server.port).toBe(4000);\n    });\n  });\n\n  // ── sentry ──────────────────────────────────────────────────────────────\n\n  describe(\"sentry\", () => {\n    it(\"disabled when SENTRY_DSN is not set\", async () => {\n      setRequiredEnv();\n      delete process.env.SENTRY_DSN;\n\n      const { config } = await import(\"../config\");\n      expect(config.sentry.enabled).toBe(false);\n      expect(config.sentry.dsn).toBe(\"\");\n    });\n\n    it(\"enabled when SENTRY_DSN is set\", async () => {\n      setRequiredEnv();\n      process.env.SENTRY_DSN = \"https://sentry.example.com/123\";\n\n      const { config } = await import(\"../config\");\n      expect(config.sentry.enabled).toBe(true);\n      expect(config.sentry.dsn).toBe(\"https://sentry.example.com/123\");\n    });\n  });\n\n  // ── isDev ───────────────────────────────────────────────────────────────\n\n  describe(\"isDev\", () => {\n    it(\"true when NODE_ENV is not set (defaults to development)\", async () => {\n      setRequiredEnv();\n      delete process.env.NODE_ENV;\n\n      const { config } = await import(\"../config\");\n      expect(config.isDev).toBe(true);\n    });\n\n    it(\"true when NODE_ENV is development\", async () => {\n      setRequiredEnv();\n      process.env.NODE_ENV = \"development\";\n\n      const { config } = await import(\"../config\");\n      expect(config.isDev).toBe(true);\n    });\n\n    it(\"false when NODE_ENV is production\", async () => {\n      setRequiredEnv();\n      process.env.NODE_ENV = \"production\";\n\n      const { config } = await import(\"../config\");\n      expect(config.isDev).toBe(false);\n    });\n  });\n\n  // ── full config loads successfully ──────────────────────────────────────\n\n  describe(\"full config\", () => {\n    it(\"loads all required and optional fields\", async () => {\n      setRequiredEnv();\n\n      const { config } = await import(\"../config\");\n      expect(config.solana.rpcUrl).toBe(\"http://localhost:8899\");\n      expect(config.solana.programId).toBe(\"52yt1gCbPeiKP4JYjUVKmMJSgBMMcUx8xRGqozMKX2Mu\");\n      expect(config.solana.oraclePrivateKey).toBe(\"fake-key\");\n      expect(config.helius.grpcEndpoint).toBe(\"http://fake-grpc\");\n      expect(config.helius.apiKey).toBe(\"fake-helius\");\n      expect(config.ai.geminiApiKey).toBe(\"fake-gemini\");\n      expect(config.ai.anthropicApiKey).toBe(\"fake-anthropic\");\n    });\n  });\n});\n"}