import { describe, expect, it } from "@suaveplan/testing/runner"; import { type CommandExecutor, MacOSKeychainBridge } from "../src/index.js"; // The default @opentelemetry/api ships a NoopMeterProvider; we exercise the // meter API and assert no throw. The bridge instruments every CRUD call with // keychain.ops_total + keychain.cli_duration_ms (plus keychain.items_returned // on listItems). Asserting on counter values requires registering an SDK // MeterProvider, which is out-of-scope for the package's runtime — the // instrumentation contract here is "we always call the meter API in the right // shape". A future @suaveplan/opentelemetry-test-harness fixture will assert // recorded values without changing this test. describe("OTel instrumentation", () => { it("addItem records on the ops counter without throwing", { timeout: 5000, }, async () => { const stub: CommandExecutor = async () => ({ stdout: "", stderr: "", exitCode: 0, }); const bridge = new MacOSKeychainBridge({}, stub); await expect( bridge.addItem({ service: "svc", account: "user", password: "p" }) ).resolves.toEqual({ success: true }); }); it("findItem records on the ops counter without throwing", { timeout: 5000, }, async () => { const stub: CommandExecutor = async () => ({ stdout: "", stderr: 'password: "p"', exitCode: 0, }); const bridge = new MacOSKeychainBridge({}, stub); await expect(bridge.findItem("svc", "user")).resolves.toMatchObject({ password: "p", }); }); it("updateItem records the delete + add invocations", { timeout: 5000, }, async () => { let n = 0; const stub: CommandExecutor = async () => { n += 1; return { stdout: "", stderr: "", exitCode: 0 }; }; const bridge = new MacOSKeychainBridge({}, stub); await bridge.updateItem("svc", "user", "newp"); expect(n).toBe(2); }); it("deleteItem records on the ops counter without throwing", { timeout: 5000, }, async () => { const stub: CommandExecutor = async () => ({ stdout: "", stderr: "", exitCode: 0, }); const bridge = new MacOSKeychainBridge({}, stub); await expect(bridge.deleteItem("svc", "user")).resolves.toEqual({ success: true, }); }); it("listItems records the items_returned histogram", { timeout: 5000, }, async () => { const dump = `keychain: "/x" "svce"="svc" "acct"="alice"`; const stub: CommandExecutor = async () => ({ stdout: dump, stderr: "", exitCode: 0, }); const bridge = new MacOSKeychainBridge({}, stub); const entries = await bridge.listItems(); expect(entries).toHaveLength(1); }); it("records on the ops counter even when the call fails", { timeout: 5000, }, async () => { const stub: CommandExecutor = async () => ({ stdout: "", stderr: "could not be found", exitCode: 44, }); const bridge = new MacOSKeychainBridge({}, stub); await expect(bridge.findItem("svc", "user")).rejects.toMatchObject({ code: "KEYCHAIN.NOT_FOUND", }); }); });