mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	fix: delta do not return archived as changed (#9062)
Our delta API was returning archived feature as updated. Now making sure we do not put `archived-feature `event into `updated` event array. Also stop returning removed as complex object.
This commit is contained in:
		
							parent
							
								
									13fb7c4a63
								
							
						
					
					
						commit
						8bf1b783e9
					
				| @ -9,10 +9,8 @@ import type { | ||||
| import type { Logger } from '../../logger'; | ||||
| 
 | ||||
| import type { FeatureConfigurationClient } from '../feature-toggle/types/feature-toggle-strategies-store-type'; | ||||
| import type { | ||||
|     RevisionDeltaEntry, | ||||
|     ClientFeatureToggleDelta, | ||||
| } from './delta/client-feature-toggle-delta'; | ||||
| import type { ClientFeatureToggleDelta } from './delta/client-feature-toggle-delta'; | ||||
| import type { ClientFeaturesDeltaSchema } from '../../openapi'; | ||||
| 
 | ||||
| export class ClientFeatureToggleService { | ||||
|     private logger: Logger; | ||||
| @ -44,7 +42,7 @@ export class ClientFeatureToggleService { | ||||
|     async getClientDelta( | ||||
|         revisionId: number | undefined, | ||||
|         query: IFeatureToggleQuery, | ||||
|     ): Promise<RevisionDeltaEntry | undefined> { | ||||
|     ): Promise<ClientFeaturesDeltaSchema | undefined> { | ||||
|         if (this.clientFeatureToggleDelta !== null) { | ||||
|             return this.clientFeatureToggleDelta.getDelta(revisionId, query); | ||||
|         } else { | ||||
|  | ||||
| @ -140,3 +140,37 @@ const syncRevisions = async () => { | ||||
|     // @ts-ignore
 | ||||
|     await app.services.clientFeatureToggleService.clientFeatureToggleDelta.onUpdateRevisionEvent(); | ||||
| }; | ||||
| 
 | ||||
| test('archived features should not be returned as updated', async () => { | ||||
|     await app.createFeature('base_feature'); | ||||
|     await syncRevisions(); | ||||
|     const { body } = await app.request.get('/api/client/delta').expect(200); | ||||
|     const currentRevisionId = body.revisionId; | ||||
| 
 | ||||
|     expect(body).toMatchObject({ | ||||
|         updated: [ | ||||
|             { | ||||
|                 name: 'base_feature', | ||||
|             }, | ||||
|         ], | ||||
|     }); | ||||
| 
 | ||||
|     await app.archiveFeature('base_feature'); | ||||
|     await app.createFeature('new_feature'); | ||||
| 
 | ||||
|     await syncRevisions(); | ||||
| 
 | ||||
|     const { body: deltaBody } = await app.request | ||||
|         .get('/api/client/delta') | ||||
|         .set('If-None-Match', currentRevisionId) | ||||
|         .expect(200); | ||||
| 
 | ||||
|     expect(deltaBody).toMatchObject({ | ||||
|         updated: [ | ||||
|             { | ||||
|                 name: 'new_feature', | ||||
|             }, | ||||
|         ], | ||||
|         removed: ['base_feature'], | ||||
|     }); | ||||
| }); | ||||
| @ -17,8 +17,10 @@ import type { OpenApiService } from '../../../services/openapi-service'; | ||||
| import { NONE } from '../../../types/permissions'; | ||||
| import { createResponseSchema } from '../../../openapi/util/create-response-schema'; | ||||
| import type { ClientFeatureToggleService } from '../client-feature-toggle-service'; | ||||
| import type { RevisionDeltaEntry } from './client-feature-toggle-delta'; | ||||
| import { clientFeaturesDeltaSchema } from '../../../openapi'; | ||||
| import { | ||||
|     type ClientFeaturesDeltaSchema, | ||||
|     clientFeaturesDeltaSchema, | ||||
| } from '../../../openapi'; | ||||
| import type { QueryOverride } from '../client-feature-toggle.controller'; | ||||
| 
 | ||||
| export default class ClientFeatureToggleDeltaController extends Controller { | ||||
| @ -75,7 +77,7 @@ export default class ClientFeatureToggleDeltaController extends Controller { | ||||
| 
 | ||||
|     async getDelta( | ||||
|         req: IAuthRequest, | ||||
|         res: Response<RevisionDeltaEntry>, | ||||
|         res: Response<ClientFeaturesDeltaSchema>, | ||||
|     ): Promise<void> { | ||||
|         if (!this.flagResolver.isEnabled('deltaApi')) { | ||||
|             throw new NotFoundError(); | ||||
|  | ||||
| @ -4,7 +4,7 @@ import type { FeatureConfigurationClient } from '../../feature-toggle/types/feat | ||||
| export interface FeatureConfigurationDeltaClient | ||||
|     extends FeatureConfigurationClient { | ||||
|     description: string; | ||||
|     impressionData: false; | ||||
|     impressionData: boolean; | ||||
| } | ||||
| 
 | ||||
| export interface IClientFeatureToggleDeltaReadModel { | ||||
|  | ||||
| @ -17,6 +17,7 @@ import type { | ||||
| import { CLIENT_DELTA_MEMORY } from '../../../metric-events'; | ||||
| import type EventEmitter from 'events'; | ||||
| import type { Logger } from '../../../logger'; | ||||
| import type { ClientFeaturesDeltaSchema } from '../../../openapi'; | ||||
| 
 | ||||
| type DeletedFeature = { | ||||
|     name: string; | ||||
| @ -79,6 +80,7 @@ const filterRevisionByProject = ( | ||||
|         (feature) => | ||||
|             projects.includes('*') || projects.includes(feature.project), | ||||
|     ); | ||||
| 
 | ||||
|     return { ...revision, updated, removed }; | ||||
| }; | ||||
| 
 | ||||
| @ -153,7 +155,7 @@ export class ClientFeatureToggleDelta { | ||||
|     async getDelta( | ||||
|         sdkRevisionId: number | undefined, | ||||
|         query: IFeatureToggleQuery, | ||||
|     ): Promise<RevisionDeltaEntry | undefined> { | ||||
|     ): Promise<ClientFeaturesDeltaSchema | undefined> { | ||||
|         const projects = query.project ? query.project : ['*']; | ||||
|         const environment = query.environment ? query.environment : 'default'; | ||||
|         // TODO: filter by tags, what is namePrefix? anything else?
 | ||||
| @ -181,9 +183,10 @@ export class ClientFeatureToggleDelta { | ||||
|             projects, | ||||
|         ); | ||||
| 
 | ||||
|         const revisionResponse = { | ||||
|         const revisionResponse: ClientFeaturesDeltaSchema = { | ||||
|             ...compressedRevision, | ||||
|             segments: this.segments, | ||||
|             removed: compressedRevision.removed.map((feature) => feature.name), | ||||
|         }; | ||||
| 
 | ||||
|         return Promise.resolve(revisionResponse); | ||||
| @ -197,6 +200,9 @@ export class ClientFeatureToggleDelta { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * This is used in client-feature-delta-api.e2e.test.ts, do not remove | ||||
|      */ | ||||
|     public resetDelta() { | ||||
|         this.delta = {}; | ||||
|     } | ||||
| @ -217,6 +223,7 @@ export class ClientFeatureToggleDelta { | ||||
|             ...new Set( | ||||
|                 changeEvents | ||||
|                     .filter((event) => event.featureName) | ||||
|                     .filter((event) => event.type !== 'feature-archived') | ||||
|                     .map((event) => event.featureName!), | ||||
|             ), | ||||
|         ]; | ||||
|  | ||||
							
								
								
									
										27
									
								
								src/lib/openapi/spec/client-features-delta-schema.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/lib/openapi/spec/client-features-delta-schema.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| import { validateSchema } from '../validate'; | ||||
| import type { ClientFeaturesDeltaSchema } from './client-features-delta-schema'; | ||||
| 
 | ||||
| test('clientFeaturesDeltaSchema all fields', () => { | ||||
|     const data: ClientFeaturesDeltaSchema = { | ||||
|         revisionId: 6, | ||||
|         updated: [ | ||||
|             { | ||||
|                 impressionData: false, | ||||
|                 enabled: false, | ||||
|                 name: 'base_feature', | ||||
|                 description: null, | ||||
|                 project: 'default', | ||||
|                 stale: false, | ||||
|                 type: 'release', | ||||
|                 variants: [], | ||||
|                 strategies: [], | ||||
|             }, | ||||
|         ], | ||||
|         removed: [], | ||||
|         segments: [], | ||||
|     }; | ||||
| 
 | ||||
|     expect( | ||||
|         validateSchema('#/components/schemas/clientFeaturesDeltaSchema', data), | ||||
|     ).toBeUndefined(); | ||||
| }); | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user