diff --git a/packages/opencode/test/altimate/connections.test.ts b/packages/opencode/test/altimate/connections.test.ts index e5facc6db..369f38893 100644 --- a/packages/opencode/test/altimate/connections.test.ts +++ b/packages/opencode/test/altimate/connections.test.ts @@ -261,6 +261,124 @@ snow: fs.rmSync(tmpDir, { recursive: true }) } }) + + // altimate_change start — tests for untested dbt profiles parser edge cases + test("resolves env_var with default fallback when env var is missing", async () => { + const fs = await import("fs") + const os = await import("os") + const path = await import("path") + + // Ensure the env var does NOT exist + delete process.env.__TEST_DBT_MISSING_VAR_12345 + + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "dbt-test-")) + const profilesPath = path.join(tmpDir, "profiles.yml") + + fs.writeFileSync( + profilesPath, + ` +myproject: + outputs: + dev: + type: postgres + host: "{{ env_var('__TEST_DBT_MISSING_VAR_12345', 'localhost') }}" + port: 5432 + user: "{{ env_var('__TEST_DBT_MISSING_USER_12345', 'default_user') }}" + password: secret + dbname: mydb +`, + ) + + try { + const connections = await parseDbtProfiles(profilesPath) + expect(connections).toHaveLength(1) + expect(connections[0].config.host).toBe("localhost") + expect(connections[0].config.user).toBe("default_user") + } finally { + fs.rmSync(tmpDir, { recursive: true }) + } + }) + + test("skips 'config' top-level key (dbt global settings)", async () => { + const fs = await import("fs") + const os = await import("os") + const path = await import("path") + + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "dbt-test-")) + const profilesPath = path.join(tmpDir, "profiles.yml") + + fs.writeFileSync( + profilesPath, + ` +config: + send_anonymous_usage_stats: false + use_colors: true + +real_project: + outputs: + dev: + type: postgres + host: localhost + dbname: analytics +`, + ) + + try { + const connections = await parseDbtProfiles(profilesPath) + expect(connections).toHaveLength(1) + expect(connections[0].name).toBe("real_project_dev") + // The 'config' key should not appear as a connection + expect(connections.find((c) => c.name.startsWith("config"))).toBeUndefined() + } finally { + fs.rmSync(tmpDir, { recursive: true }) + } + }) + + test("handles multiple profiles with multiple outputs", async () => { + const fs = await import("fs") + const os = await import("os") + const path = await import("path") + + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "dbt-test-")) + const profilesPath = path.join(tmpDir, "profiles.yml") + + fs.writeFileSync( + profilesPath, + ` +warehouse_a: + outputs: + dev: + type: postgres + host: localhost + dbname: dev_db + prod: + type: postgres + host: prod.example.com + dbname: prod_db + +warehouse_b: + outputs: + staging: + type: snowflake + account: abc123 + user: admin + password: pw + database: STAGING + warehouse: COMPUTE_WH + schema: PUBLIC +`, + ) + + try { + const connections = await parseDbtProfiles(profilesPath) + expect(connections).toHaveLength(3) + const names = connections.map((c) => c.name).sort() + expect(names).toEqual(["warehouse_a_dev", "warehouse_a_prod", "warehouse_b_staging"]) + } finally { + fs.rmSync(tmpDir, { recursive: true }) + } + }) + // altimate_change end }) // --------------------------------------------------------------------------- diff --git a/packages/opencode/test/bus/bus-event.test.ts b/packages/opencode/test/bus/bus-event.test.ts new file mode 100644 index 000000000..a18d19938 --- /dev/null +++ b/packages/opencode/test/bus/bus-event.test.ts @@ -0,0 +1,76 @@ +// altimate_change start — tests for BusEvent registry and payloads +import { describe, test, expect } from "bun:test" +import z from "zod" +import { BusEvent } from "../../src/bus/bus-event" + +// Use unique type strings prefixed with __test_ to avoid colliding with +// production events already registered in the global BusEvent registry. + +describe("BusEvent.define", () => { + test("returns an object with type string and zod schema", () => { + const schema = z.object({ count: z.number() }) + const def = BusEvent.define("__test_define_shape", schema) + + expect(def.type).toBe("__test_define_shape") + expect(def.properties).toBe(schema) + }) +}) + +describe("BusEvent.payloads", () => { + // Register a known test event before payloads() tests + const testSchema = z.object({ value: z.string() }) + BusEvent.define("__test_payloads_registered", testSchema) + + test("includes a registered event in the discriminated union", () => { + const union = BusEvent.payloads() + const result = union.safeParse({ + type: "__test_payloads_registered", + properties: { value: "hello" }, + }) + expect(result.success).toBe(true) + }) + + test("rejects event with unregistered type", () => { + const union = BusEvent.payloads() + const result = union.safeParse({ + type: "__test_payloads_NONEXISTENT_999", + properties: {}, + }) + expect(result.success).toBe(false) + }) + + test("rejects event with wrong properties shape", () => { + const union = BusEvent.payloads() + const result = union.safeParse({ + type: "__test_payloads_registered", + properties: { value: 42 }, // should be string, not number + }) + expect(result.success).toBe(false) + }) +}) + +describe("BusEvent.define duplicate handling", () => { + test("last define() wins when same type is registered twice", () => { + // First definition: requires { a: string } + BusEvent.define("__test_duplicate_overwrite", z.object({ a: z.string() })) + // Second definition: requires { b: number } + BusEvent.define("__test_duplicate_overwrite", z.object({ b: z.number() })) + + const union = BusEvent.payloads() + + // Payload matching second schema should succeed + const valid = union.safeParse({ + type: "__test_duplicate_overwrite", + properties: { b: 42 }, + }) + expect(valid.success).toBe(true) + + // Payload matching ONLY first schema (missing b) should fail + const invalid = union.safeParse({ + type: "__test_duplicate_overwrite", + properties: { a: "hello" }, + }) + expect(invalid.success).toBe(false) + }) +}) +// altimate_change end