Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions packages/server/api/src/app/benchmark/create-benchmark.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
BenchmarkCreationResult,
BenchmarkProviders,
ContentType,
Folder,
openOpsId,
} from '@openops/shared';
import { flowFolderService } from '../flows/folder/folder.service';
import { throwValidationError } from './errors';

function getBenchmarkFolderDisplayName(provider: string): string {
const normalizedProvider = provider.toLowerCase();
switch (normalizedProvider) {
case BenchmarkProviders.AWS:
return 'AWS Benchmark';
default:
throwValidationError(`Unknown provider: ${provider}`);
}
}

async function ensureBenchmarkFolder(
projectId: string,
displayName: string,
): Promise<Folder> {
return flowFolderService.getOrCreate({
projectId,
request: {
displayName,
contentType: ContentType.WORKFLOW,
},
});
}

export async function createBenchmark(params: {
provider: string;
projectId: string;
}): Promise<BenchmarkCreationResult> {
const { provider, projectId } = params;

const benchmarkFolder = await ensureBenchmarkFolder(
projectId,
getBenchmarkFolderDisplayName(provider),
);

return {
benchmarkId: openOpsId(),
folderId: benchmarkFolder.id,
provider,
workflows: [],
webhookPayload: {
webhookBaseUrl: '',
workflows: [],
cleanupWorkflows: [],
accounts: [],
regions: [],
},
};
}
69 changes: 45 additions & 24 deletions packages/server/api/src/app/flows/folder/folder.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Folder> {
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,
Expand Down Expand Up @@ -225,6 +211,41 @@ export const flowFolderService = {
},
};

async function createFolder(params: UpsertParams): Promise<FolderDto> {
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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { ContentType, type Folder } from '@openops/shared';
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', () => ({
flowFolderService: {
getOrCreate: jest.fn(),
},
}));

const flowFolderServiceMock = flowFolderService as jest.Mocked<
typeof flowFolderService
>;

describe('create-benchmark.service', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('createBenchmark with provider aws calls getOrCreate with displayName AWS Benchmark', async () => {
const projectId = 'project-1';
const folder: Folder = {
id: 'folder-1',
projectId,
displayName: 'AWS Benchmark',
created: '',
updated: '',
contentType: ContentType.WORKFLOW,
};
flowFolderServiceMock.getOrCreate.mockResolvedValue(folder);

await createBenchmark({ provider: 'aws', projectId });

expect(flowFolderServiceMock.getOrCreate).toHaveBeenCalledWith({
projectId,
request: {
displayName: 'AWS Benchmark',
contentType: ContentType.WORKFLOW,
},
});
});

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',
projectId,
displayName: 'AWS Benchmark',
created: '',
updated: '',
contentType: ContentType.WORKFLOW,
};

flowFolderServiceMock.getOrCreate.mockResolvedValue(folder);

const result = await createBenchmark({
provider: 'aws',
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();
expect(result.provider).toBe('aws');
expect(result.webhookPayload).toEqual({
webhookBaseUrl: '',
workflows: [],
cleanupWorkflows: [],
accounts: [],
regions: [],
});
});
});
Loading