From a2ca7b0d35b5e559c4ff3db20e107dccd4d04bd2 Mon Sep 17 00:00:00 2001 From: Fredrik Strand Oseberg <fredrik.no@gmail.com> Date: Tue, 10 Oct 2023 14:40:36 +0200 Subject: [PATCH] Refactor/last seen at read feature overview (#4986) Refactor feature overview to use the last seen store --- src/lib/db/feature-strategy-store.ts | 15 ++++++ .../api/admin/project/projects.e2e.test.ts | 46 +++++++++++----- .../feature-toggle-service-v2.e2e.test.ts | 54 +++++++++++++++++++ 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/src/lib/db/feature-strategy-store.ts b/src/lib/db/feature-strategy-store.ts index 8266dfab18..a5584c215e 100644 --- a/src/lib/db/feature-strategy-store.ts +++ b/src/lib/db/feature-strategy-store.ts @@ -339,6 +339,19 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { .modify(FeatureToggleStore.filterByArchived, archived); let selectColumns = ['features_view.*'] as (string | Raw<any>)[]; + + if (this.flagResolver.isEnabled('useLastSeenRefactor')) { + query.leftJoin( + 'last_seen_at_metrics', + 'last_seen_at_metrics.environment', + 'features_view.environment_name', + ); + // Override feature view for now + selectColumns.push( + 'last_seen_at_metrics.last_seen_at as env_last_seen_at', + ); + } + if (userId) { query = query.leftJoin(`favorite_features`, function () { this.on( @@ -353,8 +366,10 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { ), ]; } + const rows = await query.select(selectColumns); stopTimer(); + if (rows.length > 0) { const featureToggle = rows.reduce((acc, r) => { if (acc.environments === undefined) { diff --git a/src/test/e2e/api/admin/project/projects.e2e.test.ts b/src/test/e2e/api/admin/project/projects.e2e.test.ts index 012496a4f7..4830f3191c 100644 --- a/src/test/e2e/api/admin/project/projects.e2e.test.ts +++ b/src/test/e2e/api/admin/project/projects.e2e.test.ts @@ -6,32 +6,38 @@ import { import getLogger from '../../../../fixtures/no-logger'; import { IProjectStore } from 'lib/types'; -import { ProjectService } from 'lib/services'; +import { Knex } from 'knex'; let app: IUnleashTest; let db: ITestDb; let projectStore: IProjectStore; -const insertLastSeenAt = async ( +export const insertLastSeenAt = async ( featureName: string, + db: Knex, environment: string = 'default', date: string = '2023-10-01 12:34:56', -) => { - await db.rawDatabase.raw(`INSERT INTO last_seen_at_metrics (feature_name, environment, last_seen_at) +): Promise<string> => { + await db.raw(`INSERT INTO last_seen_at_metrics (feature_name, environment, last_seen_at) VALUES ('${featureName}', '${environment}', '${date}');`); + + return date; }; -const insertFeatureEnvironmentsLastSeen = async ( +export const insertFeatureEnvironmentsLastSeen = async ( featureName: string, + db: Knex, environment: string = 'default', date: string = '2022-05-01 12:34:56', -) => { - await db.rawDatabase.raw(` +): Promise<string> => { + await db.raw(` INSERT INTO feature_environments (feature_name, environment, last_seen_at, enabled) VALUES ('${featureName}', '${environment}', '${date}', true) ON CONFLICT (feature_name, environment) DO UPDATE SET last_seen_at = '${date}', enabled = true; `); + + return date; }; beforeAll(async () => { @@ -91,8 +97,12 @@ test('response for default project should include created_at', async () => { test('response should include last seen at per environment', async () => { await app.createFeature('my-new-feature-toggle'); - await insertLastSeenAt('my-new-feature-toggle', 'default'); - await insertFeatureEnvironmentsLastSeen('my-new-feature-toggle', 'default'); + await insertLastSeenAt('my-new-feature-toggle', db.rawDatabase, 'default'); + await insertFeatureEnvironmentsLastSeen( + 'my-new-feature-toggle', + db.rawDatabase, + 'default', + ); const { body } = await app.request .get('/api/admin/projects/default') @@ -165,9 +175,21 @@ test('response should include last seen at per environment for multiple environm 'multiple-environment-last-seen-at', ); - await insertLastSeenAt('multiple-environment-last-seen-at', 'default'); - await insertLastSeenAt('multiple-environment-last-seen-at', 'development'); - await insertLastSeenAt('multiple-environment-last-seen-at', 'production'); + await insertLastSeenAt( + 'multiple-environment-last-seen-at', + db.rawDatabase, + 'default', + ); + await insertLastSeenAt( + 'multiple-environment-last-seen-at', + db.rawDatabase, + 'development', + ); + await insertLastSeenAt( + 'multiple-environment-last-seen-at', + db.rawDatabase, + 'production', + ); const { body } = await appWithLastSeenRefactor.request .get('/api/admin/projects/default') diff --git a/src/test/e2e/services/feature-toggle-service-v2.e2e.test.ts b/src/test/e2e/services/feature-toggle-service-v2.e2e.test.ts index 624675a705..c9b04d50be 100644 --- a/src/test/e2e/services/feature-toggle-service-v2.e2e.test.ts +++ b/src/test/e2e/services/feature-toggle-service-v2.e2e.test.ts @@ -21,6 +21,10 @@ import { createFeatureToggleService, createSegmentService, } from '../../../lib/features'; +import { + insertFeatureEnvironmentsLastSeen, + insertLastSeenAt, +} from '../api/admin/project/projects.e2e.test'; let stores: IUnleashStores; let db; @@ -649,3 +653,53 @@ describe('flag name validation', () => { } }); }); + +test('Should return last seen at per environment', async () => { + const featureName = 'last-seen-at-per-env'; + const projectId = 'default'; + + const userName = 'last-seen-user'; + + await service.createFeatureToggle( + projectId, + { + name: featureName, + }, + userName, + ); + + const date = await insertFeatureEnvironmentsLastSeen( + featureName, + db.rawDatabase, + ); + + const { environments } = await service.getFeature({ + featureName, + projectId: 'default', + environmentVariants: false, + }); + + expect(environments[0].lastSeenAt).toEqual(new Date(date)); + + // Test with feature flag on + const config = createTestConfig({ + experimental: { flags: { useLastSeenRefactor: true } }, + }); + + const featureService = createFeatureToggleService(db.rawDatabase, config); + + const lastSeenAtStoreDate = await insertLastSeenAt( + featureName, + db.rawDatabase, + ); + + const featureToggle = await featureService.getFeature({ + featureName, + projectId: 'default', + environmentVariants: false, + }); + + expect(featureToggle.environments[0].lastSeenAt).toEqual( + new Date(lastSeenAtStoreDate), + ); +});