diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.test.ts index 564ba64cebb..458df1e94cc 100644 --- a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.test.ts +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/SonataFlowService.test.ts @@ -296,6 +296,51 @@ describe('SonataFlowService', () => { expect(result?.id).toBe('12345'); }); + it('should use empty CE data when workflowdata is missing or non-object', async () => { + const kafkaServiceOptionsMock: OrchestratorKafkaServiceOptions = { + clientId: 'kafkaClientId', + brokers: ['localhost:9091'], + }; + const sonataFlowServiceWithKafka = new SonataFlowService( + dataIndexServiceMock, + loggerMock, + kafkaServiceOptionsMock, + ); + + const sendMock = jest.fn(); + + jest + .spyOn( + sonataFlowServiceWithKafka.getOrchestratorKafkaImpl() as any, + 'producer', + ) + .mockImplementation(() => ({ + connect: jest.fn(), + send: sendMock, + disconnect: jest.fn(), + })); + + await sonataFlowServiceWithKafka.executeWorkflowAsCloudEvent({ + definitionId, + workflowSource: 'workflowSource', + workflowEventType: 'workflowEventType', + contextAttribute: 'lockid', + inputData: { + workflowdata: 'not-an-object' as any, + }, + }); + + expect(sendMock).toHaveBeenCalledTimes(1); + + const { messages } = sendMock.mock.calls[0][0]; + const parsed = JSON.parse(messages[0].value); + + expect(parsed.data).toEqual({ + lockid: '12345', + }); + expect(parsed.data.workflowdata).toBeUndefined(); + }); + it('should error on a bad connection', async () => { const kafkaServiceOptionsMock: OrchestratorKafkaServiceOptions = { clientId: 'kafkaClientId', diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/test-utils.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/test-utils.ts index 9cfdb6e832b..628419237ec 100644 --- a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/test-utils.ts +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/test-utils.ts @@ -350,6 +350,25 @@ states: }; } +/** Compiled workflows use start.stateName instead of a string start. */ +export function generateTestWorkflowInfoForEventypeWithStartStateName( + id: string = 'test_workflowId', + base: WorkflowInfo = generateTestWorkflowInfoForEventype(id), +): WorkflowInfo { + const startMarker = 'start: listenToLock'; + const compiledStart = 'start:\n stateName: listenToLock'; + const source = base.source as string; + if (!source.includes(startMarker)) { + throw new Error( + 'Failed to rewrite start to start.stateName: base fixture missing "start: listenToLock"', + ); + } + return { + ...base, + source: source.replace(startMarker, compiledStart), + }; +} + export function generateTestExecuteWorkflowResponse( id: string = 'test_execId', ): WorkflowExecutionResponse { diff --git a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.test.ts b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.test.ts index 05dadb518ef..3c6d3b61df7 100644 --- a/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.test.ts +++ b/workspaces/orchestrator/plugins/orchestrator-backend/src/service/api/v2.test.ts @@ -49,6 +49,7 @@ import { generateTestWorkflowInfoForEventypeNoStartStateNameStates, generateTestWorkflowInfoForEventypeNoStartStates, generateTestWorkflowInfoForEventypeWithNoCorrelationContextAttribute, + generateTestWorkflowInfoForEventypeWithStartStateName, generateTestWorkflowOverview, generateTestWorkflowOverviewList, generateWorkflowDefinition, @@ -452,6 +453,94 @@ describe('executeWorkflow as event type', () => { // Assert expect(actualResultV2).toBeDefined(); expect(actualResultV2.id).toBeDefined(); + expect( + mockOrchestratorService.executeWorkflowAsCloudEvent, + ).toHaveBeenCalledWith( + expect.objectContaining({ + definitionId: workflowInfo.id, + workflowEventType: 'lock-event', + workflowSource: 'local', + contextAttribute: 'lockid', + inputData: expect.objectContaining({ + workflowdata: workflowData, + initiatorEntity: 'someUserEntity', + targetEntity: 'someEntity', + }), + backstageToken: 'someToken', + }), + ); + }); + + it('throws when compiled start.stateName fixture cannot rewrite start', () => { + expect(() => + generateTestWorkflowInfoForEventypeWithStartStateName('test_workflowId', { + id: 'test_workflowId', + source: 'id: lock-flow\nstart: somethingElse\n', + }), + ).toThrow(/Failed to rewrite start to start.stateName/); + }); + + it('executes a given workflow: event type with compiled start.stateName', async () => { + // Arrange + const correlationContextAttributeId = '12345'; + const workflowInfo = + generateTestWorkflowInfoForEventypeWithStartStateName(); + const execResponse = generateTestExecuteWorkflowResponse( + correlationContextAttributeId, + ); + (mockOrchestratorService.fetchWorkflowInfo as jest.Mock).mockResolvedValue( + workflowInfo, + ); + ( + mockOrchestratorService.pingWorkflowService as jest.Mock + ).mockResolvedValue(workflowInfo); + + const processInstance = generateProcessInstanceForEventType( + 1, + correlationContextAttributeId, + ); + + (mockOrchestratorService.fetchInstances as jest.Mock).mockResolvedValue([ + processInstance, + ]); + + ( + mockOrchestratorService.executeWorkflowAsCloudEvent as jest.Mock + ).mockResolvedValue(execResponse); + const workflowData = { + customAttrib: 'My customAttrib', + isEvent: true, + }; + // Act + const actualResultV2: ExecuteWorkflowResponseDTO = await v2.executeWorkflow( + { + inputData: workflowData, + targetEntity: 'someEntity', + }, + workflowInfo.id, + 'someUserEntity', + 'someToken', + ); + + // Assert + expect(actualResultV2).toBeDefined(); + expect(actualResultV2.id).toBeDefined(); + expect( + mockOrchestratorService.executeWorkflowAsCloudEvent, + ).toHaveBeenCalledWith( + expect.objectContaining({ + definitionId: workflowInfo.id, + workflowEventType: 'lock-event', + workflowSource: 'local', + contextAttribute: 'lockid', + inputData: expect.objectContaining({ + workflowdata: workflowData, + initiatorEntity: 'someUserEntity', + targetEntity: 'someEntity', + }), + backstageToken: 'someToken', + }), + ); }); it('executes a given workflow: event type, no instance, not an error', async () => {