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

feat: Check production enabled live stage (#6952)

This commit is contained in:
Mateusz Kwasniewski 2024-04-26 13:38:25 +02:00 committed by GitHub
parent 514a18bf93
commit 49e84d3a91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 49 additions and 10 deletions

View File

@ -9,8 +9,10 @@ import { FeatureLifecycleStore } from './feature-lifecycle-store';
import EnvironmentStore from '../project-environments/environment-store'; import EnvironmentStore from '../project-environments/environment-store';
import EventService from '../events/event-service'; import EventService from '../events/event-service';
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store'; import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
import { EventEmitter } from 'stream';
import FeatureTagStore from '../../db/feature-tag-store'; 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 = ( export const createFeatureLifecycleService = (
db: Db, db: Db,
@ -20,6 +22,11 @@ export const createFeatureLifecycleService = (
const eventStore = new EventStore(db, getLogger); const eventStore = new EventStore(db, getLogger);
const featureLifecycleStore = new FeatureLifecycleStore(db); const featureLifecycleStore = new FeatureLifecycleStore(db);
const environmentStore = new EnvironmentStore(db, eventBus, getLogger); const environmentStore = new EnvironmentStore(db, eventBus, getLogger);
const featureEnvironmentStore = new FeatureEnvironmentStore(
db,
eventBus,
getLogger,
);
const featureTagStore = new FeatureTagStore( const featureTagStore = new FeatureTagStore(
db, db,
config.eventBus, config.eventBus,
@ -34,6 +41,7 @@ export const createFeatureLifecycleService = (
eventStore, eventStore,
featureLifecycleStore, featureLifecycleStore,
environmentStore, environmentStore,
featureEnvironmentStore,
}, },
{ {
eventService, eventService,
@ -53,6 +61,7 @@ export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => {
const eventStore = new FakeEventStore(); const eventStore = new FakeEventStore();
const featureLifecycleStore = new FakeFeatureLifecycleStore(); const featureLifecycleStore = new FakeFeatureLifecycleStore();
const environmentStore = new FakeEnvironmentStore(); const environmentStore = new FakeEnvironmentStore();
const featureEnvironmentStore = new FakeFeatureEnvironmentStore();
const eventService = new EventService( const eventService = new EventService(
{ eventStore, featureTagStore: new FakeFeatureTagStore() }, { eventStore, featureTagStore: new FakeFeatureTagStore() },
config, config,
@ -62,6 +71,7 @@ export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => {
eventStore, eventStore,
featureLifecycleStore, featureLifecycleStore,
environmentStore, environmentStore,
featureEnvironmentStore,
}, },
{ {
eventService, eventService,
@ -74,5 +84,6 @@ export const createFakeFeatureLifecycleService = (config: IUnleashConfig) => {
featureLifecycleStore, featureLifecycleStore,
eventStore, eventStore,
environmentStore, environmentStore,
featureEnvironmentStore,
}; };
}; };

View File

@ -15,13 +15,22 @@ import noLoggerProvider from '../../../test/fixtures/no-logger';
test('can insert and read lifecycle stages', async () => { test('can insert and read lifecycle stages', async () => {
const eventBus = new EventEmitter(); const eventBus = new EventEmitter();
const { featureLifecycleService, eventStore, environmentStore } = const {
createFakeFeatureLifecycleService({ featureLifecycleService,
flagResolver: { isEnabled: () => true }, eventStore,
eventBus, environmentStore,
getLogger: noLoggerProvider, featureEnvironmentStore,
} as unknown as IUnleashConfig); } = createFakeFeatureLifecycleService({
flagResolver: { isEnabled: () => true },
eventBus,
getLogger: noLoggerProvider,
} as unknown as IUnleashConfig);
const featureName = 'testFeature'; const featureName = 'testFeature';
await featureEnvironmentStore.addEnvironmentToFeature(
featureName,
'my-prod-environment',
true,
);
function emitMetricsEvent(environment: string) { function emitMetricsEvent(environment: string) {
eventBus.emit(CLIENT_METRICS, { eventBus.emit(CLIENT_METRICS, {

View File

@ -8,6 +8,7 @@ import {
type IAuditUser, type IAuditUser,
type IEnvironmentStore, type IEnvironmentStore,
type IEventStore, type IEventStore,
type IFeatureEnvironmentStore,
type IFlagResolver, type IFlagResolver,
type IUnleashConfig, type IUnleashConfig,
} from '../../types'; } from '../../types';
@ -29,6 +30,8 @@ export class FeatureLifecycleService extends EventEmitter {
private environmentStore: IEnvironmentStore; private environmentStore: IEnvironmentStore;
private featureEnvironmentStore: IFeatureEnvironmentStore;
private flagResolver: IFlagResolver; private flagResolver: IFlagResolver;
private eventBus: EventEmitter; private eventBus: EventEmitter;
@ -42,10 +45,12 @@ export class FeatureLifecycleService extends EventEmitter {
eventStore, eventStore,
featureLifecycleStore, featureLifecycleStore,
environmentStore, environmentStore,
featureEnvironmentStore,
}: { }: {
eventStore: IEventStore; eventStore: IEventStore;
environmentStore: IEnvironmentStore; environmentStore: IEnvironmentStore;
featureLifecycleStore: IFeatureLifecycleStore; featureLifecycleStore: IFeatureLifecycleStore;
featureEnvironmentStore: IFeatureEnvironmentStore;
}, },
{ {
eventService, eventService,
@ -62,6 +67,7 @@ export class FeatureLifecycleService extends EventEmitter {
this.eventStore = eventStore; this.eventStore = eventStore;
this.featureLifecycleStore = featureLifecycleStore; this.featureLifecycleStore = featureLifecycleStore;
this.environmentStore = environmentStore; this.environmentStore = environmentStore;
this.featureEnvironmentStore = featureEnvironmentStore;
this.flagResolver = flagResolver; this.flagResolver = flagResolver;
this.eventBus = eventBus; this.eventBus = eventBus;
this.eventService = eventService; this.eventService = eventService;
@ -140,7 +146,15 @@ export class FeatureLifecycleService extends EventEmitter {
} }
await this.stageReceivedMetrics(features, 'pre-live'); await this.stageReceivedMetrics(features, 'pre-live');
if (env.type === 'production') { 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) { } catch (e) {
this.logger.warn( this.logger.warn(

View File

@ -98,6 +98,7 @@ const expectFeatureStage = async (featureName: string, stage: StageName) => {
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');
eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_a' }); eventStore.emit(FEATURE_CREATED, { featureName: 'my_feature_a' });
await reachedStage('initial'); await reachedStage('initial');
await expectFeatureStage('my_feature_a', 'initial'); await expectFeatureStage('my_feature_a', 'initial');

View File

@ -233,12 +233,16 @@ export default class FakeFeatureEnvironmentStore
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
getAllByFeatures( async getAllByFeatures(
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
features: string[], features: string[],
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
environment?: string, environment?: string,
): Promise<IFeatureEnvironment[]> { ): Promise<IFeatureEnvironment[]> {
throw new Error('Method not implemented.'); return this.featureEnvironments.filter(
(featureEnv) =>
(environment ? featureEnv.environment === environment : true) &&
features.includes(featureEnv.featureName),
);
} }
} }