From a1b1edf298dd50a909f250755330260438841853 Mon Sep 17 00:00:00 2001 From: Ravi Kiran Date: Wed, 25 Feb 2026 16:53:22 +0530 Subject: [PATCH 1/7] Add helper method to ensure benchmark folder --- .../app/benchmark/create-benchmark.service.ts | 64 ++++++++ .../create-benchmark.service.test.ts | 147 ++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 packages/server/api/src/app/benchmark/create-benchmark.service.ts create mode 100644 packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts diff --git a/packages/server/api/src/app/benchmark/create-benchmark.service.ts b/packages/server/api/src/app/benchmark/create-benchmark.service.ts new file mode 100644 index 0000000000..27a0d7ca00 --- /dev/null +++ b/packages/server/api/src/app/benchmark/create-benchmark.service.ts @@ -0,0 +1,64 @@ +import { + BenchmarkProviders, + ContentType, + CreateBenchmarkResponse, + FolderDto, + openOpsId, +} from '@openops/shared'; +import { flowFolderService } from '../flows/folder/folder.service'; +import { throwValidationError } from './errors'; + +export function getBenchmarkFolderDisplayName(provider: string): string { + const normalizedProvider = provider.toLowerCase(); + switch (normalizedProvider) { + case BenchmarkProviders.AWS: + return 'AWS Benchmark'; + default: + throwValidationError(`Unknown provider: ${provider}`); + } +} + +export async function ensureBenchmarkFolder( + projectId: string, + displayName: string, +): Promise { + const existingFolder = + await flowFolderService.getOneByDisplayNameCaseInsensitive({ + projectId, + displayName, + contentType: ContentType.WORKFLOW, + }); + + if (existingFolder) { + return flowFolderService.getOneOrThrow({ + projectId, + folderId: existingFolder.id, + }); + } + + return flowFolderService.create({ + projectId, + request: { + displayName, + contentType: ContentType.WORKFLOW, + }, + }); +} + +export async function createBenchmark(params: { + provider: string; + projectId: string; +}): Promise { + const { provider, projectId } = params; + + const benchmarkFolder = await ensureBenchmarkFolder( + projectId, + getBenchmarkFolderDisplayName(provider), + ); + + return { + benchmarkId: openOpsId(), + folderId: benchmarkFolder.id, + workflows: [], + }; +} diff --git a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts new file mode 100644 index 0000000000..ade50be7c2 --- /dev/null +++ b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts @@ -0,0 +1,147 @@ +import { + ApplicationError, + ContentType, + ErrorCode, + type FolderDto, +} from '@openops/shared'; +import { + createBenchmark, + ensureBenchmarkFolder, + getBenchmarkFolderDisplayName, +} from '../../../src/app/benchmark/create-benchmark.service'; +import { flowFolderService } from '../../../src/app/flows/folder/folder.service'; + +jest.mock('../../../src/app/flows/folder/folder.service', () => ({ + flowFolderService: { + getOneByDisplayNameCaseInsensitive: jest.fn(), + getOneOrThrow: jest.fn(), + create: jest.fn(), + }, +})); + +const flowFolderServiceMock = flowFolderService as jest.Mocked< + typeof flowFolderService +>; + +describe('create-benchmark.service', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns AWS Benchmark for aws provider (case-insensitive)', () => { + expect(getBenchmarkFolderDisplayName('aws')).toBe('AWS Benchmark'); + expect(getBenchmarkFolderDisplayName('AWS')).toBe('AWS Benchmark'); + }); + + it('throws validation error for unknown provider', () => { + try { + getBenchmarkFolderDisplayName('gcp'); + throw new Error('Expected error not thrown'); + } catch (error) { + const appError = error as ApplicationError; + expect(appError.error.code).toBe(ErrorCode.VALIDATION); + } + }); + + it('returns existing folder when found by display name', async () => { + const projectId = 'project-1'; + const displayName = 'AWS Benchmark'; + const existingFolder = { + id: 'folder-1', + projectId, + displayName, + contentType: ContentType.WORKFLOW, + created: '', + updated: '', + }; + const folderDto: FolderDto = { + id: 'folder-1', + projectId, + displayName, + created: '', + updated: '', + numberOfFlows: 2, + contentType: ContentType.WORKFLOW, + }; + + flowFolderServiceMock.getOneByDisplayNameCaseInsensitive.mockResolvedValue( + existingFolder, + ); + flowFolderServiceMock.getOneOrThrow.mockResolvedValue(folderDto); + + const result = await ensureBenchmarkFolder(projectId, displayName); + + expect( + flowFolderServiceMock.getOneByDisplayNameCaseInsensitive, + ).toHaveBeenCalledWith({ + projectId, + displayName, + contentType: ContentType.WORKFLOW, + }); + expect(flowFolderServiceMock.getOneOrThrow).toHaveBeenCalledWith({ + projectId, + folderId: 'folder-1', + }); + expect(flowFolderServiceMock.create).not.toHaveBeenCalled(); + expect(result).toEqual(folderDto); + }); + + it('creates folder when display name not found', async () => { + const projectId = 'project-1'; + const displayName = 'AWS Benchmark'; + const createdFolder: FolderDto = { + id: 'folder-2', + projectId, + displayName, + created: '', + updated: '', + numberOfFlows: 0, + contentType: ContentType.WORKFLOW, + }; + + flowFolderServiceMock.getOneByDisplayNameCaseInsensitive.mockResolvedValue( + null, + ); + flowFolderServiceMock.create.mockResolvedValue(createdFolder); + + const result = await ensureBenchmarkFolder(projectId, displayName); + + expect(flowFolderServiceMock.getOneOrThrow).not.toHaveBeenCalled(); + expect(flowFolderServiceMock.create).toHaveBeenCalledWith({ + projectId, + request: { + displayName, + contentType: ContentType.WORKFLOW, + }, + }); + expect(result).toEqual(createdFolder); + }); + + it('creates a benchmark response after ensuring folder', async () => { + const projectId = 'project-1'; + const displayName = 'AWS Benchmark'; + const createdFolder: FolderDto = { + id: 'folder-2', + projectId, + displayName, + created: '', + updated: '', + numberOfFlows: 0, + contentType: ContentType.WORKFLOW, + }; + + flowFolderServiceMock.getOneByDisplayNameCaseInsensitive.mockResolvedValue( + null, + ); + flowFolderServiceMock.create.mockResolvedValue(createdFolder); + + const result = await createBenchmark({ + provider: 'aws', + projectId, + }); + + expect(result.folderId).toBe(createdFolder.id); + expect(result.workflows).toEqual([]); + expect(result.benchmarkId).toBeDefined(); + }); +}); From d2cb6755ad91fad6ce57299d2ae2d880f77629fa Mon Sep 17 00:00:00 2001 From: Ravi Kiran Date: Wed, 25 Feb 2026 17:18:02 +0530 Subject: [PATCH 2/7] Fix copilot comment about tests --- .../benchmark/create-benchmark.service.test.ts | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts index ade50be7c2..f389f3a021 100644 --- a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts +++ b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts @@ -1,9 +1,4 @@ -import { - ApplicationError, - ContentType, - ErrorCode, - type FolderDto, -} from '@openops/shared'; +import { ContentType, type FolderDto } from '@openops/shared'; import { createBenchmark, ensureBenchmarkFolder, @@ -34,13 +29,9 @@ describe('create-benchmark.service', () => { }); it('throws validation error for unknown provider', () => { - try { - getBenchmarkFolderDisplayName('gcp'); - throw new Error('Expected error not thrown'); - } catch (error) { - const appError = error as ApplicationError; - expect(appError.error.code).toBe(ErrorCode.VALIDATION); - } + expect(() => getBenchmarkFolderDisplayName('gcp')).toThrow( + 'Unknown provider: gcp', + ); }); it('returns existing folder when found by display name', async () => { From 3fdb21dd3bfbd34a27aa23435821919196bbab68 Mon Sep 17 00:00:00 2001 From: Ravi Kiran Date: Wed, 25 Feb 2026 18:29:06 +0530 Subject: [PATCH 3/7] Fix folder ensuring method as pointed out by copilot --- .../app/benchmark/create-benchmark.service.ts | 39 +++++++-- .../create-benchmark.service.test.ts | 83 +++++++++++-------- 2 files changed, 79 insertions(+), 43 deletions(-) diff --git a/packages/server/api/src/app/benchmark/create-benchmark.service.ts b/packages/server/api/src/app/benchmark/create-benchmark.service.ts index 27a0d7ca00..501756d3bf 100644 --- a/packages/server/api/src/app/benchmark/create-benchmark.service.ts +++ b/packages/server/api/src/app/benchmark/create-benchmark.service.ts @@ -1,7 +1,9 @@ import { + ApplicationError, BenchmarkProviders, ContentType, CreateBenchmarkResponse, + ErrorCode, FolderDto, openOpsId, } from '@openops/shared'; @@ -22,7 +24,7 @@ export async function ensureBenchmarkFolder( projectId: string, displayName: string, ): Promise { - const existingFolder = + let existingFolder = await flowFolderService.getOneByDisplayNameCaseInsensitive({ projectId, displayName, @@ -36,13 +38,34 @@ export async function ensureBenchmarkFolder( }); } - return flowFolderService.create({ - projectId, - request: { - displayName, - contentType: ContentType.WORKFLOW, - }, - }); + try { + return await flowFolderService.create({ + projectId, + request: { + displayName, + contentType: ContentType.WORKFLOW, + }, + }); + } catch (err) { + if ( + err instanceof ApplicationError && + err.error.code === ErrorCode.FOLDER_ALREADY_EXISTS + ) { + existingFolder = + await flowFolderService.getOneByDisplayNameCaseInsensitive({ + projectId, + displayName, + contentType: ContentType.WORKFLOW, + }); + if (existingFolder) { + return flowFolderService.getOneOrThrow({ + projectId, + folderId: existingFolder.id, + }); + } + } + throw err; + } } export async function createBenchmark(params: { diff --git a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts index f389f3a021..d6350fb437 100644 --- a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts +++ b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts @@ -1,4 +1,9 @@ -import { ContentType, type FolderDto } from '@openops/shared'; +import { + ApplicationError, + ContentType, + ErrorCode, + type FolderDto, +} from '@openops/shared'; import { createBenchmark, ensureBenchmarkFolder, @@ -34,70 +39,71 @@ describe('create-benchmark.service', () => { ); }); - it('returns existing folder when found by display name', async () => { + it('creates folder when display name not found', async () => { const projectId = 'project-1'; const displayName = 'AWS Benchmark'; - const existingFolder = { - id: 'folder-1', - projectId, - displayName, - contentType: ContentType.WORKFLOW, - created: '', - updated: '', - }; - const folderDto: FolderDto = { - id: 'folder-1', + const createdFolder: FolderDto = { + id: 'folder-2', projectId, displayName, created: '', updated: '', - numberOfFlows: 2, + numberOfFlows: 0, contentType: ContentType.WORKFLOW, }; flowFolderServiceMock.getOneByDisplayNameCaseInsensitive.mockResolvedValue( - existingFolder, + null, ); - flowFolderServiceMock.getOneOrThrow.mockResolvedValue(folderDto); + flowFolderServiceMock.create.mockResolvedValue(createdFolder); const result = await ensureBenchmarkFolder(projectId, displayName); - expect( - flowFolderServiceMock.getOneByDisplayNameCaseInsensitive, - ).toHaveBeenCalledWith({ - projectId, - displayName, - contentType: ContentType.WORKFLOW, - }); - expect(flowFolderServiceMock.getOneOrThrow).toHaveBeenCalledWith({ + expect(flowFolderServiceMock.getOneOrThrow).not.toHaveBeenCalled(); + expect(flowFolderServiceMock.create).toHaveBeenCalledWith({ projectId, - folderId: 'folder-1', + request: { + displayName, + contentType: ContentType.WORKFLOW, + }, }); - expect(flowFolderServiceMock.create).not.toHaveBeenCalled(); - expect(result).toEqual(folderDto); + expect(result).toEqual(createdFolder); }); - it('creates folder when display name not found', async () => { + it('returns existing folder when create throws FOLDER_ALREADY_EXISTS', async () => { const projectId = 'project-1'; const displayName = 'AWS Benchmark'; - const createdFolder: FolderDto = { - id: 'folder-2', + const existingFolder = { + id: 'folder-1', projectId, displayName, + contentType: ContentType.WORKFLOW, created: '', updated: '', - numberOfFlows: 0, + }; + const folderDto: FolderDto = { + id: 'folder-1', + projectId, + displayName, + created: '', + updated: '', + numberOfFlows: 2, contentType: ContentType.WORKFLOW, }; - flowFolderServiceMock.getOneByDisplayNameCaseInsensitive.mockResolvedValue( - null, + flowFolderServiceMock.getOneByDisplayNameCaseInsensitive + .mockResolvedValueOnce(null) + .mockResolvedValueOnce(existingFolder); + flowFolderServiceMock.create.mockRejectedValue( + new ApplicationError({ + code: ErrorCode.FOLDER_ALREADY_EXISTS, + params: { folderName: displayName }, + }), ); - flowFolderServiceMock.create.mockResolvedValue(createdFolder); + flowFolderServiceMock.getOneOrThrow.mockResolvedValue(folderDto); const result = await ensureBenchmarkFolder(projectId, displayName); - expect(flowFolderServiceMock.getOneOrThrow).not.toHaveBeenCalled(); expect(flowFolderServiceMock.create).toHaveBeenCalledWith({ projectId, request: { @@ -105,7 +111,14 @@ describe('create-benchmark.service', () => { contentType: ContentType.WORKFLOW, }, }); - expect(result).toEqual(createdFolder); + expect( + flowFolderServiceMock.getOneByDisplayNameCaseInsensitive, + ).toHaveBeenCalledTimes(2); + expect(flowFolderServiceMock.getOneOrThrow).toHaveBeenCalledWith({ + projectId, + folderId: 'folder-1', + }); + expect(result).toEqual(folderDto); }); it('creates a benchmark response after ensuring folder', async () => { From f118103ef52f4ef5f1f8774d25a06a3f0b4cde00 Mon Sep 17 00:00:00 2001 From: Ravi Kiran Date: Thu, 26 Feb 2026 12:32:40 +0530 Subject: [PATCH 4/7] Add new method to folder service for our use case --- .../app/benchmark/create-benchmark.service.ts | 51 ++-------- .../src/app/flows/folder/folder.service.ts | 69 +++++++++----- .../create-benchmark.service.test.ts | 92 +++---------------- 3 files changed, 64 insertions(+), 148 deletions(-) diff --git a/packages/server/api/src/app/benchmark/create-benchmark.service.ts b/packages/server/api/src/app/benchmark/create-benchmark.service.ts index 501756d3bf..37239d55ae 100644 --- a/packages/server/api/src/app/benchmark/create-benchmark.service.ts +++ b/packages/server/api/src/app/benchmark/create-benchmark.service.ts @@ -1,10 +1,8 @@ import { - ApplicationError, BenchmarkProviders, ContentType, CreateBenchmarkResponse, - ErrorCode, - FolderDto, + Folder, openOpsId, } from '@openops/shared'; import { flowFolderService } from '../flows/folder/folder.service'; @@ -23,49 +21,14 @@ export function getBenchmarkFolderDisplayName(provider: string): string { export async function ensureBenchmarkFolder( projectId: string, displayName: string, -): Promise { - let existingFolder = - await flowFolderService.getOneByDisplayNameCaseInsensitive({ - projectId, +): Promise { + return flowFolderService.getOrCreate({ + projectId, + request: { displayName, contentType: ContentType.WORKFLOW, - }); - - if (existingFolder) { - return flowFolderService.getOneOrThrow({ - projectId, - folderId: existingFolder.id, - }); - } - - try { - return await flowFolderService.create({ - projectId, - request: { - displayName, - contentType: ContentType.WORKFLOW, - }, - }); - } catch (err) { - if ( - err instanceof ApplicationError && - err.error.code === ErrorCode.FOLDER_ALREADY_EXISTS - ) { - existingFolder = - await flowFolderService.getOneByDisplayNameCaseInsensitive({ - projectId, - displayName, - contentType: ContentType.WORKFLOW, - }); - if (existingFolder) { - return flowFolderService.getOneOrThrow({ - projectId, - folderId: existingFolder.id, - }); - } - } - throw err; - } + }, + }); } export async function createBenchmark(params: { diff --git a/packages/server/api/src/app/flows/folder/folder.service.ts b/packages/server/api/src/app/flows/folder/folder.service.ts index 2478a91afd..65fb997603 100644 --- a/packages/server/api/src/app/flows/folder/folder.service.ts +++ b/packages/server/api/src/app/flows/folder/folder.service.ts @@ -86,36 +86,22 @@ export const flowFolderService = { params: { folderName: request.displayName }, }); } - - const folderId = openOpsId(); - const parentFolder = await flowFolderService.getParentFolder( - projectId, - request.parentFolderId, - ); - - await folderRepo().upsert( + return createFolder(params); + }, + async getOrCreate(params: UpsertParams): Promise { + const { projectId, request } = params; + const requestContentType = request.contentType ?? ContentType.WORKFLOW; + const folderWithDisplayName = await this.getOneByDisplayNameCaseInsensitive( { - id: folderId, projectId, - parentFolder, displayName: request.displayName, contentType: requestContentType, }, - ['projectId', 'contentType', 'displayName'], ); - - const folder = await folderRepo().findOneByOrFail({ - projectId, - id: folderId, - }); - - return { - ...folder, - numberOfFlows: 0, - flows: undefined, - subfolders: undefined, - parentFolderId: request.parentFolderId, - }; + if (!isNil(folderWithDisplayName)) { + return folderWithDisplayName; + } + return createFolder(params); }, async getParentFolder( projectId: string, @@ -225,6 +211,41 @@ export const flowFolderService = { }, }; +async function createFolder(params: UpsertParams): Promise { + const { projectId, request } = params; + const requestContentType = request.contentType ?? ContentType.WORKFLOW; + + const folderId = openOpsId(); + const parentFolder = await flowFolderService.getParentFolder( + projectId, + request.parentFolderId, + ); + + await folderRepo().upsert( + { + id: folderId, + projectId, + parentFolder, + displayName: request.displayName, + contentType: requestContentType, + }, + ['projectId', 'contentType', 'displayName'], + ); + + const folder = await folderRepo().findOneByOrFail({ + projectId, + id: folderId, + }); + + return { + ...folder, + numberOfFlows: 0, + flows: undefined, + subfolders: undefined, + parentFolderId: request.parentFolderId, + }; +} + type DeleteParams = { projectId: ProjectId; folderId: FolderId; diff --git a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts index d6350fb437..dc3464cc20 100644 --- a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts +++ b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts @@ -1,9 +1,4 @@ -import { - ApplicationError, - ContentType, - ErrorCode, - type FolderDto, -} from '@openops/shared'; +import { ContentType, type Folder } from '@openops/shared'; import { createBenchmark, ensureBenchmarkFolder, @@ -13,9 +8,7 @@ import { flowFolderService } from '../../../src/app/flows/folder/folder.service' jest.mock('../../../src/app/flows/folder/folder.service', () => ({ flowFolderService: { - getOneByDisplayNameCaseInsensitive: jest.fn(), - getOneOrThrow: jest.fn(), - create: jest.fn(), + getOrCreate: jest.fn(), }, })); @@ -39,112 +32,51 @@ describe('create-benchmark.service', () => { ); }); - it('creates folder when display name not found', async () => { - const projectId = 'project-1'; - const displayName = 'AWS Benchmark'; - const createdFolder: FolderDto = { - id: 'folder-2', - projectId, - displayName, - created: '', - updated: '', - numberOfFlows: 0, - contentType: ContentType.WORKFLOW, - }; - - flowFolderServiceMock.getOneByDisplayNameCaseInsensitive.mockResolvedValue( - null, - ); - flowFolderServiceMock.create.mockResolvedValue(createdFolder); - - const result = await ensureBenchmarkFolder(projectId, displayName); - - expect(flowFolderServiceMock.getOneOrThrow).not.toHaveBeenCalled(); - expect(flowFolderServiceMock.create).toHaveBeenCalledWith({ - projectId, - request: { - displayName, - contentType: ContentType.WORKFLOW, - }, - }); - expect(result).toEqual(createdFolder); - }); - - it('returns existing folder when create throws FOLDER_ALREADY_EXISTS', async () => { + it('ensureBenchmarkFolder calls getOrCreate and returns the folder', async () => { const projectId = 'project-1'; const displayName = 'AWS Benchmark'; - const existingFolder = { - id: 'folder-1', - projectId, - displayName, - contentType: ContentType.WORKFLOW, - created: '', - updated: '', - }; - const folderDto: FolderDto = { + const folder: Folder = { id: 'folder-1', projectId, displayName, created: '', updated: '', - numberOfFlows: 2, contentType: ContentType.WORKFLOW, }; - flowFolderServiceMock.getOneByDisplayNameCaseInsensitive - .mockResolvedValueOnce(null) - .mockResolvedValueOnce(existingFolder); - flowFolderServiceMock.create.mockRejectedValue( - new ApplicationError({ - code: ErrorCode.FOLDER_ALREADY_EXISTS, - params: { folderName: displayName }, - }), - ); - flowFolderServiceMock.getOneOrThrow.mockResolvedValue(folderDto); + flowFolderServiceMock.getOrCreate.mockResolvedValue(folder); const result = await ensureBenchmarkFolder(projectId, displayName); - expect(flowFolderServiceMock.create).toHaveBeenCalledWith({ + expect(flowFolderServiceMock.getOrCreate).toHaveBeenCalledWith({ projectId, request: { displayName, contentType: ContentType.WORKFLOW, }, }); - expect( - flowFolderServiceMock.getOneByDisplayNameCaseInsensitive, - ).toHaveBeenCalledTimes(2); - expect(flowFolderServiceMock.getOneOrThrow).toHaveBeenCalledWith({ - projectId, - folderId: 'folder-1', - }); - expect(result).toEqual(folderDto); + expect(result).toEqual(folder); }); - it('creates a benchmark response after ensuring folder', async () => { + it('createBenchmark returns benchmarkId, folderId from folder, and empty workflows', async () => { const projectId = 'project-1'; - const displayName = 'AWS Benchmark'; - const createdFolder: FolderDto = { + const folder: Folder = { id: 'folder-2', projectId, - displayName, + displayName: 'AWS Benchmark', created: '', updated: '', - numberOfFlows: 0, contentType: ContentType.WORKFLOW, }; - flowFolderServiceMock.getOneByDisplayNameCaseInsensitive.mockResolvedValue( - null, - ); - flowFolderServiceMock.create.mockResolvedValue(createdFolder); + flowFolderServiceMock.getOrCreate.mockResolvedValue(folder); const result = await createBenchmark({ provider: 'aws', projectId, }); - expect(result.folderId).toBe(createdFolder.id); + expect(result.folderId).toBe(folder.id); expect(result.workflows).toEqual([]); expect(result.benchmarkId).toBeDefined(); }); From 0c792321f1011a3db71e6b4ce5128b90fc1d4ca2 Mon Sep 17 00:00:00 2001 From: Ravi Kiran Date: Thu, 26 Feb 2026 12:54:14 +0530 Subject: [PATCH 5/7] Fix type and tests --- .../src/app/benchmark/create-benchmark.service.ts | 12 ++++++++++-- .../unit/benchmark/create-benchmark.service.test.ts | 8 ++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/server/api/src/app/benchmark/create-benchmark.service.ts b/packages/server/api/src/app/benchmark/create-benchmark.service.ts index 37239d55ae..381d575a62 100644 --- a/packages/server/api/src/app/benchmark/create-benchmark.service.ts +++ b/packages/server/api/src/app/benchmark/create-benchmark.service.ts @@ -1,7 +1,7 @@ import { + BenchmarkCreationResult, BenchmarkProviders, ContentType, - CreateBenchmarkResponse, Folder, openOpsId, } from '@openops/shared'; @@ -34,7 +34,7 @@ export async function ensureBenchmarkFolder( export async function createBenchmark(params: { provider: string; projectId: string; -}): Promise { +}): Promise { const { provider, projectId } = params; const benchmarkFolder = await ensureBenchmarkFolder( @@ -45,6 +45,14 @@ export async function createBenchmark(params: { return { benchmarkId: openOpsId(), folderId: benchmarkFolder.id, + provider, workflows: [], + webhookPayload: { + webhookBaseUrl: '', + workflows: [], + cleanupWorkflows: [], + accounts: [], + regions: [], + }, }; } diff --git a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts index dc3464cc20..3cb45b5485 100644 --- a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts +++ b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts @@ -79,5 +79,13 @@ describe('create-benchmark.service', () => { expect(result.folderId).toBe(folder.id); expect(result.workflows).toEqual([]); expect(result.benchmarkId).toBeDefined(); + expect(result.provider).toBe('aws'); + expect(result.webhookPayload).toEqual({ + webhookBaseUrl: '', + workflows: [], + cleanupWorkflows: [], + accounts: [], + regions: [], + }); }); }); From 78832b42391f031ff75095c21ceb1e0ec7a0fb38 Mon Sep 17 00:00:00 2001 From: Ravi Kiran Date: Thu, 26 Feb 2026 13:05:10 +0530 Subject: [PATCH 6/7] Fix test case name --- .../api/test/unit/benchmark/create-benchmark.service.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts index 3cb45b5485..836becfe9f 100644 --- a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts +++ b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts @@ -58,7 +58,7 @@ describe('create-benchmark.service', () => { expect(result).toEqual(folder); }); - it('createBenchmark returns benchmarkId, folderId from folder, and empty workflows', async () => { + it('createBenchmark returns benchmark creation result', async () => { const projectId = 'project-1'; const folder: Folder = { id: 'folder-2', From dae30f589568cbfc60aa5e9fc7b6153967b65d9f Mon Sep 17 00:00:00 2001 From: Ravi Kiran Date: Thu, 26 Feb 2026 14:50:36 +0530 Subject: [PATCH 7/7] Fix tests and make functions module level --- .../app/benchmark/create-benchmark.service.ts | 4 +- .../create-benchmark.service.test.ts | 45 +++++++++---------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/packages/server/api/src/app/benchmark/create-benchmark.service.ts b/packages/server/api/src/app/benchmark/create-benchmark.service.ts index 381d575a62..25ee8a251d 100644 --- a/packages/server/api/src/app/benchmark/create-benchmark.service.ts +++ b/packages/server/api/src/app/benchmark/create-benchmark.service.ts @@ -8,7 +8,7 @@ import { import { flowFolderService } from '../flows/folder/folder.service'; import { throwValidationError } from './errors'; -export function getBenchmarkFolderDisplayName(provider: string): string { +function getBenchmarkFolderDisplayName(provider: string): string { const normalizedProvider = provider.toLowerCase(); switch (normalizedProvider) { case BenchmarkProviders.AWS: @@ -18,7 +18,7 @@ export function getBenchmarkFolderDisplayName(provider: string): string { } } -export async function ensureBenchmarkFolder( +async function ensureBenchmarkFolder( projectId: string, displayName: string, ): Promise { diff --git a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts index 836becfe9f..11423b61c7 100644 --- a/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts +++ b/packages/server/api/test/unit/benchmark/create-benchmark.service.test.ts @@ -1,9 +1,5 @@ import { ContentType, type Folder } from '@openops/shared'; -import { - createBenchmark, - ensureBenchmarkFolder, - getBenchmarkFolderDisplayName, -} from '../../../src/app/benchmark/create-benchmark.service'; +import { createBenchmark } from '../../../src/app/benchmark/create-benchmark.service'; import { flowFolderService } from '../../../src/app/flows/folder/folder.service'; jest.mock('../../../src/app/flows/folder/folder.service', () => ({ @@ -21,44 +17,38 @@ describe('create-benchmark.service', () => { jest.clearAllMocks(); }); - it('returns AWS Benchmark for aws provider (case-insensitive)', () => { - expect(getBenchmarkFolderDisplayName('aws')).toBe('AWS Benchmark'); - expect(getBenchmarkFolderDisplayName('AWS')).toBe('AWS Benchmark'); - }); - - it('throws validation error for unknown provider', () => { - expect(() => getBenchmarkFolderDisplayName('gcp')).toThrow( - 'Unknown provider: gcp', - ); - }); - - it('ensureBenchmarkFolder calls getOrCreate and returns the folder', async () => { + it('createBenchmark with provider aws calls getOrCreate with displayName AWS Benchmark', async () => { const projectId = 'project-1'; - const displayName = 'AWS Benchmark'; const folder: Folder = { id: 'folder-1', projectId, - displayName, + displayName: 'AWS Benchmark', created: '', updated: '', contentType: ContentType.WORKFLOW, }; - flowFolderServiceMock.getOrCreate.mockResolvedValue(folder); - const result = await ensureBenchmarkFolder(projectId, displayName); + await createBenchmark({ provider: 'aws', projectId }); expect(flowFolderServiceMock.getOrCreate).toHaveBeenCalledWith({ projectId, request: { - displayName, + displayName: 'AWS Benchmark', contentType: ContentType.WORKFLOW, }, }); - expect(result).toEqual(folder); }); - it('createBenchmark returns benchmark creation result', async () => { + it('createBenchmark throws for unknown provider', async () => { + const projectId = 'project-1'; + await expect( + createBenchmark({ provider: 'gcp', projectId }), + ).rejects.toThrow('Unknown provider: gcp'); + expect(flowFolderServiceMock.getOrCreate).not.toHaveBeenCalled(); + }); + + it('createBenchmark returns BenchmarkCreationResult', async () => { const projectId = 'project-1'; const folder: Folder = { id: 'folder-2', @@ -76,6 +66,13 @@ describe('create-benchmark.service', () => { projectId, }); + expect(flowFolderServiceMock.getOrCreate).toHaveBeenCalledWith({ + projectId, + request: { + displayName: 'AWS Benchmark', + contentType: ContentType.WORKFLOW, + }, + }); expect(result.folderId).toBe(folder.id); expect(result.workflows).toEqual([]); expect(result.benchmarkId).toBeDefined();