1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-31 13:47:02 +02:00

chore: prepare to remove default env (#10087)

Use DEFAULT_ENV instead of just 'default'
This commit is contained in:
Gastón Fournier 2025-06-06 09:20:16 +02:00 committed by GitHub
parent 553ffc62b7
commit f1c2706db7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 400 additions and 578 deletions

View File

@ -1,5 +1,6 @@
import dbInit, { type ITestDb } from '../../test/e2e/helpers/database-init.js'; import dbInit, { type ITestDb } from '../../test/e2e/helpers/database-init.js';
import getLogger from '../../test/fixtures/no-logger.js'; import getLogger from '../../test/fixtures/no-logger.js';
import { DEFAULT_ENV } from '../server-impl.js';
import type { import type {
IFeatureStrategiesStore, IFeatureStrategiesStore,
IFeatureStrategy, IFeatureStrategy,
@ -85,7 +86,7 @@ test('counts custom strategies in use', async () => {
projectId: 'default', projectId: 'default',
featureName: 'test-toggle', featureName: 'test-toggle',
strategyName: 'strategy-1', strategyName: 'strategy-1',
environment: 'default', environment: DEFAULT_ENV,
parameters: {}, parameters: {},
constraints: [], constraints: [],
variants: [], variants: [],
@ -103,7 +104,7 @@ const baseStrategy: PartialSome<IFeatureStrategy, 'id' | 'createdAt'> = {
projectId: 'default', projectId: 'default',
featureName: 'test-toggle-increment', featureName: 'test-toggle-increment',
strategyName: 'strategy-1', strategyName: 'strategy-1',
environment: 'default', environment: DEFAULT_ENV,
parameters: {}, parameters: {},
constraints: [], constraints: [],
variants: [], variants: [],

View File

@ -5,7 +5,7 @@ import dbInit, {
import getLogger from '../../../test/fixtures/no-logger.js'; import getLogger from '../../../test/fixtures/no-logger.js';
import type { IChangeRequestSegmentUsageReadModel } from './change-request-segment-usage-read-model.js'; import type { IChangeRequestSegmentUsageReadModel } from './change-request-segment-usage-read-model.js';
import { createChangeRequestSegmentUsageReadModel } from './createChangeRequestSegmentUsageReadModel.js'; import { createChangeRequestSegmentUsageReadModel } from './createChangeRequestSegmentUsageReadModel.js';
import { randomId } from '../../util/index.js'; import { DEFAULT_ENV, randomId } from '../../util/index.js';
let db: ITestDb; let db: ITestDb;
let user: IUser; let user: IUser;
@ -65,7 +65,7 @@ const createCR = async (
) => { ) => {
await db.rawDatabase.table('change_requests').insert({ await db.rawDatabase.table('change_requests').insert({
id: changeRequestId, id: changeRequestId,
environment: 'default', environment: DEFAULT_ENV,
state, state,
project: 'default', project: 'default',
created_by: userId, created_by: userId,
@ -167,7 +167,7 @@ test.each([
{ {
projectId: 'default', projectId: 'default',
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
environment: 'default', environment: DEFAULT_ENV,
featureName: FLAG_NAME, featureName: FLAG_NAME,
changeRequest: { id: CR_ID, title: CR_TITLE }, changeRequest: { id: CR_ID, title: CR_TITLE },
}, },
@ -205,7 +205,7 @@ test.each([
id: strategyId, id: strategyId,
projectId: 'default', projectId: 'default',
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
environment: 'default', environment: DEFAULT_ENV,
featureName: FLAG_NAME, featureName: FLAG_NAME,
changeRequest: { id: CR_ID, title: CR_TITLE }, changeRequest: { id: CR_ID, title: CR_TITLE },
}, },
@ -235,7 +235,7 @@ test(`If the same strategy appears in multiple CRs with the same segment, each s
id: strategyId, id: strategyId,
projectId: 'default', projectId: 'default',
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
environment: 'default', environment: DEFAULT_ENV,
featureName: FLAG_NAME, featureName: FLAG_NAME,
changeRequest: { id: CR_ID, title: CR_TITLE }, changeRequest: { id: CR_ID, title: CR_TITLE },
}); });
@ -243,7 +243,7 @@ test(`If the same strategy appears in multiple CRs with the same segment, each s
id: strategyId, id: strategyId,
projectId: 'default', projectId: 'default',
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
environment: 'default', environment: DEFAULT_ENV,
featureName: FLAG_NAME, featureName: FLAG_NAME,
changeRequest: { id: CR_ID_2, title: null }, changeRequest: { id: CR_ID_2, title: null },
}); });

View File

@ -8,6 +8,7 @@ import type { IUnleashConfig } from '../../types/index.js';
import { createTestConfig } from '../../../test/config/test-config.js'; import { createTestConfig } from '../../../test/config/test-config.js';
import { createEventsService } from './createEventsService.js'; import { createEventsService } from './createEventsService.js';
import EventEmitter from 'node:events'; import EventEmitter from 'node:events';
import { DEFAULT_ENV } from '../../server-impl.js';
let db: ITestDb; let db: ITestDb;
@ -62,7 +63,7 @@ test('sets created_by_user_id on a mix of events and created_bys', async () => {
secret: 'token1', secret: 'token1',
username: 'adm-token', username: 'adm-token',
type: 'admin', type: 'admin',
environment: 'default', environment: DEFAULT_ENV,
token_name: 'admin-token', token_name: 'admin-token',
}); });

View File

@ -65,8 +65,6 @@ const createFlag = async (
strategy: Omit<IStrategyConfig, 'id'> = defaultStrategy, strategy: Omit<IStrategyConfig, 'id'> = defaultStrategy,
tags: string[] = [], tags: string[] = [],
projectId: string = 'default', projectId: string = 'default',
username: string = 'test',
userId: number = -9999,
) => { ) => {
await app.services.featureToggleService.createFeatureToggle( await app.services.featureToggleService.createFeatureToggle(
projectId, projectId,
@ -241,7 +239,7 @@ describe('import-export for project-specific segments', () => {
.post('/api/admin/features-batch/export') .post('/api/admin/features-batch/export')
.send({ .send({
features: [defaultFeatureName], features: [defaultFeatureName],
environment: 'default', environment: DEFAULT_ENV,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200); .expect(200);
@ -257,7 +255,7 @@ describe('import-export for project-specific segments', () => {
featureEnvironments: [ featureEnvironments: [
{ {
enabled: false, enabled: false,
environment: 'default', environment: DEFAULT_ENV,
featureName: defaultFeatureName, featureName: defaultFeatureName,
}, },
], ],
@ -322,7 +320,7 @@ test('exports features', async () => {
.post('/api/admin/features-batch/export') .post('/api/admin/features-batch/export')
.send({ .send({
features: [defaultFeatureName], features: [defaultFeatureName],
environment: 'default', environment: DEFAULT_ENV,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200); .expect(200);
@ -338,7 +336,7 @@ test('exports features', async () => {
featureEnvironments: [ featureEnvironments: [
{ {
enabled: false, enabled: false,
environment: 'default', environment: DEFAULT_ENV,
featureName: defaultFeatureName, featureName: defaultFeatureName,
}, },
], ],
@ -407,7 +405,7 @@ test('exports features by tag', async () => {
.post('/api/admin/features-batch/export') .post('/api/admin/features-batch/export')
.send({ .send({
tag: 'mytag', tag: 'mytag',
environment: 'default', environment: DEFAULT_ENV,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200); .expect(200);
@ -423,7 +421,7 @@ test('exports features by tag', async () => {
featureEnvironments: [ featureEnvironments: [
{ {
enabled: false, enabled: false,
environment: 'default', environment: DEFAULT_ENV,
featureName: defaultFeatureName, featureName: defaultFeatureName,
}, },
], ],
@ -505,7 +503,7 @@ test('should export custom context fields from strategies and variants', async (
.post('/api/admin/features-batch/export') .post('/api/admin/features-batch/export')
.send({ .send({
features: [defaultFeatureName], features: [defaultFeatureName],
environment: 'default', environment: DEFAULT_ENV,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200); .expect(200);
@ -521,7 +519,7 @@ test('should export custom context fields from strategies and variants', async (
featureEnvironments: [ featureEnvironments: [
{ {
enabled: false, enabled: false,
environment: 'default', environment: DEFAULT_ENV,
featureName: defaultFeatureName, featureName: defaultFeatureName,
}, },
], ],
@ -550,7 +548,7 @@ test('should export tags', async () => {
.post('/api/admin/features-batch/export') .post('/api/admin/features-batch/export')
.send({ .send({
features: [defaultFeatureName], features: [defaultFeatureName],
environment: 'default', environment: DEFAULT_ENV,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200); .expect(200);
@ -566,7 +564,7 @@ test('should export tags', async () => {
featureEnvironments: [ featureEnvironments: [
{ {
enabled: false, enabled: false,
environment: 'default', environment: DEFAULT_ENV,
featureName: defaultFeatureName, featureName: defaultFeatureName,
}, },
], ],
@ -593,7 +591,7 @@ test('returns all features, when no explicit feature was requested', async () =>
.post('/api/admin/features-batch/export') .post('/api/admin/features-batch/export')
.send({ .send({
features: [], features: [],
environment: 'default', environment: DEFAULT_ENV,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200); .expect(200);
@ -614,7 +612,7 @@ test('returns all project features', async () => {
const { body } = await app.request const { body } = await app.request
.post('/api/admin/features-batch/export') .post('/api/admin/features-batch/export')
.send({ .send({
environment: 'default', environment: DEFAULT_ENV,
project: DEFAULT_PROJECT, project: DEFAULT_PROJECT,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
@ -625,7 +623,7 @@ test('returns all project features', async () => {
const { body: otherProject } = await app.request const { body: otherProject } = await app.request
.post('/api/admin/features-batch/export') .post('/api/admin/features-batch/export')
.send({ .send({
environment: 'default', environment: DEFAULT_ENV,
features: [], // should be ignored because we have project features: [], // should be ignored because we have project
project: 'other_project', project: 'other_project',
}) })

View File

@ -23,6 +23,7 @@ import { FeatureLifecycleReadModel } from './feature-lifecycle-read-model.js';
import type { IFeatureLifecycleReadModel } from './feature-lifecycle-read-model-type.js'; import type { IFeatureLifecycleReadModel } from './feature-lifecycle-read-model-type.js';
import { STAGE_ENTERED } from '../../metric-events.js'; import { STAGE_ENTERED } from '../../metric-events.js';
import type ClientInstanceService from '../metrics/instance/instance-service.js'; import type ClientInstanceService from '../metrics/instance/instance-service.js';
import { DEFAULT_ENV } from '../../server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -103,8 +104,9 @@ const uncompleteFeature = async (featureName: string, expectedCode = 200) => {
function reachedStage(feature: string, stage: StageName) { function reachedStage(feature: string, stage: StageName) {
return new Promise((resolve) => return new Promise((resolve) =>
eventBus.on(STAGE_ENTERED, (event) => { eventBus.on(STAGE_ENTERED, (event) => {
if (event.stage === stage && event.feature === feature) if (event.stage === stage && event.feature === feature) {
resolve(stage); resolve(stage);
}
}), }),
); );
} }
@ -126,25 +128,25 @@ const getFeaturesLifecycleCount = async () => {
test('should return lifecycle stages', async () => { test('should return lifecycle stages', async () => {
await app.createFeature('my_feature_a'); await app.createFeature('my_feature_a');
await app.enableFeature('my_feature_a', 'default'); await app.enableFeature('my_feature_a', DEFAULT_ENV);
eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_a' }); eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_a' });
await reachedStage('my_feature_a', 'initial'); await reachedStage('my_feature_a', 'initial');
await expectFeatureStage('my_feature_a', 'initial'); await expectFeatureStage('my_feature_a', 'initial');
eventBus.emit(CLIENT_METRICS_ADDED, [ eventBus.emit(CLIENT_METRICS_ADDED, [
{ {
featureName: 'my_feature_a', featureName: 'my_feature_a',
environment: 'default', environment: DEFAULT_ENV,
}, },
{ {
featureName: 'non_existent_feature', featureName: 'non_existent_feature',
environment: 'default', environment: DEFAULT_ENV,
}, },
]); ]);
// missing feature // missing feature
eventBus.emit(CLIENT_METRICS_ADDED, [ eventBus.emit(CLIENT_METRICS_ADDED, [
{ {
environment: 'default', environment: DEFAULT_ENV,
yes: 0, yes: 0,
no: 0, no: 0,
}, },
@ -240,12 +242,12 @@ test('should backfill archived feature', async () => {
test('should not backfill for existing lifecycle', async () => { test('should not backfill for existing lifecycle', async () => {
await app.createFeature('my_feature_e'); await app.createFeature('my_feature_e');
await app.enableFeature('my_feature_e', 'default'); await app.enableFeature('my_feature_e', DEFAULT_ENV);
eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_e' }); eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_e' });
eventBus.emit(CLIENT_METRICS_ADDED, [ eventBus.emit(CLIENT_METRICS_ADDED, [
{ {
featureName: 'my_feature_e', featureName: 'my_feature_e',
environment: 'default', environment: DEFAULT_ENV,
}, },
]); ]);
await reachedStage('my_feature_e', 'live'); await reachedStage('my_feature_e', 'live');

View File

@ -450,12 +450,12 @@ test('should filter features by tag that has colon inside', async () => {
test('should filter features by environment status', async () => { test('should filter features by environment status', async () => {
await app.createFeature('my_feature_a'); await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b'); await app.createFeature('my_feature_b');
await app.enableFeature('my_feature_a', 'default'); await app.enableFeature('my_feature_a', DEFAULT_ENV);
const { body } = await filterFeaturesByEnvironmentStatus([ const { body } = await filterFeaturesByEnvironmentStatus([
'default:enabled', `${DEFAULT_ENV}:enabled`,
'nonexistentEnv:disabled', 'nonexistentEnv:disabled',
'default:wrongStatus', `${DEFAULT_ENV}:wrongStatus`,
]); ]);
expect(body).toMatchObject({ expect(body).toMatchObject({
@ -527,10 +527,10 @@ test('should sort features', async () => {
await app.createFeature('my_feature_a'); await app.createFeature('my_feature_a');
await app.createFeature('my_feature_c'); await app.createFeature('my_feature_c');
await app.createFeature('my_feature_b'); await app.createFeature('my_feature_b');
await app.enableFeature('my_feature_c', 'default'); await app.enableFeature('my_feature_c', DEFAULT_ENV);
await app.favoriteFeature('my_feature_b'); await app.favoriteFeature('my_feature_b');
await insertLastSeenAt('my_feature_c', db.rawDatabase, 'default'); await insertLastSeenAt('my_feature_c', db.rawDatabase, DEFAULT_ENV);
const { body: ascName } = await sortFeatures({ const { body: ascName } = await sortFeatures({
sortBy: 'name', sortBy: 'name',
@ -575,7 +575,7 @@ test('should sort features', async () => {
}); });
const { body: environmentAscSort } = await sortFeatures({ const { body: environmentAscSort } = await sortFeatures({
sortBy: 'environment:default', sortBy: `environment:${DEFAULT_ENV}`,
sortOrder: 'asc', sortOrder: 'asc',
}); });
@ -589,7 +589,7 @@ test('should sort features', async () => {
}); });
const { body: environmentDescSort } = await sortFeatures({ const { body: environmentDescSort } = await sortFeatures({
sortBy: 'environment:default', sortBy: `environment:${DEFAULT_ENV}`,
sortOrder: 'desc', sortOrder: 'desc',
}); });
@ -603,7 +603,7 @@ test('should sort features', async () => {
}); });
const { body: favoriteEnvironmentDescSort } = await sortFeatures({ const { body: favoriteEnvironmentDescSort } = await sortFeatures({
sortBy: 'environment:default', sortBy: `environment:${DEFAULT_ENV}`,
sortOrder: 'desc', sortOrder: 'desc',
favoritesFirst: 'true', favoritesFirst: 'true',
}); });

View File

@ -366,7 +366,7 @@ test('cloning a feature flag copies variant environments correctly', async () =>
); );
const defaultEnv = clonedFlag.environments.find( const defaultEnv = clonedFlag.environments.find(
(x) => x.name === 'default', (x) => x.name === DEFAULT_ENV,
); );
const newEnv = clonedFlag.environments.find((x) => x.name === targetEnv); const newEnv = clonedFlag.environments.find((x) => x.name === targetEnv);
@ -377,7 +377,7 @@ test('cloning a feature flag copies variant environments correctly', async () =>
test('cloning a feature flag not allowed for change requests enabled', async () => { test('cloning a feature flag not allowed for change requests enabled', async () => {
await db.rawDatabase('change_request_settings').insert({ await db.rawDatabase('change_request_settings').insert({
project: 'default', project: 'default',
environment: 'default', environment: DEFAULT_ENV,
}); });
await expect( await expect(
service.cloneFeatureToggle( service.cloneFeatureToggle(
@ -397,7 +397,7 @@ test('cloning a feature flag not allowed for change requests enabled', async ()
test('changing to a project with change requests enabled should not be allowed', async () => { test('changing to a project with change requests enabled should not be allowed', async () => {
await db.rawDatabase('change_request_settings').insert({ await db.rawDatabase('change_request_settings').insert({
project: 'default', project: 'default',
environment: 'default', environment: DEFAULT_ENV,
}); });
await expect( await expect(
service.changeProject('newFlagName', 'default', TEST_AUDIT_USER), service.changeProject('newFlagName', 'default', TEST_AUDIT_USER),
@ -453,7 +453,7 @@ test('Cloning a feature flag also clones segments correctly', async () => {
featureName: clonedFeatureName, featureName: clonedFeatureName,
}); });
expect( expect(
feature.environments.find((x) => x.name === 'default')?.strategies[0] feature.environments.find((x) => x.name === DEFAULT_ENV)?.strategies[0]
.segments, .segments,
).toHaveLength(1); ).toHaveLength(1);
}); });
@ -510,13 +510,13 @@ test('If change requests are enabled, cannot change variants without going via C
}; };
await db.rawDatabase('change_request_settings').insert({ await db.rawDatabase('change_request_settings').insert({
project: 'default', project: 'default',
environment: 'default', environment: DEFAULT_ENV,
}); });
return expect(async () => return expect(async () =>
customFeatureService.crProtectedSaveVariantsOnEnv( customFeatureService.crProtectedSaveVariantsOnEnv(
'default', 'default',
featureName, featureName,
'default', DEFAULT_ENV,
[newVariant], [newVariant],
{ {
createdAt: irrelevantDate, createdAt: irrelevantDate,
@ -852,7 +852,7 @@ test('Should not allow to revive flags to archived projects', async () => {
test('Should enable disabled strategies on feature environment enabled', async () => { test('Should enable disabled strategies on feature environment enabled', async () => {
const flagName = 'enableThisFlag'; const flagName = 'enableThisFlag';
const project = 'default'; const project = 'default';
const environment = 'default'; const environment = DEFAULT_ENV;
await service.createFeatureToggle( await service.createFeatureToggle(
project, project,
{ {

View File

@ -10,6 +10,7 @@ import type {
import getLogger from '../../../../test/fixtures/no-logger.js'; import getLogger from '../../../../test/fixtures/no-logger.js';
import { ExceedsLimitError } from '../../../error/exceeds-limit-error.js'; import { ExceedsLimitError } from '../../../error/exceeds-limit-error.js';
import { describe, test, expect } from 'vitest'; import { describe, test, expect } from 'vitest';
import { DEFAULT_ENV } from '../../../server-impl.js';
const alwaysOnFlagResolver = { const alwaysOnFlagResolver = {
isEnabled() { isEnabled() {
return true; return true;
@ -134,7 +135,7 @@ describe('Strategy limits', () => {
featureName: flagName, featureName: flagName,
constraints: constraints, constraints: constraints,
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
}); });
const updateStrategy = (newConstraints) => const updateStrategy = (newConstraints) =>
@ -146,7 +147,7 @@ describe('Strategy limits', () => {
{ {
projectId: 'default', projectId: 'default',
featureName: 'feature', featureName: 'feature',
environment: 'default', environment: DEFAULT_ENV,
}, },
{} as IAuditUser, {} as IAuditUser,
); );
@ -241,7 +242,7 @@ describe('Strategy limits', () => {
featureName: flagName, featureName: flagName,
constraints: constraints(initialConstraintValueCount), constraints: constraints(initialConstraintValueCount),
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
}); });
const updateStrategy = (valueCount) => const updateStrategy = (valueCount) =>
@ -253,7 +254,7 @@ describe('Strategy limits', () => {
{ {
projectId: 'default', projectId: 'default',
featureName: 'feature', featureName: 'feature',
environment: 'default', environment: DEFAULT_ENV,
}, },
{} as IAuditUser, {} as IAuditUser,
); );

View File

@ -10,7 +10,7 @@ import type {
IProjectStore, IProjectStore,
IUnleashStores, IUnleashStores,
} from '../../../types/index.js'; } from '../../../types/index.js';
import { randomId } from '../../../util/index.js'; import { DEFAULT_ENV, randomId } from '../../../util/index.js';
let stores: IUnleashStores; let stores: IUnleashStores;
let db: ITestDb; let db: ITestDb;
@ -45,7 +45,7 @@ afterAll(async () => {
test('Can successfully update project for all strategies belonging to feature', async () => { test('Can successfully update project for all strategies belonging to feature', async () => {
const newProjectId = 'different-project'; const newProjectId = 'different-project';
const oldProjectId = 'default'; const oldProjectId = 'default';
const environment = 'default'; const environment = DEFAULT_ENV;
await featureStrategiesStore.createStrategyFeatureEnv({ await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'default', strategyName: 'default',
projectId: oldProjectId, projectId: oldProjectId,
@ -168,7 +168,7 @@ describe('strategy parameters default to sane defaults', () => {
const strategy = await featureStrategiesStore.createStrategyFeatureEnv({ const strategy = await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: toggle.name, featureName: toggle.name,
constraints: [], constraints: [],
sortOrder: 15, sortOrder: 15,
@ -188,7 +188,7 @@ describe('strategy parameters default to sane defaults', () => {
const strategy = await featureStrategiesStore.createStrategyFeatureEnv({ const strategy = await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: toggle.name, featureName: toggle.name,
constraints: [], constraints: [],
sortOrder: 15, sortOrder: 15,
@ -211,7 +211,7 @@ describe('strategy parameters default to sane defaults', () => {
const strategy = await featureStrategiesStore.createStrategyFeatureEnv({ const strategy = await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'applicationHostname', strategyName: 'applicationHostname',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: toggle.name, featureName: toggle.name,
constraints: [], constraints: [],
sortOrder: 15, sortOrder: 15,
@ -240,7 +240,7 @@ describe('strategy parameters default to sane defaults', () => {
const strategy = await featureStrategiesStore.createStrategyFeatureEnv({ const strategy = await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
projectId: project.id, projectId: project.id,
environment: 'default', environment: DEFAULT_ENV,
featureName: toggle.name, featureName: toggle.name,
constraints: [], constraints: [],
sortOrder: 15, sortOrder: 15,
@ -267,7 +267,7 @@ describe('max metrics collection', () => {
await featureStrategiesStore.createStrategyFeatureEnv({ await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'gradualRollout', strategyName: 'gradualRollout',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: toggle.name, featureName: toggle.name,
constraints: [], constraints: [],
sortOrder: 0, sortOrder: 0,
@ -276,7 +276,7 @@ describe('max metrics collection', () => {
await featureStrategiesStore.createStrategyFeatureEnv({ await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'gradualRollout', strategyName: 'gradualRollout',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: toggle.name, featureName: toggle.name,
constraints: [], constraints: [],
sortOrder: 0, sortOrder: 0,
@ -290,7 +290,7 @@ describe('max metrics collection', () => {
expect(maxStrategies).toEqual({ feature: 'featureA', count: 2 }); expect(maxStrategies).toEqual({ feature: 'featureA', count: 2 });
expect(maxEnvStrategies).toEqual({ expect(maxEnvStrategies).toEqual({
feature: 'featureA', feature: 'featureA',
environment: 'default', environment: DEFAULT_ENV,
count: 2, count: 2,
}); });
}); });
@ -312,7 +312,7 @@ describe('max metrics collection', () => {
return { return {
strategyName: 'gradualRollout', strategyName: 'gradualRollout',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: feature, featureName: feature,
constraints: [constraint], constraints: [constraint],
@ -364,7 +364,7 @@ describe('max metrics collection', () => {
await featureStrategiesReadModel.getMaxConstraintValues(); await featureStrategiesReadModel.getMaxConstraintValues();
expect(maxConstraintValues).toEqual({ expect(maxConstraintValues).toEqual({
feature: flagA.name, feature: flagA.name,
environment: 'default', environment: DEFAULT_ENV,
count: maxValueCount, count: maxValueCount,
}); });
}); });
@ -387,7 +387,7 @@ describe('max metrics collection', () => {
await featureStrategiesStore.createStrategyFeatureEnv({ await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'gradualRollout', strategyName: 'gradualRollout',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: flagA.name, featureName: flagA.name,
constraints: [ constraints: [
{ {
@ -408,7 +408,7 @@ describe('max metrics collection', () => {
await featureStrategiesStore.createStrategyFeatureEnv({ await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'gradualRollout', strategyName: 'gradualRollout',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: flagB.name, featureName: flagB.name,
constraints: [], constraints: [],
sortOrder: 0, sortOrder: 0,
@ -419,7 +419,7 @@ describe('max metrics collection', () => {
await featureStrategiesReadModel.getMaxConstraintsPerStrategy(); await featureStrategiesReadModel.getMaxConstraintsPerStrategy();
expect(maxConstraintValues).toEqual({ expect(maxConstraintValues).toEqual({
feature: flagA.name, feature: flagA.name,
environment: 'default', environment: DEFAULT_ENV,
count: 2, count: 2,
}); });
}); });

View File

@ -139,10 +139,10 @@ test('Should not be possible auto-enable feature flag without CREATE_FEATURE_STR
await db.stores.accessStore.removePermissionFromRole( await db.stores.accessStore.removePermissionFromRole(
role.id, role.id,
CREATE_FEATURE_STRATEGY, CREATE_FEATURE_STRATEGY,
'default', DEFAULT_ENV,
); );
await app.request await app.request
.post(`${url}/${name}/environments/default/on`) .post(`${url}/${name}/environments/${DEFAULT_ENV}/on`)
.expect(403); .expect(403);
}); });

View File

@ -64,7 +64,7 @@ const createStrategy = async (
) => { ) => {
return app.request return app.request
.post( .post(
`/api/admin/projects/default/features/${featureName}/environments/default/strategies`, `/api/admin/projects/default/features/${featureName}/environments/${DEFAULT_ENV}/strategies`,
) )
.send(payload) .send(payload)
.expect(expectedCode); .expect(expectedCode);
@ -78,7 +78,7 @@ const updateStrategy = async (
) => { ) => {
const { body } = await app.request const { body } = await app.request
.put( .put(
`/api/admin/projects/default/features/${featureName}/environments/default/strategies/${strategyId}`, `/api/admin/projects/default/features/${featureName}/environments/${DEFAULT_ENV}/strategies/${strategyId}`,
) )
.send(payload) .send(payload)
.expect(expectedCode); .expect(expectedCode);
@ -107,7 +107,7 @@ beforeAll(async () => {
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: 'tester', tokenName: 'tester',
}); });
}); });
@ -952,7 +952,7 @@ test('Can add strategy to feature flag to a "some-env-2"', async () => {
}); });
test('Can update strategy on feature flag', async () => { test('Can update strategy on feature flag', async () => {
const envName = 'default'; const envName = DEFAULT_ENV;
const featureName = 'feature.strategy.update.strat'; const featureName = 'feature.strategy.update.strat';
const projectPath = '/api/admin/projects/default'; const projectPath = '/api/admin/projects/default';
const featurePath = `${projectPath}/features/${featureName}`; const featurePath = `${projectPath}/features/${featureName}`;
@ -986,7 +986,7 @@ test('Can update strategy on feature flag', async () => {
}); });
test('should coerce all strategy parameter values to strings', async () => { test('should coerce all strategy parameter values to strings', async () => {
const envName = 'default'; const envName = DEFAULT_ENV;
const featureName = randomId(); const featureName = randomId();
const projectPath = '/api/admin/projects/default'; const projectPath = '/api/admin/projects/default';
const featurePath = `${projectPath}/features/${featureName}`; const featurePath = `${projectPath}/features/${featureName}`;
@ -1010,7 +1010,7 @@ test('should coerce all strategy parameter values to strings', async () => {
}); });
test('should NOT limit the length of parameter values', async () => { test('should NOT limit the length of parameter values', async () => {
const envName = 'default'; const envName = DEFAULT_ENV;
const featureName = randomId(); const featureName = randomId();
const projectPath = '/api/admin/projects/default'; const projectPath = '/api/admin/projects/default';
const featurePath = `${projectPath}/features/${featureName}`; const featurePath = `${projectPath}/features/${featureName}`;
@ -1027,7 +1027,7 @@ test('should NOT limit the length of parameter values', async () => {
}); });
test('Can NOT delete strategy with wrong projectId', async () => { test('Can NOT delete strategy with wrong projectId', async () => {
const envName = 'default'; const envName = DEFAULT_ENV;
const featureName = 'feature.strategy.delete.strat.error'; const featureName = 'feature.strategy.delete.strat.error';
const projectPath = '/api/admin/projects/default'; const projectPath = '/api/admin/projects/default';
@ -1059,7 +1059,7 @@ test('Can NOT delete strategy with wrong projectId', async () => {
}); });
test('add strategy cannot use wrong projectId', async () => { test('add strategy cannot use wrong projectId', async () => {
const envName = 'default'; const envName = DEFAULT_ENV;
const featureName = 'feature.strategy.add.strat.wrong.projectId'; const featureName = 'feature.strategy.add.strat.wrong.projectId';
// create feature flag // create feature flag
@ -1083,7 +1083,7 @@ test('add strategy cannot use wrong projectId', async () => {
}); });
test('update strategy on feature flag cannot use wrong projectId', async () => { test('update strategy on feature flag cannot use wrong projectId', async () => {
const envName = 'default'; const envName = DEFAULT_ENV;
const featureName = 'feature.strategy.update.strat.wrong.projectId'; const featureName = 'feature.strategy.update.strat.wrong.projectId';
const projectPath = '/api/admin/projects/default'; const projectPath = '/api/admin/projects/default';
@ -2040,7 +2040,7 @@ test('should clone feature flag WITH variants', async () => {
}); });
test('should clone feature flag without replacing groupId', async () => { test('should clone feature flag without replacing groupId', async () => {
const envName = 'default'; const envName = DEFAULT_ENV;
const featureName = 'feature.flag.base.4'; const featureName = 'feature.flag.base.4';
const cloneName = 'feature.flag.clone.4'; const cloneName = 'feature.flag.clone.4';
@ -2135,13 +2135,13 @@ test('Should not allow changing project to target project without the same enabl
); );
await db.stores.projectStore.addEnvironmentToProject( await db.stores.projectStore.addEnvironmentToProject(
targetProject, targetProject,
'default', DEFAULT_ENV,
); );
await app.createFeature(featureName, project); await app.createFeature(featureName, project);
await app.request await app.request
.post( .post(
`/api/admin/projects/${project}/features/${featureName}/environments/default/strategies`, `/api/admin/projects/${project}/features/${featureName}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -2163,7 +2163,7 @@ test('Should not allow changing project to target project without the same enabl
.expect(200); .expect(200);
await app.request await app.request
.post( .post(
`/api/admin/projects/${project}/features/${featureName}/environments/default/on`, `/api/admin/projects/${project}/features/${featureName}/environments/${DEFAULT_ENV}/on`,
) )
.send({}) .send({})
.expect(200); .expect(200);
@ -2215,14 +2215,14 @@ test('Should allow changing project to target project with the same enabled envi
await db.stores.projectStore.addEnvironmentToProject('default', inBoth); await db.stores.projectStore.addEnvironmentToProject('default', inBoth);
await db.stores.projectStore.addEnvironmentToProject( await db.stores.projectStore.addEnvironmentToProject(
targetProject, targetProject,
'default', DEFAULT_ENV,
); );
await db.stores.projectStore.addEnvironmentToProject(targetProject, inBoth); await db.stores.projectStore.addEnvironmentToProject(targetProject, inBoth);
await app.createFeature(featureName, project); await app.createFeature(featureName, project);
await app.request await app.request
.post( .post(
`/api/admin/projects/${project}/features/${featureName}/environments/default/strategies`, `/api/admin/projects/${project}/features/${featureName}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -2244,7 +2244,7 @@ test('Should allow changing project to target project with the same enabled envi
.expect(200); .expect(200);
await app.request await app.request
.post( .post(
`/api/admin/projects/${project}/features/${featureName}/environments/default/on`, `/api/admin/projects/${project}/features/${featureName}/environments/${DEFAULT_ENV}/on`,
) )
.send({}) .send({})
.expect(200); .expect(200);
@ -2461,7 +2461,7 @@ test('should handle strategy variants', async () => {
variants: [variant], variants: [variant],
}; };
const featureStrategiesPath = `/api/admin/projects/default/features/${feature.name}/environments/default/strategies`; const featureStrategiesPath = `/api/admin/projects/default/features/${feature.name}/environments/${DEFAULT_ENV}/strategies`;
await app.request await app.request
.post(featureStrategiesPath) .post(featureStrategiesPath)
@ -2513,7 +2513,7 @@ test('should reject invalid constraint values for multi-valued constraints', asy
constraints: [{ contextName: 'userId', operator: 'IN', values }], constraints: [{ contextName: 'userId', operator: 'IN', values }],
}); });
const featureStrategiesPath = `/api/admin/projects/${project.id}/features/${flag.name}/environments/default/strategies`; const featureStrategiesPath = `/api/admin/projects/${project.id}/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`;
await app.request await app.request
.post(featureStrategiesPath) .post(featureStrategiesPath)
@ -2578,7 +2578,7 @@ test('should add default constraint values for single-valued constraints', async
expect(res.body.constraints[0].values).toEqual(values); expect(res.body.constraints[0].values).toEqual(values);
}; };
const featureStrategiesPath = `/api/admin/projects/${project.id}/features/${flag.name}/environments/default/strategies`; const featureStrategiesPath = `/api/admin/projects/${project.id}/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`;
await app.request await app.request
.post(featureStrategiesPath) .post(featureStrategiesPath)
@ -2623,7 +2623,7 @@ test('should allow long parameter values', async () => {
await app.request await app.request
.post( .post(
`/api/admin/projects/${project.id}/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/${project.id}/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send(strategy) .send(strategy)
.expect(200); .expect(200);
@ -2640,7 +2640,7 @@ test('should change strategy sort order when payload is valid', async () => {
const { body: strategyOne } = await app.request const { body: strategyOne } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'default', name: 'default',
@ -2652,7 +2652,7 @@ test('should change strategy sort order when payload is valid', async () => {
const { body: strategyTwo } = await app.request const { body: strategyTwo } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -2663,7 +2663,7 @@ test('should change strategy sort order when payload is valid', async () => {
.expect(200); .expect(200);
const { body: strategies } = await app.request.get( const { body: strategies } = await app.request.get(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
); );
expect(strategies[0].sortOrder).toBe(0); expect(strategies[0].sortOrder).toBe(0);
@ -2673,7 +2673,7 @@ test('should change strategy sort order when payload is valid', async () => {
await app.request await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies/set-sort-order`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies/set-sort-order`,
) )
.send([ .send([
{ {
@ -2688,7 +2688,7 @@ test('should change strategy sort order when payload is valid', async () => {
.expect(200); .expect(200);
const { body: strategiesOrdered } = await app.request.get( const { body: strategiesOrdered } = await app.request.get(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
); );
expect(strategiesOrdered[0].sortOrder).toBe(1); expect(strategiesOrdered[0].sortOrder).toBe(1);
@ -2702,7 +2702,7 @@ test('should reject set sort order request when payload is invalid', async () =>
await app.request await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies/set-sort-order`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies/set-sort-order`,
) )
.send([ .send([
{ {
@ -2726,7 +2726,7 @@ test('should return strategies in correct order when new strategies are added',
const { body: strategyOne } = await app.request const { body: strategyOne } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'default', name: 'default',
@ -2738,7 +2738,7 @@ test('should return strategies in correct order when new strategies are added',
const { body: strategyTwo } = await app.request const { body: strategyTwo } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -2749,7 +2749,7 @@ test('should return strategies in correct order when new strategies are added',
.expect(200); .expect(200);
const { body: strategies } = await app.request.get( const { body: strategies } = await app.request.get(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
); );
expect(strategies[0].sortOrder).toBe(0); expect(strategies[0].sortOrder).toBe(0);
@ -2759,7 +2759,7 @@ test('should return strategies in correct order when new strategies are added',
await app.request await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies/set-sort-order`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies/set-sort-order`,
) )
.send([ .send([
{ {
@ -2775,7 +2775,7 @@ test('should return strategies in correct order when new strategies are added',
const { body: strategyThree } = await app.request const { body: strategyThree } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -2787,7 +2787,7 @@ test('should return strategies in correct order when new strategies are added',
const { body: strategyFour } = await app.request const { body: strategyFour } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -2798,7 +2798,7 @@ test('should return strategies in correct order when new strategies are added',
.expect(200); .expect(200);
const { body: strategiesOrdered } = await app.request.get( const { body: strategiesOrdered } = await app.request.get(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
); );
expect(strategiesOrdered[0].sortOrder).toBe(1); expect(strategiesOrdered[0].sortOrder).toBe(1);
@ -2810,7 +2810,7 @@ test('should return strategies in correct order when new strategies are added',
await app.request await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies/set-sort-order`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies/set-sort-order`,
) )
.send([ .send([
{ {
@ -2821,7 +2821,7 @@ test('should return strategies in correct order when new strategies are added',
.expect(200); .expect(200);
const { body: strategiesReOrdered } = await app.request.get( const { body: strategiesReOrdered } = await app.request.get(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
); );
// This block checks the order of the strategies retrieved from the endpoint. After partial update, the order should // This block checks the order of the strategies retrieved from the endpoint. After partial update, the order should
@ -2853,7 +2853,7 @@ test('should create a strategy with segments', async () => {
.get(`/api/admin/projects/default/features/${feature.name}`) .get(`/api/admin/projects/default/features/${feature.name}`)
.expect((res) => { .expect((res) => {
const defaultEnv = res.body.environments.find( const defaultEnv = res.body.environments.find(
(env) => env.name === 'default', (env) => env.name === DEFAULT_ENV,
); );
const strategy = defaultEnv.strategies.find( const strategy = defaultEnv.strategies.find(
(strat) => strat.id === strategyOne.id, (strat) => strat.id === strategyOne.id,
@ -2874,7 +2874,7 @@ test('should create a strategy with segments', async () => {
.get(`/api/admin/projects/default/features/${feature.name}`) .get(`/api/admin/projects/default/features/${feature.name}`)
.expect((res) => { .expect((res) => {
const defaultEnv = res.body.environments.find( const defaultEnv = res.body.environments.find(
(env) => env.name === 'default', (env) => env.name === DEFAULT_ENV,
); );
const strategy = defaultEnv.strategies.find( const strategy = defaultEnv.strategies.find(
(strat) => strat.id === strategyOne.id, (strat) => strat.id === strategyOne.id,
@ -2903,7 +2903,7 @@ test('should add multiple segments to a strategy', async () => {
.get(`/api/admin/projects/default/features/${feature.name}`) .get(`/api/admin/projects/default/features/${feature.name}`)
.expect((res) => { .expect((res) => {
const defaultEnv = res.body.environments.find( const defaultEnv = res.body.environments.find(
(env) => env.name === 'default', (env) => env.name === DEFAULT_ENV,
); );
const strategy = defaultEnv?.strategies.find( const strategy = defaultEnv?.strategies.find(
(strat) => strat.id === strategyOne.id, (strat) => strat.id === strategyOne.id,
@ -3075,7 +3075,7 @@ test('should return disabled strategies', async () => {
const { body: strategyOne } = await app.request const { body: strategyOne } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'default', name: 'default',
@ -3088,7 +3088,7 @@ test('should return disabled strategies', async () => {
const { body: strategyTwo } = await app.request const { body: strategyTwo } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -3099,7 +3099,7 @@ test('should return disabled strategies', async () => {
.expect(200); .expect(200);
const { body: strategies } = await app.request.get( const { body: strategies } = await app.request.get(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
); );
expect(strategies[0].id).toBe(strategyOne.id); expect(strategies[0].id).toBe(strategyOne.id);
@ -3119,7 +3119,7 @@ test('should disable strategies in place', async () => {
const { body: strategyOne } = await app.request const { body: strategyOne } = await app.request
.post( .post(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -3133,7 +3133,7 @@ test('should disable strategies in place', async () => {
.expect(200); .expect(200);
const { body: strategies } = await app.request.get( const { body: strategies } = await app.request.get(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
); );
expect(strategies[0].id).toBe(strategyOne.id); expect(strategies[0].id).toBe(strategyOne.id);
@ -3141,7 +3141,7 @@ test('should disable strategies in place', async () => {
const { body: updatedStrategyOne } = await app.request const { body: updatedStrategyOne } = await app.request
.put( .put(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies/${strategyOne.id}`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies/${strategyOne.id}`,
) )
.send({ .send({
name: 'flexibleRollout', name: 'flexibleRollout',
@ -3156,7 +3156,7 @@ test('should disable strategies in place', async () => {
.expect(200); .expect(200);
const { body: updatedStrategies } = await app.request.get( const { body: updatedStrategies } = await app.request.get(
`/api/admin/projects/default/features/${flag.name}/environments/default/strategies`, `/api/admin/projects/default/features/${flag.name}/environments/${DEFAULT_ENV}/strategies`,
); );
expect(updatedStrategies[0].id).toBe(updatedStrategyOne.id); expect(updatedStrategies[0].id).toBe(updatedStrategyOne.id);
@ -3530,7 +3530,7 @@ test('can get evaluation metrics', async () => {
name: 'metric-feature', name: 'metric-feature',
environments: [ environments: [
{ {
name: 'default', name: DEFAULT_ENV,
yes: 123, yes: 123,
no: 321, no: 321,
}, },

View File

@ -6,7 +6,7 @@ import dbInit, {
type ITestDb, type ITestDb,
} from '../../../test/e2e/helpers/database-init.js'; } from '../../../test/e2e/helpers/database-init.js';
import getLogger from '../../../test/fixtures/no-logger.js'; import getLogger from '../../../test/fixtures/no-logger.js';
import { randomId } from '../../util/index.js'; import { DEFAULT_ENV, randomId } from '../../util/index.js';
import { ApiTokenType } from '../../types/model.js'; import { ApiTokenType } from '../../types/model.js';
import { vi } from 'vitest'; import { vi } from 'vitest';
@ -58,7 +58,7 @@ test('multiple parallel calls to api/frontend should not create multiple instanc
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.FRONTEND, type: ApiTokenType.FRONTEND,
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: `test-token-${randomId()}`, tokenName: `test-token-${randomId()}`,
}); });
const address = app.server.address(); const address = app.server.address();

View File

@ -6,7 +6,7 @@ import dbInit, {
type ITestDb, type ITestDb,
} from '../../../test/e2e/helpers/database-init.js'; } from '../../../test/e2e/helpers/database-init.js';
import getLogger from '../../../test/fixtures/no-logger.js'; import getLogger from '../../../test/fixtures/no-logger.js';
import { randomId } from '../../util/index.js'; import { DEFAULT_ENV, randomId } from '../../util/index.js';
import { import {
ApiTokenType, ApiTokenType,
type IApiToken, type IApiToken,
@ -64,7 +64,7 @@ export const createApiToken = (
return app.services.apiTokenService.createApiTokenWithProjects({ return app.services.apiTokenService.createApiTokenWithProjects({
type, type,
projects: ['*'], projects: ['*'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: `${type}-token-${randomId()}`, tokenName: `${type}-token-${randomId()}`,
...overrides, ...overrides,
}); });
@ -73,7 +73,7 @@ export const createApiToken = (
const createFeatureToggle = async ({ const createFeatureToggle = async ({
name, name,
project = 'default', project = 'default',
environment = 'default', environment = DEFAULT_ENV,
strategies, strategies,
enabled, enabled,
}: { }: {
@ -233,13 +233,13 @@ test('should allow requests with an admin token', async () => {
environment: '*', environment: '*',
}); });
await frontendApiService.refreshData(); await frontendApiService.refreshData();
await app.request const { body } = await app.request
.get('/api/frontend') .get('/api/frontend')
.set('Authorization', adminToken.secret) .set('Authorization', adminToken.secret)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200);
.expect((res) => expect(res.body.toggles).toHaveLength(1)) expect(body.toggles).toHaveLength(1);
.expect((res) => expect(res.body.toggles[0].name).toEqual(featureA)); expect(body.toggles[0].name).toEqual(featureA);
}); });
test('should not allow admin requests with a frontend token', async () => { test('should not allow admin requests with a frontend token', async () => {
@ -341,7 +341,7 @@ test('should accept client registration requests', async () => {
appName: randomId(), appName: randomId(),
instanceId: randomId(), instanceId: randomId(),
sdkVersion: randomId(), sdkVersion: randomId(),
environment: 'default', environment: DEFAULT_ENV,
interval: 10000, interval: 10000,
started: new Date(), started: new Date(),
strategies: ['default'], strategies: ['default'],
@ -419,7 +419,7 @@ test('should store frontend api client metrics', async () => {
featureName, featureName,
lastHourUsage: [ lastHourUsage: [
{ {
environment: 'default', environment: DEFAULT_ENV,
timestamp: startOfHour(now).toISOString(), timestamp: startOfHour(now).toISOString(),
yes: 3, yes: 3,
no: 30, no: 30,
@ -1174,7 +1174,7 @@ test('should return 204 if metrics are disabled', async () => {
await localApp.services.apiTokenService.createApiTokenWithProjects({ await localApp.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.FRONTEND, type: ApiTokenType.FRONTEND,
projects: ['*'], projects: ['*'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: `disabledMetric-token-${randomId()}`, tokenName: `disabledMetric-token-${randomId()}`,
}); });

View File

@ -141,7 +141,7 @@ test('Can read initial features', async () => {
const defaultProjectFeatures = cache.getToggles({ const defaultProjectFeatures = cache.getToggles({
environment: '*', environment: '*',
projects: ['*'], projects: ['default'],
} as IApiUser); } as IApiUser);
expect(defaultProjectFeatures.length).toBe(0); expect(defaultProjectFeatures.length).toBe(0);

View File

@ -11,7 +11,7 @@ import {
mapFeatureForClient, mapFeatureForClient,
mapSegmentsForClient, mapSegmentsForClient,
} from '../playground/offline-unleash-client.js'; } from '../playground/offline-unleash-client.js';
import { ALL_ENVS } from '../../util/constants.js'; import { ALL_ENVS, DEFAULT_ENV } from '../../util/constants.js';
import type { Logger } from '../../logger.js'; import type { Logger } from '../../logger.js';
import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service.js'; import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service.js';
import type { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type.js'; import type { IClientFeatureToggleReadModel } from './client-feature-toggle-read-model-type.js';
@ -141,7 +141,7 @@ export class GlobalFrontendApiCache extends EventEmitter {
private environmentNameForToken(token: IApiUser): string { private environmentNameForToken(token: IApiUser): string {
if (token.environment === ALL_ENVS) { if (token.environment === ALL_ENVS) {
return 'default'; return DEFAULT_ENV;
} }
return token.environment; return token.environment;
} }

View File

@ -13,6 +13,7 @@ import type {
} from '../../types/index.js'; } from '../../types/index.js';
import { createFakeGetLicensedUsers } from './getLicensedUsers.js'; import { createFakeGetLicensedUsers } from './getLicensedUsers.js';
import { vi } from 'vitest'; import { vi } from 'vitest';
import { DEFAULT_ENV } from '../../server-impl.js';
let instanceStatsService: InstanceStatsService; let instanceStatsService: InstanceStatsService;
let versionService: VersionService; let versionService: VersionService;
@ -146,7 +147,7 @@ describe.each([true, false])(
).mockReturnValue( ).mockReturnValue(
Promise.resolve({ Promise.resolve({
feature: 'x', feature: 'x',
environment: 'default', environment: DEFAULT_ENV,
count: 3, count: 3,
}), }),
); );

View File

@ -6,6 +6,7 @@ import {
setupAppWithCustomConfig, setupAppWithCustomConfig,
} from '../../../../test/e2e/helpers/test-helper.js'; } from '../../../../test/e2e/helpers/test-helper.js';
import getLogger from '../../../../test/fixtures/no-logger.js'; import getLogger from '../../../../test/fixtures/no-logger.js';
import { DEFAULT_ENV } from '../../../server-impl.js';
import type { IClientMetricsEnv } from './client-metrics-store-v2-type.js'; import type { IClientMetricsEnv } from './client-metrics-store-v2-type.js';
import { subHours } from 'date-fns'; import { subHours } from 'date-fns';
@ -55,7 +56,7 @@ test('should return raw metrics, aggregated on key', async () => {
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 2, yes: 2,
no: 2, no: 2,
@ -63,7 +64,7 @@ test('should return raw metrics, aggregated on key', async () => {
{ {
featureName: 't2', featureName: 't2',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 5, yes: 5,
no: 5, no: 5,
@ -71,7 +72,7 @@ test('should return raw metrics, aggregated on key', async () => {
{ {
featureName: 't2', featureName: 't2',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 2, yes: 2,
no: 99, no: 99,
@ -79,7 +80,7 @@ test('should return raw metrics, aggregated on key', async () => {
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 3, yes: 3,
no: 2, no: 2,
@ -106,7 +107,7 @@ test('should return raw metrics, aggregated on key', async () => {
.expect(200); .expect(200);
expect(demo.data).toHaveLength(48); expect(demo.data).toHaveLength(48);
expect(demo.data[46].environment).toBe('default'); expect(demo.data[46].environment).toBe(DEFAULT_ENV);
expect(demo.data[46].yes).toBe(5); expect(demo.data[46].yes).toBe(5);
expect(demo.data[46].no).toBe(4); expect(demo.data[46].no).toBe(4);
expect(demo.data[47].environment).toBe('test'); expect(demo.data[47].environment).toBe('test');
@ -114,7 +115,7 @@ test('should return raw metrics, aggregated on key', async () => {
expect(demo.data[47].no).toBe(3); expect(demo.data[47].no).toBe(3);
expect(t2.data).toHaveLength(24); expect(t2.data).toHaveLength(24);
expect(t2.data[23].environment).toBe('default'); expect(t2.data[23].environment).toBe(DEFAULT_ENV);
expect(t2.data[23].yes).toBe(7); expect(t2.data[23].yes).toBe(7);
expect(t2.data[23].no).toBe(104); expect(t2.data[23].no).toBe(104);
}); });
@ -125,7 +126,7 @@ test('should support the hoursBack query param for raw metrics', async () => {
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 1, yes: 1,
no: 1, no: 1,
@ -133,7 +134,7 @@ test('should support the hoursBack query param for raw metrics', async () => {
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: subHours(date, 12), timestamp: subHours(date, 12),
yes: 2, yes: 2,
no: 2, no: 2,
@ -141,7 +142,7 @@ test('should support the hoursBack query param for raw metrics', async () => {
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: subHours(date, 32), timestamp: subHours(date, 32),
yes: 3, yes: 3,
no: 3, no: 3,
@ -172,7 +173,7 @@ test('should return toggle summary', async () => {
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 2, yes: 2,
no: 2, no: 2,
@ -180,7 +181,7 @@ test('should return toggle summary', async () => {
{ {
featureName: 't2', featureName: 't2',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 5, yes: 5,
no: 5, no: 5,
@ -188,7 +189,7 @@ test('should return toggle summary', async () => {
{ {
featureName: 't2', featureName: 't2',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 2, yes: 2,
no: 99, no: 99,
@ -196,7 +197,7 @@ test('should return toggle summary', async () => {
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 3, yes: 3,
no: 2, no: 2,
@ -228,7 +229,7 @@ test('should return toggle summary', async () => {
const test = demo.lastHourUsage.find((u) => u.environment === 'test'); const test = demo.lastHourUsage.find((u) => u.environment === 'test');
const defaultEnv = demo.lastHourUsage.find( const defaultEnv = demo.lastHourUsage.find(
(u) => u.environment === 'default', (u) => u.environment === DEFAULT_ENV,
); );
expect(demo.featureName).toBe('demo'); expect(demo.featureName).toBe('demo');
@ -236,7 +237,7 @@ test('should return toggle summary', async () => {
expect(test.environment).toBe('test'); expect(test.environment).toBe('test');
expect(test.yes).toBe(2); expect(test.yes).toBe(2);
expect(test.no).toBe(6); expect(test.no).toBe(6);
expect(defaultEnv.environment).toBe('default'); expect(defaultEnv.environment).toBe(DEFAULT_ENV);
expect(defaultEnv.yes).toBe(5); expect(defaultEnv.yes).toBe(5);
expect(defaultEnv.no).toBe(4); expect(defaultEnv.no).toBe(4);
expect(demo.seenApplications).toStrictEqual(['backend-api', 'web']); expect(demo.seenApplications).toStrictEqual(['backend-api', 'web']);
@ -249,7 +250,7 @@ test('should only include last hour of metrics return toggle summary', async ()
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: now, timestamp: now,
yes: 2, yes: 2,
no: 2, no: 2,
@ -257,7 +258,7 @@ test('should only include last hour of metrics return toggle summary', async ()
{ {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: now, timestamp: now,
yes: 3, yes: 3,
no: 2, no: 2,
@ -297,12 +298,12 @@ test('should only include last hour of metrics return toggle summary', async ()
const test = demo.lastHourUsage.find((u) => u.environment === 'test'); const test = demo.lastHourUsage.find((u) => u.environment === 'test');
const defaultEnv = demo.lastHourUsage.find( const defaultEnv = demo.lastHourUsage.find(
(u) => u.environment === 'default', (u) => u.environment === DEFAULT_ENV,
); );
expect(demo.featureName).toBe('demo'); expect(demo.featureName).toBe('demo');
expect(demo.lastHourUsage).toHaveLength(2); expect(demo.lastHourUsage).toHaveLength(2);
expect(defaultEnv.environment).toBe('default'); expect(defaultEnv.environment).toBe(DEFAULT_ENV);
expect(defaultEnv.yes).toBe(5); expect(defaultEnv.yes).toBe(5);
expect(defaultEnv.no).toBe(4); expect(defaultEnv.no).toBe(4);
expect(test.environment).toBe('test'); expect(test.environment).toBe('test');
@ -316,7 +317,7 @@ test('should support posting and receiving variants data', async () => {
const metric = { const metric = {
featureName: 'demo', featureName: 'demo',
appName: 'web', appName: 'web',
environment: 'default', environment: DEFAULT_ENV,
timestamp: date, timestamp: date,
yes: 7, yes: 7,
no: 1, no: 1,

View File

@ -19,6 +19,7 @@ import { startOfHour } from 'date-fns';
import { ApiTokenType } from '../../../types/model.js'; import { ApiTokenType } from '../../../types/model.js';
import type TestAgent from 'supertest/lib/agent.d.ts'; import type TestAgent from 'supertest/lib/agent.d.ts';
import type { BulkRegistrationSchema } from '../../../openapi/index.js'; import type { BulkRegistrationSchema } from '../../../openapi/index.js';
import { DEFAULT_ENV } from '../../../server-impl.js';
let db: ITestDb; let db: ITestDb;
let config: IUnleashConfig; let config: IUnleashConfig;
@ -427,7 +428,7 @@ describe('bulk metrics', () => {
{ {
featureName: 'test_feature_one', featureName: 'test_feature_one',
appName: 'test_application', appName: 'test_application',
environment: 'default', environment: DEFAULT_ENV,
timestamp: startOfHour(now), timestamp: startOfHour(now),
yes: 1000, yes: 1000,
no: 800, no: 800,

View File

@ -6,6 +6,7 @@ import {
setupAppWithCustomConfig, setupAppWithCustomConfig,
} from '../../../../../test/e2e/helpers/test-helper.js'; } from '../../../../../test/e2e/helpers/test-helper.js';
import getLogger from '../../../../../test/fixtures/no-logger.js'; import getLogger from '../../../../../test/fixtures/no-logger.js';
import { DEFAULT_ENV } from '../../../../server-impl.js';
import { TEST_AUDIT_USER } from '../../../../types/index.js'; import { TEST_AUDIT_USER } from '../../../../types/index.js';
let app: IUnleashTest; let app: IUnleashTest;
@ -54,7 +55,7 @@ test('should clean unknown feature flag names from last seen store', async () =>
const inserts = [...clean, ...dirty].map((feature) => { const inserts = [...clean, ...dirty].map((feature) => {
return { return {
featureName: feature, featureName: feature,
environment: 'default', environment: DEFAULT_ENV,
yes: 1, yes: 1,
no: 0, no: 0,
appName: 'test', appName: 'test',
@ -90,8 +91,8 @@ test('should clean unknown feature flag environments from last seen store', asyn
const { lastSeenService, featureToggleService } = app.services; const { lastSeenService, featureToggleService } = app.services;
const clean = [ const clean = [
{ name: 'clean5', environment: 'default' }, { name: 'clean5', environment: DEFAULT_ENV },
{ name: 'clean6', environment: 'default' }, { name: 'clean6', environment: DEFAULT_ENV },
{ name: 'clean7', environment: 'nonexisting' }, { name: 'clean7', environment: 'nonexisting' },
{ name: 'clean8', environment: 'nonexisting' }, { name: 'clean8', environment: 'nonexisting' },
]; ];
@ -138,9 +139,9 @@ test('should not fail with feature names longer than 255 chars', async () => {
const { lastSeenService } = app.services; const { lastSeenService } = app.services;
const longFeatureNames = [ const longFeatureNames = [
{ name: 'a'.repeat(254), environment: 'default' }, { name: 'a'.repeat(254), environment: DEFAULT_ENV },
{ name: 'b'.repeat(255), environment: 'default' }, { name: 'b'.repeat(255), environment: DEFAULT_ENV },
{ name: 'c'.repeat(256), environment: 'default' }, // this one should be filtered out { name: 'c'.repeat(256), environment: DEFAULT_ENV }, // this one should be filtered out
]; ];
const inserts = [...longFeatureNames].map((feature) => { const inserts = [...longFeatureNames].map((feature) => {

View File

@ -6,6 +6,7 @@ import type { IFeatureToggleStore } from '../../feature-toggle/types/feature-tog
import getLogger from '../../../../test/fixtures/no-logger.js'; import getLogger from '../../../../test/fixtures/no-logger.js';
import type { IFeatureStrategiesStore } from '../../feature-toggle/types/feature-toggle-strategies-store-type.js'; import type { IFeatureStrategiesStore } from '../../feature-toggle/types/feature-toggle-strategies-store-type.js';
import type { IFeatureStrategy } from '../../../types/index.js'; import type { IFeatureStrategy } from '../../../types/index.js';
import { DEFAULT_ENV } from '../../../server-impl.js';
let db: ITestDb; let db: ITestDb;
let largestResourcesReadModel: ILargestResourcesReadModel; let largestResourcesReadModel: ILargestResourcesReadModel;
@ -41,7 +42,7 @@ const createFeature = async (config: FeatureConfig) => {
await featureStrategiesStore.createStrategyFeatureEnv({ await featureStrategiesStore.createStrategyFeatureEnv({
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
featureName: config.featureName, featureName: config.featureName,
constraints: config.constraints, constraints: config.constraints,
parameters: config.parameters, parameters: config.parameters,

View File

@ -15,6 +15,7 @@ import {
setupAppWithCustomConfig, setupAppWithCustomConfig,
} from '../../../test/e2e/helpers/test-helper.js'; } from '../../../test/e2e/helpers/test-helper.js';
import { ApiTokenType } from '../../types/model.js'; import { ApiTokenType } from '../../types/model.js';
import { DEFAULT_ENV } from '../../server-impl.js';
let db: ITestDb; let db: ITestDb;
let onboardingReadModel: IOnboardingReadModel; let onboardingReadModel: IOnboardingReadModel;
@ -167,7 +168,7 @@ test('can get project onboarding status', async () => {
await lastSeenStore.setLastSeen([ await lastSeenStore.setLastSeen([
{ {
environment: 'default', environment: DEFAULT_ENV,
featureName: 'my-flag', featureName: 'my-flag',
}, },
]); ]);
@ -188,7 +189,7 @@ test('archived feature counts as onboarded', async () => {
await lastSeenStore.setLastSeen([ await lastSeenStore.setLastSeen([
{ {
environment: 'default', environment: DEFAULT_ENV,
featureName: 'my-flag', featureName: 'my-flag',
}, },
]); ]);
@ -213,7 +214,7 @@ test('sdk register also onboards a project', async () => {
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: 'tester', tokenName: 'tester',
}); });

View File

@ -7,6 +7,7 @@ import dbInit, {
} from '../../../test/e2e/helpers/database-init.js'; } from '../../../test/e2e/helpers/database-init.js';
import getLogger from '../../../test/fixtures/no-logger.js'; import getLogger from '../../../test/fixtures/no-logger.js';
import type { AdvancedPlaygroundResponseSchema } from '../../openapi/index.js'; import type { AdvancedPlaygroundResponseSchema } from '../../openapi/index.js';
import { DEFAULT_ENV } from '../../server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -50,7 +51,7 @@ const createFeatureToggleWithStrategy = async (
await createFeatureToggle(featureName); await createFeatureToggle(featureName);
return app.request return app.request
.post( .post(
`/api/admin/projects/default/features/${featureName}/environments/default/strategies`, `/api/admin/projects/default/features/${featureName}/environments/${DEFAULT_ENV}/strategies`,
) )
.send(strategy) .send(strategy)
.expect(200); .expect(200);
@ -59,14 +60,14 @@ const createFeatureToggleWithStrategy = async (
const enableToggle = (featureName: string) => const enableToggle = (featureName: string) =>
app.request app.request
.post( .post(
`/api/admin/projects/default/features/${featureName}/environments/default/on`, `/api/admin/projects/default/features/${featureName}/environments/${DEFAULT_ENV}/on`,
) )
.send({}) .send({})
.expect(200); .expect(200);
const disableToggle = (featureName: string) => const disableToggle = (featureName: string) =>
app.request app.request
.post( .post(
`/api/admin/projects/default/features/${featureName}/environments/default/off`, `/api/admin/projects/default/features/${featureName}/environments/${DEFAULT_ENV}/off`,
) )
.send({}) .send({})
.expect(200); .expect(200);
@ -85,7 +86,7 @@ test('advanced playground evaluation with no toggles', async () => {
const { body: result } = await app.request const { body: result } = await app.request
.post('/api/admin/playground/advanced') .post('/api/admin/playground/advanced')
.send({ .send({
environments: ['default'], environments: [DEFAULT_ENV],
projects: ['default'], projects: ['default'],
context: { appName: 'test', userId: '1,2', channel: 'web,mobile' }, context: { appName: 'test', userId: '1,2', channel: 'web,mobile' },
}) })
@ -94,7 +95,7 @@ test('advanced playground evaluation with no toggles', async () => {
expect(result).toMatchObject({ expect(result).toMatchObject({
input: { input: {
environments: ['default'], environments: [DEFAULT_ENV],
projects: ['default'], projects: ['default'],
context: { context: {
appName: 'test', appName: 'test',
@ -117,15 +118,15 @@ test('advanced playground evaluation with unsatisfied parent dependency', async
const { body: result } = await app.request const { body: result } = await app.request
.post('/api/admin/playground/advanced') .post('/api/admin/playground/advanced')
.send({ .send({
environments: ['default'], environments: [DEFAULT_ENV],
projects: ['default'], projects: ['default'],
context: { appName: 'test' }, context: { appName: 'test' },
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200); .expect(200);
const child = result.features[0].environments.default[0]; const child = result.features[0].environments[DEFAULT_ENV][0];
const parent = result.features[1].environments.default[0]; const parent = result.features[1].environments[DEFAULT_ENV][0];
// child is disabled because of the parent // child is disabled because of the parent
expect(child.hasUnsatisfiedDependency).toBe(true); expect(child.hasUnsatisfiedDependency).toBe(true);
expect(child.isEnabled).toBe(false); expect(child.isEnabled).toBe(false);
@ -154,15 +155,15 @@ test('advanced playground evaluation with satisfied disabled parent dependency',
const { body: result } = await app.request const { body: result } = await app.request
.post('/api/admin/playground/advanced') .post('/api/admin/playground/advanced')
.send({ .send({
environments: ['default'], environments: [DEFAULT_ENV],
projects: ['default'], projects: ['default'],
context: { appName: 'test' }, context: { appName: 'test' },
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(200); .expect(200);
const child = result.features[0].environments.default[0]; const child = result.features[0].environments[DEFAULT_ENV][0];
const parent = result.features[1].environments.default[0]; const parent = result.features[1].environments[DEFAULT_ENV][0];
expect(child.hasUnsatisfiedDependency).toBe(false); expect(child.hasUnsatisfiedDependency).toBe(false);
expect(child.isEnabled).toBe(true); expect(child.isEnabled).toBe(true);
@ -177,7 +178,7 @@ test('advanced playground evaluation happy path', async () => {
const { body: result } = await app.request const { body: result } = await app.request
.post('/api/admin/playground/advanced') .post('/api/admin/playground/advanced')
.send({ .send({
environments: ['default'], environments: [DEFAULT_ENV],
projects: ['default'], projects: ['default'],
context: { appName: 'test', userId: '1,2', channel: 'web,mobile' }, context: { appName: 'test', userId: '1,2', channel: 'web,mobile' },
}) })
@ -186,7 +187,7 @@ test('advanced playground evaluation happy path', async () => {
expect(result).toMatchObject({ expect(result).toMatchObject({
input: { input: {
environments: ['default'], environments: [DEFAULT_ENV],
projects: ['default'], projects: ['default'],
context: { context: {
appName: 'test', appName: 'test',
@ -199,7 +200,7 @@ test('advanced playground evaluation happy path', async () => {
name: 'test-playground-feature', name: 'test-playground-feature',
projectId: 'default', projectId: 'default',
environments: { environments: {
default: [ [DEFAULT_ENV]: [
{ {
isEnabled: true, isEnabled: true,
isEnabledInCurrentEnvironment: true, isEnabledInCurrentEnvironment: true,
@ -226,7 +227,7 @@ test('advanced playground evaluation happy path', async () => {
enabled: false, enabled: false,
}, },
name: 'test-playground-feature', name: 'test-playground-feature',
environment: 'default', environment: DEFAULT_ENV,
context: { context: {
appName: 'test', appName: 'test',
userId: '1', userId: '1',
@ -260,7 +261,7 @@ test('advanced playground evaluation happy path', async () => {
enabled: false, enabled: false,
}, },
name: 'test-playground-feature', name: 'test-playground-feature',
environment: 'default', environment: DEFAULT_ENV,
context: { context: {
appName: 'test', appName: 'test',
userId: '1', userId: '1',
@ -294,7 +295,7 @@ test('advanced playground evaluation happy path', async () => {
enabled: false, enabled: false,
}, },
name: 'test-playground-feature', name: 'test-playground-feature',
environment: 'default', environment: DEFAULT_ENV,
context: { context: {
appName: 'test', appName: 'test',
userId: '2', userId: '2',
@ -328,7 +329,7 @@ test('advanced playground evaluation happy path', async () => {
enabled: false, enabled: false,
}, },
name: 'test-playground-feature', name: 'test-playground-feature',
environment: 'default', environment: DEFAULT_ENV,
context: { context: {
appName: 'test', appName: 'test',
userId: '2', userId: '2',
@ -373,7 +374,7 @@ test('show matching variant from variants selection only for enabled toggles', a
const { body: result } = await app.request const { body: result } = await app.request
.post('/api/admin/playground/advanced') .post('/api/admin/playground/advanced')
.send({ .send({
environments: ['default'], environments: [DEFAULT_ENV],
projects: ['default'], projects: ['default'],
context: { appName: 'playground', someProperty: '1,2,3,4,5' }, // generate 5 combinations context: { appName: 'playground', someProperty: '1,2,3,4,5' }, // generate 5 combinations
}) })
@ -381,13 +382,12 @@ test('show matching variant from variants selection only for enabled toggles', a
.expect(200); .expect(200);
const typedResult: AdvancedPlaygroundResponseSchema = result; const typedResult: AdvancedPlaygroundResponseSchema = result;
const enabledFeatures = typedResult.features[0].environments.default.filter( const enabledFeatures = typedResult.features[0].environments[
(item) => item.isEnabled, DEFAULT_ENV
); ].filter((item) => item.isEnabled);
const disabledFeatures = const disabledFeatures = typedResult.features[0].environments[
typedResult.features[0].environments.default.filter( DEFAULT_ENV
(item) => !item.isEnabled, ].filter((item) => !item.isEnabled);
);
enabledFeatures.forEach((feature) => { enabledFeatures.forEach((feature) => {
expect(feature.variant?.name).toBe('a'); expect(feature.variant?.name).toBe('a');
@ -417,7 +417,7 @@ test('should return disabled strategies with unevaluated result', async () => {
const { body: result } = await app.request const { body: result } = await app.request
.post('/api/admin/playground/advanced') .post('/api/admin/playground/advanced')
.send({ .send({
environments: ['default'], environments: [DEFAULT_ENV],
projects: ['default'], projects: ['default'],
context: { appName: 'playground' }, context: { appName: 'playground' },
}) })
@ -432,7 +432,7 @@ test('should return disabled strategies with unevaluated result', async () => {
); );
expect( expect(
feature?.environments.default[0].strategies.data[0].result feature?.environments[DEFAULT_ENV][0].strategies.data[0].result
.evaluationStatus, .evaluationStatus,
).toBe('unevaluated'); ).toBe('unevaluated');
}); });

View File

@ -10,6 +10,7 @@ import {
} from 'unleash-client'; } from 'unleash-client';
import { once } from 'events'; import { once } from 'events';
import { playgroundStrategyEvaluation } from '../../openapi/spec/playground-strategy-schema.js'; import { playgroundStrategyEvaluation } from '../../openapi/spec/playground-strategy-schema.js';
import { DEFAULT_ENV } from '../../server-impl.js';
export const offlineUnleashClientNode = async ({ export const offlineUnleashClientNode = async ({
features, features,
@ -54,7 +55,7 @@ describe('offline client', () => {
stale: false, stale: false,
}, },
], ],
context: { appName: 'other-app', environment: 'default' }, context: { appName: 'other-app', environment: DEFAULT_ENV },
logError: console.log, logError: console.log,
}); });
@ -108,7 +109,7 @@ describe('offline client', () => {
stale: false, stale: false,
}, },
], ],
context: { appName, environment: 'default' }, context: { appName, environment: DEFAULT_ENV },
logError: console.log, logError: console.log,
}); });

View File

@ -13,6 +13,7 @@ import NameExistsError from '../../error/name-exists-error.js';
import type { EventService } from '../../services/index.js'; import type { EventService } from '../../services/index.js';
import { createEventsService } from '../events/createEventsService.js'; import { createEventsService } from '../events/createEventsService.js';
import { test, beforeAll, afterAll, expect } from 'vitest'; import { test, beforeAll, afterAll, expect } from 'vitest';
import { DEFAULT_ENV } from '../../server-impl.js';
let stores: IUnleashStores; let stores: IUnleashStores;
let db: ITestDb; let db: ITestDb;
let service: EnvironmentService; let service: EnvironmentService;
@ -76,7 +77,7 @@ test('Can manage required approvals', async () => {
const changeRequestEnvs = const changeRequestEnvs =
await db.stores.environmentStore.getChangeRequestEnvironments([ await db.stores.environmentStore.getChangeRequestEnvironments([
'approval_env', 'approval_env',
'default', DEFAULT_ENV,
'other', 'other',
]); ]);
@ -345,7 +346,7 @@ test('When given overrides should remap projects to override environments', asyn
}); });
test('Override works correctly when enabling default and disabling prod and dev', async () => { test('Override works correctly when enabling default and disabling prod and dev', async () => {
const defaultEnvironment = 'default'; const defaultEnvironment = DEFAULT_ENV;
const prodEnvironment = 'production'; const prodEnvironment = 'production';
const devEnvironment = 'development'; const devEnvironment = 'development';

View File

@ -65,7 +65,7 @@ test('Should add environment to project', async () => {
const environment = envs.find((env) => env.environment === 'test'); const environment = envs.find((env) => env.environment === 'test');
expect(environment).toBeDefined(); expect(environment).toBeDefined();
expect(envs).toHaveLength(2); expect(envs).toHaveLength(2); // test + default
}); });
test('Should validate environment', async () => { test('Should validate environment', async () => {
@ -113,7 +113,7 @@ test('Should add default strategy to environment', async () => {
await app.request await app.request
.post( .post(
`/api/admin/projects/default/environments/default/default-strategy`, `/api/admin/projects/default/environments/${DEFAULT_ENV}/default-strategy`,
) )
.send(defaultStrategy) .send(defaultStrategy)
.expect(200); .expect(200);
@ -123,14 +123,14 @@ test('Should add default strategy to environment', async () => {
expect(envs).toHaveLength(1); expect(envs).toHaveLength(1);
expect(envs[0]).toStrictEqual({ expect(envs[0]).toStrictEqual({
environment: 'default', environment: DEFAULT_ENV,
defaultStrategy, defaultStrategy,
}); });
const { body } = await app.getRecordedEvents(); const { body } = await app.getRecordedEvents();
expect(body.events[0]).toMatchObject({ expect(body.events[0]).toMatchObject({
type: 'default-strategy-updated', type: 'default-strategy-updated',
project: 'default', project: 'default',
environment: 'default', environment: DEFAULT_ENV,
data: defaultStrategy, data: defaultStrategy,
preData: null, preData: null,
}); });
@ -139,7 +139,7 @@ test('Should add default strategy to environment', async () => {
test('Should throw an error if you try to set defaultStrategy other than flexibleRollout', async () => { test('Should throw an error if you try to set defaultStrategy other than flexibleRollout', async () => {
await app.request await app.request
.post( .post(
`/api/admin/projects/default/environments/default/default-strategy`, `/api/admin/projects/default/environments/${DEFAULT_ENV}/default-strategy`,
) )
.send({ .send({
name: 'default', name: 'default',
@ -153,7 +153,7 @@ test('Add environment to project should return 404 when given a projectid that d
await app.request await app.request
.post(`/api/admin/projects/unknown/environments`) .post(`/api/admin/projects/unknown/environments`)
.send({ .send({
environment: 'default', environment: DEFAULT_ENV,
}) })
.expect(404); .expect(404);
}); });

View File

@ -116,7 +116,7 @@ test('should return average time to production per toggle', async () => {
enabled: true, enabled: true,
project: project.id, project: project.id,
featureName: toggle.name, featureName: toggle.name,
environment: 'default', environment: 'production',
auditUser: TEST_AUDIT_USER, auditUser: TEST_AUDIT_USER,
}), }),
); );
@ -202,7 +202,7 @@ test('should return average time to production per toggle for a specific project
enabled: true, enabled: true,
project: project1.id, project: project1.id,
featureName: toggle.name, featureName: toggle.name,
environment: 'default', environment: 'production',
auditUser: TEST_AUDIT_USER, auditUser: TEST_AUDIT_USER,
}), }),
); );
@ -216,7 +216,7 @@ test('should return average time to production per toggle for a specific project
enabled: true, enabled: true,
project: project2.id, project: project2.id,
featureName: toggle.name, featureName: toggle.name,
environment: 'default', environment: 'production',
auditUser: TEST_AUDIT_USER, auditUser: TEST_AUDIT_USER,
}), }),
); );
@ -287,7 +287,7 @@ test('should return average time to production per toggle and include archived t
enabled: true, enabled: true,
project: project1.id, project: project1.id,
featureName: toggle.name, featureName: toggle.name,
environment: 'default', environment: 'production',
auditUser: TEST_AUDIT_USER, auditUser: TEST_AUDIT_USER,
}), }),
); );

View File

@ -15,7 +15,7 @@ import {
import type { EventService } from '../../services/index.js'; import type { EventService } from '../../services/index.js';
import { createEventsService } from '../events/createEventsService.js'; import { createEventsService } from '../events/createEventsService.js';
import { createTestConfig } from '../../../test/config/test-config.js'; import { createTestConfig } from '../../../test/config/test-config.js';
import { randomId } from '../../util/index.js'; import { DEFAULT_ENV, randomId } from '../../util/index.js';
import { ApiTokenType } from '../../types/model.js'; import { ApiTokenType } from '../../types/model.js';
import { FEATURE_CREATED } from '../../events/index.js'; import { FEATURE_CREATED } from '../../events/index.js';
@ -160,7 +160,7 @@ test('project resources should contain the right data', async () => {
tokenName: 'test-token', tokenName: 'test-token',
projects: ['default'], projects: ['default'],
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
environment: 'default', environment: DEFAULT_ENV,
}); });
await app.services.segmentService.create( await app.services.segmentService.create(

View File

@ -6,6 +6,7 @@ import {
setupAppWithCustomConfig, setupAppWithCustomConfig,
} from '../../../test/e2e/helpers/test-helper.js'; } from '../../../test/e2e/helpers/test-helper.js';
import getLogger from '../../../test/fixtures/no-logger.js'; import getLogger from '../../../test/fixtures/no-logger.js';
import { DEFAULT_ENV } from '../../server-impl.js';
import { ApiTokenType, type IApiToken } from '../../types/model.js'; import { ApiTokenType, type IApiToken } from '../../types/model.js';
@ -49,7 +50,7 @@ beforeAll(async () => {
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: 'tester', tokenName: 'tester',
}); });
}); });
@ -94,7 +95,7 @@ test('should return applications', async () => {
expect(body).toMatchObject({ expect(body).toMatchObject({
applications: [ applications: [
{ {
environments: ['default'], environments: [DEFAULT_ENV],
instances: ['instanceId'], instances: ['instanceId'],
name: 'appName', name: 'appName',
sdks: [ sdks: [
@ -136,7 +137,7 @@ test('should return applications if sdk was not in database', async () => {
expect(body).toMatchObject({ expect(body).toMatchObject({
applications: [ applications: [
{ {
environments: ['default'], environments: [DEFAULT_ENV],
instances: ['instanceId'], instances: ['instanceId'],
name: 'appName', name: 'appName',
sdks: [], sdks: [],
@ -174,7 +175,7 @@ test('should return application without version if sdk has just name', async ()
expect(body).toMatchObject({ expect(body).toMatchObject({
applications: [ applications: [
{ {
environments: ['default'], environments: [DEFAULT_ENV],
instances: ['instanceId'], instances: ['instanceId'],
name: 'appName', name: 'appName',
sdks: [ sdks: [
@ -235,7 +236,7 @@ test('should sort by appName descending', async () => {
expect(body).toMatchObject({ expect(body).toMatchObject({
applications: [ applications: [
{ {
environments: ['default'], environments: [DEFAULT_ENV],
instances: ['instanceId'], instances: ['instanceId'],
name: 'second-app', name: 'second-app',
sdks: [ sdks: [
@ -246,7 +247,7 @@ test('should sort by appName descending', async () => {
], ],
}, },
{ {
environments: ['default'], environments: [DEFAULT_ENV],
instances: ['instanceId'], instances: ['instanceId'],
name: 'appName', name: 'appName',
sdks: [ sdks: [
@ -307,7 +308,7 @@ test('should filter by sdk', async () => {
expect(body).toMatchObject({ expect(body).toMatchObject({
applications: [ applications: [
{ {
environments: ['default'], environments: [DEFAULT_ENV],
instances: ['instanceId'], instances: ['instanceId'],
name: 'appName', name: 'appName',
sdks: [ sdks: [
@ -376,7 +377,7 @@ test('should show correct number of total', async () => {
expect(body).toMatchObject({ expect(body).toMatchObject({
applications: [ applications: [
{ {
environments: ['default'], environments: [DEFAULT_ENV],
instances: ['instanceId'], instances: ['instanceId'],
name: 'second-app', name: 'second-app',
sdks: [ sdks: [

View File

@ -22,7 +22,6 @@ import {
} from '../index.js'; } from '../index.js';
import { import {
type IAuditUser, type IAuditUser,
type IGroup,
type IUnleashStores, type IUnleashStores,
type IUser, type IUser,
SYSTEM_USER_AUDIT, SYSTEM_USER_AUDIT,
@ -30,18 +29,11 @@ import {
TEST_AUDIT_USER, TEST_AUDIT_USER,
} from '../../types/index.js'; } from '../../types/index.js';
import { BadDataError, InvalidOperationError } from '../../error/index.js'; import { BadDataError, InvalidOperationError } from '../../error/index.js';
import { DEFAULT_ENV, extractAuditInfoFromUser } from '../../util/index.js'; import { extractAuditInfoFromUser } from '../../util/index.js';
import { ApiTokenType } from '../../types/model.js'; import { ApiTokenType } from '../../types/model.js';
import { createApiTokenService } from '../api-tokens/createApiTokenService.js'; import { createApiTokenService } from '../api-tokens/createApiTokenService.js';
import type User from '../../types/user.js'; import type User from '../../types/user.js';
import { import { beforeAll, expect, test, beforeEach, afterAll } from 'vitest';
beforeAll,
expect,
test,
beforeEach,
afterEach,
afterAll,
} from 'vitest';
let stores: IUnleashStores; let stores: IUnleashStores;
let db: ITestDb; let db: ITestDb;
@ -55,7 +47,6 @@ let auditUser: IAuditUser;
let apiTokenService: ApiTokenService; let apiTokenService: ApiTokenService;
let opsUser: IUser; let opsUser: IUser;
let group: IGroup;
const isProjectUser = async ( const isProjectUser = async (
userId: number, userId: number,
@ -80,10 +71,6 @@ beforeAll(async () => {
username: user.email, username: user.email,
ip: '127.0.0.1', ip: '127.0.0.1',
}; };
group = await stores.groupStore.create({
name: 'aTestGroup',
description: '',
});
opsUser = await stores.userStore.insert({ opsUser = await stores.userStore.insert({
name: 'Test user', name: 'Test user',
email: 'test@example.com', email: 'test@example.com',
@ -101,29 +88,31 @@ beforeAll(async () => {
environmentService = new EnvironmentService(stores, config, eventService); environmentService = new EnvironmentService(stores, config, eventService);
projectService = createProjectService(db.rawDatabase, config); projectService = createProjectService(db.rawDatabase, config);
apiTokenService = createApiTokenService(db.rawDatabase, config); apiTokenService = createApiTokenService(db.rawDatabase, config);
// await stores.environmentStore.updateProperty(DEFAULT_ENV, 'enabled', false);
// await stores.environmentStore.updateProperty(
// 'production',
// 'enabled',
// false,
// );
}); });
beforeEach(async () => { beforeEach(async () => {
await stores.accessStore.addUserToRole(opsUser.id, 1, '');
});
afterAll(async () => {
await db.destroy();
});
afterEach(async () => {
const envs = await stores.environmentStore.getAll(); const envs = await stores.environmentStore.getAll();
const deleteEnvs = envs const deleteEnvs = envs.map(async (env) => {
.filter((env) => env.name !== 'default') await stores.environmentStore.delete(env.name);
.map(async (env) => { });
await stores.environmentStore.delete(env.name); await Promise.allSettled(deleteEnvs);
});
const users = await stores.userStore.getAll(); const users = await stores.userStore.getAll();
const wipeUserPermissions = users.map(async (u) => { const wipeUserPermissions = users.map(async (u) => {
await stores.accessStore.unlinkUserRoles(u.id); await stores.accessStore.unlinkUserRoles(u.id);
}); });
await stores.eventStore.deleteAll(); await stores.eventStore.deleteAll();
await Promise.allSettled(deleteEnvs);
await Promise.allSettled(wipeUserPermissions); await Promise.allSettled(wipeUserPermissions);
await stores.accessStore.addUserToRole(opsUser.id, 1, '');
});
afterAll(async () => {
await db.destroy();
}); });
test('should have default project', async () => { test('should have default project', async () => {
@ -1850,6 +1839,11 @@ const updateFeature = async (featureName: string, update: any) => {
}; };
test('should calculate average time to production', async () => { test('should calculate average time to production', async () => {
await stores.environmentStore.create({
name: 'prod-env',
type: 'production',
enabled: true,
});
const project = { const project = {
id: 'average-time-to-prod', id: 'average-time-to-prod',
name: 'average-time-to-prod', name: 'average-time-to-prod',
@ -1884,7 +1878,7 @@ test('should calculate average time to production', async () => {
enabled: true, enabled: true,
project: project.id, project: project.id,
featureName: flag.name, featureName: flag.name,
environment: 'default', environment: 'prod-env',
auditUser, auditUser,
}), }),
); );
@ -1908,6 +1902,11 @@ test('should calculate average time to production', async () => {
}); });
test('should calculate average time to production ignoring some items', async () => { test('should calculate average time to production ignoring some items', async () => {
await stores.environmentStore.create({
name: 'prod-env',
type: 'production',
enabled: true,
});
const project = { const project = {
id: 'average-time-to-prod-corner-cases', id: 'average-time-to-prod-corner-cases',
name: 'average-time-to-prod', name: 'average-time-to-prod',
@ -1918,7 +1917,7 @@ test('should calculate average time to production ignoring some items', async ()
enabled: true, enabled: true,
project: project.id, project: project.id,
featureName, featureName,
environment: 'default', environment: 'prod-env',
auditUser, auditUser,
tags: [], tags: [],
}); });
@ -2125,222 +2124,6 @@ test('should get correct amount of project members for current and past window',
expect(result.updates.projectActivityPastWindow).toBe(0); expect(result.updates.projectActivityPastWindow).toBe(0);
}); });
test('should return average time to production per flag', async () => {
const project = {
id: 'average-time-to-prod-per-flag',
name: 'average-time-to-prod-per-flag',
mode: 'open' as const,
defaultStickiness: 'clientId',
};
await projectService.createProject(project, user, auditUser);
const flags = [
{ name: 'average-prod-time-pt', subdays: 7 },
{ name: 'average-prod-time-pt-2', subdays: 14 },
{ name: 'average-prod-time-pt-3', subdays: 40 },
{ name: 'average-prod-time-pt-4', subdays: 15 },
{ name: 'average-prod-time-pt-5', subdays: 2 },
];
const featureFlags = await Promise.all(
flags.map((flag) => {
return featureToggleService.createFeatureToggle(
project.id,
flag,
auditUser,
);
}),
);
await Promise.all(
featureFlags.map((flag) => {
return eventService.storeEvent(
new FeatureEnvironmentEvent({
enabled: true,
project: project.id,
featureName: flag.name,
environment: 'default',
auditUser,
}),
);
}),
);
await Promise.all(
flags.map((flag) =>
updateFeature(flag.name, {
created_at: subDays(new Date(), flag.subdays),
}),
),
);
const result = await projectService.getDoraMetrics(project.id);
expect(result.features).toHaveLength(5);
expect(result.features[0].timeToProduction).toBeTruthy();
expect(result.projectAverage).toBeTruthy();
});
test('should return average time to production per flag for a specific project', async () => {
const project1 = {
id: 'average-time-to-prod-per-flag-1',
name: 'Project 1',
mode: 'open' as const,
defaultStickiness: 'clientId',
};
const project2 = {
id: 'average-time-to-prod-per-flag-2',
name: 'Project 2',
mode: 'open' as const,
defaultStickiness: 'clientId',
};
await projectService.createProject(project1, user, auditUser);
await projectService.createProject(project2, user, auditUser);
const flagsProject1 = [
{ name: 'average-prod-time-pt-10', subdays: 7 },
{ name: 'average-prod-time-pt-11', subdays: 14 },
{ name: 'average-prod-time-pt-12', subdays: 40 },
];
const flagsProject2 = [
{ name: 'average-prod-time-pt-13', subdays: 15 },
{ name: 'average-prod-time-pt-14', subdays: 2 },
];
const featureFlagsProject1 = await Promise.all(
flagsProject1.map((flag) => {
return featureToggleService.createFeatureToggle(
project1.id,
flag,
auditUser,
);
}),
);
const featureFlagsProject2 = await Promise.all(
flagsProject2.map((flag) => {
return featureToggleService.createFeatureToggle(
project2.id,
flag,
auditUser,
);
}),
);
await Promise.all(
featureFlagsProject1.map((flag) => {
return eventService.storeEvent(
new FeatureEnvironmentEvent({
enabled: true,
project: project1.id,
featureName: flag.name,
environment: 'default',
auditUser,
}),
);
}),
);
await Promise.all(
featureFlagsProject2.map((flag) => {
return eventService.storeEvent(
new FeatureEnvironmentEvent({
enabled: true,
project: project2.id,
featureName: flag.name,
environment: 'default',
auditUser,
}),
);
}),
);
await Promise.all(
flagsProject1.map((flag) =>
updateFeature(flag.name, {
created_at: subDays(new Date(), flag.subdays),
}),
),
);
await Promise.all(
flagsProject2.map((flag) =>
updateFeature(flag.name, {
created_at: subDays(new Date(), flag.subdays),
}),
),
);
const resultProject1 = await projectService.getDoraMetrics(project1.id);
const resultProject2 = await projectService.getDoraMetrics(project2.id);
expect(resultProject1.features).toHaveLength(3);
expect(resultProject2.features).toHaveLength(2);
});
test('should return average time to production per flag and include archived flags', async () => {
const project1 = {
id: 'average-time-to-prod-per-flag-12',
name: 'Project 1',
mode: 'open' as const,
defaultStickiness: 'clientId',
};
await projectService.createProject(project1, user, auditUser);
const flagsProject1 = [
{ name: 'average-prod-time-pta-10', subdays: 7 },
{ name: 'average-prod-time-pta-11', subdays: 14 },
{ name: 'average-prod-time-pta-12', subdays: 40 },
];
const featureFlagsProject1 = await Promise.all(
flagsProject1.map((flag) => {
return featureToggleService.createFeatureToggle(
project1.id,
flag,
auditUser,
);
}),
);
await Promise.all(
featureFlagsProject1.map((flag) => {
return eventService.storeEvent(
new FeatureEnvironmentEvent({
enabled: true,
project: project1.id,
featureName: flag.name,
environment: 'default',
auditUser,
}),
);
}),
);
await Promise.all(
flagsProject1.map((flag) =>
updateFeature(flag.name, {
created_at: subDays(new Date(), flag.subdays),
}),
),
);
await featureToggleService.archiveToggle(
'average-prod-time-pta-12',
user,
auditUser,
);
const resultProject1 = await projectService.getDoraMetrics(project1.id);
expect(resultProject1.features).toHaveLength(3);
});
describe('feature flag naming patterns', () => { describe('feature flag naming patterns', () => {
test(`should clear existing example and description if the payload doesn't contain them`, async () => { test(`should clear existing example and description if the payload doesn't contain them`, async () => {
const featureNaming = { const featureNaming = {
@ -2424,6 +2207,11 @@ test('deleting a project with archived flags should result in any remaining arch
}); });
test('should also delete api tokens that were only bound to deleted project', async () => { test('should also delete api tokens that were only bound to deleted project', async () => {
await stores.environmentStore.create({
name: 'prod-env',
type: 'production',
enabled: true,
});
const project = 'some'; const project = 'some';
const tokenName = 'test'; const tokenName = 'test';
@ -2439,7 +2227,7 @@ test('should also delete api tokens that were only bound to deleted project', as
const token = await apiTokenService.createApiTokenWithProjects({ const token = await apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
tokenName, tokenName,
environment: DEFAULT_ENV, environment: 'prod-env',
projects: [project], projects: [project],
}); });
@ -2449,6 +2237,11 @@ test('should also delete api tokens that were only bound to deleted project', as
}); });
test('should not delete project-bound api tokens still bound to project', async () => { test('should not delete project-bound api tokens still bound to project', async () => {
await stores.environmentStore.create({
name: 'prod-env',
type: 'production',
enabled: true,
});
const project1 = 'token-deleted-project'; const project1 = 'token-deleted-project';
const project2 = 'token-not-deleted-project'; const project2 = 'token-not-deleted-project';
const tokenName = 'test'; const tokenName = 'test';
@ -2474,7 +2267,7 @@ test('should not delete project-bound api tokens still bound to project', async
const token = await apiTokenService.createApiTokenWithProjects({ const token = await apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
tokenName, tokenName,
environment: DEFAULT_ENV, environment: 'prod-env',
projects: [project1, project2], projects: [project1, project2],
}); });
@ -2485,6 +2278,11 @@ test('should not delete project-bound api tokens still bound to project', async
}); });
test('should delete project-bound api tokens when all projects they belong to are deleted', async () => { test('should delete project-bound api tokens when all projects they belong to are deleted', async () => {
await stores.environmentStore.create({
name: 'prod-env',
type: 'production',
enabled: true,
});
const project1 = 'token-deleted-project-1'; const project1 = 'token-deleted-project-1';
const project2 = 'token-deleted-project-2'; const project2 = 'token-deleted-project-2';
const tokenName = 'test'; const tokenName = 'test';
@ -2510,7 +2308,7 @@ test('should delete project-bound api tokens when all projects they belong to ar
const token = await apiTokenService.createApiTokenWithProjects({ const token = await apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
tokenName, tokenName,
environment: DEFAULT_ENV, environment: 'prod-env',
projects: [project1, project2], projects: [project1, project2],
}); });

View File

@ -15,6 +15,7 @@ import {
} from '../../../test/e2e/helpers/test-helper.js'; } from '../../../test/e2e/helpers/test-helper.js';
import type { StrategiesUsingSegment } from './segment-service-interface.js'; import type { StrategiesUsingSegment } from './segment-service-interface.js';
import type { IFeatureOverview, IUser } from '../../types/index.js'; import type { IFeatureOverview, IUser } from '../../types/index.js';
import { DEFAULT_ENV } from '../../server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -23,7 +24,7 @@ const SEGMENTS_BASE_PATH = '/api/admin/segments';
const FEATURES_LIST_BASE_PATH = '/api/admin/projects/default/features'; const FEATURES_LIST_BASE_PATH = '/api/admin/projects/default/features';
const getFeatureStrategiesPath = (featureName: string) => { const getFeatureStrategiesPath = (featureName: string) => {
return `/api/admin/projects/default/features/${featureName}/environments/default/strategies`; return `/api/admin/projects/default/features/${featureName}/environments/${DEFAULT_ENV}/strategies`;
}; };
// Recursively change all Date properties to string properties. // Recursively change all Date properties to string properties.
@ -87,7 +88,7 @@ const addSegmentsToStrategy = (
strategyId, strategyId,
segmentIds, segmentIds,
projectId: 'default', projectId: 'default',
environmentId: 'default', environmentId: DEFAULT_ENV,
additional: 'property', additional: 'property',
}) })
.expect(expectStatusCode); .expect(expectStatusCode);
@ -182,7 +183,7 @@ test('should fail on missing properties', async () => {
.set('Content-type', 'application/json') .set('Content-type', 'application/json')
.send({ .send({
projectId: 'default', projectId: 'default',
environmentId: 'default', environmentId: DEFAULT_ENV,
additional: 'property', additional: 'property',
}); });
@ -291,7 +292,7 @@ test('should not delete segments used by strategies', async () => {
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag.strategies[0] }, { ...flag.strategies[0] },
'default', DEFAULT_ENV,
flag.name, flag.name,
); );
const [feature] = await fetchFeatures(); const [feature] = await fetchFeatures();
@ -320,7 +321,7 @@ test('should delete segments used by strategies in archived feature flags', asyn
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag.strategies[0] }, { ...flag.strategies[0] },
'default', DEFAULT_ENV,
flag.name, flag.name,
); );
const [feature] = await fetchFeatures(); const [feature] = await fetchFeatures();
@ -362,19 +363,19 @@ test('should list strategies by segment', async () => {
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag1.strategies[0] }, { ...flag1.strategies[0] },
'default', DEFAULT_ENV,
flag1.name, flag1.name,
); );
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag1.strategies[0] }, { ...flag1.strategies[0] },
'default', DEFAULT_ENV,
flag2.name, flag2.name,
); );
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag3.strategies[0] }, { ...flag3.strategies[0] },
'default', DEFAULT_ENV,
flag3.name, flag3.name,
); );
@ -442,19 +443,19 @@ test('should list segments by strategy', async () => {
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag1.strategies[0] }, { ...flag1.strategies[0] },
'default', DEFAULT_ENV,
flag1.name, flag1.name,
); );
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag1.strategies[0] }, { ...flag1.strategies[0] },
'default', DEFAULT_ENV,
flag2.name, flag2.name,
); );
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag3.strategies[0] }, { ...flag3.strategies[0] },
'default', DEFAULT_ENV,
flag3.name, flag3.name,
); );
@ -594,7 +595,7 @@ test('Should show usage in features and projects', async () => {
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
app, app,
{ ...flag.strategies[0] }, { ...flag.strategies[0] },
'default', DEFAULT_ENV,
flag.name, flag.name,
); );
const [feature] = await fetchFeatures(); const [feature] = await fetchFeatures();
@ -673,7 +674,7 @@ describe('detect strategy usage in change requests', () => {
await db.rawDatabase.table('change_requests').insert({ await db.rawDatabase.table('change_requests').insert({
id: CR_ID, id: CR_ID,
environment: 'default', environment: DEFAULT_ENV,
state: 'In review', state: 'In review',
project: 'default', project: 'default',
created_by: user.id, created_by: user.id,
@ -770,7 +771,7 @@ describe('detect strategy usage in change requests', () => {
expect(changeRequestStrategies).toMatchObject([ expect(changeRequestStrategies).toMatchObject([
{ {
environment: 'default', environment: DEFAULT_ENV,
featureName: flag.name, featureName: flag.name,
projectId: 'default', projectId: 'default',
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
@ -797,7 +798,7 @@ describe('detect strategy usage in change requests', () => {
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
enterpriseApp, enterpriseApp,
{ ...flag.strategies[0] }, { ...flag.strategies[0] },
'default', DEFAULT_ENV,
flag.name, flag.name,
); );
@ -857,7 +858,7 @@ describe('detect strategy usage in change requests', () => {
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
enterpriseApp, enterpriseApp,
{ ...flag.strategies[0] }, { ...flag.strategies[0] },
'default', DEFAULT_ENV,
flag.name, flag.name,
); );
@ -958,7 +959,7 @@ describe('detect strategy usage in change requests', () => {
await addStrategyToFeatureEnv( await addStrategyToFeatureEnv(
enterpriseApp, enterpriseApp,
{ ...flag.strategies[0] }, { ...flag.strategies[0] },
'default', DEFAULT_ENV,
flag.name, flag.name,
); );

View File

@ -46,7 +46,7 @@ const fetchFeatures = (): Promise<IFeatureOverview[]> => {
}; };
const getFeatureStrategiesPath = (featureName: string) => { const getFeatureStrategiesPath = (featureName: string) => {
return `/api/admin/projects/default/features/${featureName}/environments/default/strategies`; return `/api/admin/projects/default/features/${featureName}/environments/${DEFAULT_ENV}/strategies`;
}; };
const fetchFeatureStrategies = (featureName: string) => const fetchFeatureStrategies = (featureName: string) =>

View File

@ -9,6 +9,7 @@ import {
type IUser, type IUser,
TEST_AUDIT_USER, TEST_AUDIT_USER,
} from '../../types/index.js'; } from '../../types/index.js';
import { DEFAULT_ENV } from '../../server-impl.js';
let stores: IUnleashStores; let stores: IUnleashStores;
let db: ITestDb; let db: ITestDb;
@ -78,7 +79,7 @@ describe('usage counting', () => {
await db.rawDatabase.table('change_requests').insert({ await db.rawDatabase.table('change_requests').insert({
id: CR_ID, id: CR_ID,
environment: 'default', environment: DEFAULT_ENV,
state: 'In Review', state: 'In Review',
project: 'default', project: 'default',
created_by: user.id, created_by: user.id,
@ -174,7 +175,7 @@ describe('usage counting', () => {
await stores.featureStrategiesStore.createStrategyFeatureEnv({ await stores.featureStrategiesStore.createStrategyFeatureEnv({
featureName: flag.name, featureName: flag.name,
projectId: 'default', projectId: 'default',
environment: 'default', environment: DEFAULT_ENV,
strategyName: 'flexibleRollout', strategyName: 'flexibleRollout',
segments: [segment1.id], segments: [segment1.id],
parameters: { parameters: {
@ -187,7 +188,7 @@ describe('usage counting', () => {
await db.rawDatabase.table('change_requests').insert({ await db.rawDatabase.table('change_requests').insert({
id: CR_ID, id: CR_ID,
environment: 'default', environment: DEFAULT_ENV,
state: 'In Review', state: 'In Review',
project: 'default', project: 'default',
created_by: user.id, created_by: user.id,

View File

@ -89,19 +89,6 @@ beforeAll(async () => {
eventBus, eventBus,
); );
const metricsDbConf = {
client: {
pool: {
min: 0,
max: 4,
numUsed: () => 2,
numFree: () => 2,
numPendingAcquires: () => 0,
numPendingCreates: () => 1,
},
},
};
const { collectAggDbMetrics, collectStaticCounters } = const { collectAggDbMetrics, collectStaticCounters } =
registerPrometheusMetrics( registerPrometheusMetrics(
config, config,

View File

@ -1,3 +1,4 @@
import { DEFAULT_ENV } from '../server-impl.js';
import { ALL } from '../types/models/api-token.js'; import { ALL } from '../types/models/api-token.js';
import { createApiToken } from './api-token-schema.js'; import { createApiToken } from './api-token-schema.js';
@ -51,10 +52,10 @@ test('should allow for embedded proxy (frontend) key', async () => {
expect(token.error).toBeUndefined(); expect(token.error).toBeUndefined();
}); });
test('should set environment to default for frontend key', async () => { test('should set environment to default environment for frontend key', async () => {
const token = await createApiToken.validateAsync({ const token = await createApiToken.validateAsync({
tokenName: 'test', tokenName: 'test',
type: 'frontend', type: 'frontend',
}); });
expect(token.environment).toEqual('default'); expect(token.environment).toEqual(DEFAULT_ENV);
}); });

View File

@ -7,7 +7,7 @@ import {
TEST_AUDIT_USER, TEST_AUDIT_USER,
} from '../types/index.js'; } from '../types/index.js';
import { addDays, minutesToMilliseconds, subDays } from 'date-fns'; import { addDays, minutesToMilliseconds, subDays } from 'date-fns';
import { extractAuditInfoFromUser } from '../util/index.js'; import { DEFAULT_ENV, extractAuditInfoFromUser } from '../util/index.js';
import { createFakeApiTokenService } from '../features/api-tokens/createApiTokenService.js'; import { createFakeApiTokenService } from '../features/api-tokens/createApiTokenService.js';
import { import {
API_TOKEN_CREATED, API_TOKEN_CREATED,
@ -50,7 +50,7 @@ test('Should init api token', async () => {
test("Shouldn't return frontend token when secret is undefined", async () => { test("Shouldn't return frontend token when secret is undefined", async () => {
const token: IApiTokenCreate = { const token: IApiTokenCreate = {
environment: 'default', environment: DEFAULT_ENV,
projects: ['*'], projects: ['*'],
secret: '*:*:some-random-string', secret: '*:*:some-random-string',
type: ApiTokenType.FRONTEND, type: ApiTokenType.FRONTEND,
@ -62,7 +62,7 @@ test("Shouldn't return frontend token when secret is undefined", async () => {
const { environmentStore, apiTokenService } = const { environmentStore, apiTokenService } =
createFakeApiTokenService(config); createFakeApiTokenService(config);
await environmentStore.create({ await environmentStore.create({
name: 'default', name: DEFAULT_ENV,
enabled: true, enabled: true,
type: 'test', type: 'test',
sortOrder: 1, sortOrder: 1,
@ -76,7 +76,7 @@ test("Shouldn't return frontend token when secret is undefined", async () => {
test('Api token operations should all have events attached', async () => { test('Api token operations should all have events attached', async () => {
const token: IApiTokenCreate = { const token: IApiTokenCreate = {
environment: 'default', environment: DEFAULT_ENV,
projects: ['*'], projects: ['*'],
secret: '*:*:some-random-string', secret: '*:*:some-random-string',
type: ApiTokenType.FRONTEND, type: ApiTokenType.FRONTEND,
@ -89,7 +89,7 @@ test('Api token operations should all have events attached', async () => {
const { environmentStore, apiTokenService, eventService } = const { environmentStore, apiTokenService, eventService } =
createFakeApiTokenService(config); createFakeApiTokenService(config);
await environmentStore.create({ await environmentStore.create({
name: 'default', name: DEFAULT_ENV,
enabled: true, enabled: true,
type: 'test', type: 'test',
sortOrder: 1, sortOrder: 1,
@ -150,7 +150,7 @@ test('getUserForToken should get a user with admin token user id and token name'
describe('API token getTokenWithCache', () => { describe('API token getTokenWithCache', () => {
const token: IApiTokenCreate = { const token: IApiTokenCreate = {
environment: 'default', environment: DEFAULT_ENV,
projects: ['*'], projects: ['*'],
secret: '*:*:some-random-string', secret: '*:*:some-random-string',
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
@ -228,7 +228,7 @@ test('normalizes api token type casing to lowercase', async () => {
createFakeApiTokenService(config); createFakeApiTokenService(config);
await environmentStore.create({ await environmentStore.create({
name: 'default', name: DEFAULT_ENV,
enabled: true, enabled: true,
type: 'test', type: 'test',
sortOrder: 1, sortOrder: 1,
@ -238,7 +238,7 @@ test('normalizes api token type casing to lowercase', async () => {
await apiTokenService.createApiTokenWithProjects( await apiTokenService.createApiTokenWithProjects(
{ {
environment: 'default', environment: DEFAULT_ENV,
// @ts-ignore // @ts-ignore
type: 'CLIENT', type: 'CLIENT',
projects: [], projects: [],
@ -249,7 +249,7 @@ test('normalizes api token type casing to lowercase', async () => {
await apiTokenService.createApiTokenWithProjects( await apiTokenService.createApiTokenWithProjects(
{ {
environment: 'default', environment: DEFAULT_ENV,
// @ts-ignore // @ts-ignore
type: 'client', type: 'client',
projects: [], projects: [],

View File

@ -200,7 +200,9 @@ test('should prefix default token with "*:*."', async () => {
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(201) .expect(201)
.expect((res) => { .expect((res) => {
expect(res.body.secret).toMatch(/\*:default\..*/); expect(res.body.secret).toMatch(
new RegExp(`\\*:${DEFAULT_ENV}\\..*`),
);
}); });
}); });
@ -216,7 +218,9 @@ test('should prefix token with "project:environment."', async () => {
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(201) .expect(201)
.expect((res) => { .expect((res) => {
expect(res.body.secret).toMatch(/default:default\..*/); expect(res.body.secret).toMatch(
new RegExp(`default:${DEFAULT_ENV}\\..*`),
);
}); });
}); });

View File

@ -5,6 +5,7 @@ import {
} from '../../helpers/test-helper.js'; } from '../../helpers/test-helper.js';
import getLogger from '../../../fixtures/no-logger.js'; import getLogger from '../../../fixtures/no-logger.js';
import { ApiTokenType, type IApiToken } from '../../../../lib/types/model.js'; import { ApiTokenType, type IApiToken } from '../../../../lib/types/model.js';
import { DEFAULT_ENV } from '../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -65,7 +66,7 @@ beforeAll(async () => {
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: 'tester', tokenName: 'tester',
}); });
@ -73,16 +74,17 @@ beforeAll(async () => {
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.FRONTEND, type: ApiTokenType.FRONTEND,
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: 'tester', tokenName: 'tester',
}); });
}); });
afterEach(async () => { beforeEach(async () => {
await Promise.all([ await Promise.all([
db.stores.clientMetricsStoreV2.deleteAll(), db.stores.clientMetricsStoreV2.deleteAll(),
db.stores.clientInstanceStore.deleteAll(), db.stores.clientInstanceStore.deleteAll(),
db.stores.featureToggleStore.deleteAll(), db.stores.featureToggleStore.deleteAll(),
db.stores.clientApplicationsStore.deleteAll(),
]); ]);
}); });
@ -134,7 +136,7 @@ test('should show correct application metrics', async () => {
environments: [ environments: [
{ {
instanceCount: 2, instanceCount: 2,
name: 'default', name: DEFAULT_ENV,
frontendSdks: [], frontendSdks: [],
backendSdks: [ backendSdks: [
'unleash-client-node:3.2.1', 'unleash-client-node:3.2.1',
@ -153,7 +155,7 @@ test('should show correct application metrics', async () => {
const { body: instancesBody } = await app.request const { body: instancesBody } = await app.request
.get( .get(
`/api/admin/metrics/instances/${metrics.appName}/environment/default`, `/api/admin/metrics/instances/${metrics.appName}/environment/${DEFAULT_ENV}`,
) )
.expect(200); .expect(200);
@ -198,7 +200,7 @@ test('should report frontend application instances', async () => {
const { body } = await app.request const { body } = await app.request
.get( .get(
`/api/admin/metrics/instances/${metrics.appName}/environment/default`, `/api/admin/metrics/instances/${metrics.appName}/environment/${DEFAULT_ENV}`,
) )
.expect(200); .expect(200);
@ -243,7 +245,7 @@ test('should show missing features and strategies', async () => {
environments: [ environments: [
{ {
instanceCount: 1, instanceCount: 1,
name: 'default', name: DEFAULT_ENV,
sdks: ['unleash-client-node:1.0.0'], sdks: ['unleash-client-node:1.0.0'],
issues: { issues: {
missingFeatures: ['toggle-name-2', 'toggle-name-3'], missingFeatures: ['toggle-name-2', 'toggle-name-3'],
@ -296,7 +298,7 @@ test('should not return instances older than 24h', async () => {
const { body: instancesBody } = await app.request const { body: instancesBody } = await app.request
.get( .get(
`/api/admin/metrics/instances/${metrics.appName}/environment/default`, `/api/admin/metrics/instances/${metrics.appName}/environment/${DEFAULT_ENV}`,
) )
.expect(200); .expect(200);

View File

@ -5,6 +5,7 @@ import {
setupAppWithCustomConfig, setupAppWithCustomConfig,
} from '../../helpers/test-helper.js'; } from '../../helpers/test-helper.js';
import getLogger from '../../../fixtures/no-logger.js'; import getLogger from '../../../fixtures/no-logger.js';
import { DEFAULT_ENV } from '../../../../lib/server-impl.js';
let db: ITestDb; let db: ITestDb;
let app: IUnleashTest; let app: IUnleashTest;
@ -194,7 +195,7 @@ test('should not delete a context field that is in use by active flags', async (
.expect(201); .expect(201);
await app.request await app.request
.post( .post(
`/api/admin/projects/default/features/${feature}/environments/default/strategies`, `/api/admin/projects/default/features/${feature}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'default', name: 'default',
@ -297,7 +298,7 @@ test('should show context field usage for active flags', async () => {
.expect(201); .expect(201);
await app.request await app.request
.post( .post(
`/api/admin/projects/default/features/${feature}/environments/default/strategies`, `/api/admin/projects/default/features/${feature}/environments/${DEFAULT_ENV}/strategies`,
) )
.send({ .send({
name: 'default', name: 'default',
@ -327,7 +328,9 @@ test('should show context field usage for active flags', async () => {
expect(body.strategies).toHaveLength(1); expect(body.strategies).toHaveLength(1);
expect(body).toMatchObject({ expect(body).toMatchObject({
strategies: [{ environment: 'default', featureName: 'contextFeature' }], strategies: [
{ environment: DEFAULT_ENV, featureName: 'contextFeature' },
],
}); });
const { body: getAllBody } = await app.request const { body: getAllBody } = await app.request

View File

@ -7,6 +7,7 @@ import getLogger from '../../../fixtures/no-logger.js';
import type { IUnleashStores } from '../../../../lib/types/index.js'; import type { IUnleashStores } from '../../../../lib/types/index.js';
import { ApiTokenType } from '../../../../lib/types/model.js'; import { ApiTokenType } from '../../../../lib/types/model.js';
import { registerPrometheusMetrics } from '../../../../lib/metrics.js'; import { registerPrometheusMetrics } from '../../../../lib/metrics.js';
import { DEFAULT_ENV } from '../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -73,13 +74,13 @@ test('api tokens are serialized correctly', async () => {
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
tokenName: 'frontend', tokenName: 'frontend',
type: ApiTokenType.FRONTEND, type: ApiTokenType.FRONTEND,
environment: 'default', environment: DEFAULT_ENV,
projects: ['*'], projects: ['*'],
}); });
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
tokenName: 'client', tokenName: 'client',
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
environment: 'default', environment: DEFAULT_ENV,
projects: ['*'], projects: ['*'],
}); });

View File

@ -5,6 +5,7 @@ import {
} from '../../helpers/test-helper.js'; } from '../../helpers/test-helper.js';
import getLogger from '../../../fixtures/no-logger.js'; import getLogger from '../../../fixtures/no-logger.js';
import { ApiTokenType } from '../../../../lib/types/model.js'; import { ApiTokenType } from '../../../../lib/types/model.js';
import { DEFAULT_ENV } from '../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -156,7 +157,7 @@ test('should save multiple projects from token', async () => {
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default', 'mainProject'], projects: ['default', 'mainProject'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: 'tester', tokenName: 'tester',
}); });
@ -184,11 +185,11 @@ test('should save multiple projects from token', async () => {
appName: 'multi-project-app', appName: 'multi-project-app',
usage: [ usage: [
{ {
environments: ['default'], environments: [DEFAULT_ENV],
project: 'default', project: 'default',
}, },
{ {
environments: ['default'], environments: [DEFAULT_ENV],
project: 'mainProject', project: 'mainProject',
}, },
], ],

View File

@ -14,6 +14,7 @@ import type { PlaygroundFeatureSchema } from '../../../../lib/openapi/spec/playg
import type { ClientFeatureSchema } from '../../../../lib/openapi/spec/client-feature-schema.js'; import type { ClientFeatureSchema } from '../../../../lib/openapi/spec/client-feature-schema.js';
import type { PlaygroundResponseSchema } from '../../../../lib/openapi/spec/playground-response-schema.js'; import type { PlaygroundResponseSchema } from '../../../../lib/openapi/spec/playground-response-schema.js';
import type { PlaygroundRequestSchema } from '../../../../lib/openapi/spec/playground-request-schema.js'; import type { PlaygroundRequestSchema } from '../../../../lib/openapi/spec/playground-request-schema.js';
import { DEFAULT_ENV } from '../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -240,7 +241,7 @@ describe('Playground API E2E', () => {
token.secret, token.secret,
{ {
projects: ALL, projects: ALL,
environment: 'default', environment: DEFAULT_ENV,
context: { context: {
appName: 'playground-test', appName: 'playground-test',
}, },
@ -287,14 +288,14 @@ describe('Playground API E2E', () => {
clientFeatures(), clientFeatures(),
fc.context(), fc.context(),
async (features, ctx) => { async (features, ctx) => {
await seedDatabase(db, features, 'default'); await seedDatabase(db, features, DEFAULT_ENV);
const body = await playgroundRequest( const body = await playgroundRequest(
app, app,
token.secret, token.secret,
{ {
projects: ALL, projects: ALL,
environment: 'default', environment: DEFAULT_ENV,
context: { context: {
appName: 'playground-test', appName: 'playground-test',
}, },
@ -372,7 +373,7 @@ describe('Playground API E2E', () => {
// one of the above values // one of the above values
context: { context: {
appName: generatedAppName, appName: generatedAppName,
environment: 'default', environment: DEFAULT_ENV,
}, },
})), })),
constrainedFeatures(), constrainedFeatures(),

View File

@ -5,6 +5,7 @@ import {
} from '../../../helpers/test-helper.js'; } from '../../../helpers/test-helper.js';
import getLogger from '../../../../fixtures/no-logger.js'; import getLogger from '../../../../fixtures/no-logger.js';
import { ApiTokenType } from '../../../../../lib/types/model.js'; import { ApiTokenType } from '../../../../../lib/types/model.js';
import { DEFAULT_ENV } from '../../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -50,7 +51,7 @@ test('Returns list of tokens', async () => {
tokenName: 'test', tokenName: 'test',
secret: tokenSecret, secret: tokenSecret,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
environment: 'default', environment: DEFAULT_ENV,
projects: ['default'], projects: ['default'],
}); });
return app.request return app.request
@ -80,7 +81,7 @@ test('fails to create new client token when given wrong project', async () => {
tokenName: 'default-client', tokenName: 'default-client',
type: 'client', type: 'client',
projects: ['wrong'], projects: ['wrong'],
environment: 'default', environment: DEFAULT_ENV,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(404); .expect(404);
@ -93,7 +94,7 @@ test('creates new client token', async () => {
tokenName: 'default-client', tokenName: 'default-client',
type: 'client', type: 'client',
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
}) })
.set('Content-Type', 'application/json') .set('Content-Type', 'application/json')
.expect(201) .expect(201)
@ -109,7 +110,7 @@ test('Deletes existing tokens', async () => {
tokenName: 'test', tokenName: 'test',
secret: tokenSecret, secret: tokenSecret,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
environment: 'default', environment: DEFAULT_ENV,
projects: ['default'], projects: ['default'],
}); });
@ -142,7 +143,7 @@ test('Returns Bad Request when deleting tokens with more than one project', asyn
tokenName: 'test', tokenName: 'test',
secret: tokenSecret, secret: tokenSecret,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
environment: 'default', environment: DEFAULT_ENV,
projects: ['default', 'other'], projects: ['default', 'other'],
}); });

View File

@ -5,6 +5,7 @@ import {
import dbInit, { type ITestDb } from '../../../helpers/database-init.js'; import dbInit, { type ITestDb } from '../../../helpers/database-init.js';
import getLogger from '../../../../fixtures/no-logger.js'; import getLogger from '../../../../fixtures/no-logger.js';
import { WeightType } from '../../../../../lib/types/model.js'; import { WeightType } from '../../../../../lib/types/model.js';
import { DEFAULT_ENV } from '../../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -86,7 +87,7 @@ test('Can add environment variants when existing ones exist for this feature', a
); );
await db.stores.featureEnvironmentStore.addVariantsToFeatureEnvironment( await db.stores.featureEnvironmentStore.addVariantsToFeatureEnvironment(
featureName, featureName,
'default', DEFAULT_ENV,
[ [
{ {
name: 'existing-variant', name: 'existing-variant',

View File

@ -6,6 +6,7 @@ import dbInit, { type ITestDb } from '../../../helpers/database-init.js';
import getLogger from '../../../../fixtures/no-logger.js'; import getLogger from '../../../../fixtures/no-logger.js';
import * as jsonpatch from 'fast-json-patch/index.mjs'; import * as jsonpatch from 'fast-json-patch/index.mjs';
import { type IVariant, WeightType } from '../../../../../lib/types/model.js'; import { type IVariant, WeightType } from '../../../../../lib/types/model.js';
import { DEFAULT_ENV } from '../../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -40,12 +41,12 @@ test('Can get variants for a feature', async () => {
}); });
await db.stores.featureEnvironmentStore.addEnvironmentToFeature( await db.stores.featureEnvironmentStore.addEnvironmentToFeature(
featureName, featureName,
'default', DEFAULT_ENV,
true, true,
); );
await db.stores.featureEnvironmentStore.addVariantsToFeatureEnvironment( await db.stores.featureEnvironmentStore.addVariantsToFeatureEnvironment(
featureName, featureName,
'default', DEFAULT_ENV,
[ [
{ {
name: variantName, name: variantName,
@ -57,7 +58,7 @@ test('Can get variants for a feature', async () => {
); );
await app.request await app.request
.get( .get(
`/api/admin/projects/default/features/${featureName}/environments/default/variants`, `/api/admin/projects/default/features/${featureName}/environments/${DEFAULT_ENV}/variants`,
) )
.expect(200) .expect(200)
.expect((res) => { .expect((res) => {

View File

@ -6,6 +6,7 @@ import {
} from '../../helpers/test-helper.js'; } from '../../helpers/test-helper.js';
import { IAuthType, type IUnleashStores } from '../../../../lib/types/index.js'; import { IAuthType, type IUnleashStores } from '../../../../lib/types/index.js';
import { ApiTokenType } from '../../../../lib/types/model.js'; import { ApiTokenType } from '../../../../lib/types/model.js';
import { DEFAULT_ENV } from '../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let appWithBaseUrl: IUnleashTest; let appWithBaseUrl: IUnleashTest;
@ -63,7 +64,7 @@ test('multiple slashes after base path is also rejected with 404', async () => {
test('Access with API token is granted', async () => { test('Access with API token is granted', async () => {
const token = await app.services.apiTokenService.createApiTokenWithProjects( const token = await app.services.apiTokenService.createApiTokenWithProjects(
{ {
environment: 'default', environment: DEFAULT_ENV,
projects: ['default'], projects: ['default'],
tokenName: 'test', tokenName: 'test',
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,

View File

@ -46,7 +46,7 @@ test('returns feature flag for default env', async () => {
await app.services.featureToggleService.updateEnabled( await app.services.featureToggleService.updateEnabled(
'default', 'default',
'feature.default.1', 'feature.default.1',
'default', DEFAULT_ENV,
true, true,
TEST_AUDIT_USER, TEST_AUDIT_USER,
); );
@ -64,12 +64,12 @@ test('returns feature flag for default env', async () => {
test('returns feature flag for default env even if it is removed from project', async () => { test('returns feature flag for default env even if it is removed from project', async () => {
await db.stores.featureEnvironmentStore.disconnectFeatures( await db.stores.featureEnvironmentStore.disconnectFeatures(
'default', DEFAULT_ENV,
'default', 'default',
); );
await db.stores.featureEnvironmentStore.disconnectProject( await db.stores.featureEnvironmentStore.disconnectProject(
'default', DEFAULT_ENV,
'default', 'default',
); );

View File

@ -10,6 +10,7 @@ import getLogger from '../../../fixtures/no-logger.js';
import { ApiTokenType, type IApiToken } from '../../../../lib/types/model.js'; import { ApiTokenType, type IApiToken } from '../../../../lib/types/model.js';
import { TEST_AUDIT_USER } from '../../../../lib/types/index.js'; import { TEST_AUDIT_USER } from '../../../../lib/types/index.js';
import { vi } from 'vitest'; import { vi } from 'vitest';
import { DEFAULT_ENV } from '../../../../lib/server-impl.js';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
@ -23,7 +24,7 @@ beforeAll(async () => {
await app.services.apiTokenService.createApiTokenWithProjects({ await app.services.apiTokenService.createApiTokenWithProjects({
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: 'tester', tokenName: 'tester',
}); });
}); });
@ -135,7 +136,7 @@ test('should set lastSeen for toggles with metrics both for toggle and toggle en
{ {
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default'], projects: ['default'],
environment: 'default', environment: DEFAULT_ENV,
tokenName: 'tester', tokenName: 'tester',
}, },
); );
@ -178,8 +179,8 @@ test('should set lastSeen for toggles with metrics both for toggle and toggle en
projectId: 'default', projectId: 'default',
}); });
const t1Env = t1.environments.find((e) => e.name === 'default'); const t1Env = t1.environments.find((e) => e.name === DEFAULT_ENV);
const t2Env = t2.environments.find((e) => e.name === 'default'); const t2Env = t2.environments.find((e) => e.name === DEFAULT_ENV);
expect(t1.lastSeenAt?.getTime()).toBeGreaterThanOrEqual(start); expect(t1.lastSeenAt?.getTime()).toBeGreaterThanOrEqual(start);
expect(t1Env?.lastSeenAt.getTime()).toBeGreaterThanOrEqual(start); expect(t1Env?.lastSeenAt.getTime()).toBeGreaterThanOrEqual(start);

View File

@ -63,10 +63,12 @@ test('should allow client to register multiple times', async () => {
.send(clientRegistration) .send(clientRegistration)
.expect(202); .expect(202);
vi.advanceTimersByTime(6000); await app.services.clientInstanceService.bulkAdd();
// @ts-expect-error - Incomplete client registration
expect(clientApplicationsStore.exists(clientRegistration)).toBeTruthy(); expect(
expect(clientInstanceStore.exists(clientRegistration)).toBeTruthy(); await clientApplicationsStore.exists(clientRegistration.appName),
).toBeTruthy();
expect(await clientInstanceStore.exists(clientRegistration)).toBeTruthy();
vi.useRealTimers(); vi.useRealTimers();
}); });

View File

@ -15,6 +15,7 @@ import {
} from '../../lib/types/index.js'; } from '../../lib/types/index.js';
import { createTestConfig } from '../config/test-config.js'; import { createTestConfig } from '../config/test-config.js';
import dbInit, { type ITestDb } from './helpers/database-init.js'; import dbInit, { type ITestDb } from './helpers/database-init.js';
import { DEFAULT_ENV } from '../../lib/server-impl.js';
let stores: IUnleashStores; let stores: IUnleashStores;
let db: ITestDb; let db: ITestDb;
@ -145,7 +146,7 @@ test('admin tokens get populated to admin token user', async () => {
secret: 'token1', secret: 'token1',
username: 'adm-token', username: 'adm-token',
type: 'admin', type: 'admin',
environment: 'default', environment: DEFAULT_ENV,
token_name: 'admin-token', token_name: 'admin-token',
}); });
@ -222,7 +223,7 @@ test('emits event with updated rows count', async () => {
secret: 'token2', secret: 'token2',
username: 'adm-token2', username: 'adm-token2',
type: 'admin', type: 'admin',
environment: 'default', environment: DEFAULT_ENV,
token_name: 'admin-token2', token_name: 'admin-token2',
}); });

View File

@ -517,7 +517,7 @@ export async function setupAppWithBaseUrl(
export const insertLastSeenAt = async ( export const insertLastSeenAt = async (
featureName: string, featureName: string,
db: Knex, db: Knex,
environment: string = 'default', environment: string = DEFAULT_ENV,
date: string = '2023-10-01T12:34:56.000Z', date: string = '2023-10-01T12:34:56.000Z',
): Promise<string> => { ): Promise<string> => {
try { try {

View File

@ -22,6 +22,7 @@ import { DEFAULT_PROJECT } from '../../../lib/types/project.js';
import { import {
ALL_PROJECTS, ALL_PROJECTS,
CUSTOM_ROOT_ROLE_TYPE, CUSTOM_ROOT_ROLE_TYPE,
DEFAULT_ENV,
} from '../../../lib/util/constants.js'; } from '../../../lib/util/constants.js';
import { import {
createAccessService, createAccessService,
@ -93,7 +94,7 @@ const createRole = async (rolePermissions: PermissionRef[]) => {
}; };
const hasCommonProjectAccess = async (user, projectName, condition) => { const hasCommonProjectAccess = async (user, projectName, condition) => {
const defaultEnv = 'default'; const defaultEnv = DEFAULT_ENV;
const { const {
CREATE_FEATURE, CREATE_FEATURE,
@ -312,7 +313,7 @@ test('should remove CREATE_FEATURE on default environment', async () => {
await accessService.addPermissionToRole( await accessService.addPermissionToRole(
editRole.id, editRole.id,
permissions.CREATE_FEATURE, permissions.CREATE_FEATURE,
'default', DEFAULT_ENV,
); );
// TODO: to validate the remove works, we should make sure that we had permission before removing it // TODO: to validate the remove works, we should make sure that we had permission before removing it
@ -571,7 +572,7 @@ test('should support permission with "ALL" environment requirement', async () =>
await accessStore.addPermissionsToRole( await accessStore.addPermissionsToRole(
customRole.id, customRole.id,
[{ name: CREATE_FEATURE_STRATEGY }], [{ name: CREATE_FEATURE_STRATEGY }],
'default', DEFAULT_ENV,
); );
await accessStore.addUserToRole(user.id, customRole.id, ALL_PROJECTS); await accessStore.addUserToRole(user.id, customRole.id, ALL_PROJECTS);
@ -579,7 +580,7 @@ test('should support permission with "ALL" environment requirement', async () =>
user, user,
CREATE_FEATURE_STRATEGY, CREATE_FEATURE_STRATEGY,
'default', 'default',
'default', DEFAULT_ENV,
); );
expect(hasAccess).toBe(true); expect(hasAccess).toBe(true);
@ -588,7 +589,7 @@ test('should support permission with "ALL" environment requirement', async () =>
user, user,
CREATE_FEATURE_STRATEGY, CREATE_FEATURE_STRATEGY,
'default', 'default',
'development', 'production',
); );
expect(hasNotAccess).toBe(false); expect(hasNotAccess).toBe(false);
}); });
@ -601,7 +602,7 @@ test('Should have access to create a strategy in an environment', async () => {
user, user,
CREATE_FEATURE_STRATEGY, CREATE_FEATURE_STRATEGY,
'default', 'default',
'default', DEFAULT_ENV,
), ),
).toBe(true); ).toBe(true);
}); });
@ -627,7 +628,7 @@ test('Should have access to edit a strategy in an environment', async () => {
user, user,
UPDATE_FEATURE_STRATEGY, UPDATE_FEATURE_STRATEGY,
'default', 'default',
'default', DEFAULT_ENV,
), ),
).toBe(true); ).toBe(true);
}); });
@ -640,7 +641,7 @@ test('Should have access to delete a strategy in an environment', async () => {
user, user,
DELETE_FEATURE_STRATEGY, DELETE_FEATURE_STRATEGY,
'default', 'default',
'default', DEFAULT_ENV,
), ),
).toBe(true); ).toBe(true);
}); });

View File

@ -27,6 +27,7 @@ import type { PlaygroundSegmentSchema } from '../../../lib/openapi/spec/playgrou
import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker.js'; import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker.js';
import { createFeatureToggleService } from '../../../lib/features/index.js'; import { createFeatureToggleService } from '../../../lib/features/index.js';
import { SegmentReadModel } from '../../../lib/features/segment/segment-read-model.js'; import { SegmentReadModel } from '../../../lib/features/segment/segment-read-model.js';
import { DEFAULT_ENV } from '../../../lib/server-impl.js';
let stores: IUnleashStores; let stores: IUnleashStores;
let db: ITestDb; let db: ITestDb;
@ -194,7 +195,7 @@ describe('the playground service (e2e)', () => {
const insertAndEvaluateFeatures = async ({ const insertAndEvaluateFeatures = async ({
features, features,
context, context,
env = 'default', env = DEFAULT_ENV,
segments, segments,
}: { }: {
features: ClientFeatureSchema[]; features: ClientFeatureSchema[];

View File

@ -2,7 +2,7 @@ import dbInit, { type ITestDb } from '../helpers/database-init.js';
import getLogger from '../../fixtures/no-logger.js'; import getLogger from '../../fixtures/no-logger.js';
import type { IUnleashStores } from '../../../lib/types/index.js'; import type { IUnleashStores } from '../../../lib/types/index.js';
import { ApiTokenType } from '../../../lib/types/model.js'; import { ApiTokenType } from '../../../lib/types/model.js';
import { randomId } from '../../../lib/util/index.js'; import { DEFAULT_ENV, randomId } from '../../../lib/util/index.js';
let stores: IUnleashStores; let stores: IUnleashStores;
let db: ITestDb; let db: ITestDb;
@ -14,8 +14,8 @@ beforeAll(async () => {
stores = db.stores; stores = db.stores;
}); });
afterEach(async () => { beforeEach(async () => {
await db.reset(); await stores.apiTokenStore.deleteAll();
}); });
afterAll(async () => { afterAll(async () => {
@ -30,7 +30,7 @@ test('get token is undefined when not exist', async () => {
test('get token returns the token when exists', async () => { test('get token returns the token when exists', async () => {
const newToken = await stores.apiTokenStore.insert({ const newToken = await stores.apiTokenStore.insert({
secret: 'abcde321', secret: 'abcde321',
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.ADMIN, type: ApiTokenType.ADMIN,
projects: [], projects: [],
tokenName: 'admin-test-token', tokenName: 'admin-test-token',
@ -51,28 +51,28 @@ describe('count deprecated tokens', () => {
}); });
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: '*:*.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178', secret: '*:*.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178',
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.ADMIN, type: ApiTokenType.ADMIN,
projects: [], projects: [],
tokenName: 'admin-token', tokenName: 'admin-token',
}); });
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: 'default:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178', secret: 'default:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178',
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default'], projects: ['default'],
tokenName: 'client-token', tokenName: 'client-token',
}); });
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: '*:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178', secret: '*:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178',
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: [], projects: [],
tokenName: 'client-wildcard-token', tokenName: 'client-wildcard-token',
}); });
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: '[]:production.3d6bdada42ddbd63a019d26955178be44368985f7fb3237c584ef86f', secret: '[]:production.3d6bdada42ddbd63a019d26955178be44368985f7fb3237c584ef86f',
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.FRONTEND, type: ApiTokenType.FRONTEND,
projects: ['default', 'test'], projects: ['default', 'test'],
tokenName: 'frontend-token', tokenName: 'frontend-token',
@ -92,7 +92,7 @@ describe('count deprecated tokens', () => {
test('should return 1 for legacy tokens', async () => { test('should return 1 for legacy tokens', async () => {
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: 'be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178', secret: 'be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178',
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.ADMIN, type: ApiTokenType.ADMIN,
projects: [], projects: [],
tokenName: 'admin-test-token', tokenName: 'admin-test-token',
@ -112,7 +112,7 @@ describe('count deprecated tokens', () => {
test('should return 1 for orphaned tokens', async () => { test('should return 1 for orphaned tokens', async () => {
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: 'deleted-project:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178', secret: 'deleted-project:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178',
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: [], projects: [],
tokenName: 'admin-test-token', tokenName: 'admin-test-token',
@ -132,7 +132,7 @@ describe('count deprecated tokens', () => {
test('should not count wildcard tokens as orphaned', async () => { test('should not count wildcard tokens as orphaned', async () => {
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: '*:*.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178', secret: '*:*.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178',
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: [], projects: [],
tokenName: 'client-test-token', tokenName: 'client-test-token',
@ -156,14 +156,14 @@ describe('count deprecated tokens', () => {
'[]:production.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178'; '[]:production.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178';
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: legacyTokenSecret, secret: legacyTokenSecret,
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.ADMIN, type: ApiTokenType.ADMIN,
projects: [], projects: [],
tokenName: 'admin-test-token', tokenName: 'admin-test-token',
}); });
await stores.apiTokenStore.insert({ await stores.apiTokenStore.insert({
secret: orphanedTokenSecret, secret: orphanedTokenSecret,
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.FRONTEND, type: ApiTokenType.FRONTEND,
projects: [], projects: [],
tokenName: 'frontend-test-token', tokenName: 'frontend-test-token',
@ -196,14 +196,14 @@ describe('count project tokens', () => {
const store = stores.apiTokenStore; const store = stores.apiTokenStore;
await store.insert({ await store.insert({
secret: `default:default.${randomId()}`, secret: `default:default.${randomId()}`,
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['default'], projects: ['default'],
tokenName: 'token1', tokenName: 'token1',
}); });
await store.insert({ await store.insert({
secret: `*:*.${randomId()}`, secret: `*:*.${randomId()}`,
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: ['*'], projects: ['*'],
tokenName: 'token2', tokenName: 'token2',
@ -211,7 +211,7 @@ describe('count project tokens', () => {
await store.insert({ await store.insert({
secret: `${project.id}:default.${randomId()}`, secret: `${project.id}:default.${randomId()}`,
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: [project.id], projects: [project.id],
tokenName: 'token3', tokenName: 'token3',
@ -219,7 +219,7 @@ describe('count project tokens', () => {
await store.insert({ await store.insert({
secret: `[]:default.${randomId()}`, secret: `[]:default.${randomId()}`,
environment: 'default', environment: DEFAULT_ENV,
type: ApiTokenType.CLIENT, type: ApiTokenType.CLIENT,
projects: [project.id, 'default'], projects: [project.id, 'default'],
tokenName: 'token4', tokenName: 'token4',