From 3f6cd794a82d40ecc6ccb138609d9ed701c0f672 Mon Sep 17 00:00:00 2001 From: Eugene Molodkin Date: Thu, 28 Nov 2024 10:50:54 +0100 Subject: [PATCH] wip: add pagination --- .../repositories/test-run.repository.ee.ts | 16 ++++++++ .../cli/src/evaluation/metrics.controller.ts | 2 +- .../src/evaluation/test-runs.controller.ee.ts | 9 ++--- .../evaluation/test-runs.api.test.ts | 40 +++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/databases/repositories/test-run.repository.ee.ts b/packages/cli/src/databases/repositories/test-run.repository.ee.ts index e8e2a1a5ef..3be1eb3790 100644 --- a/packages/cli/src/databases/repositories/test-run.repository.ee.ts +++ b/packages/cli/src/databases/repositories/test-run.repository.ee.ts @@ -1,8 +1,10 @@ +import type { FindManyOptions } from '@n8n/typeorm'; import { DataSource, Repository } from '@n8n/typeorm'; import { Service } from 'typedi'; import type { AggregatedTestRunMetrics } from '@/databases/entities/test-run.ee'; import { TestRun } from '@/databases/entities/test-run.ee'; +import type { ListQuery } from '@/requests'; @Service() export class TestRunRepository extends Repository { @@ -26,4 +28,18 @@ export class TestRunRepository extends Repository { public async markAsCompleted(id: string, metrics: AggregatedTestRunMetrics) { return await this.update(id, { status: 'completed', completedAt: new Date(), metrics }); } + + public async getMany(testDefinitionId: string, options: ListQuery.Options) { + const findManyOptions: FindManyOptions = { + where: { testDefinition: { id: testDefinitionId } }, + order: { createdAt: 'DESC' }, + }; + + if (options?.take) { + findManyOptions.skip = options.skip; + findManyOptions.take = options.take; + } + + return await this.find(findManyOptions); + } } diff --git a/packages/cli/src/evaluation/metrics.controller.ts b/packages/cli/src/evaluation/metrics.controller.ts index af8f5c0408..816228bf13 100644 --- a/packages/cli/src/evaluation/metrics.controller.ts +++ b/packages/cli/src/evaluation/metrics.controller.ts @@ -112,7 +112,7 @@ export class TestMetricsController { } @Delete('/:testDefinitionId/metrics/:id') - async delete(req: TestMetricsRequest.GetOne) { + async delete(req: TestMetricsRequest.Delete) { const { id: metricId, testDefinitionId } = req.params; await this.getTestDefinition(req); diff --git a/packages/cli/src/evaluation/test-runs.controller.ee.ts b/packages/cli/src/evaluation/test-runs.controller.ee.ts index 09905d0b13..1ed8b562f9 100644 --- a/packages/cli/src/evaluation/test-runs.controller.ee.ts +++ b/packages/cli/src/evaluation/test-runs.controller.ee.ts @@ -5,6 +5,7 @@ import { TestRunsRequest } from '@/evaluation/test-definitions.types.ee'; import { getSharedWorkflowIds } from '@/public-api/v1/handlers/workflows/workflows.service'; import { TestDefinitionService } from './test-definition.service.ee'; +import { listQueryMiddleware } from '@/middlewares'; @RestController('/evaluation/test-definitions') export class TestRunsController { @@ -32,15 +33,13 @@ export class TestRunsController { return testDefinition; } - @Get('/:testDefinitionId/runs') + @Get('/:testDefinitionId/runs', { middlewares: listQueryMiddleware }) async getMany(req: TestRunsRequest.GetMany) { const { testDefinitionId } = req.params; await this.getTestDefinition(req); - return await this.testRunRepository.find({ - where: { testDefinition: { id: testDefinitionId } }, - }); + return await this.testRunRepository.getMany(testDefinitionId, req.listQueryOptions); } @Get('/:testDefinitionId/runs/:id') @@ -59,7 +58,7 @@ export class TestRunsController { } @Delete('/:testDefinitionId/runs/:id') - async delete(req: TestRunsRequest.GetOne) { + async delete(req: TestRunsRequest.Delete) { const { id: testRunId, testDefinitionId } = req.params; await this.getTestDefinition(req); diff --git a/packages/cli/test/integration/evaluation/test-runs.api.test.ts b/packages/cli/test/integration/evaluation/test-runs.api.test.ts index ef8911976c..00e85bcd78 100644 --- a/packages/cli/test/integration/evaluation/test-runs.api.test.ts +++ b/packages/cli/test/integration/evaluation/test-runs.api.test.ts @@ -84,6 +84,46 @@ describe('GET /evaluation/test-definitions/:testDefinitionId/runs', () => { }), ]); }); + + test('should retrieve list of runs for a test definition with pagination', async () => { + const testRunRepository = Container.get(TestRunRepository); + const testRun1 = await testRunRepository.createTestRun(testDefinition.id); + // Mark as running just to make a slight delay between the runs + await testRunRepository.markAsRunning(testRun1.id); + const testRun2 = await testRunRepository.createTestRun(testDefinition.id); + + // Fetch the first page + const resp = await authOwnerAgent.get( + `/evaluation/test-definitions/${testDefinition.id}/runs?take=1`, + ); + + expect(resp.statusCode).toBe(200); + expect(resp.body.data).toEqual([ + expect.objectContaining({ + id: testRun2.id, + status: 'new', + testDefinitionId: testDefinition.id, + runAt: null, + completedAt: null, + }), + ]); + + // Fetch the second page + const resp2 = await authOwnerAgent.get( + `/evaluation/test-definitions/${testDefinition.id}/runs?take=1&skip=1`, + ); + + expect(resp2.statusCode).toBe(200); + expect(resp2.body.data).toEqual([ + expect.objectContaining({ + id: testRun1.id, + status: 'running', + testDefinitionId: testDefinition.id, + runAt: expect.any(String), + completedAt: null, + }), + ]); + }); }); describe('GET /evaluation/test-definitions/:testDefinitionId/runs/:id', () => {