diff --git a/lib/services/mimecast-blast-radius.test.ts b/lib/services/mimecast-blast-radius.test.ts index 0945ad1..120bb88 100644 --- a/lib/services/mimecast-blast-radius.test.ts +++ b/lib/services/mimecast-blast-radius.test.ts @@ -224,4 +224,62 @@ describe('getBlastRadius', () => { source: 'fan-out', }); }); + + it('uses an injected tenant client via options.client and never calls getMimecastClient', async () => { + const tenantGetMessageInfoMock = vi.fn().mockResolvedValue(null); + const tenantSearchDeliveredMessagesMock = vi.fn().mockResolvedValue({ messages: [] }); + const tenantGetHeldMessagesMock = vi.fn().mockResolvedValue({ messages: [], totalCount: 0 }); + const tenantGetThreatEventsMock = vi.fn().mockResolvedValue({ items: [], nextCursor: null }); + const fakeTenantClient = { + getMessageInfo: tenantGetMessageInfoMock, + searchDeliveredMessages: tenantSearchDeliveredMessagesMock, + getHeldMessages: tenantGetHeldMessagesMock, + getThreatEvents: tenantGetThreatEventsMock, + }; + + const result = await getBlastRadius(BASE_INPUT, { client: fakeTenantClient as any, cacheScope: 'company-123' }); + + expect(result.status).toBe('ok'); + expect(getMimecastClientMock).not.toHaveBeenCalled(); + expect(tenantSearchDeliveredMessagesMock).toHaveBeenCalledTimes(1); + expect(tenantGetHeldMessagesMock).toHaveBeenCalledTimes(1); + expect(tenantGetThreatEventsMock).toHaveBeenCalledTimes(1); + // Global client's mocked methods must not have been touched. + expect(searchDeliveredMessagesMock).not.toHaveBeenCalled(); + }); + + it('runs the fan-out with an injected tenant client even when isMimecastConfigured() is false', async () => { + isMimecastConfiguredMock.mockReturnValue(false); + const tenantSearchDeliveredMessagesMock = vi.fn().mockResolvedValue({ messages: [] }); + const tenantGetHeldMessagesMock = vi.fn().mockResolvedValue({ messages: [], totalCount: 0 }); + const tenantGetThreatEventsMock = vi.fn().mockResolvedValue({ items: [], nextCursor: null }); + const fakeTenantClient = { + getMessageInfo: vi.fn().mockResolvedValue(null), + searchDeliveredMessages: tenantSearchDeliveredMessagesMock, + getHeldMessages: tenantGetHeldMessagesMock, + getThreatEvents: tenantGetThreatEventsMock, + }; + + const result = await getBlastRadius(BASE_INPUT, { client: fakeTenantClient as any }); + + expect(result.status).toBe('ok'); + expect(getMimecastClientMock).not.toHaveBeenCalled(); + expect(tenantSearchDeliveredMessagesMock).toHaveBeenCalledTimes(1); + }); + + it('degrades to unavailable/lookup_failed when searchDeliveredMessages swallows an error internally (Bug 1 defense-in-depth)', async () => { + searchDeliveredMessagesMock.mockResolvedValue({ + messages: [], + error: 'err_track_and_trace_invalid_end_date', + }); + + const result = await getBlastRadius(BASE_INPUT); + + expect(result).toEqual({ + status: 'unavailable', + reason: 'lookup_failed', + error: 'err_track_and_trace_invalid_end_date', + }); + expect(setCachedDataMock).not.toHaveBeenCalled(); + }); });