From edd12709effec3abf09c6c2e7d8a169fde3002c4 Mon Sep 17 00:00:00 2001 From: andreas-unleash Date: Thu, 16 Mar 2023 14:00:18 +0200 Subject: [PATCH] fix: remove proxy return all toggles functionality (#3331) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR removes the return all toggles functionality. Removes the flag as well ## About the changes Closes # [1-778](https://linear.app/unleash/issue/1-778/remove-proxyalltoggles-functionality) ### Important files ## Discussion points --------- Signed-off-by: andreas-unleash --- .../__snapshots__/create-config.test.ts.snap | 2 - src/lib/routes/proxy-api/index.ts | 16 +- src/lib/services/proxy-service.ts | 15 -- src/lib/types/experimental.ts | 4 - src/test/e2e/api/proxy/proxy.e2e.test.ts | 162 ++++++++++++------ 5 files changed, 117 insertions(+), 82 deletions(-) diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index 324e554be2..ea2e4797fb 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -85,7 +85,6 @@ exports[`should create default config 1`] = ` "projectScopedSegments": false, "projectScopedStickiness": false, "projectStatusApi": false, - "proxyReturnAllToggles": false, "responseTimeWithAppNameKillSwitch": false, "showProjectApiAccess": false, "strictSchemaValidation": false, @@ -111,7 +110,6 @@ exports[`should create default config 1`] = ` "projectScopedSegments": false, "projectScopedStickiness": false, "projectStatusApi": false, - "proxyReturnAllToggles": false, "responseTimeWithAppNameKillSwitch": false, "showProjectApiAccess": false, "strictSchemaValidation": false, diff --git a/src/lib/routes/proxy-api/index.ts b/src/lib/routes/proxy-api/index.ts index 24e9383f1e..32a6db18f4 100644 --- a/src/lib/routes/proxy-api/index.ts +++ b/src/lib/routes/proxy-api/index.ts @@ -144,18 +144,10 @@ export default class ProxyController extends Controller { req: ApiUserRequest, res: Response, ) { - let toggles; - if (this.flagResolver.isEnabled('proxyReturnAllToggles')) { - toggles = await this.services.proxyService.getAllProxyFeatures( - req.user, - ProxyController.createContext(req), - ); - } else { - toggles = await this.services.proxyService.getProxyFeatures( - req.user, - ProxyController.createContext(req), - ); - } + const toggles = await this.services.proxyService.getProxyFeatures( + req.user, + ProxyController.createContext(req), + ); res.set('Cache-control', 'public, max-age=2'); diff --git a/src/lib/services/proxy-service.ts b/src/lib/services/proxy-service.ts index cc9526db93..1490ed15b6 100644 --- a/src/lib/services/proxy-service.ts +++ b/src/lib/services/proxy-service.ts @@ -77,21 +77,6 @@ export class ProxyService { })); } - async getAllProxyFeatures( - token: ApiUser, - context: Context, - ): Promise { - const client = await this.clientForProxyToken(token); - const definitions = client.getFeatureToggleDefinitions() || []; - - return definitions.map((feature) => ({ - name: feature.name, - enabled: Boolean(feature.enabled), - variant: client.forceGetVariant(feature.name, context), - impressionData: Boolean(feature.impressionData), - })); - } - async registerProxyMetrics( token: ApiUser, metrics: ClientMetricsSchema, diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 84055a8325..06d0dcb1ed 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -26,10 +26,6 @@ const flags = { process.env.UNLEASH_RESPONSE_TIME_WITH_APP_NAME_KILL_SWITCH, false, ), - proxyReturnAllToggles: parseEnvVarBoolean( - process.env.UNLEASH_EXPERIMENTAL_PROXY_RETURN_ALL_TOGGLES, - false, - ), maintenanceMode: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_MAINTENANCE_MODE, false, diff --git a/src/test/e2e/api/proxy/proxy.e2e.test.ts b/src/test/e2e/api/proxy/proxy.e2e.test.ts index e32dffff82..6cae5d1f65 100644 --- a/src/test/e2e/api/proxy/proxy.e2e.test.ts +++ b/src/test/e2e/api/proxy/proxy.e2e.test.ts @@ -936,55 +936,6 @@ test('Should not recursively set off timers on events', async () => { jest.useRealTimers(); }); -test('should return all features when specified', async () => { - app.config.experimental!.flags.proxyReturnAllToggles = true; - const frontendToken = await createApiToken(ApiTokenType.FRONTEND); - await createFeatureToggle({ - name: 'enabledFeature1', - enabled: true, - strategies: [{ name: 'default', constraints: [], parameters: {} }], - }); - await createFeatureToggle({ - name: 'enabledFeature2', - enabled: true, - strategies: [{ name: 'default', constraints: [], parameters: {} }], - }); - await createFeatureToggle({ - name: 'disabledFeature', - enabled: false, - strategies: [{ name: 'default', constraints: [], parameters: {} }], - }); - await app.request - .get('/api/frontend') - .set('Authorization', frontendToken.secret) - .expect('Content-Type', /json/) - .expect(200) - .expect((res) => { - expect(res.body).toEqual({ - toggles: [ - { - name: 'enabledFeature1', - enabled: true, - impressionData: false, - variant: { enabled: false, name: 'disabled' }, - }, - { - name: 'enabledFeature2', - enabled: true, - impressionData: false, - variant: { enabled: false, name: 'disabled' }, - }, - { - name: 'disabledFeature', - enabled: false, - impressionData: false, - variant: { enabled: false, name: 'disabled' }, - }, - ], - }); - }); -}); - test('should return maxAge header on options call', async () => { await app.request .options('/api/frontend') @@ -1038,3 +989,116 @@ test('should terminate data polling when stop is called', async () => { 'Shutting down data polling for proxy repository', ); }); + +test('should evaluate strategies when returning toggles', async () => { + const frontendToken = await createApiToken(ApiTokenType.FRONTEND); + await createFeatureToggle({ + name: 'enabledFeature', + enabled: true, + strategies: [ + { + name: 'flexibleRollout', + constraints: [], + parameters: { + rollout: '100', + stickiness: 'default', + groupId: 'some-new', + }, + }, + ], + }); + await createFeatureToggle({ + name: 'disabledFeature', + enabled: true, + strategies: [ + { + name: 'flexibleRollout', + constraints: [], + parameters: { + rollout: '0', + stickiness: 'default', + groupId: 'some-new', + }, + }, + ], + }); + + await app.request + .get('/api/frontend') + .set('Authorization', frontendToken.secret) + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + expect(res.body).toEqual({ + toggles: [ + { + name: 'enabledFeature', + enabled: true, + impressionData: false, + variant: { enabled: false, name: 'disabled' }, + }, + ], + }); + }); +}); +test('should not return all features', async () => { + const frontendToken = await createApiToken(ApiTokenType.FRONTEND); + await createFeatureToggle({ + name: 'enabledFeature1', + enabled: true, + strategies: [{ name: 'default', constraints: [], parameters: {} }], + }); + await createFeatureToggle({ + name: 'enabledFeature2', + enabled: true, + strategies: [ + { + name: 'flexibleRollout', + constraints: [], + parameters: { + rollout: '100', + stickiness: 'default', + groupId: 'some-new', + }, + }, + ], + }); + await createFeatureToggle({ + name: 'disabledFeature', + enabled: true, + strategies: [ + { + name: 'flexibleRollout', + constraints: [], + parameters: { + rollout: '0', + stickiness: 'default', + groupId: 'some-new', + }, + }, + ], + }); + await app.request + .get('/api/frontend') + .set('Authorization', frontendToken.secret) + .expect('Content-Type', /json/) + .expect(200) + .expect((res) => { + expect(res.body).toEqual({ + toggles: [ + { + name: 'enabledFeature1', + enabled: true, + impressionData: false, + variant: { enabled: false, name: 'disabled' }, + }, + { + name: 'enabledFeature2', + enabled: true, + impressionData: false, + variant: { enabled: false, name: 'disabled' }, + }, + ], + }); + }); +});