mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-24 17:51:14 +02:00
Fix
This commit is contained in:
parent
327454f81c
commit
efcad967d6
@ -14,32 +14,6 @@ import EventEmitter from 'events';
|
|||||||
import noLoggerProvider from '../../../test/fixtures/no-logger.js';
|
import noLoggerProvider from '../../../test/fixtures/no-logger.js';
|
||||||
import { STAGE_ENTERED } from '../../metric-events.js';
|
import { STAGE_ENTERED } from '../../metric-events.js';
|
||||||
|
|
||||||
function emitMetricsEvent(
|
|
||||||
eventBus: EventEmitter,
|
|
||||||
featureName: string,
|
|
||||||
environment: string,
|
|
||||||
) {
|
|
||||||
eventBus.emit(CLIENT_METRICS_ADDED, [
|
|
||||||
{
|
|
||||||
featureName,
|
|
||||||
environment,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function reachedStage(
|
|
||||||
eventBus: EventEmitter,
|
|
||||||
feature: string,
|
|
||||||
name: StageName,
|
|
||||||
) {
|
|
||||||
return new Promise((resolve) =>
|
|
||||||
eventBus.on(STAGE_ENTERED, (event) => {
|
|
||||||
if (event.stage === name && event.feature === feature)
|
|
||||||
resolve(name);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
const {
|
||||||
@ -59,6 +33,23 @@ test('can insert and read lifecycle stages', async () => {
|
|||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function emitMetricsEvent(environment: string) {
|
||||||
|
eventBus.emit(CLIENT_METRICS_ADDED, [
|
||||||
|
{
|
||||||
|
featureName,
|
||||||
|
environment,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
function reachedStage(feature: string, name: StageName) {
|
||||||
|
return new Promise((resolve) =>
|
||||||
|
eventBus.on(STAGE_ENTERED, (event) => {
|
||||||
|
if (event.stage === name && event.feature === feature)
|
||||||
|
resolve(name);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
await environmentStore.create({
|
await environmentStore.create({
|
||||||
name: 'my-dev-environment',
|
name: 'my-dev-environment',
|
||||||
type: 'test',
|
type: 'test',
|
||||||
@ -78,20 +69,20 @@ test('can insert and read lifecycle stages', async () => {
|
|||||||
featureLifecycleService.listen();
|
featureLifecycleService.listen();
|
||||||
|
|
||||||
eventStore.emit(FEATURE_CREATED, { featureName });
|
eventStore.emit(FEATURE_CREATED, { featureName });
|
||||||
await reachedStage(eventBus, featureName, 'initial');
|
await reachedStage(featureName, 'initial');
|
||||||
|
|
||||||
emitMetricsEvent(eventBus, featureName, 'unknown-environment');
|
emitMetricsEvent('unknown-environment');
|
||||||
emitMetricsEvent(eventBus, featureName, 'my-dev-environment');
|
emitMetricsEvent('my-dev-environment');
|
||||||
await reachedStage(eventBus, featureName, 'pre-live');
|
await reachedStage(featureName, 'pre-live');
|
||||||
emitMetricsEvent(eventBus, featureName, 'my-dev-environment');
|
emitMetricsEvent('my-dev-environment');
|
||||||
emitMetricsEvent(eventBus, featureName, 'my-another-dev-environment');
|
emitMetricsEvent('my-another-dev-environment');
|
||||||
emitMetricsEvent(eventBus, featureName, 'my-prod-environment');
|
emitMetricsEvent('my-prod-environment');
|
||||||
await reachedStage(eventBus, featureName, 'live');
|
await reachedStage(featureName, 'live');
|
||||||
emitMetricsEvent(eventBus, featureName, 'my-prod-environment');
|
emitMetricsEvent('my-prod-environment');
|
||||||
emitMetricsEvent(eventBus, featureName, 'my-another-prod-environment');
|
emitMetricsEvent('my-another-prod-environment');
|
||||||
|
|
||||||
eventStore.emit(FEATURE_ARCHIVED, { featureName });
|
eventStore.emit(FEATURE_ARCHIVED, { featureName });
|
||||||
await reachedStage(eventBus, featureName, 'archived');
|
await reachedStage(featureName, 'archived');
|
||||||
|
|
||||||
const lifecycle =
|
const lifecycle =
|
||||||
await featureLifecycleService.getFeatureLifecycle(featureName);
|
await featureLifecycleService.getFeatureLifecycle(featureName);
|
||||||
@ -104,251 +95,10 @@ test('can insert and read lifecycle stages', async () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
eventStore.emit(FEATURE_REVIVED, { featureName });
|
eventStore.emit(FEATURE_REVIVED, { featureName });
|
||||||
await reachedStage(eventBus, featureName, 'initial');
|
await reachedStage(featureName, 'initial');
|
||||||
const initialLifecycle =
|
const initialLifecycle =
|
||||||
await featureLifecycleService.getFeatureLifecycle(featureName);
|
await featureLifecycleService.getFeatureLifecycle(featureName);
|
||||||
expect(initialLifecycle).toEqual([
|
expect(initialLifecycle).toEqual([
|
||||||
{ stage: 'initial', enteredStageAt: expect.any(Date) },
|
{ stage: 'initial', enteredStageAt: expect.any(Date) },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('handles bulk metrics efficiently with multiple environments and features', async () => {
|
|
||||||
const eventBus = new EventEmitter();
|
|
||||||
const {
|
|
||||||
featureLifecycleService,
|
|
||||||
eventStore,
|
|
||||||
environmentStore,
|
|
||||||
featureEnvironmentStore,
|
|
||||||
} = createFakeFeatureLifecycleService({
|
|
||||||
flagResolver: { isEnabled: () => true },
|
|
||||||
eventBus,
|
|
||||||
getLogger: noLoggerProvider,
|
|
||||||
} as unknown as IUnleashConfig);
|
|
||||||
|
|
||||||
await environmentStore.create({
|
|
||||||
name: 'dev-env',
|
|
||||||
type: 'development',
|
|
||||||
} as IEnvironment);
|
|
||||||
|
|
||||||
await environmentStore.create({
|
|
||||||
name: 'staging-env',
|
|
||||||
type: 'staging',
|
|
||||||
} as IEnvironment);
|
|
||||||
|
|
||||||
await environmentStore.create({
|
|
||||||
name: 'prod-env',
|
|
||||||
type: 'production',
|
|
||||||
} as IEnvironment);
|
|
||||||
|
|
||||||
const feature1 = 'feature-1';
|
|
||||||
const feature2 = 'feature-2';
|
|
||||||
const feature3 = 'feature-3';
|
|
||||||
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature1,
|
|
||||||
'dev-env',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature1,
|
|
||||||
'staging-env',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature1,
|
|
||||||
'prod-env',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature2,
|
|
||||||
'dev-env',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature2,
|
|
||||||
'staging-env',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature2,
|
|
||||||
'prod-env',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature3,
|
|
||||||
'dev-env',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature3,
|
|
||||||
'staging-env',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature3,
|
|
||||||
'prod-env',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
featureLifecycleService.listen();
|
|
||||||
|
|
||||||
eventStore.emit(FEATURE_CREATED, { featureName: feature1 });
|
|
||||||
eventStore.emit(FEATURE_CREATED, { featureName: feature2 });
|
|
||||||
eventStore.emit(FEATURE_CREATED, { featureName: feature3 });
|
|
||||||
|
|
||||||
const bulkMetricsEvent = [
|
|
||||||
{
|
|
||||||
featureName: feature1,
|
|
||||||
environment: 'dev-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 10,
|
|
||||||
no: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature2,
|
|
||||||
environment: 'dev-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 15,
|
|
||||||
no: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature3,
|
|
||||||
environment: 'dev-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 8,
|
|
||||||
no: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature1,
|
|
||||||
environment: 'staging-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 20,
|
|
||||||
no: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature2,
|
|
||||||
environment: 'staging-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 12,
|
|
||||||
no: 6,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature3,
|
|
||||||
environment: 'staging-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 25,
|
|
||||||
no: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature1,
|
|
||||||
environment: 'prod-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 100,
|
|
||||||
no: 20,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature2,
|
|
||||||
environment: 'prod-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 80,
|
|
||||||
no: 15,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature3,
|
|
||||||
environment: 'prod-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 150,
|
|
||||||
no: 30,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
eventBus.emit(CLIENT_METRICS_ADDED, bulkMetricsEvent);
|
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
||||||
|
|
||||||
const lifecycle1 =
|
|
||||||
await featureLifecycleService.getFeatureLifecycle(feature1);
|
|
||||||
const lifecycle2 =
|
|
||||||
await featureLifecycleService.getFeatureLifecycle(feature2);
|
|
||||||
const lifecycle3 =
|
|
||||||
await featureLifecycleService.getFeatureLifecycle(feature3);
|
|
||||||
|
|
||||||
expect(lifecycle1.some((stage) => stage.stage === 'initial')).toBe(true);
|
|
||||||
expect(lifecycle2.some((stage) => stage.stage === 'initial')).toBe(true);
|
|
||||||
expect(lifecycle3.some((stage) => stage.stage === 'initial')).toBe(true);
|
|
||||||
|
|
||||||
expect(lifecycle1.length).toBeGreaterThan(1);
|
|
||||||
expect(lifecycle2.length).toBeGreaterThan(1);
|
|
||||||
expect(lifecycle3.length).toBeGreaterThan(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('handles bulk metrics with unknown environments gracefully', async () => {
|
|
||||||
const eventBus = new EventEmitter();
|
|
||||||
const {
|
|
||||||
featureLifecycleService,
|
|
||||||
eventStore,
|
|
||||||
environmentStore,
|
|
||||||
featureEnvironmentStore,
|
|
||||||
} = createFakeFeatureLifecycleService({
|
|
||||||
flagResolver: { isEnabled: () => true },
|
|
||||||
eventBus,
|
|
||||||
getLogger: noLoggerProvider,
|
|
||||||
} as unknown as IUnleashConfig);
|
|
||||||
|
|
||||||
await environmentStore.create({
|
|
||||||
name: 'known-env',
|
|
||||||
type: 'development',
|
|
||||||
} as IEnvironment);
|
|
||||||
|
|
||||||
const feature = 'test-feature';
|
|
||||||
await featureEnvironmentStore.addEnvironmentToFeature(
|
|
||||||
feature,
|
|
||||||
'known-env',
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
featureLifecycleService.listen();
|
|
||||||
eventStore.emit(FEATURE_CREATED, { featureName: feature });
|
|
||||||
await reachedStage(eventBus, feature, 'initial');
|
|
||||||
|
|
||||||
const metricsWithUnknownEnv = [
|
|
||||||
{
|
|
||||||
featureName: feature,
|
|
||||||
environment: 'known-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 10,
|
|
||||||
no: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
featureName: feature,
|
|
||||||
environment: 'unknown-env',
|
|
||||||
appName: 'test-app',
|
|
||||||
timestamp: new Date(),
|
|
||||||
yes: 5,
|
|
||||||
no: 2,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
eventBus.emit(CLIENT_METRICS_ADDED, metricsWithUnknownEnv);
|
|
||||||
|
|
||||||
await reachedStage(eventBus, feature, 'pre-live');
|
|
||||||
|
|
||||||
const lifecycle =
|
|
||||||
await featureLifecycleService.getFeatureLifecycle(feature);
|
|
||||||
expect(lifecycle).toEqual([
|
|
||||||
{ stage: 'initial', enteredStageAt: expect.any(Date) },
|
|
||||||
{ stage: 'pre-live', enteredStageAt: expect.any(Date) },
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
Loading…
Reference in New Issue
Block a user