diff --git a/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts b/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts index 2114215b06..cf8c344616 100644 --- a/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts +++ b/src/lib/features/feature-lifecycle/createFeatureLifecycle.ts @@ -9,8 +9,10 @@ import { FeatureLifecycleStore } from './feature-lifecycle-store'; import EnvironmentStore from '../project-environments/environment-store'; import EventService from '../events/event-service'; import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store'; -import { EventEmitter } from 'stream'; import FeatureTagStore from '../../db/feature-tag-store'; +import { FeatureEnvironmentStore } from '../../db/feature-environment-store'; +import FakeFeatureEnvironmentStore from '../../../test/fixtures/fake-feature-environment-store'; +import EventEmitter from 'events'; export const createFeatureLifecycleService = ( db: Db, @@ -20,6 +22,11 @@ export const createFeatureLifecycleService = ( const eventStore = new EventStore(db, getLogger); const featureLifecycleStore = new FeatureLifecycleStore(db); const environmentStore = new EnvironmentStore(db, eventBus, getLogger); + const featureEnvironmentStore = new FeatureEnvironmentStore( + db, + eventBus, + getLogger, + ); const featureTagStore = new FeatureTagStore( db, config.eventBus, @@ -34,6 +41,7 @@ export const createFeatureLifecycleService = ( eventStore, featureLifecycleStore, environmentStore, + featureEnvironmentStore, }, { eventService, @@ -53,6 +61,7 @@ export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => { const eventStore = new FakeEventStore(); const featureLifecycleStore = new FakeFeatureLifecycleStore(); const environmentStore = new FakeEnvironmentStore(); + const featureEnvironmentStore = new FakeFeatureEnvironmentStore(); const eventService = new EventService( { eventStore, featureTagStore: new FakeFeatureTagStore() }, config, @@ -62,6 +71,7 @@ export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => { eventStore, featureLifecycleStore, environmentStore, + featureEnvironmentStore, }, { eventService, @@ -74,5 +84,6 @@ export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => { featureLifecycleStore, eventStore, environmentStore, + featureEnvironmentStore, }; }; diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts index 431a4208c4..82f5f962bc 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-service.test.ts @@ -15,13 +15,22 @@ import noLoggerProvider from '../../../test/fixtures/no-logger'; test('can insert and read lifecycle stages', async () => { const eventBus = new EventEmitter(); - const { featureLifecycleService, eventStore, environmentStore } = - createFakeFeatureLifecycleService({ - flagResolver: { isEnabled: () => true }, - eventBus, - getLogger: noLoggerProvider, - } as unknown as IUnleashConfig); + const { + featureLifecycleService, + eventStore, + environmentStore, + featureEnvironmentStore, + } = createFakeFeatureLifecycleService({ + flagResolver: { isEnabled: () => true }, + eventBus, + getLogger: noLoggerProvider, + } as unknown as IUnleashConfig); const featureName = 'testFeature'; + await featureEnvironmentStore.addEnvironmentToFeature( + featureName, + 'my-prod-environment', + true, + ); function emitMetricsEvent(environment: string) { eventBus.emit(CLIENT_METRICS, { diff --git a/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts b/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts index 604ebffdc5..351a1e7a71 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle-service.ts @@ -8,6 +8,7 @@ import { type IAuditUser, type IEnvironmentStore, type IEventStore, + type IFeatureEnvironmentStore, type IFlagResolver, type IUnleashConfig, } from '../../types'; @@ -29,6 +30,8 @@ export class FeatureLifecycleService extends EventEmitter { private environmentStore: IEnvironmentStore; + private featureEnvironmentStore: IFeatureEnvironmentStore; + private flagResolver: IFlagResolver; private eventBus: EventEmitter; @@ -42,10 +45,12 @@ export class FeatureLifecycleService extends EventEmitter { eventStore, featureLifecycleStore, environmentStore, + featureEnvironmentStore, }: { eventStore: IEventStore; environmentStore: IEnvironmentStore; featureLifecycleStore: IFeatureLifecycleStore; + featureEnvironmentStore: IFeatureEnvironmentStore; }, { eventService, @@ -62,6 +67,7 @@ export class FeatureLifecycleService extends EventEmitter { this.eventStore = eventStore; this.featureLifecycleStore = featureLifecycleStore; this.environmentStore = environmentStore; + this.featureEnvironmentStore = featureEnvironmentStore; this.flagResolver = flagResolver; this.eventBus = eventBus; this.eventService = eventService; @@ -140,7 +146,15 @@ export class FeatureLifecycleService extends EventEmitter { } await this.stageReceivedMetrics(features, 'pre-live'); if (env.type === 'production') { - await this.stageReceivedMetrics(features, 'live'); + const featureEnv = + await this.featureEnvironmentStore.getAllByFeatures( + features, + env.name, + ); + const enabledFeatures = featureEnv + .filter((feature) => feature.enabled) + .map((feature) => feature.featureName); + await this.stageReceivedMetrics(enabledFeatures, 'live'); } } catch (e) { this.logger.warn( 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 252456f442..8902f9ba44 100644 --- a/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts +++ b/src/lib/features/feature-lifecycle/feature-lifecycle.e2e.test.ts @@ -98,6 +98,7 @@ const expectFeatureStage = async (featureName: string, stage: StageName) => { test('should return lifecycle stages', async () => { await app.createFeature('my_feature_a'); + await app.enableFeature('my_feature_a', 'default'); eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_a' }); await reachedStage('initial'); await expectFeatureStage('my_feature_a', 'initial'); diff --git a/src/test/fixtures/fake-feature-environment-store.ts b/src/test/fixtures/fake-feature-environment-store.ts index da9d3d3af5..82ba2de6cb 100644 --- a/src/test/fixtures/fake-feature-environment-store.ts +++ b/src/test/fixtures/fake-feature-environment-store.ts @@ -233,12 +233,16 @@ export default class FakeFeatureEnvironmentStore throw new Error('Method not implemented.'); } - getAllByFeatures( + async getAllByFeatures( // eslint-disable-next-line @typescript-eslint/no-unused-vars features: string[], // eslint-disable-next-line @typescript-eslint/no-unused-vars environment?: string, ): Promise { - throw new Error('Method not implemented.'); + return this.featureEnvironments.filter( + (featureEnv) => + (environment ? featureEnv.environment === environment : true) && + features.includes(featureEnv.featureName), + ); } }