Logic function refactorization (#17861)

As title
This commit is contained in:
martmull
2026-02-12 11:40:49 +01:00
committed by GitHub
parent b456f79167
commit a4ed043d43
122 changed files with 1441 additions and 1897 deletions
@@ -1,4 +1,4 @@
import { createDefaultLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/create-default-logic-function.util';
import { createOneLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/create-logic-function.util';
import { deleteLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/delete-logic-function.util';
import { executeLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/execute-logic-function.util';
import { updateLogicFunctionSource } from 'test/integration/metadata/suites/logic-function/utils/update-logic-function-source.util';
@@ -6,15 +6,12 @@ import { updateLogicFunctionSource } from 'test/integration/metadata/suites/logi
import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
// Default template function code that matches the expected behavior
const DEFAULT_TEMPLATE_FUNCTION_CODE = {
'src/index.ts': `export const main = async (params: { a: string; b: number }): Promise<object> => {
return { message: \`Hello, input: \${params.a} and \${params.b}\` };
};`,
};
const DEFAULT_TEMPLATE_FUNCTION_CODE = `export const main = async (params: { a: string; b: number }): Promise<object> => {
return { message: \`Toto: \${params.a} and \${params.b}\` };
};`;
// Test function using external packages from default layer (lodash.groupby)
const EXTERNAL_PACKAGES_FUNCTION_CODE = {
'src/index.ts': `import groupBy from 'lodash.groupby';
const EXTERNAL_PACKAGES_FUNCTION_CODE = `import groupBy from 'lodash.groupby';
export const main = async (params: { items: Array<{ category: string; name: string }> }): Promise<object> => {
const grouped = groupBy(params.items, 'category');
@@ -22,18 +19,15 @@ export const main = async (params: { items: Array<{ category: string; name: stri
grouped,
categories: Object.keys(grouped),
};
};`,
};
};`;
// Test function that throws an error
const ERROR_FUNCTION_CODE = {
'src/index.ts': `export const main = async (params: { shouldFail: boolean }): Promise<object> => {
const ERROR_FUNCTION_CODE = `export const main = async (params: { shouldFail: boolean }): Promise<object> => {
if (params.shouldFail) {
throw new Error('Intentional test error');
}
return { success: true };
};`,
};
};`;
describe('Logic Function Execution', () => {
const createdFunctionIds: string[] = [];
@@ -54,22 +48,28 @@ describe('Logic Function Execution', () => {
it('should execute the default logic function template', async () => {
// Create the function with default template code
const { data: createData } = await createDefaultLogicFunction({
const { data: createData } = await createOneLogicFunction({
input: {
name: 'Test Default Function',
},
expectToFail: false,
});
const functionId = createData?.createDefaultLogicFunction?.id;
const functionId = createData?.createOneLogicFunction?.id;
expect(functionId).toBeDefined();
createdFunctionIds.push(functionId);
await updateLogicFunctionSource({
input: {
id: createData.createDefaultLogicFunction.id,
code: DEFAULT_TEMPLATE_FUNCTION_CODE,
id: createData.createOneLogicFunction.id,
update: {
sourceHandlerCode: DEFAULT_TEMPLATE_FUNCTION_CODE,
toolInputSchema: {
type: 'object',
properties: { message: { type: 'string' } },
},
},
},
expectToFail: false,
});
@@ -79,7 +79,6 @@ describe('Logic Function Execution', () => {
input: {
id: functionId,
payload: { a: 'hello', b: 42 },
forceRebuild: true,
},
expectToFail: false,
});
@@ -92,29 +91,35 @@ describe('Logic Function Execution', () => {
expect(result?.status).toBe(LogicFunctionExecutionStatus.SUCCESS);
expect(result?.data).toMatchObject({
message: 'Hello, input: hello and 42',
message: 'Toto: hello and 42',
});
expect(result?.duration).toBeGreaterThan(0);
});
it('should execute a function with external packages (lodash.groupby)', async () => {
// Create the function with the external packages code
const { data: createData } = await createDefaultLogicFunction({
const { data: createData } = await createOneLogicFunction({
input: {
name: 'External Packages Test',
},
expectToFail: false,
});
const functionId = createData?.createDefaultLogicFunction?.id;
const functionId = createData?.createOneLogicFunction?.id;
expect(functionId).toBeDefined();
createdFunctionIds.push(functionId);
await updateLogicFunctionSource({
input: {
id: createData.createDefaultLogicFunction.id,
code: EXTERNAL_PACKAGES_FUNCTION_CODE,
id: createData.createOneLogicFunction.id,
update: {
sourceHandlerCode: EXTERNAL_PACKAGES_FUNCTION_CODE,
toolInputSchema: {
type: 'object',
properties: { message: { type: 'string' } },
},
},
},
expectToFail: false,
});
@@ -130,7 +135,6 @@ describe('Logic Function Execution', () => {
{ category: 'fruit', name: 'banana' },
],
},
forceRebuild: true,
},
expectToFail: false,
});
@@ -160,24 +164,110 @@ describe('Logic Function Execution', () => {
);
});
it('should create logic function without source', async () => {
// Create the function with default template code
const { data: createData } = await createOneLogicFunction({
input: {
name: 'Test Default Function',
},
expectToFail: false,
});
const functionId = createData?.createOneLogicFunction?.id;
expect(functionId).toBeDefined();
createdFunctionIds.push(functionId);
// Execute with the default template's expected params: { a: string, b: number }
const { data: executeData } = await executeLogicFunction({
input: {
id: functionId,
payload: { a: 'hello', b: 42 },
},
expectToFail: false,
});
const result = executeData?.executeOneLogicFunction;
if (result?.status !== LogicFunctionExecutionStatus.SUCCESS) {
throw new Error(JSON.stringify(result?.error, null, 2));
}
expect(result?.status).toBe(LogicFunctionExecutionStatus.SUCCESS);
expect(result?.data).toMatchObject({
message: 'Hello, input: hello and 42',
});
expect(result?.duration).toBeGreaterThan(0);
});
it('should create logic function with source', async () => {
// Create the function with default template code
const { data: createData } = await createOneLogicFunction({
input: {
name: 'Test Default Function',
source: {
sourceHandlerCode: DEFAULT_TEMPLATE_FUNCTION_CODE,
toolInputSchema: {
type: 'object',
properties: { message: { type: 'string' } },
},
handlerName: 'main',
},
},
expectToFail: false,
});
const functionId = createData?.createOneLogicFunction?.id;
expect(functionId).toBeDefined();
createdFunctionIds.push(functionId);
// Execute with the default template's expected params: { a: string, b: number }
const { data: executeData } = await executeLogicFunction({
input: {
id: functionId,
payload: { a: 'hello', b: 42 },
},
expectToFail: false,
});
const result = executeData?.executeOneLogicFunction;
if (result?.status !== LogicFunctionExecutionStatus.SUCCESS) {
throw new Error(JSON.stringify(result?.error, null, 2));
}
expect(result?.status).toBe(LogicFunctionExecutionStatus.SUCCESS);
expect(result?.data).toMatchObject({
message: 'Toto: hello and 42',
});
expect(result?.duration).toBeGreaterThan(0);
});
it('should handle errors thrown by logic functions', async () => {
// Create the function with error-throwing code
const { data: createData } = await createDefaultLogicFunction({
const { data: createData } = await createOneLogicFunction({
input: {
name: 'Error Test Function',
},
expectToFail: false,
});
const functionId = createData?.createDefaultLogicFunction?.id;
const functionId = createData?.createOneLogicFunction?.id;
expect(functionId).toBeDefined();
createdFunctionIds.push(functionId);
await updateLogicFunctionSource({
input: {
id: createData.createDefaultLogicFunction.id,
code: ERROR_FUNCTION_CODE,
id: createData.createOneLogicFunction.id,
update: {
sourceHandlerCode: ERROR_FUNCTION_CODE,
toolInputSchema: {
type: 'object',
properties: { message: { type: 'string' } },
},
},
},
expectToFail: false,
});
@@ -187,7 +277,6 @@ describe('Logic Function Execution', () => {
input: {
id: functionId,
payload: { shouldFail: false },
forceRebuild: true,
},
expectToFail: false,
});
@@ -204,7 +293,6 @@ describe('Logic Function Execution', () => {
input: {
id: functionId,
payload: { shouldFail: true },
forceRebuild: true,
},
expectToFail: false, // The GraphQL call succeeds, but the function execution fails
});
@@ -1,32 +0,0 @@
import gql from 'graphql-tag';
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
import { type CreateDefaultLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input';
export type CreateDefaultLogicFunctionFactoryInput =
CreateDefaultLogicFunctionInput;
const DEFAULT_LOGIC_FUNCTION_GQL_FIELDS = `
id
name
description
runtime
createdAt
updatedAt
`;
export const createDefaultLogicFunctionQueryFactory = ({
input,
gqlFields = DEFAULT_LOGIC_FUNCTION_GQL_FIELDS,
}: PerformMetadataQueryParams<CreateDefaultLogicFunctionFactoryInput>) => ({
query: gql`
mutation CreateDefaultOneLogicFunction($input: CreateDefaultLogicFunctionInput!) {
createDefaultLogicFunction(input: $input) {
${gqlFields}
}
}
`,
variables: {
input,
},
});
@@ -0,0 +1,32 @@
import gql from 'graphql-tag';
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
import { type CreateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function-from-source.input';
export type CreateLogicFunctionFactoryInput =
CreateLogicFunctionFromSourceInput;
const LOGIC_FUNCTION_GQL_FIELDS = `
id
name
description
runtime
createdAt
updatedAt
`;
export const createOneLogicFunctionQueryFactory = ({
input,
gqlFields = LOGIC_FUNCTION_GQL_FIELDS,
}: PerformMetadataQueryParams<CreateLogicFunctionFactoryInput>) => ({
query: gql`
mutation CreateOneLogicFunction($input: CreateLogicFunctionFromSourceInput!) {
createOneLogicFunction(input: $input) {
${gqlFields}
}
}
`,
variables: {
input,
},
});
@@ -1,7 +1,4 @@
import {
type CreateDefaultLogicFunctionFactoryInput,
createDefaultLogicFunctionQueryFactory,
} from 'test/integration/metadata/suites/logic-function/utils/create-default-logic-function-query-factory.util';
import { createOneLogicFunctionQueryFactory } from 'test/integration/metadata/suites/logic-function/utils/create-logic-function-query-factory.util';
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
@@ -9,16 +6,17 @@ import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
import { type LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto';
import { type CreateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function-from-source.input';
export const createDefaultLogicFunction = async ({
export const createOneLogicFunction = async ({
input,
gqlFields,
expectToFail = false,
token,
}: PerformMetadataQueryParams<CreateDefaultLogicFunctionFactoryInput>): CommonResponseBody<{
createDefaultLogicFunction: LogicFunctionDTO;
}: PerformMetadataQueryParams<CreateLogicFunctionFromSourceInput>): CommonResponseBody<{
createOneLogicFunction: LogicFunctionDTO;
}> => {
const graphqlOperation = createDefaultLogicFunctionQueryFactory({
const graphqlOperation = createOneLogicFunctionQueryFactory({
input,
gqlFields,
});
@@ -1,19 +1,19 @@
import gql from 'graphql-tag';
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
import { type UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-source.input';
import { type UpdateLogicFunctionFromSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-from-source.input';
export type UpdateLogicFunctionSourceFactoryInput =
UpdateLogicFunctionSourceInput;
export type UpdateLogicFunctionFromSourceFactoryInput =
UpdateLogicFunctionFromSourceInput;
export const updateLogicFunctionSourceQueryFactory = ({
export const updateLogicFunctionFromSourceQueryFactory = ({
input,
}: PerformMetadataQueryParams<UpdateLogicFunctionSourceFactoryInput>) => ({
}: PerformMetadataQueryParams<UpdateLogicFunctionFromSourceFactoryInput>) => ({
query: gql`
mutation UpdateLogicFunctionSource(
$input: UpdateLogicFunctionSourceInput!
mutation UpdateOneLogicFunction(
$input: UpdateLogicFunctionFromSourceInput!
) {
updateLogicFunctionSource(input: $input)
updateOneLogicFunction(input: $input)
}
`,
variables: {
@@ -4,8 +4,8 @@ import { type PerformMetadataQueryParams } from 'test/integration/metadata/types
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
import {
type UpdateLogicFunctionSourceFactoryInput,
updateLogicFunctionSourceQueryFactory,
type UpdateLogicFunctionFromSourceFactoryInput,
updateLogicFunctionFromSourceQueryFactory,
} from 'test/integration/metadata/suites/logic-function/utils/update-logic-function-source-query-factory.util';
import { type LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto';
@@ -15,10 +15,10 @@ export const updateLogicFunctionSource = async ({
gqlFields,
expectToFail = false,
token,
}: PerformMetadataQueryParams<UpdateLogicFunctionSourceFactoryInput>): CommonResponseBody<{
}: PerformMetadataQueryParams<UpdateLogicFunctionFromSourceFactoryInput>): CommonResponseBody<{
updateOneLogicFunction: LogicFunctionDTO;
}> => {
const graphqlOperation = updateLogicFunctionSourceQueryFactory({
const graphqlOperation = updateLogicFunctionFromSourceQueryFactory({
input,
gqlFields,
});