diff --git a/src/lib/features/client-feature-toggles/tests/__snapshots__/client-feature-toggles.e2e.test.ts.snap b/src/lib/features/client-feature-toggles/tests/__snapshots__/client-feature-toggles.e2e.test.ts.snap index c30a0ec6bc..4b824ee976 100644 --- a/src/lib/features/client-feature-toggles/tests/__snapshots__/client-feature-toggles.e2e.test.ts.snap +++ b/src/lib/features/client-feature-toggles/tests/__snapshots__/client-feature-toggles.e2e.test.ts.snap @@ -63,12 +63,12 @@ exports[`should match snapshot from /api/client/features 1`] = ` }, ], "meta": { - "etag": ""61824cd0:19"", - "queryHash": "61824cd0", + "etag": ""76d8bb0e:19"", + "queryHash": "76d8bb0e", "revisionId": 19, }, "query": { - "environment": "default", + "environment": "development", "inlineSegmentConstraints": true, }, "version": 2, diff --git a/src/lib/features/dependent-features/dependent.features.e2e.test.ts b/src/lib/features/dependent-features/dependent.features.e2e.test.ts index f5f9800bee..507e8754c7 100644 --- a/src/lib/features/dependent-features/dependent.features.e2e.test.ts +++ b/src/lib/features/dependent-features/dependent.features.e2e.test.ts @@ -21,9 +21,7 @@ let db: ITestDb; let eventStore: IEventStore; beforeAll(async () => { - db = await dbInit('dependent_features', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('dependent_features', getLogger); app = await setupAppWithCustomConfig( db.stores, { diff --git a/src/lib/features/environments/environment-oss.e2e.test.ts b/src/lib/features/environments/environment-oss.e2e.test.ts index 9f9829f490..32f36c2406 100644 --- a/src/lib/features/environments/environment-oss.e2e.test.ts +++ b/src/lib/features/environments/environment-oss.e2e.test.ts @@ -53,9 +53,9 @@ test('querying environments in OSS only returns environments that are included i .get('/api/admin/environments') .expect(200) .expect((res) => { - expect(res.body.environments).toHaveLength(3); + expect(res.body.environments).toHaveLength(2); const names = res.body.environments.map((env) => env.name); - expect(names).toEqual(['default', 'development', 'production']); + expect(names).toEqual(['development', 'production']); }); }); @@ -64,8 +64,8 @@ test('querying project environments in OSS only returns environments that are in .get('/api/admin/environments/project/default') .expect(200) .expect((res) => { - expect(res.body.environments).toHaveLength(3); + expect(res.body.environments).toHaveLength(2); const names = res.body.environments.map((env) => env.name); - expect(names).toEqual(['default', 'development', 'production']); + expect(names).toEqual(['development', 'production']); }); }); diff --git a/src/lib/features/environments/environment.test.ts b/src/lib/features/environments/environment.test.ts index 6a0c5a383e..94dded8619 100644 --- a/src/lib/features/environments/environment.test.ts +++ b/src/lib/features/environments/environment.test.ts @@ -12,9 +12,7 @@ let app: IUnleashTest; let db: ITestDb; beforeAll(async () => { - db = await dbInit('environment_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('environment_api_serial', getLogger); app = await setupAppWithCustomConfig( db.stores, { @@ -34,24 +32,33 @@ afterAll(async () => { }); test('Can list all existing environments', async () => { - await app.request + const { body } = await app.request .get('/api/admin/environments') .expect(200) - .expect('Content-Type', /json/) - .expect((res) => { - expect(res.body.version).toBe(1); - expect(res.body.environments[0]).toStrictEqual({ - name: DEFAULT_ENV, - enabled: true, - sortOrder: 1, - type: 'production', - protected: true, - requiredApprovals: null, - projectCount: 1, - apiTokenCount: 0, - enabledToggleCount: 0, - }); - }); + .expect('Content-Type', /json/); + expect(body.version).toBe(1); + expect(body.environments[0]).toStrictEqual({ + name: DEFAULT_ENV, + enabled: true, + sortOrder: 2, + type: 'development', + protected: false, + requiredApprovals: null, + projectCount: 1, + apiTokenCount: 0, + enabledToggleCount: 0, + }); + expect(body.environments[1]).toStrictEqual({ + name: 'production', + enabled: true, + sortOrder: 3, + type: 'production', + protected: false, + requiredApprovals: null, + projectCount: 1, + apiTokenCount: 0, + enabledToggleCount: 0, + }); }); test('Can update sort order', async () => { diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts index f6733c5d10..d7cf035824 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts @@ -23,7 +23,6 @@ import { FeatureLifecycleReadModel } from './feature-lifecycle-read-model.js'; import type { IFeatureLifecycleReadModel } from './feature-lifecycle-read-model-type.js'; import { STAGE_ENTERED } from '../../metric-events.js'; import type ClientInstanceService from '../metrics/instance/instance-service.js'; -import { DEFAULT_ENV } from '../../server-impl.js'; let app: IUnleashTest; let db: ITestDb; @@ -34,9 +33,7 @@ let featureLifecycleReadModel: IFeatureLifecycleReadModel; let clientInstanceService: ClientInstanceService; beforeAll(async () => { - db = await dbInit('feature_lifecycle', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('feature_lifecycle', getLogger); app = await setupAppWithAuth( db.stores, { @@ -127,26 +124,27 @@ const getFeaturesLifecycleCount = async () => { }; test('should return lifecycle stages', async () => { + const environment = 'production'; // prod environment moves lifecycle to live stage await app.createFeature('my_feature_a'); - await app.enableFeature('my_feature_a', DEFAULT_ENV); + await app.enableFeature('my_feature_a', environment); eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_a' }); await reachedStage('my_feature_a', 'initial'); await expectFeatureStage('my_feature_a', 'initial'); eventBus.emit(CLIENT_METRICS_ADDED, [ { featureName: 'my_feature_a', - environment: DEFAULT_ENV, + environment: environment, }, { featureName: 'non_existent_feature', - environment: DEFAULT_ENV, + environment: environment, }, ]); // missing feature eventBus.emit(CLIENT_METRICS_ADDED, [ { - environment: DEFAULT_ENV, + environment: environment, yes: 0, no: 0, }, @@ -241,13 +239,14 @@ test('should backfill archived feature', async () => { }); test('should not backfill for existing lifecycle', async () => { + const environment = 'production'; // prod environment moves lifecycle to live stage await app.createFeature('my_feature_e'); - await app.enableFeature('my_feature_e', DEFAULT_ENV); + await app.enableFeature('my_feature_e', environment); eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_e' }); eventBus.emit(CLIENT_METRICS_ADDED, [ { featureName: 'my_feature_e', - environment: DEFAULT_ENV, + environment: environment, }, ]); await reachedStage('my_feature_e', 'live'); diff --git a/src/lib/features/feature-links/feature-link.e2e.test.ts b/src/lib/features/feature-links/feature-link.e2e.test.ts index 651ff64570..83a1a3c277 100644 --- a/src/lib/features/feature-links/feature-link.e2e.test.ts +++ b/src/lib/features/feature-links/feature-link.e2e.test.ts @@ -18,9 +18,7 @@ let eventStore: IEventStore; let featureLinkReadModel: IFeatureLinksReadModel; beforeAll(async () => { - db = await dbInit('feature_link', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('feature_link', getLogger); app = await setupAppWithAuth( db.stores, { diff --git a/src/lib/features/feature-search/feature.search.e2e.test.ts b/src/lib/features/feature-search/feature.search.e2e.test.ts index 63f3d48e24..4ad2150650 100644 --- a/src/lib/features/feature-search/feature.search.e2e.test.ts +++ b/src/lib/features/feature-search/feature.search.e2e.test.ts @@ -9,11 +9,9 @@ import { import getLogger from '../../../test/fixtures/no-logger.js'; import type { FeatureSearchQueryParameters } from '../../openapi/spec/feature-search-query-parameters.js'; import { - CREATE_FEATURE_STRATEGY, DEFAULT_PROJECT, type IUnleashStores, TEST_AUDIT_USER, - UPDATE_FEATURE_ENVIRONMENT, } from '../../types/index.js'; import { DEFAULT_ENV } from '../../util/index.js'; @@ -22,9 +20,7 @@ let db: ITestDb; let stores: IUnleashStores; beforeAll(async () => { - db = await dbInit('feature_search', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('feature_search', getLogger); app = await setupAppWithAuth( db.stores, { @@ -46,38 +42,6 @@ beforeAll(async () => { }) .expect(200); - await stores.environmentStore.create({ - name: 'development', - type: 'development', - }); - - await app.linkProjectToEnvironment('default', 'development'); - - await stores.accessStore.addPermissionsToRole( - body.rootRole, - [ - { name: UPDATE_FEATURE_ENVIRONMENT }, - { name: CREATE_FEATURE_STRATEGY }, - ], - 'development', - ); - - await stores.environmentStore.create({ - name: 'production', - type: 'production', - }); - - await app.linkProjectToEnvironment('default', 'production'); - - await stores.accessStore.addPermissionsToRole( - body.rootRole, - [ - { name: UPDATE_FEATURE_ENVIRONMENT }, - { name: CREATE_FEATURE_STRATEGY }, - ], - 'production', - ); - await app.services.userService.createUser( { username: 'admin@test.com', @@ -865,11 +829,6 @@ test('should return segments in payload with no duplicates/nulls', async () => { name: 'my_feature_a', segments: [mySegment.name], environments: [ - { - name: 'default', - hasStrategies: true, - hasEnabledStrategies: true, - }, { name: 'development', hasStrategies: true, @@ -1183,11 +1142,6 @@ test('should return environment usage metrics and lifecycle', async () => { name: 'my_feature_b', lifecycle: { stage: 'completed', status: 'discarded' }, environments: [ - { - name: 'default', - yes: 0, - no: 0, - }, { name: 'development', yes: 10, @@ -1448,7 +1402,6 @@ test('should return change request ids per environment', async () => { { name: 'my_feature_a', environments: [ - { name: 'default', changeRequestIds: [] }, { name: 'development', changeRequestIds: [5, 6, 7] }, { name: 'production', changeRequestIds: [1] }, ], @@ -1456,7 +1409,6 @@ test('should return change request ids per environment', async () => { { name: 'my_feature_b', environments: [ - { name: 'default', changeRequestIds: [] }, { name: 'development', changeRequestIds: [8] }, { name: 'production', changeRequestIds: [] }, ], @@ -1557,7 +1509,6 @@ test('should return release plan milestones', async () => { { name: 'my_feature_a', environments: [ - { name: 'default' }, { name: 'development', totalMilestones: 3, @@ -1569,6 +1520,5 @@ test('should return release plan milestones', async () => { }, ], }); - expect(body.features[0].environments[0].milestoneName).toBeUndefined(); - expect(body.features[0].environments[2].milestoneName).toBeUndefined(); + expect(body.features[0].environments[1].milestoneName).toBeUndefined(); }); diff --git a/src/lib/features/feature-toggle/tests/archive-feature-toggles.e2e.test.ts b/src/lib/features/feature-toggle/tests/archive-feature-toggles.e2e.test.ts index 5d0f14a78f..6192194462 100644 --- a/src/lib/features/feature-toggle/tests/archive-feature-toggles.e2e.test.ts +++ b/src/lib/features/feature-toggle/tests/archive-feature-toggles.e2e.test.ts @@ -11,9 +11,7 @@ let app: IUnleashTest; let db: ITestDb; beforeAll(async () => { - db = await dbInit('archive_test_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('archive_test_serial', getLogger); app = await setupAppWithCustomConfig( db.stores, { @@ -125,26 +123,6 @@ test('Should disable all environments when reviving a toggle', async () => { archived: true, createdByUserId: 9999, }); - - await db.stores.environmentStore.create({ - name: 'development', - enabled: true, - type: 'development', - sortOrder: 1, - }); - - await db.stores.environmentStore.create({ - name: 'production', - enabled: true, - type: 'production', - sortOrder: 2, - }); - - await db.stores.featureEnvironmentStore.addEnvironmentToFeature( - 'feat-proj-1', - 'default', - true, - ); await db.stores.featureEnvironmentStore.addEnvironmentToFeature( 'feat-proj-1', 'production', diff --git a/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts b/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts index 0c0f578f55..0682911929 100644 --- a/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts +++ b/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts @@ -64,9 +64,6 @@ beforeAll(async () => { db = await dbInit( 'feature_toggle_service_v2_service_serial', config.getLogger, - { - dbInitMethod: 'legacy' as const, - }, ); unleashConfig = config; stores = db.stores; diff --git a/src/lib/features/feature-toggle/tests/feature-toggles.auth.e2e.test.ts b/src/lib/features/feature-toggle/tests/feature-toggles.auth.e2e.test.ts index ae8626e259..1e5aef0ac9 100644 --- a/src/lib/features/feature-toggle/tests/feature-toggles.auth.e2e.test.ts +++ b/src/lib/features/feature-toggle/tests/feature-toggles.auth.e2e.test.ts @@ -17,9 +17,7 @@ let app: IUnleashTest; let db: ITestDb; beforeAll(async () => { - db = await dbInit('feature_strategy_auth_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('feature_strategy_auth_api_serial', getLogger); app = await setupAppWithAuth( db.stores, { diff --git a/src/lib/features/feature-toggle/tests/feature-toggles.e2e.test.ts b/src/lib/features/feature-toggle/tests/feature-toggles.e2e.test.ts index c32c862bfb..e94123353e 100644 --- a/src/lib/features/feature-toggle/tests/feature-toggles.e2e.test.ts +++ b/src/lib/features/feature-toggle/tests/feature-toggles.e2e.test.ts @@ -87,9 +87,7 @@ const updateStrategy = async ( }; beforeAll(async () => { - db = await dbInit('feature_strategy_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('feature_strategy_api_serial', getLogger); app = await setupAppWithCustomConfig( db.stores, { diff --git a/src/lib/features/frontend-api/frontend-api.e2e.test.ts b/src/lib/features/frontend-api/frontend-api.e2e.test.ts index 56f98cad81..afd3fe9895 100644 --- a/src/lib/features/frontend-api/frontend-api.e2e.test.ts +++ b/src/lib/features/frontend-api/frontend-api.e2e.test.ts @@ -27,9 +27,7 @@ let app: IUnleashTest; let db: ITestDb; let frontendApiService: FrontendApiService; beforeAll(async () => { - db = await dbInit('frontend_api', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('frontend_api', getLogger); app = await setupAppWithAuth( db.stores, { diff --git a/src/lib/features/metrics/instance/metrics.test.ts b/src/lib/features/metrics/instance/metrics.test.ts index 865407897c..0f729d9cb8 100644 --- a/src/lib/features/metrics/instance/metrics.test.ts +++ b/src/lib/features/metrics/instance/metrics.test.ts @@ -417,7 +417,7 @@ describe('bulk metrics', () => { }); }); - test('filters out metrics for environments we do not have access for. No auth setup so we can only access default env', async () => { + test('without access to production environment due to no auth setup, we can only access the default env', async () => { const now = new Date(); await request @@ -437,7 +437,7 @@ describe('bulk metrics', () => { { featureName: 'test_feature_two', appName: 'test_application', - environment: 'development', + environment: 'production', timestamp: startOfHour(now), yes: 1000, no: 800, diff --git a/src/lib/features/playground/advanced-playground.test.ts b/src/lib/features/playground/advanced-playground.test.ts index f071337026..159ddcbc08 100644 --- a/src/lib/features/playground/advanced-playground.test.ts +++ b/src/lib/features/playground/advanced-playground.test.ts @@ -13,9 +13,7 @@ let app: IUnleashTest; let db: ITestDb; beforeAll(async () => { - db = await dbInit('advanced_playground', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('advanced_playground', getLogger); app = await setupAppWithCustomConfig( db.stores, { diff --git a/src/lib/features/project-environments/environment-service.test.ts b/src/lib/features/project-environments/environment-service.test.ts index 6e64847c6f..0e45ffbaf6 100644 --- a/src/lib/features/project-environments/environment-service.test.ts +++ b/src/lib/features/project-environments/environment-service.test.ts @@ -5,6 +5,7 @@ import dbInit, { } from '../../../test/e2e/helpers/database-init.js'; import NotFoundError from '../../error/notfound-error.js'; import { + type IEnvironment, type IUnleashStores, SYSTEM_USER, SYSTEM_USER_AUDIT, @@ -13,54 +14,48 @@ import NameExistsError from '../../error/name-exists-error.js'; import type { EventService } from '../../services/index.js'; import { createEventsService } from '../events/createEventsService.js'; import { test, beforeAll, afterAll, expect } from 'vitest'; -import { DEFAULT_ENV } from '../../server-impl.js'; let stores: IUnleashStores; let db: ITestDb; let service: EnvironmentService; let eventService: EventService; +let createdEnvironment: IEnvironment; +let withApprovals: IEnvironment; beforeAll(async () => { const config = createTestConfig(); - db = await dbInit('environment_service_serial', config.getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('environment_service_serial', config.getLogger); stores = db.stores; eventService = createEventsService(db.rawDatabase, config); service = new EnvironmentService(stores, config, eventService); + + createdEnvironment = await db.stores.environmentStore.create({ + name: 'testenv', + type: 'production', + }); + + withApprovals = await db.stores.environmentStore.create({ + name: 'approval_env', + type: 'production', + requiredApprovals: 1, + }); }); + afterAll(async () => { await db.destroy(); }); test('Can get environment', async () => { - const created = await db.stores.environmentStore.create({ - name: 'testenv', - type: 'production', - }); - - const retrieved = await service.get('testenv'); - expect(retrieved).toEqual(created); + const retrieved = await service.get(createdEnvironment.name); + expect(retrieved).toEqual(createdEnvironment); }); test('Can get all', async () => { - await db.stores.environmentStore.create({ - name: 'testenv2', - type: 'production', - }); - const environments = await service.getAll(); - expect(environments).toHaveLength(3); // the one we created plus 'default' + expect(environments).toHaveLength(4); // the 2 created plus 'development' and 'production'' }); test('Can manage required approvals', async () => { - const created = await db.stores.environmentStore.create({ - name: 'approval_env', - type: 'production', - requiredApprovals: 1, - }); - - const retrieved = await service.get('approval_env'); - + const retrieved = await service.get(withApprovals.name); await db.stores.environmentStore.update( { type: 'production', @@ -77,13 +72,16 @@ test('Can manage required approvals', async () => { const changeRequestEnvs = await db.stores.environmentStore.getChangeRequestEnvironments([ 'approval_env', - DEFAULT_ENV, + 'development', 'other', ]); - expect(retrieved).toEqual(created); - expect(updated).toEqual({ ...created, requiredApprovals: 2 }); - expect(groupRetrieved).toMatchObject({ ...created, requiredApprovals: 2 }); + expect(retrieved).toEqual(withApprovals); + expect(updated).toEqual({ ...withApprovals, requiredApprovals: 2 }); + expect(groupRetrieved).toMatchObject({ + ...withApprovals, + requiredApprovals: 2, + }); expect(changeRequestEnvs).toEqual([ { name: 'approval_env', requiredApprovals: 2 }, ]); @@ -345,32 +343,22 @@ test('When given overrides should remap projects to override environments', asyn expect(projects).not.toContain('default'); }); -test('Override works correctly when enabling default and disabling prod and dev', async () => { - const defaultEnvironment = DEFAULT_ENV; - const prodEnvironment = 'production'; - const devEnvironment = 'development'; - +test('Override works correctly when enabling a custom environment and disabling prod and dev', async () => { + const newEnvironment = 'custom'; await db.stores.environmentStore.create({ - name: prodEnvironment, + name: newEnvironment, type: 'production', }); - - await db.stores.environmentStore.create({ - name: devEnvironment, - type: 'development', - }); - await service.toggleEnvironment(prodEnvironment, true); - await service.toggleEnvironment(devEnvironment, true); - - await service.overrideEnabledProjects([defaultEnvironment]); + await service.toggleEnvironment(newEnvironment, true); + await service.overrideEnabledProjects([newEnvironment]); const environments = await service.getAll(); const targetedEnvironment = environments.find( - (env) => env.name === defaultEnvironment, + (env) => env.name === newEnvironment, ); const allOtherEnvironments = environments - .filter((x) => x.name !== defaultEnvironment) + .filter((x) => x.name !== newEnvironment) .map((env) => env.enabled); const envNames = environments.map((x) => x.name); diff --git a/src/lib/features/project-environments/project-environments.e2e.test.ts b/src/lib/features/project-environments/project-environments.e2e.test.ts index 8ef35fc581..f7c6173747 100644 --- a/src/lib/features/project-environments/project-environments.e2e.test.ts +++ b/src/lib/features/project-environments/project-environments.e2e.test.ts @@ -12,9 +12,7 @@ let app: IUnleashTest; let db: ITestDb; beforeAll(async () => { - db = await dbInit('project_environments_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('project_environments_api_serial', getLogger); app = await setupAppWithCustomConfig( db.stores, { @@ -65,7 +63,7 @@ test('Should add environment to project', async () => { const environment = envs.find((env) => env.environment === 'test'); expect(environment).toBeDefined(); - expect(envs).toHaveLength(2); // test + default + expect(envs).toHaveLength(3); // test + development + production }); test('Should validate environment', async () => { diff --git a/src/lib/features/project/projects.e2e.test.ts b/src/lib/features/project/projects.e2e.test.ts index 802aec3f7d..8c183a94b2 100644 --- a/src/lib/features/project/projects.e2e.test.ts +++ b/src/lib/features/project/projects.e2e.test.ts @@ -16,9 +16,7 @@ let projectStore: IProjectStore; const testDate = '2023-10-01T12:34:56.000Z'; beforeAll(async () => { - db = await dbInit('projects_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('projects_api_serial', getLogger); app = await setupAppWithCustomConfig( db.stores, { diff --git a/src/lib/features/segment/admin-segment.e2e.test.ts b/src/lib/features/segment/admin-segment.e2e.test.ts index 80c9832492..ffd2fb7f81 100644 --- a/src/lib/features/segment/admin-segment.e2e.test.ts +++ b/src/lib/features/segment/admin-segment.e2e.test.ts @@ -121,7 +121,6 @@ beforeAll(async () => { anonymiseEventLog: true, }, }, - dbInitMethod: 'legacy' as const, }; db = await dbInit('segments_api_serial', getLogger, customOptions); diff --git a/src/lib/features/segment/client-segment.e2e.test.ts b/src/lib/features/segment/client-segment.e2e.test.ts index 79611b94c6..8cc8826ecd 100644 --- a/src/lib/features/segment/client-segment.e2e.test.ts +++ b/src/lib/features/segment/client-segment.e2e.test.ts @@ -197,9 +197,7 @@ const createTestSegments = async () => { }; beforeAll(async () => { - db = await dbInit('segments', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('segments', getLogger); app = await setupAppWithCustomConfig( db.stores, { diff --git a/src/lib/metrics.test.ts b/src/lib/metrics.test.ts index edf99ae52a..531ec6355c 100644 --- a/src/lib/metrics.test.ts +++ b/src/lib/metrics.test.ts @@ -128,7 +128,7 @@ test('should collect metrics for updated toggles', async () => { const metrics = await prometheusRegister.metrics(); expect(metrics).toMatch( - /feature_toggle_update_total\{toggle="TestToggle",project="default",environment="default",environmentType="production",action="updated"\} 1/, + /feature_toggle_update_total\{toggle="TestToggle",project="default",environment="n\/a",environmentType="n\/a",action="updated"\} 1/, ); }); diff --git a/src/lib/metrics.ts b/src/lib/metrics.ts index e92fec5836..a483c7313c 100644 --- a/src/lib/metrics.ts +++ b/src/lib/metrics.ts @@ -902,8 +902,8 @@ export function registerPrometheusMetrics( featureFlagUpdateTotal.increment({ toggle: featureName, project, - environment: 'default', - environmentType: 'production', + environment: 'n/a', + environmentType: 'n/a', action: 'updated', }); }); diff --git a/src/lib/openapi/spec/api-token-schema.ts b/src/lib/openapi/spec/api-token-schema.ts index 3172a92f0b..62b24adb4b 100644 --- a/src/lib/openapi/spec/api-token-schema.ts +++ b/src/lib/openapi/spec/api-token-schema.ts @@ -27,9 +27,9 @@ export const apiTokenSchema = { }, environment: { type: 'string', - description: - 'The environment the token has access to. `*` if it has access to all environments.', + description: 'The environment the token has access to.', example: 'development', + default: 'development', }, project: { type: 'string', diff --git a/src/lib/schema/api-token-schema.ts b/src/lib/schema/api-token-schema.ts index 00078d3888..a8925ba1ba 100644 --- a/src/lib/schema/api-token-schema.ts +++ b/src/lib/schema/api-token-schema.ts @@ -1,7 +1,6 @@ import joi from 'joi'; import { ALL } from '../types/models/api-token.js'; import { ApiTokenType } from '../types/model.js'; -import { DEFAULT_ENV } from '../util/constants.js'; export const createApiToken = joi .object() @@ -14,10 +13,6 @@ export const createApiToken = joi .valid(ApiTokenType.CLIENT, ApiTokenType.FRONTEND), expiresAt: joi.date().optional(), projects: joi.array().min(1).optional().default([ALL]), - environment: joi.when('type', { - is: joi.string().valid(ApiTokenType.CLIENT, ApiTokenType.FRONTEND), - then: joi.string().optional().default(DEFAULT_ENV), - otherwise: joi.string().optional().default(ALL), - }), + environment: joi.string().optional().default('development'), }) .options({ stripUnknown: true, allowUnknown: false, abortEarly: false }); diff --git a/src/lib/util/constants.ts b/src/lib/util/constants.ts index af28acb4cb..3143134385 100644 --- a/src/lib/util/constants.ts +++ b/src/lib/util/constants.ts @@ -1,4 +1,4 @@ -export const DEFAULT_ENV = 'default'; +export const DEFAULT_ENV = 'development'; export const ALL_PROJECTS = '*'; export const ALL_ENVS = '*'; diff --git a/src/migrations/20250604110546-remove-default-env-from-new-installs.js b/src/migrations/20250604110546-remove-default-env-from-new-installs.js new file mode 100644 index 0000000000..c9aed4a3cb --- /dev/null +++ b/src/migrations/20250604110546-remove-default-env-from-new-installs.js @@ -0,0 +1,23 @@ +'use strict'; + +exports.up = function(db, cb) { + db.runSql( + `SELECT count(*) as count FROM events;`, + (err, results) => { + if (Number(results.rows[0].count) === 4) { + // If there are exactly 4 events, it means this is a new install + db.runSql( + `DELETE FROM environments WHERE name = 'default';`, + + cb); + } else { + // If there are not exactly 4 events, do nothing + cb(); + } + }, + ); +}; + +exports.down = function(db, cb) { + cb(); +}; diff --git a/src/test/e2e/api/admin/context.e2e.test.ts b/src/test/e2e/api/admin/context.e2e.test.ts index de942a513d..f800fd5a34 100644 --- a/src/test/e2e/api/admin/context.e2e.test.ts +++ b/src/test/e2e/api/admin/context.e2e.test.ts @@ -11,9 +11,7 @@ let db: ITestDb; let app: IUnleashTest; beforeAll(async () => { - db = await dbInit('context_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('context_api_serial', getLogger); app = await setupAppWithCustomConfig( db.stores, { @@ -34,13 +32,15 @@ afterAll(async () => { test('gets all context fields', async () => { expect.assertions(1); - return app.request + const { body } = await app.request .get('/api/admin/context') .expect('Content-Type', /json/) - .expect(200) - .expect((res) => { - expect(res.body.length).toBe(3); - }); + .expect(200); + + // because tests share the database, we might have more fields than expected + expect(body.map((field) => field.name)).toEqual( + expect.arrayContaining(['environment', 'userId', 'sessionId']), + ); }); test('get the context field', async () => { diff --git a/src/test/e2e/api/admin/instance-admin.e2e.test.ts b/src/test/e2e/api/admin/instance-admin.e2e.test.ts index d9d537840d..35496e8e88 100644 --- a/src/test/e2e/api/admin/instance-admin.e2e.test.ts +++ b/src/test/e2e/api/admin/instance-admin.e2e.test.ts @@ -15,9 +15,7 @@ let stores: IUnleashStores; let refreshDbMetrics: () => Promise; beforeAll(async () => { - db = await dbInit('instance_admin_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('instance_admin_api_serial', getLogger); stores = db.stores; await stores.settingStore.insert('instanceInfo', { id: 'test-static' }); app = await setupAppWithCustomConfig( @@ -126,7 +124,7 @@ test('should return signed instance statistics', async () => { .expect((res) => { expect(res.body.instanceId).toBe('test-static'); expect(res.body.sum).toBe( - '5ba2cb7c3e29f4e5b3382c560b92b837f3603dc7db73a501ec331c7f0ed17bd0', + 'd9bac94bba7afa20d98f0a9d54a84b79a6668f8103b8f89db85d05d38e84f519', ); }); }); diff --git a/src/test/e2e/api/admin/metrics.e2e.test.ts b/src/test/e2e/api/admin/metrics.e2e.test.ts index 92779d2b35..641ff12147 100644 --- a/src/test/e2e/api/admin/metrics.e2e.test.ts +++ b/src/test/e2e/api/admin/metrics.e2e.test.ts @@ -11,9 +11,7 @@ let app: IUnleashTest; let db: ITestDb; beforeAll(async () => { - db = await dbInit('metrics_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('metrics_serial', getLogger); app = await setupAppWithCustomConfig( db.stores, { @@ -179,9 +177,9 @@ test('should save multiple projects from token', async () => { .expect('Content-Type', /json/) .expect(200); - expect(body).toMatchObject({ - applications: [ - { + expect(body.applications).toEqual( + expect.arrayContaining([ + expect.objectContaining({ appName: 'multi-project-app', usage: [ { @@ -193,8 +191,7 @@ test('should save multiple projects from token', async () => { project: 'mainProject', }, ], - }, - ], - total: 1, - }); + }), + ]), + ); }); diff --git a/src/test/e2e/api/admin/project/project.health.e2e.test.ts b/src/test/e2e/api/admin/project/project.health.e2e.test.ts index 5e0f6454ef..c1e35ea5fa 100644 --- a/src/test/e2e/api/admin/project/project.health.e2e.test.ts +++ b/src/test/e2e/api/admin/project/project.health.e2e.test.ts @@ -12,9 +12,7 @@ let db: ITestDb; let user: IUser; beforeAll(async () => { - db = await dbInit('project_health_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('project_health_api_serial', getLogger); app = await setupAppWithCustomConfig( db.stores, { diff --git a/src/test/e2e/api/admin/strategy.e2e.test.ts b/src/test/e2e/api/admin/strategy.e2e.test.ts index 8d559af4da..36fc5b0393 100644 --- a/src/test/e2e/api/admin/strategy.e2e.test.ts +++ b/src/test/e2e/api/admin/strategy.e2e.test.ts @@ -9,9 +9,7 @@ let app: IUnleashTest; let db: ITestDb; beforeAll(async () => { - db = await dbInit('strategy_api_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('strategy_api_serial', getLogger); app = await setupAppWithCustomConfig(db.stores, { experimental: { flags: { @@ -19,6 +17,16 @@ beforeAll(async () => { }, }, }); + await db.stores.strategyStore.createStrategy({ + name: 'toBeDeleted', + description: 'toBeDeleted strategy', + parameters: [], + }); + await db.stores.strategyStore.createStrategy({ + name: 'toBeUpdated', + description: 'toBeUpdated strategy', + parameters: [], + }); }); afterAll(async () => { @@ -29,13 +37,11 @@ afterAll(async () => { test('gets all strategies', async () => { expect.assertions(1); - return app.request + const { body } = await app.request .get('/api/admin/strategies') .expect('Content-Type', /json/) - .expect(200) - .expect((res) => { - expect(res.body.strategies).toHaveLength(3); - }); + .expect(200); + expect(body.strategies).toHaveLength(6); }); test('gets a strategy by name', async () => { @@ -93,9 +99,7 @@ test('refuses to create a strategy with an existing name', async () => { test('deletes a new strategy', async () => { expect.assertions(0); - return app.request - .delete('/api/admin/strategies/usersWithEmail') - .expect(200); + return app.request.delete('/api/admin/strategies/toBeDeleted').expect(200); }); test("can't delete a strategy that dose not exist", async () => { @@ -108,10 +112,10 @@ test('updates a exiting strategy', async () => { expect.assertions(0); return app.request - .put('/api/admin/strategies/default') + .put('/api/admin/strategies/toBeUpdated') .send({ - name: 'default', - description: 'Default is the best!', + name: 'toBeUpdated', + description: 'toBeUpdated is the best!', parameters: [], }) .set('Content-Type', 'application/json') diff --git a/src/test/e2e/api/client/feature.env.disabled.e2e.test.ts b/src/test/e2e/api/client/feature.env.disabled.e2e.test.ts index 816f689b11..abb1c0eaad 100644 --- a/src/test/e2e/api/client/feature.env.disabled.e2e.test.ts +++ b/src/test/e2e/api/client/feature.env.disabled.e2e.test.ts @@ -15,9 +15,7 @@ const userId = -9999; const projectId = 'default'; beforeAll(async () => { - db = await dbInit('feature_env_api_client', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('feature_env_api_client', getLogger); app = await setupAppWithCustomConfig(db.stores, {}, db.rawDatabase); await app.services.featureToggleService.createFeatureToggle( diff --git a/src/test/e2e/api/client/feature.optimal304.e2e.test.ts b/src/test/e2e/api/client/feature.optimal304.e2e.test.ts index f852106ff1..b6651bf39e 100644 --- a/src/test/e2e/api/client/feature.optimal304.e2e.test.ts +++ b/src/test/e2e/api/client/feature.optimal304.e2e.test.ts @@ -152,26 +152,26 @@ describe.each([ .expect(200); if (etagVariant.feature_enabled) { - expect(res.headers.etag).toBe(`"61824cd0:16:${etagVariant.name}"`); + expect(res.headers.etag).toBe(`"76d8bb0e:16:${etagVariant.name}"`); expect(res.body.meta.etag).toBe( - `"61824cd0:16:${etagVariant.name}"`, + `"76d8bb0e:16:${etagVariant.name}"`, ); } else { - expect(res.headers.etag).toBe('"61824cd0:16"'); - expect(res.body.meta.etag).toBe('"61824cd0:16"'); + expect(res.headers.etag).toBe('"76d8bb0e:16"'); + expect(res.body.meta.etag).toBe('"76d8bb0e:16"'); } }); test(`returns ${etagVariant.feature_enabled ? 200 : 304} for pre-calculated hash${etagVariant.feature_enabled ? ' because hash changed' : ''}`, async () => { const res = await app.request .get('/api/client/features') - .set('if-none-match', '"61824cd0:16"') + .set('if-none-match', '"76d8bb0e:16"') .expect(etagVariant.feature_enabled ? 200 : 304); if (etagVariant.feature_enabled) { - expect(res.headers.etag).toBe(`"61824cd0:16:${etagVariant.name}"`); + expect(res.headers.etag).toBe(`"76d8bb0e:16:${etagVariant.name}"`); expect(res.body.meta.etag).toBe( - `"61824cd0:16:${etagVariant.name}"`, + `"76d8bb0e:16:${etagVariant.name}"`, ); } }); @@ -193,13 +193,13 @@ describe.each([ .expect(200); if (etagVariant.feature_enabled) { - expect(res.headers.etag).toBe(`"61824cd0:16:${etagVariant.name}"`); + expect(res.headers.etag).toBe(`"76d8bb0e:16:${etagVariant.name}"`); expect(res.body.meta.etag).toBe( - `"61824cd0:16:${etagVariant.name}"`, + `"76d8bb0e:16:${etagVariant.name}"`, ); } else { - expect(res.headers.etag).toBe('"61824cd0:16"'); - expect(res.body.meta.etag).toBe('"61824cd0:16"'); + expect(res.headers.etag).toBe('"76d8bb0e:16"'); + expect(res.body.meta.etag).toBe('"76d8bb0e:16"'); } }); }); diff --git a/src/test/e2e/api/client/metricsV2.e2e.test.ts b/src/test/e2e/api/client/metricsV2.e2e.test.ts index a1d080dc49..98ca918b89 100644 --- a/src/test/e2e/api/client/metricsV2.e2e.test.ts +++ b/src/test/e2e/api/client/metricsV2.e2e.test.ts @@ -16,9 +16,7 @@ let db: ITestDb; let defaultToken: IApiToken; beforeAll(async () => { - db = await dbInit('metrics_two_api_client', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('metrics_two_api_client', getLogger); app = await setupAppWithAuth(db.stores, {}, db.rawDatabase); defaultToken = await app.services.apiTokenService.createApiTokenWithProjects({ diff --git a/src/test/e2e/api/client/register.e2e.test.ts b/src/test/e2e/api/client/register.e2e.test.ts index f47345e28d..678347cb49 100644 --- a/src/test/e2e/api/client/register.e2e.test.ts +++ b/src/test/e2e/api/client/register.e2e.test.ts @@ -15,9 +15,7 @@ let app: IUnleashTest; let db: ITestDb; beforeAll(async () => { - db = await dbInit('register_client', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('register_client', getLogger); app = await setupApp(db.stores); }); diff --git a/src/test/e2e/helpers/database-init.ts b/src/test/e2e/helpers/database-init.ts index 03bd7f5db4..439e991f66 100644 --- a/src/test/e2e/helpers/database-init.ts +++ b/src/test/e2e/helpers/database-init.ts @@ -1,16 +1,11 @@ import { log } from 'db-migrate-shared'; -import { migrateDb } from '../../../migrator.js'; import { createStores } from '../../../lib/db/index.js'; import { createDb } from '../../../lib/db/db-pool.js'; import { getDbConfig } from './database-config.js'; import { createTestConfig } from '../../config/test-config.js'; -import dbState from './database.json' with { type: 'json' }; import type { LogProvider } from '../../../lib/logger.js'; import noLoggerProvider from '../../fixtures/no-logger.js'; -import type EnvironmentStore from '../../../lib/features/project-environments/environment-store.js'; import type { IUnleashStores } from '../../../lib/types/index.js'; -import type { IFeatureEnvironmentStore } from '../../../lib/types/stores/feature-environment-store.js'; -import { DEFAULT_ENV } from '../../../lib/util/constants.js'; import type { IUnleashConfig, IUnleashOptions, @@ -27,72 +22,6 @@ process.setMaxListeners(0); export const testDbPrefix = 'unleashtestdb_'; -async function getDefaultEnvRolePermissions(knex) { - return knex.table('role_permission').whereIn('environment', ['default']); -} - -async function restoreRolePermissions(knex, rolePermissions) { - await knex.table('role_permission').insert(rolePermissions); -} - -async function resetDatabase(knex) { - return Promise.all([ - knex - .table('environments') - .del(), // deletes role permissions transitively - knex.table('strategies').del(), - knex.table('features').del(), - knex.table('client_applications').del(), - knex.table('client_instances').del(), - knex.table('context_fields').del(), - knex.table('users').del(), - knex.table('projects').del(), - knex.table('tags').del(), - knex.table('tag_types').del(), - knex.table('addons').del(), - knex.table('users').del(), - knex.table('api_tokens').del(), - knex.table('api_token_project').del(), - knex - .table('reset_tokens') - .del(), - // knex.table('settings').del(), - ]); -} - -function createStrategies(store) { - return dbState.strategies.map((s) => store.createStrategy(s)); -} - -function createContextFields(store) { - return dbState.contextFields.map((c) => store.create(c)); -} - -function createProjects(store) { - return dbState.projects.map((i) => store.create(i)); -} - -function createTagTypes(store) { - return dbState.tag_types.map((t) => store.createTagType(t)); -} - -async function connectProject(store: IFeatureEnvironmentStore): Promise { - await store.connectProject(DEFAULT_ENV, 'default'); -} - -async function createEnvironments(store: EnvironmentStore): Promise { - await Promise.all(dbState.environments.map(async (e) => store.create(e))); -} - -async function setupDatabase(stores) { - await createEnvironments(stores.environmentStore); - await Promise.all(createStrategies(stores.strategyStore)); - await Promise.all(createContextFields(stores.contextFieldStore)); - await Promise.all(createProjects(stores.projectStore)); - await Promise.all(createTagTypes(stores.tagTypeStore)); - await connectProject(stores.featureEnvironmentStore); -} - export interface ITestDb { config: IUnleashConfig; stores: IUnleashStores; @@ -102,7 +31,6 @@ export interface ITestDb { } type DBTestOptions = { - dbInitMethod?: 'legacy' | 'template'; stopMigrationAt?: string; // filename where migration should stop }; @@ -112,16 +40,12 @@ export default async function init( configOverride: Partial = {}, ): Promise { const testDbName = `${testDbPrefix}${uuidv4().replace(/-/g, '')}`; - const useDbTemplate = - (configOverride.dbInitMethod ?? 'template') === 'template'; const testDBTemplateName = process.env.TEST_DB_TEMPLATE_NAME; const config = createTestConfig({ db: { ...getDbConfig(), pool: { min: 1, max: 4 }, - ...(useDbTemplate - ? { database: testDbName } - : { schema: databaseSchema }), + database: testDbName, ssl: false, }, ...configOverride, @@ -130,55 +54,30 @@ export default async function init( log.setLogLevel('error'); - if (useDbTemplate) { - if (!testDBTemplateName) { - throw new Error( - 'TEST_DB_TEMPLATE_NAME environment variable is not set', - ); - } - const client = new Client(getDbConfig()); - await client.connect(); - - await client.query( - `CREATE DATABASE ${testDbName} TEMPLATE ${testDBTemplateName}`, + if (!testDBTemplateName) { + throw new Error( + 'TEST_DB_TEMPLATE_NAME environment variable is not set', ); - await client.query(`ALTER DATABASE ${testDbName} SET TIMEZONE TO UTC`); - - await client.end(); - } else { - const db = createDb(config); - - await db.raw(`DROP SCHEMA IF EXISTS ${config.db.schema} CASCADE`); - await db.raw(`CREATE SCHEMA IF NOT EXISTS ${config.db.schema}`); - await migrateDb(config, configOverride.stopMigrationAt); - await db.destroy(); } + const client = new Client(getDbConfig()); + await client.connect(); + + await client.query( + `CREATE DATABASE ${testDbName} TEMPLATE ${testDBTemplateName}`, + ); + await client.query(`ALTER DATABASE ${testDbName} SET TIMEZONE TO UTC`); + + await client.end(); const testDb = createDb(config); const stores = createStores(config, testDb); stores.eventStore.setMaxListeners(0); - if (!useDbTemplate) { - const defaultRolePermissions = - await getDefaultEnvRolePermissions(testDb); - await resetDatabase(testDb); - await setupDatabase(stores); - await restoreRolePermissions(testDb, defaultRolePermissions); - } - return { config, rawDatabase: testDb, stores, - reset: async () => { - if (!useDbTemplate) { - const defaultRolePermissions = - await getDefaultEnvRolePermissions(testDb); - await resetDatabase(testDb); - await setupDatabase(stores); - await restoreRolePermissions(testDb, defaultRolePermissions); - } - }, + reset: async () => {}, destroy: async () => { return new Promise((resolve, reject) => { testDb.destroy((error) => (error ? reject(error) : resolve())); diff --git a/src/test/e2e/stores/api-token-store.e2e.test.ts b/src/test/e2e/stores/api-token-store.e2e.test.ts index a8b62950ba..57b6959aa7 100644 --- a/src/test/e2e/stores/api-token-store.e2e.test.ts +++ b/src/test/e2e/stores/api-token-store.e2e.test.ts @@ -8,9 +8,7 @@ let stores: IUnleashStores; let db: ITestDb; beforeAll(async () => { - db = await dbInit('api_token_store_serial', getLogger, { - dbInitMethod: 'legacy' as const, - }); + db = await dbInit('api_token_store_serial', getLogger); stores = db.stores; });