UNPKG

unleash-server

Version:

Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.

199 lines • 8.84 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const test_config_1 = require("../../test/config/test-config"); const api_token_1 = require("../types/models/api-token"); const types_1 = require("../types"); const date_fns_1 = require("date-fns"); const util_1 = require("../util"); const createApiTokenService_1 = require("../features/api-tokens/createApiTokenService"); test('Should init api token', async () => { const token = { environment: '*', project: '*', secret: '*:*:some-random-string', type: api_token_1.ApiTokenType.ADMIN, tokenName: 'admin', }; const config = (0, test_config_1.createTestConfig)({ authentication: { initApiTokens: [token], }, experimental: { flags: { useMemoizedActiveTokens: true, }, }, }); const { apiTokenStore } = (0, createApiTokenService_1.createFakeApiTokenService)(config); const insertCalled = new Promise((resolve) => { apiTokenStore.on('insert', resolve); }); await insertCalled; const tokens = await apiTokenStore.getAll(); expect(tokens).toHaveLength(1); }); test("Shouldn't return frontend token when secret is undefined", async () => { const token = { environment: 'default', projects: ['*'], secret: '*:*:some-random-string', type: api_token_1.ApiTokenType.FRONTEND, tokenName: 'front', expiresAt: undefined, }; const config = (0, test_config_1.createTestConfig)({}); const { environmentStore, apiTokenService } = (0, createApiTokenService_1.createFakeApiTokenService)(config); await environmentStore.create({ name: 'default', enabled: true, type: 'test', sortOrder: 1, }); await apiTokenService.createApiTokenWithProjects(token); await apiTokenService.fetchActiveTokens(); expect(await apiTokenService.getUserForToken('')).toEqual(undefined); }); test('Api token operations should all have events attached', async () => { const token = { environment: 'default', projects: ['*'], secret: '*:*:some-random-string', type: api_token_1.ApiTokenType.FRONTEND, tokenName: 'front', expiresAt: undefined, }; const config = (0, test_config_1.createTestConfig)({}); const { environmentStore, apiTokenService, eventService } = (0, createApiTokenService_1.createFakeApiTokenService)(config); await environmentStore.create({ name: 'default', enabled: true, type: 'test', sortOrder: 1, }); const saved = await apiTokenService.createApiTokenWithProjects(token); const newExpiry = (0, date_fns_1.addDays)(new Date(), 30); await apiTokenService.updateExpiry(saved.secret, newExpiry, types_1.TEST_AUDIT_USER); await apiTokenService.delete(saved.secret, types_1.TEST_AUDIT_USER); const { events } = await eventService.getEvents(); const createdApiTokenEvents = events.filter((e) => e.type === types_1.API_TOKEN_CREATED); expect(createdApiTokenEvents).toHaveLength(1); expect(createdApiTokenEvents[0].preData).toBeUndefined(); expect(createdApiTokenEvents[0].data.secret).toBeUndefined(); const updatedApiTokenEvents = events.filter((e) => e.type === types_1.API_TOKEN_UPDATED); expect(updatedApiTokenEvents).toHaveLength(1); expect(updatedApiTokenEvents[0].preData.expiresAt).toBeUndefined(); expect(updatedApiTokenEvents[0].preData.secret).toBeUndefined(); expect(updatedApiTokenEvents[0].data.secret).toBeUndefined(); expect(updatedApiTokenEvents[0].data.expiresAt).toBe(newExpiry); const deletedApiTokenEvents = events.filter((e) => e.type === types_1.API_TOKEN_DELETED); expect(deletedApiTokenEvents).toHaveLength(1); expect(deletedApiTokenEvents[0].data).toBeUndefined(); expect(deletedApiTokenEvents[0].preData).toBeDefined(); expect(deletedApiTokenEvents[0].preData.secret).toBeUndefined(); }); test('getUserForToken should get a user with admin token user id and token name', async () => { const config = (0, test_config_1.createTestConfig)(); const { apiTokenService } = (0, createApiTokenService_1.createFakeApiTokenService)(config); const token = await apiTokenService.createApiTokenWithProjects({ environment: '*', projects: ['*'], type: api_token_1.ApiTokenType.ADMIN, tokenName: 'admin.token', }, (0, util_1.extractAuditInfoFromUser)(types_1.ADMIN_TOKEN_USER)); const user = await apiTokenService.getUserForToken(token.secret); expect(user).toBeDefined(); expect(user.username).toBe(token.tokenName); expect(user.internalAdminTokenUserId).toBe(types_1.ADMIN_TOKEN_USER.id); }); describe('API token getTokenWithCache', () => { const token = { environment: 'default', projects: ['*'], secret: '*:*:some-random-string', type: api_token_1.ApiTokenType.CLIENT, tokenName: 'new-token-by-another-instance', expiresAt: undefined, }; const setup = (options) => { const config = (0, test_config_1.createTestConfig)(options); const { apiTokenService, apiTokenStore } = (0, createApiTokenService_1.createFakeApiTokenService)(config); return { apiTokenService, apiTokenStore, }; }; test('should return the token and perform only one db query', async () => { const { apiTokenService, apiTokenStore } = setup(); const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get'); // valid token not present in cache (could be inserted by another instance) apiTokenStore.insert(token); for (let i = 0; i < 5; i++) { const found = await apiTokenService.getTokenWithCache(token.secret); expect(found).toBeDefined(); expect(found?.tokenName).toBe(token.tokenName); expect(found?.createdAt).toBeDefined(); } expect(apiTokenStoreGet).toHaveBeenCalledTimes(1); }); test('should query the db only once for invalid tokens', async () => { jest.useFakeTimers(); const { apiTokenService, apiTokenStore } = setup(); const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get'); const invalidToken = 'invalid-token'; for (let i = 0; i < 5; i++) { expect(await apiTokenService.getTokenWithCache(invalidToken)).toBeUndefined(); } expect(apiTokenStoreGet).toHaveBeenCalledTimes(1); // after more than 5 minutes we should be able to query again jest.advanceTimersByTime((0, date_fns_1.minutesToMilliseconds)(6)); for (let i = 0; i < 5; i++) { expect(await apiTokenService.getTokenWithCache(invalidToken)).toBeUndefined(); } expect(apiTokenStoreGet).toHaveBeenCalledTimes(2); }); test('should not return the token if it has expired and shoud perform only one db query', async () => { const { apiTokenService, apiTokenStore } = setup(); const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get'); // valid token not present in cache but expired apiTokenStore.insert({ ...token, expiresAt: (0, date_fns_1.subDays)(new Date(), 1) }); for (let i = 0; i < 5; i++) { const found = await apiTokenService.getTokenWithCache(token.secret); expect(found).toBeUndefined(); } expect(apiTokenStoreGet).toHaveBeenCalledTimes(1); }); }); test('normalizes api token type casing to lowercase', async () => { const config = (0, test_config_1.createTestConfig)(); const { apiTokenStore, apiTokenService, environmentStore } = (0, createApiTokenService_1.createFakeApiTokenService)(config); await environmentStore.create({ name: 'default', enabled: true, type: 'test', sortOrder: 1, }); const apiTokenStoreInsert = jest.spyOn(apiTokenStore, 'insert'); await apiTokenService.createApiTokenWithProjects({ environment: 'default', // @ts-ignore type: 'CLIENT', projects: [], tokenName: 'uppercase-token', }, types_1.SYSTEM_USER); await apiTokenService.createApiTokenWithProjects({ environment: 'default', // @ts-ignore type: 'client', projects: [], tokenName: 'lowercase-token', }, types_1.SYSTEM_USER); expect(apiTokenStoreInsert).toHaveBeenCalledWith(expect.objectContaining({ type: 'client', })); expect(apiTokenStoreInsert).not.toHaveBeenCalledWith(expect.objectContaining({ type: 'CLIENT', })); const tokens = await apiTokenStore.getAll(); expect(tokens.every((token) => token.type === 'client')).toBeTruthy(); }); //# sourceMappingURL=api-token-service.test.js.map