Add scouthub-home-be
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import nock from 'nock';
|
||||
|
||||
process.env.KEYCLOAK_BASE_URL = 'http://keycloak.test';
|
||||
process.env.KEYCLOAK_REALM = 'scouthub';
|
||||
process.env.KEYCLOAK_ORG_SERVICE_CLIENT_ID = 'test-client';
|
||||
process.env.KEYCLOAK_ORG_SERVICE_CLIENT_SECRET = 'test-secret';
|
||||
process.env.DATABASE_URL = 'postgresql://user:pass@localhost:5432/scouthub_home_test';
|
||||
process.env.FRONTEND_BASE_URL = 'http://localhost:4200';
|
||||
|
||||
import { getAccessToken, resetTokenCache } from '../../../src/keycloak-admin/tokenManager';
|
||||
|
||||
const KEYCLOAK_HOST = 'http://keycloak.test';
|
||||
const TOKEN_PATH = '/realms/scouthub/protocol/openid-connect/token';
|
||||
|
||||
function mockTokenEndpoint(accessToken: string, expiresInSeconds: number) {
|
||||
return nock(KEYCLOAK_HOST)
|
||||
.post(TOKEN_PATH)
|
||||
.reply(200, { access_token: accessToken, expires_in: expiresInSeconds, token_type: 'Bearer' });
|
||||
}
|
||||
|
||||
// Il modulo calcola la scadenza con Date.now(): per simulare il passare del
|
||||
// tempo mockiamo solo Date.now (non i timer), così le richieste HTTP mockate
|
||||
// da nock continuano a risolversi normalmente sull'event loop reale.
|
||||
let nowSpy: jest.SpyInstance<number, []> | undefined;
|
||||
|
||||
function advanceTimeBy(ms: number): void {
|
||||
const current = nowSpy ? (nowSpy.getMockImplementation()?.() ?? Date.now()) : Date.now();
|
||||
nowSpy = jest.spyOn(Date, 'now').mockReturnValue(current + ms);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
resetTokenCache();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
nowSpy?.mockRestore();
|
||||
nowSpy = undefined;
|
||||
nock.cleanAll();
|
||||
});
|
||||
|
||||
describe('keycloak-admin tokenManager', () => {
|
||||
test("ottiene un access token dall'endpoint client_credentials", async () => {
|
||||
const scope = mockTokenEndpoint('token-1', 300);
|
||||
|
||||
const token = await getAccessToken();
|
||||
|
||||
expect(token).toBe('token-1');
|
||||
expect(scope.isDone()).toBe(true);
|
||||
});
|
||||
|
||||
test('riutilizza il token in cache invece di richiederne uno nuovo ad ogni chiamata', async () => {
|
||||
const scope = mockTokenEndpoint('token-1', 300);
|
||||
|
||||
const first = await getAccessToken();
|
||||
const second = await getAccessToken();
|
||||
const third = await getAccessToken();
|
||||
|
||||
expect(first).toBe('token-1');
|
||||
expect(second).toBe('token-1');
|
||||
expect(third).toBe('token-1');
|
||||
// Un solo interceptor registrato (consumato una volta sola): se il codice
|
||||
// avesse richiesto un nuovo token per ogni chiamata, la seconda/terza
|
||||
// sarebbero fallite per mancanza di un match su nock.
|
||||
expect(scope.isDone()).toBe(true);
|
||||
});
|
||||
|
||||
test('rinnova il token quando è vicino alla scadenza (entro il margine di sicurezza)', async () => {
|
||||
mockTokenEndpoint('token-1', 300);
|
||||
await getAccessToken();
|
||||
|
||||
// 295s dopo: mancano 5s alla scadenza reale, sotto al margine di sicurezza di 10s.
|
||||
advanceTimeBy(295_000);
|
||||
|
||||
const renewalScope = mockTokenEndpoint('token-2', 300);
|
||||
const renewed = await getAccessToken();
|
||||
|
||||
expect(renewed).toBe('token-2');
|
||||
expect(renewalScope.isDone()).toBe(true);
|
||||
});
|
||||
|
||||
test('non rinnova il token se la scadenza è ancora lontana', async () => {
|
||||
mockTokenEndpoint('token-1', 300);
|
||||
await getAccessToken();
|
||||
|
||||
advanceTimeBy(60_000); // ben dentro la validità dei 300s
|
||||
|
||||
const token = await getAccessToken();
|
||||
|
||||
expect(token).toBe('token-1');
|
||||
});
|
||||
|
||||
test('richieste concorrenti senza token in cache generano una sola chiamata HTTP', async () => {
|
||||
const scope = mockTokenEndpoint('token-1', 300);
|
||||
|
||||
const [a, b, c] = await Promise.all([getAccessToken(), getAccessToken(), getAccessToken()]);
|
||||
|
||||
expect(a).toBe('token-1');
|
||||
expect(b).toBe('token-1');
|
||||
expect(c).toBe('token-1');
|
||||
expect(scope.isDone()).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user