UNPKG

unleash-server

Version:

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

341 lines • 13.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const database_init_1 = __importDefault(require("../../../../test/e2e/helpers/database-init")); const no_logger_1 = __importDefault(require("../../../../test/fixtures/no-logger")); const util_1 = require("../../../util"); let stores; let db; let featureStrategiesStore; let featureToggleStore; let projectStore; let featureStrategiesReadModel; const featureName = 'test-strategies-move-project'; beforeAll(async () => { db = await (0, database_init_1.default)('feature_strategies_store_serial', no_logger_1.default); stores = db.stores; featureStrategiesStore = stores.featureStrategiesStore; featureToggleStore = stores.featureToggleStore; projectStore = stores.projectStore; featureStrategiesReadModel = stores.featureStrategiesReadModel; await featureToggleStore.create('default', { name: featureName, createdByUserId: 9999, }); }); afterEach(async () => { await featureStrategiesStore.deleteAll(); }); afterAll(async () => { await db.destroy(); }); test('Can successfully update project for all strategies belonging to feature', async () => { const newProjectId = 'different-project'; const oldProjectId = 'default'; const environment = 'default'; await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'default', projectId: oldProjectId, environment, featureName, constraints: [], parameters: {}, sortOrder: 15, }); await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'default', projectId: oldProjectId, environment, featureName, constraints: [], parameters: {}, sortOrder: 20, }); const strats = await featureStrategiesStore.getStrategiesForFeatureEnv(oldProjectId, featureName, environment); expect(strats).toHaveLength(2); await featureStrategiesStore.setProjectForStrategiesBelongingToFeature(featureName, newProjectId); const newProjectStrats = await featureStrategiesStore.getStrategiesForFeatureEnv(newProjectId, featureName, environment); expect(newProjectStrats).toHaveLength(2); const oldProjectStrats = await featureStrategiesStore.getStrategiesForFeatureEnv(oldProjectId, featureName, environment); return expect(oldProjectStrats).toHaveLength(0); }); test('Can query for features with tags', async () => { const tag = { type: 'simple', value: 'hello-tags' }; await stores.tagStore.createTag(tag); await featureToggleStore.create('default', { name: 'to-be-tagged', createdByUserId: 9999, }); await featureToggleStore.create('default', { name: 'not-tagged', createdByUserId: 9999, }); await stores.featureTagStore.tagFeature('to-be-tagged', tag, -1337); const features = await featureStrategiesStore.getFeatureOverview({ projectId: 'default', tag: [[tag.type, tag.value]], }); expect(features).toHaveLength(1); }); test('Can query for features with namePrefix', async () => { await featureToggleStore.create('default', { name: 'nameprefix-to-be-hit', createdByUserId: 9999, }); await featureToggleStore.create('default', { name: 'nameprefix-not-be-hit', createdByUserId: 9999, }); const features = await featureStrategiesStore.getFeatureOverview({ projectId: 'default', namePrefix: 'nameprefix-to', }); expect(features).toHaveLength(1); }); test('Can query for features with namePrefix and tags', async () => { const tag = { type: 'simple', value: 'hello-nameprefix-and-tags' }; await stores.tagStore.createTag(tag); await featureToggleStore.create('default', { name: 'to-be-tagged-nameprefix-and-tags', createdByUserId: 9999, }); await featureToggleStore.create('default', { name: 'not-tagged-nameprefix-and-tags', createdByUserId: 9999, }); await featureToggleStore.create('default', { name: 'tagged-but-not-hit-nameprefix-and-tags', createdByUserId: 9999, }); await stores.featureTagStore.tagFeature('to-be-tagged-nameprefix-and-tags', tag, 9999); await stores.featureTagStore.tagFeature('tagged-but-not-hit-nameprefix-and-tags', tag, 9999); const features = await featureStrategiesStore.getFeatureOverview({ projectId: 'default', tag: [[tag.type, tag.value]], namePrefix: 'to', }); expect(features).toHaveLength(1); }); describe('strategy parameters default to sane defaults', () => { test('Creating a gradualRollout strategy with no parameters uses the default for all necessary fields', async () => { const toggle = await featureToggleStore.create('default', { name: 'testing-strategy-parameters', createdByUserId: 9999, }); const strategy = await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'flexibleRollout', projectId: 'default', environment: 'default', featureName: toggle.name, constraints: [], sortOrder: 15, parameters: {}, }); expect(strategy.parameters).toEqual({ rollout: '100', groupId: toggle.name, stickiness: 'default', }); }); test('Creating a gradualRollout strategy with some parameters, only uses defaults for those not set', async () => { const toggle = await featureToggleStore.create('default', { name: 'testing-strategy-parameters-with-some-parameters', createdByUserId: 9999, }); const strategy = await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'flexibleRollout', projectId: 'default', environment: 'default', featureName: toggle.name, constraints: [], sortOrder: 15, parameters: { rollout: '60', stickiness: 'userId', }, }); expect(strategy.parameters).toEqual({ rollout: '60', groupId: toggle.name, stickiness: 'userId', }); }); test('Creating an applicationHostname strategy does not get unnecessary parameters set', async () => { const toggle = await featureToggleStore.create('default', { name: 'testing-strategy-parameters-for-applicationHostname', createdByUserId: 9999, }); const strategy = await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'applicationHostname', projectId: 'default', environment: 'default', featureName: toggle.name, constraints: [], sortOrder: 15, parameters: { hostnames: 'myfantastichost', }, }); expect(strategy.parameters).toEqual({ hostnames: 'myfantastichost', }); }); test('Strategy picks the default stickiness set for the project', async () => { const project = await projectStore.create({ name: 'customDefaultStickiness', id: 'custom_default_stickiness', }); const defaultStickiness = 'userId'; await db.rawDatabase.raw(`UPDATE project_settings SET default_stickiness = ? WHERE project = ?`, [defaultStickiness, project.id]); const toggle = await featureToggleStore.create(project.id, { name: 'testing-default-strategy-on-project', createdByUserId: 9999, }); const strategy = await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'flexibleRollout', projectId: project.id, environment: 'default', featureName: toggle.name, constraints: [], sortOrder: 15, parameters: {}, }); expect(strategy.parameters.stickiness).toBe(defaultStickiness); }); }); describe('max metrics collection', () => { test('Read feature with max number of strategies', async () => { const toggle = await featureToggleStore.create('default', { name: 'featureA', createdByUserId: 9999, }); const maxStrategiesBefore = await featureStrategiesReadModel.getMaxFeatureStrategies(); const maxEnvStrategiesBefore = await featureStrategiesReadModel.getMaxFeatureEnvironmentStrategies(); expect(maxStrategiesBefore).toBe(null); expect(maxEnvStrategiesBefore).toBe(null); await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'gradualRollout', projectId: 'default', environment: 'default', featureName: toggle.name, constraints: [], sortOrder: 0, parameters: {}, }); await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'gradualRollout', projectId: 'default', environment: 'default', featureName: toggle.name, constraints: [], sortOrder: 0, parameters: {}, }); const maxStrategies = await featureStrategiesReadModel.getMaxFeatureStrategies(); const maxEnvStrategies = await featureStrategiesReadModel.getMaxFeatureEnvironmentStrategies(); expect(maxStrategies).toEqual({ feature: 'featureA', count: 2 }); expect(maxEnvStrategies).toEqual({ feature: 'featureA', environment: 'default', count: 2, }); }); const bigConstraint = (maxValueCount) => { return { values: Array.from({ length: maxValueCount }, (_, i) => i.toString()), operator: 'IN', contextName: 'appName', }; }; const strategyWithConstraints = (feature, constraint) => { return { strategyName: 'gradualRollout', projectId: 'default', environment: 'default', featureName: feature, constraints: [constraint], sortOrder: 0, parameters: {}, }; }; test('Read feature with max number of constraint values', async () => { const flagA = await featureToggleStore.create('default', { name: (0, util_1.randomId)(), createdByUserId: 9999, }); const flagB = await featureToggleStore.create('default', { name: (0, util_1.randomId)(), createdByUserId: 9999, }); const flagC = await featureToggleStore.create('default', { name: (0, util_1.randomId)(), createdByUserId: 9999, }); const maxConstraintValuesBefore = await featureStrategiesReadModel.getMaxConstraintValues(); expect(maxConstraintValuesBefore).toBe(null); const maxValueCount = 100; await featureStrategiesStore.createStrategyFeatureEnv(strategyWithConstraints(flagA.name, bigConstraint(maxValueCount))); await featureStrategiesStore.createStrategyFeatureEnv(strategyWithConstraints(flagB.name, { operator: 'IN', contextName: 'appName', })); await featureStrategiesStore.createStrategyFeatureEnv(strategyWithConstraints(flagC.name, bigConstraint(maxValueCount + 1))); await featureToggleStore.archive(flagC.name); const maxConstraintValues = await featureStrategiesReadModel.getMaxConstraintValues(); expect(maxConstraintValues).toEqual({ feature: flagA.name, environment: 'default', count: maxValueCount, }); }); test('Read feature strategy with max number of constraints', async () => { const flagA = await featureToggleStore.create('default', { name: (0, util_1.randomId)(), createdByUserId: 9999, }); const flagB = await featureToggleStore.create('default', { name: (0, util_1.randomId)(), createdByUserId: 9999, }); const maxConstraintValuesBefore = await featureStrategiesReadModel.getMaxConstraintsPerStrategy(); expect(maxConstraintValuesBefore).toBe(null); await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'gradualRollout', projectId: 'default', environment: 'default', featureName: flagA.name, constraints: [ { values: ['blah'], operator: 'IN', contextName: 'appName', }, { values: ['blah'], operator: 'IN', contextName: 'appName', }, ], sortOrder: 0, parameters: {}, }); await featureStrategiesStore.createStrategyFeatureEnv({ strategyName: 'gradualRollout', projectId: 'default', environment: 'default', featureName: flagB.name, constraints: [], sortOrder: 0, parameters: {}, }); const maxConstraintValues = await featureStrategiesReadModel.getMaxConstraintsPerStrategy(); expect(maxConstraintValues).toEqual({ feature: flagA.name, environment: 'default', count: 2, }); }); }); //# sourceMappingURL=feature-toggle-strategies-store.e2e.test.js.map