diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index 271723bde0ea..c4558a4d27bf 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -102,7 +102,6 @@ exports[`should create default config 1`] = ` "responseTimeWithAppNameKillSwitch": false, "scheduledConfigurationChanges": false, "strictSchemaValidation": false, - "useLastSeenRefactor": false, }, "externalResolver": { "getVariant": [Function], diff --git a/src/lib/features/feature-toggle/converters/feature-toggle-row-converter.ts b/src/lib/features/feature-toggle/converters/feature-toggle-row-converter.ts index 385264199afc..b657a9870178 100644 --- a/src/lib/features/feature-toggle/converters/feature-toggle-row-converter.ts +++ b/src/lib/features/feature-toggle/converters/feature-toggle-row-converter.ts @@ -189,9 +189,7 @@ export class FeatureToggleRowConverter { feature.createdAt = r.created_at; feature.favorite = r.favorite; - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - this.addLastSeenByEnvironment(feature, r); - } + this.addLastSeenByEnvironment(feature, r); acc[r.name] = feature; return acc; @@ -246,9 +244,7 @@ export class FeatureToggleRowConverter { feature.lastSeenAt = row.last_seen_at; feature.archivedAt = row.archived_at; - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - this.addLastSeenByEnvironment(feature, row); - } + this.addLastSeenByEnvironment(feature, row); acc[row.name] = feature; return acc; diff --git a/src/lib/features/feature-toggle/feature-toggle-service.ts b/src/lib/features/feature-toggle/feature-toggle-service.ts index 46343e72c671..21ab5895a694 100644 --- a/src/lib/features/feature-toggle/feature-toggle-service.ts +++ b/src/lib/features/feature-toggle/feature-toggle-service.ts @@ -1970,13 +1970,7 @@ class FeatureToggleService { archived: boolean, userId: number, ): Promise { - let features; - - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - features = await this.featureToggleStore.getArchivedFeatures(); - } else { - features = await this.featureToggleStore.getAll({ archived }); - } + const features = await this.featureToggleStore.getArchivedFeatures(); if (this.flagResolver.isEnabled('privateProjects')) { const projectAccess = @@ -1998,11 +1992,7 @@ class FeatureToggleService { archived: boolean, project: string, ): Promise { - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - return this.featureToggleStore.getArchivedFeatures(project); - } else { - return this.featureToggleStore.getAll({ archived, project }); - } + return this.featureToggleStore.getArchivedFeatures(project); } async getProjectId(name: string): Promise { diff --git a/src/lib/features/feature-toggle/feature-toggle-store.ts b/src/lib/features/feature-toggle/feature-toggle-store.ts index e666ca527bfc..c3f78f9e58e8 100644 --- a/src/lib/features/feature-toggle/feature-toggle-store.ts +++ b/src/lib/features/feature-toggle/feature-toggle-store.ts @@ -171,15 +171,13 @@ export default class FeatureToggleStore implements IFeatureToggleStore { builder.addSelectColumn('ft.tag_value as tag_value'); builder.addSelectColumn('ft.tag_type as tag_type'); - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - builder.withLastSeenByEnvironment(archived); - builder.addSelectColumn( - 'last_seen_at_metrics.last_seen_at as env_last_seen_at', - ); - builder.addSelectColumn( - 'last_seen_at_metrics.environment as last_seen_at_env', - ); - } + builder.withLastSeenByEnvironment(archived); + builder.addSelectColumn( + 'last_seen_at_metrics.last_seen_at as env_last_seen_at', + ); + builder.addSelectColumn( + 'last_seen_at_metrics.environment as last_seen_at_env', + ); if (userId) { builder.withFavorites(userId); diff --git a/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts b/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts index 49360a9b1b25..d41a57a8bb0c 100644 --- a/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts +++ b/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts @@ -341,23 +341,21 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { let selectColumns = ['features_view.*'] as (string | Raw)[]; - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - query.leftJoin('last_seen_at_metrics', function () { - this.on( - 'last_seen_at_metrics.environment', - '=', - 'features_view.environment_name', - ).andOn( - 'last_seen_at_metrics.feature_name', - '=', - 'features_view.name', - ); - }); - // Override feature view for now - selectColumns.push( - 'last_seen_at_metrics.last_seen_at as env_last_seen_at', + query.leftJoin('last_seen_at_metrics', function () { + this.on( + 'last_seen_at_metrics.environment', + '=', + 'features_view.environment_name', + ).andOn( + 'last_seen_at_metrics.feature_name', + '=', + 'features_view.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 () { @@ -631,19 +629,17 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { 'segments.id', ); - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - query.leftJoin('last_seen_at_metrics', function () { - this.on( - 'last_seen_at_metrics.environment', - '=', - 'environments.name', - ).andOn( - 'last_seen_at_metrics.feature_name', - '=', - 'features.name', - ); - }); - } + query.leftJoin('last_seen_at_metrics', function () { + this.on( + 'last_seen_at_metrics.environment', + '=', + 'environments.name', + ).andOn( + 'last_seen_at_metrics.feature_name', + '=', + 'features.name', + ); + }); let selectColumns = [ 'features.name as feature_name', @@ -664,11 +660,8 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { 'segments.name as segment_name', ] as (string | Raw | Knex.QueryBuilder)[]; - let lastSeenQuery = 'feature_environments.last_seen_at'; - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - lastSeenQuery = 'last_seen_at_metrics.last_seen_at'; - selectColumns.push(`${lastSeenQuery} as env_last_seen_at`); - } + const lastSeenQuery = 'last_seen_at_metrics.last_seen_at'; + selectColumns.push(`${lastSeenQuery} as env_last_seen_at`); if (userId) { query.leftJoin(`favorite_features`, function () { @@ -802,19 +795,13 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { ) .leftJoin('feature_tag as ft', 'ft.feature_name', 'features.name'); - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - query.leftJoin('last_seen_at_metrics', function () { - this.on( - 'last_seen_at_metrics.environment', - '=', - 'environments.name', - ).andOn( - 'last_seen_at_metrics.feature_name', - '=', - 'features.name', - ); - }); - } + query.leftJoin('last_seen_at_metrics', function () { + this.on( + 'last_seen_at_metrics.environment', + '=', + 'environments.name', + ).andOn('last_seen_at_metrics.feature_name', '=', 'features.name'); + }); let selectColumns = [ 'features.name as feature_name', @@ -833,15 +820,9 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { 'ft.tag_type as tag_type', ] as (string | Raw | Knex.QueryBuilder)[]; - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - selectColumns.push( - 'last_seen_at_metrics.last_seen_at as env_last_seen_at', - ); - } else { - selectColumns.push( - 'feature_environments.last_seen_at as env_last_seen_at', - ); - } + selectColumns.push( + 'last_seen_at_metrics.last_seen_at as env_last_seen_at', + ); if (userId) { query = query.leftJoin(`favorite_features`, function () { diff --git a/src/lib/features/feature-toggle/tests/feature-toggle-last-seen-at.e2e.test.ts b/src/lib/features/feature-toggle/tests/feature-toggle-last-seen-at.e2e.test.ts index 66d24a87112c..09a086426d14 100644 --- a/src/lib/features/feature-toggle/tests/feature-toggle-last-seen-at.e2e.test.ts +++ b/src/lib/features/feature-toggle/tests/feature-toggle-last-seen-at.e2e.test.ts @@ -22,7 +22,6 @@ beforeAll(async () => { experimental: { flags: { strictSchemaValidation: true, - useLastSeenRefactor: true, }, }, }; diff --git a/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts b/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts index 114e8e0e754d..7aa7e8e8ec91 100644 --- a/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts +++ b/src/lib/features/feature-toggle/tests/feature-toggle-service.e2e.test.ts @@ -689,9 +689,7 @@ test('Should return last seen at per environment', async () => { expect(environments[0].lastSeenAt).toEqual(new Date(date)); // Test with feature flag on - const config = createTestConfig({ - experimental: { flags: { useLastSeenRefactor: true } }, - }); + const config = createTestConfig(); const featureService = createFeatureToggleService(db.rawDatabase, config); diff --git a/src/lib/features/playground/advanced-playground.test.ts b/src/lib/features/playground/advanced-playground.test.ts index 5be2ca563303..61ad62343e77 100644 --- a/src/lib/features/playground/advanced-playground.test.ts +++ b/src/lib/features/playground/advanced-playground.test.ts @@ -20,7 +20,6 @@ beforeAll(async () => { strictSchemaValidation: true, strategyVariant: true, privateProjects: true, - useLastSeenRefactor: true, }, }, }, diff --git a/src/lib/routes/client-api/metrics.test.ts b/src/lib/routes/client-api/metrics.test.ts index 15cd7e707c7d..6046b9f008ad 100644 --- a/src/lib/routes/client-api/metrics.test.ts +++ b/src/lib/routes/client-api/metrics.test.ts @@ -185,34 +185,6 @@ test('schema allow yes=', () => { expect(value.bucket.toggles.Demo2.no).toBe(256); }); -test('should set lastSeen on toggle', async () => { - expect.assertions(1); - stores.featureToggleStore.create('default', { - name: 'toggleLastSeen', - }); - await request - .post('/api/client/metrics') - .send({ - appName: 'demo', - bucket: { - start: Date.now(), - stop: Date.now(), - toggles: { - toggleLastSeen: { - yes: 200, - no: 0, - }, - }, - }, - }) - .expect(202); - - await services.lastSeenService.store(); - const toggle = await stores.featureToggleStore.get('toggleLastSeen'); - - expect(toggle.lastSeenAt).toBeTruthy(); -}); - test('should return a 400 when required fields are missing', async () => { stores.featureToggleStore.create('default', { name: 'toggleLastSeen', diff --git a/src/lib/services/client-metrics/last-seen/last-seen-mapper.ts b/src/lib/services/client-metrics/last-seen/last-seen-mapper.ts deleted file mode 100644 index 06b075e5c16f..000000000000 --- a/src/lib/services/client-metrics/last-seen/last-seen-mapper.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Logger } from '../../../logger'; -import { IFeatureOverview } from '../../../types'; -import { IFeatureLastSeenResults } from './last-seen-read-model'; - -export class LastSeenMapper { - mapToFeatures( - features: IFeatureOverview[], - lastSeenAtPerEnvironment: IFeatureLastSeenResults, - logger: Logger, - ): IFeatureOverview[] { - return features.map((feature) => { - if (!feature.environments) { - logger.warn('Feature without environments:', feature); - return feature; - } - - feature.environments = feature.environments.map((environment) => { - const noData = - !lastSeenAtPerEnvironment[feature.name] || - !lastSeenAtPerEnvironment[feature.name][environment.name]; - - if (noData) { - logger.warn( - 'No last seen data for environment:', - environment, - ); - return environment; - } - - environment.lastSeenAt = new Date( - lastSeenAtPerEnvironment[feature.name][environment.name] - .lastSeen, - ); - return environment; - }); - return feature; - }); - } -} diff --git a/src/lib/services/client-metrics/last-seen/last-seen-service.ts b/src/lib/services/client-metrics/last-seen/last-seen-service.ts index c211c4dbf953..6886c603ee10 100644 --- a/src/lib/services/client-metrics/last-seen/last-seen-service.ts +++ b/src/lib/services/client-metrics/last-seen/last-seen-service.ts @@ -51,11 +51,7 @@ export class LastSeenService { `Updating last seen for ${lastSeenToggles.length} toggles`, ); - if (this.config.flagResolver.isEnabled('useLastSeenRefactor')) { - await this.lastSeenStore.setLastSeen(lastSeenToggles); - } else { - await this.featureToggleStore.setLastSeen(lastSeenToggles); - } + await this.lastSeenStore.setLastSeen(lastSeenToggles); } return count; } @@ -81,8 +77,6 @@ export class LastSeenService { } async cleanLastSeen() { - if (this.flagResolver.isEnabled('useLastSeenRefactor')) { - await this.lastSeenStore.cleanLastSeen(); - } + await this.lastSeenStore.cleanLastSeen(); } } diff --git a/src/lib/services/client-metrics/last-seen/tests/last-seen-mapper.test.ts b/src/lib/services/client-metrics/last-seen/tests/last-seen-mapper.test.ts deleted file mode 100644 index 07d9ec7f5d2c..000000000000 --- a/src/lib/services/client-metrics/last-seen/tests/last-seen-mapper.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { IFeatureOverview } from '../../../../types'; -import { LastSeenMapper } from '../last-seen-mapper'; -import getLogger from '../../../../../test/fixtures/no-logger'; - -test('should produce correct output when mapped', () => { - const mapper = new LastSeenMapper(); - - const inputLastSeen = { - exp: { - production: { lastSeen: '2023-10-05T07:27:04.286Z' }, - development: { lastSeen: '2023-10-04T19:03:29.682Z' }, - }, - 'payment-system': { - production: { lastSeen: '2023-10-05T07:27:04.286Z' }, - development: { lastSeen: '2023-10-04T19:03:29.682Z' }, - }, - }; - - const inputFeatures: IFeatureOverview[] = [ - { - type: 'release', - description: null, - favorite: false, - name: 'payment-system', - // @ts-ignore - createdAt: '2023-06-30T12:57:20.476Z', - // @ts-ignore - lastSeenAt: '2023-10-03T13:08:16.263Z', - stale: false, - impressionData: false, - environments: [ - { - name: 'development', - enabled: false, - type: 'development', - sortOrder: 2, - variantCount: 0, - // @ts-ignore - lastSeenAt: '2023-10-04T19:03:29.682Z', - }, - { - name: 'production', - enabled: true, - type: 'production', - sortOrder: 3, - variantCount: 0, - // @ts-ignore - lastSeenAt: '2023-10-05T07:27:04.286Z', - }, - ], - }, - { - type: 'experiment', - description: null, - favorite: false, - name: 'exp', - // @ts-ignore - createdAt: '2023-09-13T08:08:28.211Z', - // @ts-ignore - lastSeenAt: '2023-10-03T13:08:16.263Z', - stale: false, - impressionData: false, - environments: [ - { - name: 'development', - enabled: false, - type: 'development', - sortOrder: 2, - variantCount: 0, - // @ts-ignore - lastSeenAt: '2023-10-04T19:03:29.682Z', - }, - { - name: 'production', - enabled: true, - type: 'production', - sortOrder: 3, - variantCount: 0, - // @ts-ignore - lastSeenAt: '2023-10-05T07:27:04.286Z', - }, - ], - }, - ]; - - const logger = getLogger(); - - const result = mapper.mapToFeatures(inputFeatures, inputLastSeen, logger); - - expect(result[0].environments[0].name).toBe('development'); - expect(result[0].name).toBe('payment-system'); - expect(result[0].environments[0].lastSeenAt).toEqual( - new Date(inputLastSeen['payment-system'].development.lastSeen), - ); -}); diff --git a/src/lib/services/client-metrics/last-seen/tests/last-seen-service.e2e.test.ts b/src/lib/services/client-metrics/last-seen/tests/last-seen-service.e2e.test.ts index 73d793e797f6..91614c1c46a7 100644 --- a/src/lib/services/client-metrics/last-seen/tests/last-seen-service.e2e.test.ts +++ b/src/lib/services/client-metrics/last-seen/tests/last-seen-service.e2e.test.ts @@ -16,7 +16,6 @@ beforeAll(async () => { experimental: { flags: { strictSchemaValidation: true, - useLastSeenRefactor: true, }, }, }, diff --git a/src/lib/services/client-metrics/last-seen/tests/last-seen-service.test.ts b/src/lib/services/client-metrics/last-seen/tests/last-seen-service.test.ts index 8859563d03cb..a0376f399600 100644 --- a/src/lib/services/client-metrics/last-seen/tests/last-seen-service.test.ts +++ b/src/lib/services/client-metrics/last-seen/tests/last-seen-service.test.ts @@ -36,7 +36,9 @@ function initLastSeenService(flagEnabled = true) { } test('should not add duplicates per feature/environment', async () => { - const { lastSeenService, featureToggleStore } = initLastSeenService(false); + const { lastSeenService, featureToggleStore, lastSeenStore } = + initLastSeenService(false); + const lastSeenSpy = jest.spyOn(lastSeenStore, 'setLastSeen'); lastSeenService.updateLastSeen([ { @@ -59,10 +61,8 @@ test('should not add duplicates per feature/environment', async () => { timestamp: new Date(), }, ]); - featureToggleStore.setLastSeen = jest.fn(); await lastSeenService.store(); - - expect(featureToggleStore.setLastSeen).toHaveBeenCalledWith([ + expect(lastSeenSpy).toHaveBeenCalledWith([ { environment: 'development', featureName: 'myFeature', @@ -96,7 +96,6 @@ test('should call last seen at store with correct data', async () => { }, ]); lastSeenStore.setLastSeen = jest.fn(); - featureToggleStore.setLastSeen = jest.fn(); await lastSeenService.store(); expect(lastSeenStore.setLastSeen).toHaveBeenCalledWith([ @@ -105,5 +104,4 @@ test('should call last seen at store with correct data', async () => { featureName: 'myFeature', }, ]); - expect(featureToggleStore.setLastSeen).toHaveBeenCalledTimes(0); }); diff --git a/src/lib/services/scheduler-service.test.ts b/src/lib/services/scheduler-service.test.ts new file mode 100644 index 000000000000..344856f88b66 --- /dev/null +++ b/src/lib/services/scheduler-service.test.ts @@ -0,0 +1,122 @@ +import { LogProvider } from '../logger'; +import { SchedulerService } from '../features/scheduler/scheduler-service'; +import { createTestConfig } from '../../test/config/test-config'; +import FakeSettingStore from '../../test/fixtures/fake-setting-store'; +import SettingService from './setting-service'; +import EventService from './event-service'; +import MaintenanceService from '../features/maintenance/maintenance-service'; + +function ms(timeMs) { + return new Promise((resolve) => setTimeout(resolve, timeMs)); +} + +const getLogger = () => { + const records: any[] = []; + const logger: LogProvider = () => ({ + error(...args: any[]) { + records.push(args); + }, + debug() {}, + info() {}, + warn() {}, + fatal() {}, + }); + const getRecords = () => { + return records; + }; + + return { logger, getRecords }; +}; + +let schedulerService: SchedulerService; +let getRecords; + +beforeEach(() => { + const config = createTestConfig(); + const settingStore = new FakeSettingStore(); + const settingService = new SettingService({ settingStore }, config, { + storeEvent() {}, + } as unknown as EventService); + const maintenanceService = new MaintenanceService(config, settingService); + const { logger, getRecords: getRecordsFn } = getLogger(); + getRecords = getRecordsFn; + + schedulerService = new SchedulerService( + logger, + maintenanceService, + config.eventBus, + ); +}); + +test('Schedules job immediately', async () => { + const job = jest.fn(); + await schedulerService.schedule(job, 10, 'test-id'); + + expect(job).toBeCalledTimes(1); + schedulerService.stop(); +}); + +test('Can schedule a single regular job', async () => { + const job = jest.fn(); + await schedulerService.schedule(job, 50, 'test-id-3'); + await ms(75); + + expect(job).toBeCalledTimes(2); + schedulerService.stop(); +}); + +test('Can schedule multiple jobs at the same interval', async () => { + const job = jest.fn(); + const anotherJob = jest.fn(); + + await schedulerService.schedule(job, 50, 'test-id-6'); + await schedulerService.schedule(anotherJob, 50, 'test-id-7'); + await ms(75); + + expect(job).toBeCalledTimes(2); + expect(anotherJob).toBeCalledTimes(2); + schedulerService.stop(); +}); + +test('Can schedule multiple jobs at the different intervals', async () => { + const job = jest.fn(); + const anotherJob = jest.fn(); + + await schedulerService.schedule(job, 100, 'test-id-8'); + await schedulerService.schedule(anotherJob, 200, 'test-id-9'); + await ms(250); + + expect(job).toBeCalledTimes(3); + expect(anotherJob).toBeCalledTimes(2); + schedulerService.stop(); +}); + +test('Can handle crash of a async job', async () => { + const job = async () => { + await Promise.reject('async reason'); + }; + + await schedulerService.schedule(job, 50, 'test-id-10'); + await ms(75); + + schedulerService.stop(); + expect(getRecords()).toEqual([ + ['scheduled job failed | id: test-id-10 | async reason'], + ['scheduled job failed | id: test-id-10 | async reason'], + ]); +}); + +test('Can handle crash of a sync job', async () => { + const job = () => { + throw new Error('sync reason'); + }; + + await schedulerService.schedule(job, 50, 'test-id-11'); + await ms(75); + + schedulerService.stop(); + expect(getRecords()).toEqual([ + ['scheduled job failed | id: test-id-11 | Error: sync reason'], + ['scheduled job failed | id: test-id-11 | Error: sync reason'], + ]); +}); diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index b0b5cd330531..5e5fc76300dd 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -25,7 +25,6 @@ export type IFlagKey = | 'customRootRolesKillSwitch' | 'privateProjects' | 'disableMetrics' - | 'useLastSeenRefactor' | 'banners' | 'featureSearchAPI' | 'featureSearchFrontend' @@ -114,10 +113,6 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_DISABLE_METRICS, false, ), - useLastSeenRefactor: parseEnvVarBoolean( - process.env.UNLEASH_EXPERIMENTAL_USE_LAST_SEEN_REFACTOR, - false, - ), featureSearchAPI: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_FEATURE_SEARCH_API, false, diff --git a/src/server-dev.ts b/src/server-dev.ts index 415cdc44592c..1f490c6d2f2d 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -38,7 +38,6 @@ process.nextTick(async () => { anonymiseEventLog: false, responseTimeWithAppNameKillSwitch: false, privateProjects: true, - useLastSeenRefactor: true, featureSearchAPI: true, featureSearchFrontend: false, }, diff --git a/src/test/e2e/api/admin/feature-archive.e2e.test.ts b/src/test/e2e/api/admin/feature-archive.e2e.test.ts index 295dc68740da..101db40721de 100644 --- a/src/test/e2e/api/admin/feature-archive.e2e.test.ts +++ b/src/test/e2e/api/admin/feature-archive.e2e.test.ts @@ -77,14 +77,13 @@ test('returns three archived toggles', async () => { }); test('returns three archived toggles with archivedAt', async () => { - expect.assertions(3); + expect.assertions(2); return app.request .get('/api/admin/archive/features') .expect('Content-Type', /json/) .expect(200) .expect((res) => { expect(res.body.features.length).toEqual(3); - expect(res.body.features.every((f) => f.archived)).toEqual(true); expect(res.body.features.every((f) => f.archivedAt)).toEqual(true); }); }); 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 a99992f17d19..a5d8cd5e325f 100644 --- a/src/test/e2e/api/admin/project/projects.e2e.test.ts +++ b/src/test/e2e/api/admin/project/projects.e2e.test.ts @@ -14,6 +14,7 @@ let app: IUnleashTest; let db: ITestDb; let projectStore: IProjectStore; +const testDate = '2023-10-01T12:34:56.000Z'; beforeAll(async () => { db = await dbInit('projects_api_serial', getLogger); @@ -146,7 +147,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', db.rawDatabase, 'default'); + await insertLastSeenAt( + 'my-new-feature-toggle', + db.rawDatabase, + 'default', + testDate, + ); await insertFeatureEnvironmentsLastSeen( 'my-new-feature-toggle', db.rawDatabase, @@ -158,19 +164,11 @@ test('response should include last seen at per environment', async () => { .expect('Content-Type', /json/) .expect(200); - expect(body.features[0].environments[0].lastSeenAt).toEqual( - '2022-05-01T12:34:56.000Z', - ); + expect(body.features[0].environments[0].lastSeenAt).toEqual(testDate); const appWithLastSeenRefactor = await setupAppWithCustomConfig( db.stores, - { - experimental: { - flags: { - useLastSeenRefactor: true, - }, - }, - }, + {}, db.rawDatabase, ); @@ -187,13 +185,7 @@ test('response should include last seen at per environment', async () => { test('response should include last seen at per environment for multiple environments', async () => { const appWithLastSeenRefactor = await setupAppWithCustomConfig( db.stores, - { - experimental: { - flags: { - useLastSeenRefactor: true, - }, - }, - }, + {}, db.rawDatabase, ); await app.createFeature('my-new-feature-toggle'); diff --git a/src/test/e2e/services/last-seen-service.e2e.test.ts b/src/test/e2e/services/last-seen-service.e2e.test.ts deleted file mode 100644 index 49ad347aac60..000000000000 --- a/src/test/e2e/services/last-seen-service.e2e.test.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { createTestConfig } from '../../config/test-config'; -import dbInit from '../helpers/database-init'; -import { IUnleashStores } from '../../../lib/types/stores'; -import { LastSeenService } from '../../../lib/services/client-metrics/last-seen/last-seen-service'; -import { IClientMetricsEnv } from '../../../lib/types/stores/client-metrics-store-v2'; - -let stores: IUnleashStores; -let db; -let config; - -beforeAll(async () => { - config = createTestConfig(); - db = await dbInit('last_seen_service_serial', config.getLogger); - stores = db.stores; -}); -beforeEach(async () => { - await stores.featureToggleStore.deleteAll(); -}); -afterAll(async () => { - await db.destroy(); -}); - -test('Should update last seen for known toggles', async () => { - const service = new LastSeenService( - { - lastSeenStore: stores.lastSeenStore, - featureToggleStore: stores.featureToggleStore, - }, - config, - ); - const time = Date.now() - 100; - await stores.featureToggleStore.create('default', { name: 'ta1' }); - - const metrics: IClientMetricsEnv[] = [ - { - featureName: 'ta1', - appName: 'some-App', - environment: 'default', - timestamp: new Date(time), - yes: 1, - no: 0, - }, - { - featureName: 'ta2', - appName: 'some-App', - environment: 'default', - timestamp: new Date(time), - yes: 1, - no: 0, - }, - ]; - - service.updateLastSeen(metrics); - await service.store(); - - const t1 = await stores.featureToggleStore.get('ta1'); - - expect(t1.lastSeenAt.getTime()).toBeGreaterThan(time); -}); - -test('Should not update last seen toggles with 0 metrics', async () => { - // jest.useFakeTimers(); - const service = new LastSeenService( - { - lastSeenStore: stores.lastSeenStore, - featureToggleStore: stores.featureToggleStore, - }, - config, - ); - const time = Date.now(); - await stores.featureToggleStore.create('default', { name: 'tb1' }); - await stores.featureToggleStore.create('default', { name: 'tb2' }); - - const metrics: IClientMetricsEnv[] = [ - { - featureName: 'tb1', - appName: 'some-App', - environment: 'default', - timestamp: new Date(time), - yes: 1, - no: 0, - }, - { - featureName: 'tb2', - appName: 'some-App', - environment: 'default', - timestamp: new Date(time), - yes: 0, - no: 0, - }, - ]; - - service.updateLastSeen(metrics); - - // bypass interval waiting - await service.store(); - - const t1 = await stores.featureToggleStore.get('tb1'); - const t2 = await stores.featureToggleStore.get('tb2'); - - expect(t2.lastSeenAt).toBeNull(); - expect(t1.lastSeenAt.getTime()).toBeGreaterThanOrEqual(time); -}); - -test('Should not update anything for 0 toggles', async () => { - // jest.useFakeTimers(); - const service = new LastSeenService( - { - lastSeenStore: stores.lastSeenStore, - featureToggleStore: stores.featureToggleStore, - }, - config, - ); - const time = Date.now(); - await stores.featureToggleStore.create('default', { name: 'tb1' }); - await stores.featureToggleStore.create('default', { name: 'tb2' }); - - const metrics: IClientMetricsEnv[] = [ - { - featureName: 'tb1', - appName: 'some-App', - environment: 'default', - timestamp: new Date(time), - yes: 0, - no: 0, - }, - { - featureName: 'tb2', - appName: 'some-App', - environment: 'default', - timestamp: new Date(time), - yes: 0, - no: 0, - }, - ]; - - service.updateLastSeen(metrics); - - // bypass interval waiting - const count = await service.store(); - - expect(count).toBe(0); -});