1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-26 01:17:00 +02:00

fix: mutating delta events (#9303)

Fix a bug where delta events would be mutated due to Object.assign.
This commit is contained in:
Fredrik Strand Oseberg 2025-02-14 09:30:14 +01:00 committed by GitHub
parent aa15fbee9a
commit fa43420ab9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 6 deletions

View File

@ -183,4 +183,67 @@ describe('RevisionCache', () => {
]),
);
});
it('should not mutate previous feature-updated events when new events with the same feature name are added', () => {
const baseEvent: DeltaHydrationEvent = {
eventId: 1,
features: [
{
name: 'base-flag',
type: 'release',
enabled: true,
project: 'streaming-deltas',
stale: false,
strategies: [],
variants: [],
description: null,
impressionData: false,
},
],
type: 'hydration',
segments: [],
};
const deltaCache = new DeltaCache(baseEvent, 10);
const initialFeatureEvent: DeltaEvent = {
eventId: 129,
type: DELTA_EVENT_TYPES.FEATURE_UPDATED,
feature: {
impressionData: false,
enabled: false,
name: 'streaming-test',
description: null,
project: 'streaming-deltas',
stale: false,
type: 'release',
variants: [],
strategies: [],
},
};
// This tests is to verify that the initialFeatureEvent is not mutated when a new event with the same feature name is added
// the following dirty way to clone this object is to avoid mutation on the comparison object. Because the object is passed by reference
// we would be comparing the same object with itself which would cause the expect check to always pass because the comparison would
// also change to match the object being compared.
deltaCache.addEvents([JSON.parse(JSON.stringify(initialFeatureEvent))]);
const updatedFeatureEvent: DeltaEvent = {
eventId: 130,
type: DELTA_EVENT_TYPES.FEATURE_UPDATED,
feature: {
impressionData: false,
enabled: true,
name: 'streaming-test',
description: null,
project: 'streaming-deltas',
stale: false,
type: 'release',
variants: [],
strategies: [{ name: 'new-strategy', parameters: {} }],
},
};
deltaCache.addEvents([updatedFeatureEvent]);
// @ts-ignore
expect(deltaCache.events[1]).toStrictEqual(initialFeatureEvent);
});
});

View File

@ -55,11 +55,13 @@ export class DeltaCache {
for (const appliedEvent of events) {
switch (appliedEvent.type) {
case DELTA_EVENT_TYPES.FEATURE_UPDATED: {
const featureToUpdate = this.hydrationEvent.features.find(
const featureIndex = this.hydrationEvent.features.findIndex(
(feature) => feature.name === appliedEvent.feature.name,
);
if (featureToUpdate) {
Object.assign(featureToUpdate, appliedEvent.feature);
if (featureIndex > -1) {
this.hydrationEvent.features[featureIndex] =
appliedEvent.feature;
} else {
this.hydrationEvent.features.push(appliedEvent.feature);
}
@ -74,11 +76,12 @@ export class DeltaCache {
break;
}
case DELTA_EVENT_TYPES.SEGMENT_UPDATED: {
const segmentToUpdate = this.hydrationEvent.segments.find(
const segmentIndex = this.hydrationEvent.segments.findIndex(
(segment) => segment.id === appliedEvent.segment.id,
);
if (segmentToUpdate) {
Object.assign(segmentToUpdate, appliedEvent.segment);
if (segmentIndex > -1) {
this.hydrationEvent.segments[segmentIndex] =
appliedEvent.segment;
} else {
this.hydrationEvent.segments.push(appliedEvent.segment);
}