UNPKG

unleash-server

Version:

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

692 lines • 25.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const joi_1 = require("joi"); const no_logger_1 = __importDefault(require("../../test/fixtures/no-logger")); const tag_type_service_1 = __importDefault(require("../features/tag-type/tag-type-service")); const events_1 = require("../types/events"); const store_1 = __importDefault(require("../../test/fixtures/store")); const addon_service_1 = __importDefault(require("./addon-service")); const addon_service_test_simple_addon_1 = __importDefault(require("./addon-service-test-simple-addon")); const types_1 = require("../types"); const internals_1 = require("../internals"); const test_config_1 = require("../../test/config/test-config"); const MASKED_VALUE = '*****'; const TEST_USER_ID = -9999; let addonProvider; const config = (0, test_config_1.createTestConfig)(); function getSetup() { const stores = (0, store_1.default)(); const eventService = (0, internals_1.createFakeEventsService)(config); const tagTypeService = new tag_type_service_1.default(stores, { getLogger: no_logger_1.default }, eventService); const integrationEventsService = new internals_1.IntegrationEventsService(stores, { getLogger: no_logger_1.default, flagResolver: {}, }); addonProvider = { simple: new addon_service_test_simple_addon_1.default() }; return { addonService: new addon_service_1.default(stores, { getLogger: no_logger_1.default, // @ts-ignore server: { unleashUrl: 'http://test' }, }, tagTypeService, eventService, integrationEventsService, addonProvider), eventService, stores, tagTypeService, }; } test('should load addon configurations', async () => { const { addonService } = getSetup(); const configs = await addonService.getAddons(); expect(configs.length).toBe(0); }); test('should load provider definitions', async () => { const { addonService } = getSetup(); const providerDefinitions = addonService.getProviderDefinitions(); const simple = providerDefinitions.find((p) => p.name === 'simple'); expect(providerDefinitions.length).toBe(1); expect(simple.name).toBe('simple'); }); test('should not allow addon-config for unknown provider', async () => { const { addonService } = getSetup(); await expect(async () => { await addonService.createAddon({ provider: 'unknown', enabled: true, parameters: {}, events: [], description: '', }, types_1.TEST_AUDIT_USER); }).rejects.toThrow(joi_1.ValidationError); }); test('should trigger simple-addon eventHandler', async () => { const { addonService, eventService } = getSetup(); const config = { provider: 'simple', enabled: true, parameters: { url: 'http://localhost/wh', var: 'some-value', }, events: [events_1.FEATURE_CREATED], description: '', }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); // Feature flag was created await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, data: { name: 'some-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); const simpleProvider = addonService.addonProviders.simple; // @ts-ignore const events = simpleProvider.getEvents(); expect(events.length).toBe(1); expect(events[0].event.type).toBe(events_1.FEATURE_CREATED); expect(events[0].event.data.name).toBe('some-toggle'); }); test('should not trigger event handler if project of event is different from addon', async () => { const { addonService, eventService } = getSetup(); const config = { provider: 'simple', enabled: true, events: [events_1.FEATURE_CREATED], projects: ['someproject'], description: '', parameters: { url: 'http://localhost:wh', }, }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: 'someotherproject', data: { name: 'some-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); const simpleProvider = addonService.addonProviders.simple; // @ts-expect-error const events = simpleProvider.getEvents(); expect(events.length).toBe(0); }); test('should trigger event handler if project for event is one of the desired projects for addon', async () => { const { addonService, eventService } = getSetup(); const desiredProject = 'desired'; const otherProject = 'other'; const config = { provider: 'simple', enabled: true, events: [events_1.FEATURE_CREATED], projects: [desiredProject], description: '', parameters: { url: 'http://localhost:wh', }, }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProject, data: { name: 'some-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: otherProject, data: { name: 'other-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); const simpleProvider = addonService.addonProviders.simple; // @ts-expect-error const events = simpleProvider.getEvents(); expect(events.length).toBe(1); expect(events[0].event.type).toBe(events_1.FEATURE_CREATED); expect(events[0].event.data.name).toBe('some-toggle'); }); test('should trigger events for multiple projects if addon is setup to filter multiple projects', async () => { const { addonService, eventService } = getSetup(); const desiredProjects = ['desired', 'desired2']; const otherProject = 'other'; const config = { provider: 'simple', enabled: true, events: [events_1.FEATURE_CREATED], projects: desiredProjects, description: '', parameters: { url: 'http://localhost:wh', }, }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProjects[0], data: { name: 'some-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: otherProject, data: { name: 'other-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProjects[1], data: { name: 'third-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); const simpleProvider = addonService.addonProviders.simple; // @ts-expect-error const events = simpleProvider.getEvents(); expect(events.length).toBe(2); expect(events[0].event.type).toBe(events_1.FEATURE_CREATED); expect(events[0].event.data.name).toBe('some-toggle'); expect(events[1].event.type).toBe(events_1.FEATURE_CREATED); expect(events[1].event.data.name).toBe('third-toggle'); }); test('should filter events on environment if addon is setup to filter for it', async () => { const { addonService, eventService } = getSetup(); const desiredEnvironment = 'desired'; const otherEnvironment = 'other'; const config = { provider: 'simple', enabled: true, events: [events_1.FEATURE_CREATED], projects: [], environments: [desiredEnvironment], description: '', parameters: { url: 'http://localhost:wh', }, }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredEnvironment, environment: desiredEnvironment, data: { name: 'some-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, environment: otherEnvironment, data: { name: 'other-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); const simpleProvider = addonService.addonProviders.simple; // @ts-expect-error const events = simpleProvider.getEvents(); expect(events.length).toBe(1); expect(events[0].event.type).toBe(events_1.FEATURE_CREATED); expect(events[0].event.data.name).toBe('some-toggle'); }); test('should not filter out global events (no specific environment) even if addon is setup to filter for environments', async () => { const { addonService, eventService } = getSetup(); const filteredEnvironment = 'filtered'; const config = { provider: 'simple', enabled: true, events: [events_1.FEATURE_CREATED], projects: [], environments: [filteredEnvironment], description: '', parameters: { url: 'http://localhost:wh', }, }; const globalEventWithNoEnvironment = { type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: 'some-project', data: { name: 'some-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await eventService.storeEvent(globalEventWithNoEnvironment); const simpleProvider = addonService.addonProviders.simple; // @ts-expect-error const events = simpleProvider.getEvents(); expect(events.length).toBe(1); expect(events[0].event.type).toBe(events_1.FEATURE_CREATED); expect(events[0].event.data.name).toBe('some-toggle'); }); test('should not filter out global events (no specific project) even if addon is setup to filter for projects', async () => { const { addonService, eventService } = getSetup(); const filteredProject = 'filtered'; const config = { provider: 'simple', enabled: true, events: [events_1.FEATURE_CREATED], projects: [filteredProject], environments: [], description: '', parameters: { url: 'http://localhost:wh', }, }; const globalEventWithNoProject = { type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, data: { name: 'some-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await eventService.storeEvent(globalEventWithNoProject); const simpleProvider = addonService.addonProviders.simple; // @ts-expect-error const events = simpleProvider.getEvents(); expect(events.length).toBe(1); expect(events[0].event.type).toBe(events_1.FEATURE_CREATED); expect(events[0].event.data.name).toBe('some-toggle'); }); test('should support wildcard option for filtering addons', async () => { const { addonService, eventService } = getSetup(); const desiredProjects = ['desired', 'desired2']; const otherProject = 'other'; const config = { provider: 'simple', enabled: true, events: [events_1.FEATURE_CREATED], projects: ['*'], description: '', parameters: { url: 'http://localhost:wh', }, }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProjects[0], data: { name: 'some-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: otherProject, data: { name: 'other-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProjects[1], data: { name: 'third-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); const simpleProvider = addonService.addonProviders.simple; // @ts-expect-error const events = simpleProvider.getEvents(); expect(events).toHaveLength(3); expect(events[0].event.type).toBe(events_1.FEATURE_CREATED); expect(events[0].event.data.name).toBe('some-toggle'); expect(events[1].event.type).toBe(events_1.FEATURE_CREATED); expect(events[1].event.data.name).toBe('other-toggle'); expect(events[2].event.type).toBe(events_1.FEATURE_CREATED); expect(events[2].event.data.name).toBe('third-toggle'); }); test('Should support filtering by both project and environment', async () => { const { addonService, eventService } = getSetup(); const desiredProjects = ['desired1', 'desired2', 'desired3']; const desiredEnvironments = ['env1', 'env2', 'env3']; const config = { provider: 'simple', enabled: true, events: [events_1.FEATURE_CREATED], projects: desiredProjects, environments: desiredEnvironments, description: '', parameters: { url: 'http://localhost:wh', }, }; const expectedFeatureNames = [ 'desired-toggle1', 'desired-toggle2', 'desired-toggle3', ]; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProjects[0], environment: desiredEnvironments[0], data: { name: expectedFeatureNames[0], enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProjects[0], environment: 'wrongenvironment', data: { name: 'other-toggle', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProjects[2], environment: desiredEnvironments[1], data: { name: expectedFeatureNames[1], enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: desiredProjects[2], environment: desiredEnvironments[2], data: { name: expectedFeatureNames[2], enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); await eventService.storeEvent({ type: events_1.FEATURE_CREATED, createdBy: types_1.SYSTEM_USER.username, createdByUserId: types_1.SYSTEM_USER.id, project: 'wrongproject', environment: desiredEnvironments[0], data: { name: 'not-expected', enabled: false, strategies: [{ name: 'default' }], }, ip: '127.0.0.1', }); const simpleProvider = addonService.addonProviders.simple; // @ts-expect-error const events = simpleProvider.getEvents(); expect(events.length).toBe(3); expect(events[0].event.type).toBe(events_1.FEATURE_CREATED); expect(events[0].event.data.name).toBe(expectedFeatureNames[0]); expect(events[1].event.type).toBe(events_1.FEATURE_CREATED); expect(events[1].event.data.name).toBe(expectedFeatureNames[1]); expect(events[2].event.type).toBe(events_1.FEATURE_CREATED); expect(events[2].event.data.name).toBe(expectedFeatureNames[2]); }); test('should create simple-addon config', async () => { const { addonService } = getSetup(); const config = { provider: 'simple', enabled: true, parameters: { url: 'http://localhost/wh', var: 'some-value', }, events: [events_1.FEATURE_CREATED], description: '', }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); const addons = await addonService.getAddons(); expect(addons.length).toBe(1); expect(addons[0].provider).toBe('simple'); }); test('should create tag type for simple-addon', async () => { const { addonService, tagTypeService } = getSetup(); const config = { provider: 'simple', enabled: true, parameters: { url: 'http://localhost/wh', var: 'some-value', }, events: [events_1.FEATURE_CREATED], description: '', }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); const tagType = await tagTypeService.getTagType('me'); expect(tagType.name).toBe('me'); }); test('should store ADDON_CONFIG_CREATE event', async () => { const { addonService, eventService } = getSetup(); const config = { provider: 'simple', enabled: true, parameters: { url: 'http://localhost/wh', var: 'some-value', }, events: [events_1.FEATURE_CREATED], description: '', }; await addonService.createAddon(config, types_1.TEST_AUDIT_USER); const { events } = await eventService.getEvents(); expect(events.length).toBe(2); // Also tag-types where created expect(events[1].type).toBe(events_1.ADDON_CONFIG_CREATED); expect(events[1].data.provider).toBe('simple'); }); test('should store ADDON_CONFIG_UPDATE event', async () => { const { addonService, eventService } = getSetup(); const config = { description: '', provider: 'simple', enabled: true, parameters: { url: 'http://localhost/wh', var: 'some-value', }, events: [events_1.FEATURE_CREATED], }; const addonConfig = await addonService.createAddon(config, types_1.TEST_AUDIT_USER); const updated = { ...addonConfig, description: 'test' }; await addonService.updateAddon(addonConfig.id, updated, types_1.TEST_AUDIT_USER); const { events } = await eventService.getEvents(); expect(events.length).toBe(3); expect(events[2].type).toBe(events_1.ADDON_CONFIG_UPDATED); expect(events[2].data.provider).toBe('simple'); }); test('should store ADDON_CONFIG_REMOVE event', async () => { const { addonService, eventService } = getSetup(); const config = { provider: 'simple', description: '', enabled: true, parameters: { url: 'http://localhost/wh', var: 'some-value', }, events: [events_1.FEATURE_CREATED], }; const addonConfig = await addonService.createAddon(config, types_1.TEST_AUDIT_USER); await addonService.removeAddon(addonConfig.id, types_1.TEST_AUDIT_USER); const { events } = await eventService.getEvents(); expect(events.length).toBe(3); expect(events[2].type).toBe(events_1.ADDON_CONFIG_DELETED); expect(events[2].preData.id).toBe(addonConfig.id); }); test('should hide sensitive fields when fetching', async () => { const { addonService } = getSetup(); const config = { provider: 'simple', enabled: true, description: '', parameters: { url: 'http://localhost/wh', var: 'some-value', sensitiveParam: 'should be hidden when fetching', }, events: [events_1.FEATURE_CREATED], }; const createdConfig = await addonService.createAddon(config, types_1.TEST_AUDIT_USER); const addons = await addonService.getAddons(); const addonRetrieved = await addonService.getAddon(createdConfig.id); expect(addons.length).toBe(1); // @ts-ignore expect(addons[0].parameters.sensitiveParam).toBe(MASKED_VALUE); // @ts-ignore expect(addonRetrieved.parameters.sensitiveParam).toBe(MASKED_VALUE); }); test('should not overwrite masked values when updating', async () => { const { addonService, stores } = getSetup(); const config = { provider: 'simple', enabled: true, parameters: { url: 'http://localhost/wh', var: 'some-value', }, events: [events_1.FEATURE_CREATED], description: '', }; const addonConfig = await addonService.createAddon(config, types_1.TEST_AUDIT_USER); const updated = { ...addonConfig, parameters: { url: MASKED_VALUE, var: 'some-new-value' }, description: 'test', }; await addonService.updateAddon(addonConfig.id, updated, types_1.TEST_AUDIT_USER); const updatedConfig = await stores.addonStore.get(addonConfig.id); // @ts-ignore expect(updatedConfig.parameters.url).toBe('http://localhost/wh'); // @ts-ignore expect(updatedConfig.parameters.var).toBe('some-new-value'); }); test('should reject addon config with missing required parameter when creating', async () => { const { addonService } = getSetup(); const config = { provider: 'simple', enabled: true, parameters: { var: 'some-value', }, events: [events_1.FEATURE_CREATED], description: '', }; await expect(async () => addonService.createAddon(config, types_1.TEST_AUDIT_USER)).rejects.toThrow(joi_1.ValidationError); }); test('should reject updating addon config with missing required parameter', async () => { const { addonService } = getSetup(); const addonConfig = { provider: 'simple', enabled: true, parameters: { url: 'https://some.site/api', var: 'some-value', }, events: [events_1.FEATURE_CREATED], description: '', }; const config = await addonService.createAddon(addonConfig, types_1.TEST_AUDIT_USER); const updated = { ...config, parameters: { var: 'some-new-value' }, description: 'test', }; await expect(async () => addonService.updateAddon(config.id, updated, types_1.TEST_AUDIT_USER)).rejects.toThrow(joi_1.ValidationError); }); test('Should reject addon config if a required parameter is just the empty string', async () => { const { addonService } = getSetup(); const config = { provider: 'simple', enabled: true, parameters: { url: '', var: 'some-value', }, events: [events_1.FEATURE_CREATED], description: '', }; await expect(async () => addonService.createAddon(config, types_1.TEST_AUDIT_USER)).rejects.toThrow(joi_1.ValidationError); }); //# sourceMappingURL=addon-service.test.js.map