| import { beforeEach, describe, expect, it, vi } from "vitest"; |
| import type { SlackMonitorContext } from "./context.js"; |
|
|
| const readChannelAllowFromStoreMock = vi.hoisted(() => vi.fn()); |
|
|
| vi.mock("../../pairing/pairing-store.js", () => ({ |
| readChannelAllowFromStore: (...args: unknown[]) => readChannelAllowFromStoreMock(...args), |
| })); |
|
|
| import { clearSlackAllowFromCacheForTest, resolveSlackEffectiveAllowFrom } from "./auth.js"; |
|
|
| function makeSlackCtx(allowFrom: string[]): SlackMonitorContext { |
| return { |
| allowFrom, |
| accountId: "main", |
| dmPolicy: "pairing", |
| } as unknown as SlackMonitorContext; |
| } |
|
|
| describe("resolveSlackEffectiveAllowFrom", () => { |
| const prevTtl = process.env.OPENCLAW_SLACK_PAIRING_ALLOWFROM_CACHE_TTL_MS; |
|
|
| beforeEach(() => { |
| readChannelAllowFromStoreMock.mockReset(); |
| clearSlackAllowFromCacheForTest(); |
| if (prevTtl === undefined) { |
| delete process.env.OPENCLAW_SLACK_PAIRING_ALLOWFROM_CACHE_TTL_MS; |
| } else { |
| process.env.OPENCLAW_SLACK_PAIRING_ALLOWFROM_CACHE_TTL_MS = prevTtl; |
| } |
| }); |
|
|
| it("falls back to channel config allowFrom when pairing store throws", async () => { |
| readChannelAllowFromStoreMock.mockRejectedValueOnce(new Error("boom")); |
|
|
| const effective = await resolveSlackEffectiveAllowFrom(makeSlackCtx(["u1"])); |
|
|
| expect(effective.allowFrom).toEqual(["u1"]); |
| expect(effective.allowFromLower).toEqual(["u1"]); |
| }); |
|
|
| it("treats malformed non-array pairing-store responses as empty", async () => { |
| readChannelAllowFromStoreMock.mockReturnValueOnce(undefined); |
|
|
| const effective = await resolveSlackEffectiveAllowFrom(makeSlackCtx(["u1"])); |
|
|
| expect(effective.allowFrom).toEqual(["u1"]); |
| expect(effective.allowFromLower).toEqual(["u1"]); |
| }); |
|
|
| it("memoizes pairing-store allowFrom reads within TTL", async () => { |
| readChannelAllowFromStoreMock.mockResolvedValue(["u2"]); |
| const ctx = makeSlackCtx(["u1"]); |
|
|
| const first = await resolveSlackEffectiveAllowFrom(ctx, { includePairingStore: true }); |
| const second = await resolveSlackEffectiveAllowFrom(ctx, { includePairingStore: true }); |
|
|
| expect(first.allowFrom).toEqual(["u1", "u2"]); |
| expect(second.allowFrom).toEqual(["u1", "u2"]); |
| expect(readChannelAllowFromStoreMock).toHaveBeenCalledTimes(1); |
| }); |
|
|
| it("refreshes pairing-store allowFrom when cache TTL is zero", async () => { |
| process.env.OPENCLAW_SLACK_PAIRING_ALLOWFROM_CACHE_TTL_MS = "0"; |
| readChannelAllowFromStoreMock.mockResolvedValue(["u2"]); |
| const ctx = makeSlackCtx(["u1"]); |
|
|
| await resolveSlackEffectiveAllowFrom(ctx, { includePairingStore: true }); |
| await resolveSlackEffectiveAllowFrom(ctx, { includePairingStore: true }); |
|
|
| expect(readChannelAllowFromStoreMock).toHaveBeenCalledTimes(2); |
| }); |
| }); |
|
|