From eb08ed0b55e633d4431c6c0db013b43005bef48a Mon Sep 17 00:00:00 2001 From: olav Date: Thu, 17 Feb 2022 10:47:05 +0100 Subject: [PATCH] refactor: add an hoursBack query param to the raw metrics endpoint (#1373) * refactor: add an hoursBack query param to the raw metrics endpoint * refactor: explicitly return undefined * refactor: make parseHoursBackQueryParam non-static * refactor: add test for hoursBack query param * refactor: improve arg name * refactor: add a 1 hour test case --- src/lib/routes/admin-api/client-metrics.ts | 28 +++++++++- .../client-metrics/metrics-service-v2.ts | 6 ++- .../e2e/api/admin/client-metrics.e2e.test.ts | 54 +++++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/lib/routes/admin-api/client-metrics.ts b/src/lib/routes/admin-api/client-metrics.ts index 7986f51065a..099640425c9 100644 --- a/src/lib/routes/admin-api/client-metrics.ts +++ b/src/lib/routes/admin-api/client-metrics.ts @@ -1,7 +1,7 @@ import { Request, Response } from 'express'; import Controller from '../controller'; import { IUnleashConfig } from '../../types/option'; -import { IUnleashServices } from '../../types/services'; +import { IUnleashServices } from '../../types'; import { Logger } from '../../logger'; import ClientMetricsServiceV2 from '../../services/client-metrics/metrics-service-v2'; @@ -10,6 +10,10 @@ class ClientMetricsController extends Controller { private metrics: ClientMetricsServiceV2; + private static HOURS_BACK_MIN = 1; + + private static HOURS_BACK_MAX = 48; + constructor( config: IUnleashConfig, { @@ -27,7 +31,11 @@ class ClientMetricsController extends Controller { async getRawToggleMetrics(req: Request, res: Response): Promise { const { name } = req.params; - const data = await this.metrics.getClientMetricsForToggle(name); + const { hoursBack } = req.query; + const data = await this.metrics.getClientMetricsForToggle( + name, + this.parseHoursBackQueryParam(hoursBack), + ); res.json({ version: 1, maturity: 'stable', @@ -44,5 +52,21 @@ class ClientMetricsController extends Controller { ...data, }); } + + private parseHoursBackQueryParam(param: unknown): number | undefined { + if (typeof param !== 'string') { + return undefined; + } + + const parsed = Number(param); + + if ( + parsed >= ClientMetricsController.HOURS_BACK_MIN && + parsed <= ClientMetricsController.HOURS_BACK_MAX + ) { + return parsed; + } + } } + export default ClientMetricsController; diff --git a/src/lib/services/client-metrics/metrics-service-v2.ts b/src/lib/services/client-metrics/metrics-service-v2.ts index f180e480a8e..a5aa4a2d6e1 100644 --- a/src/lib/services/client-metrics/metrics-service-v2.ts +++ b/src/lib/services/client-metrics/metrics-service-v2.ts @@ -114,8 +114,12 @@ export default class ClientMetricsServiceV2 { async getClientMetricsForToggle( toggleName: string, + hoursBack?: number, ): Promise { - return this.clientMetricsStoreV2.getMetricsForFeatureToggle(toggleName); + return this.clientMetricsStoreV2.getMetricsForFeatureToggle( + toggleName, + hoursBack, + ); } destroy(): void { diff --git a/src/test/e2e/api/admin/client-metrics.e2e.test.ts b/src/test/e2e/api/admin/client-metrics.e2e.test.ts index 61ddef37fb7..f961bde0c25 100644 --- a/src/test/e2e/api/admin/client-metrics.e2e.test.ts +++ b/src/test/e2e/api/admin/client-metrics.e2e.test.ts @@ -95,6 +95,60 @@ test('should return raw metrics, aggregated on key', async () => { expect(t2.data[0].no).toBe(104); }); +test('should support the hoursBack query param for raw metrics', async () => { + const date = new Date(); + const metrics: IClientMetricsEnv[] = [ + { + featureName: 'demo', + appName: 'web', + environment: 'default', + timestamp: date, + yes: 1, + no: 1, + }, + { + featureName: 'demo', + appName: 'web', + environment: 'default', + timestamp: subHours(date, 12), + yes: 2, + no: 2, + }, + { + featureName: 'demo', + appName: 'web', + environment: 'default', + timestamp: subHours(date, 32), + yes: 3, + no: 3, + }, + ]; + + await db.stores.clientMetricsStoreV2.batchInsertMetrics(metrics); + + const fetchHoursBack = (hoursBack: number) => { + return app.request + .get( + `/api/admin/client-metrics/features/demo/raw?hoursBack=${hoursBack}`, + ) + .expect('Content-Type', /json/) + .expect(200) + .then((res) => res.body); + }; + + const hours1 = await fetchHoursBack(1); + const hours24 = await fetchHoursBack(24); + const hours48 = await fetchHoursBack(48); + const hoursTooFew = await fetchHoursBack(-999); + const hoursTooMany = await fetchHoursBack(999); + + expect(hours1.data).toHaveLength(1); + expect(hours24.data).toHaveLength(2); + expect(hours48.data).toHaveLength(3); + expect(hoursTooFew.data).toHaveLength(2); + expect(hoursTooMany.data).toHaveLength(2); +}); + test('should return toggle summary', async () => { const date = new Date(); const metrics: IClientMetricsEnv[] = [