Files
wehub-resource-sync 0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

108 lines
4.2 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { AzureGenericProvider } from '../../../src/providers/azure/generic';
import { mockProcessEnv } from '../../util/utils';
describe('AzureGenericProvider', () => {
describe('getApiBaseUrl', () => {
let restoreEnv: () => void;
beforeEach(() => {
restoreEnv = mockProcessEnv({ AZURE_OPENAI_API_HOST: undefined });
});
afterEach(() => {
restoreEnv();
});
it('should return apiBaseUrl if set', () => {
const provider = new AzureGenericProvider('test-deployment', {
config: { apiBaseUrl: 'https://custom.azure.com' },
});
expect(provider.getApiBaseUrl()).toBe('https://custom.azure.com');
});
it('should return apiBaseUrl without trailing slash if set', () => {
const provider = new AzureGenericProvider('test-deployment', {
config: { apiBaseUrl: 'https://custom.azure.com/' },
});
expect(provider.getApiBaseUrl()).toBe('https://custom.azure.com');
});
it('should construct URL from apiHost without protocol', () => {
const provider = new AzureGenericProvider('test-deployment', {
config: { apiHost: 'api.azure.com' },
});
expect(provider.getApiBaseUrl()).toBe('https://api.azure.com');
});
it('should remove protocol from apiHost if present', () => {
const provider = new AzureGenericProvider('test-deployment', {
config: { apiHost: 'https://api.azure.com' },
});
expect(provider.getApiBaseUrl()).toBe('https://api.azure.com');
});
it('should remove trailing slash from apiHost if present', () => {
const provider = new AzureGenericProvider('test-deployment', {
config: { apiHost: 'api.azure.com/' },
});
expect(provider.getApiBaseUrl()).toBe('https://api.azure.com');
});
it('should return undefined if neither apiBaseUrl nor apiHost is set', () => {
const provider = new AzureGenericProvider('test-deployment', {});
expect(provider.getApiBaseUrl()).toBeUndefined();
});
});
describe('Entra ID token refresh', () => {
let restoreEnv: () => void;
beforeEach(() => {
restoreEnv = mockProcessEnv({ AZURE_API_KEY: undefined, AZURE_OPENAI_API_KEY: undefined });
});
afterEach(() => {
restoreEnv();
vi.restoreAllMocks();
});
it('does not re-fetch api-key auth headers on subsequent requests', async () => {
const spy = vi
.spyOn(AzureGenericProvider.prototype as any, 'getAuthHeaders')
.mockResolvedValue({ 'api-key': 'k' });
const p = new AzureGenericProvider('d', { config: { apiKey: 'k' } });
await p.ensureInitialized();
const callsAfterInit = spy.mock.calls.length;
await p.ensureInitialized();
await p.ensureInitialized();
expect(spy.mock.calls.length).toBe(callsAfterInit); // api-key never refreshes
});
it('refreshes a bearer token that is at/near expiry', async () => {
const spy = vi
.spyOn(AzureGenericProvider.prototype as any, 'getAuthHeaders')
.mockResolvedValueOnce({ Authorization: 'Bearer first' })
.mockResolvedValue({ Authorization: 'Bearer refreshed' });
const p = new AzureGenericProvider('d', {});
await p.ensureInitialized();
expect((p as any).authHeaders).toEqual({ Authorization: 'Bearer first' });
// Simulate the captured token being already expired.
(p as any).authTokenExpiresOnTimestamp = Date.now() - 1000;
await p.ensureInitialized();
expect((p as any).authHeaders).toEqual({ Authorization: 'Bearer refreshed' });
expect(spy).toHaveBeenCalledTimes(2); // once at init, once on refresh
});
it('does not refresh a still-valid bearer token', async () => {
const spy = vi
.spyOn(AzureGenericProvider.prototype as any, 'getAuthHeaders')
.mockResolvedValue({ Authorization: 'Bearer t' });
const p = new AzureGenericProvider('d', {});
await p.ensureInitialized();
(p as any).authTokenExpiresOnTimestamp = Date.now() + 60 * 60 * 1000; // valid for ~1h
const callsAfterInit = spy.mock.calls.length;
await p.ensureInitialized();
expect(spy.mock.calls.length).toBe(callsAfterInit); // no refetch while valid
});
});
});