test improved

This commit is contained in:
Lucio Lelii 2025-07-03 15:49:29 +02:00
parent d9f733e845
commit c01271e98b
10 changed files with 303 additions and 286 deletions

View File

@ -60,6 +60,9 @@ public class ExecutionObject implements ResultListener {
public void setInputSteps(List<InputStep> inputSteps) {
this.inputSteps = inputSteps;
this.exepectedInputsDescription = new HashMap<>();
for (InputStep inputStep : inputSteps)
this.exepectedInputsDescription.put(inputStep.getInputName(), inputStep.getType());
}
@Override

View File

@ -35,14 +35,18 @@ public class ExecutionContext {
return initState;
}
public boolean isFinaltate() {
public boolean isFinalState() {
return finalState;
}
public boolean isRunningState() {
return !finalState && !initState;
}
}
Map<String, Object> inputs = new HashMap<>();
@Getter(AccessLevel.PROTECTED)
@Getter()
private Map<String, Object> result = new HashMap<>();
Long startTime = null;

View File

@ -1,5 +1,6 @@
package it.cnr.isti.workflow.manager.model.steps;
import it.cnr.isti.workflow.manager.model.types.IOType;
import it.cnr.isti.workflow.manager.model.types.nodes.definitions.InputNodeDefinition;
import lombok.Builder;
import lombok.Data;
@ -10,15 +11,17 @@ import lombok.NonNull;
@EqualsAndHashCode(callSuper = true)
public class InputStep extends Step implements ExecutableStep {
IOType type;
Object fieldValue;
String inputName;
@Builder
InputStep(@NonNull String id,@NonNull String inputName) {
InputStep(@NonNull String id,@NonNull String inputName, @NonNull IOType type) {
this.id = id;
this.inputName = inputName;
this.type = type;
}
public void setFieldValue(Object fieldValue) {

View File

@ -7,7 +7,6 @@ import java.util.Map;
import it.cnr.isti.workflow.manager.model.InputReadyListener;
import it.cnr.isti.workflow.manager.model.types.IOType;
import it.cnr.isti.workflow.manager.model.types.nodes.definitions.OutputNodeDefinition;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -70,13 +70,14 @@ public class TransformerService {
Step step = switch (getNodeDefinition(node.getType())) {
case InputNodeDefinition id -> {
String inputName = (String) node.getParameters().get(InputNodeDefinition.INPUT_PARAMETER_KEY);
yield InputStep.builder().id(node.getKey()).inputName(inputName).build();
IOType type = IOType.fromString(node.getOutputs().getFirst().getType());
yield InputStep.builder().id(node.getKey()).inputName(inputName).type(type).build();
}
case UserNodeDefinition ud -> getExecutionStep(node, ud, execObject.getContext());
case OutputNodeDefinition od -> {
IOType inputType = IOType.fromString(node.getInputs().getFirst().getType());
IOType type = IOType.fromString(node.getInputs().getFirst().getType());
String outputName = (String) node.getParameters().get(OutputNodeDefinition.INPUT_PARAMETER_KEY);
yield OutputStep.builder().id(node.getKey()).type(inputType).outputName(outputName).build();
yield OutputStep.builder().id(node.getKey()).type(type).outputName(outputName).build();
}
default -> throw new IllegalArgumentException("Node type " + node.getType() + " not supported");
};

View File

@ -0,0 +1,21 @@
package it.cnr.isti.workflow.manager;
import org.aspectj.weaver.ast.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import it.cnr.isti.workflow.manager.repositories.NodeDefinitionRepository;
@TestConfiguration
public class Configurations {
@Autowired
NodeDefinitionRepository nodeDefinitionRepository;
@Bean
public TestFlowCreator myTestHelper() {
return new TestFlowCreator(nodeDefinitionRepository);
}
}

View File

@ -0,0 +1,57 @@
package it.cnr.isti.workflow.manager;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import it.cnr.isti.workflow.manager.executors.ExecutionObject;
import it.cnr.isti.workflow.manager.model.ExecutionContext.Status;
import it.cnr.isti.workflow.manager.services.ExecutionService;
@SpringBootTest
@TestPropertySource(locations = "classpath:test.properties")
@Import(Configurations.class)
public class ExecutionServiceTest {
private static final Logger log = LoggerFactory.getLogger(ExecutionServiceTest.class);
@Autowired
TestFlowCreator testFlowCreator;
@Autowired
ExecutionService executionService;
@Test()
void testExecutionStateError() {
ExecutionObject execution = executionService.createExecution(testFlowCreator.create());
assertThrows(IllegalStateException.class, () -> executionService.startExecution(execution.getId()));
}
@Test()
void testExecutionRunningSuccess() {
ExecutionObject execution = executionService.createExecution(testFlowCreator.create());
execution = executionService.prepareInput(execution.getId(), TestFlowCreator.INPUT_KEY, "ciao come stai");
execution = executionService.startExecution(execution.getId());
while (execution.getContext().getStatus().isRunningState())
try {
Thread.sleep(1000);
} catch (InterruptedException e) { }
assert execution.getContext().getStatus() == Status.SUCCESS;
assert execution.getContext().getResult().size() == 1;
execution.getContext().getResult().forEach((k, v) -> {
log.info("Output: {} = {}", k, v);
});
}
}

View File

@ -4,36 +4,27 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import org.springframework.util.ResourceUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.cnr.isti.workflow.manager.executors.ExecutionObject;
import it.cnr.isti.workflow.manager.model.ExecutionContext.Status;
import it.cnr.isti.workflow.manager.model.flows.Connection;
import it.cnr.isti.workflow.manager.model.flows.Flow;
import it.cnr.isti.workflow.manager.model.flows.IOModel;
import it.cnr.isti.workflow.manager.model.flows.Node;
import it.cnr.isti.workflow.manager.model.flows.errors.FlowError;
import it.cnr.isti.workflow.manager.model.steps.ResultListener;
import it.cnr.isti.workflow.manager.model.types.IOType;
import it.cnr.isti.workflow.manager.model.types.Translator;
import it.cnr.isti.workflow.manager.model.types.nodes.definitions.NodeDefinition;
import it.cnr.isti.workflow.manager.model.types.nodes.definitions.UserNodeDefinition;
import it.cnr.isti.workflow.manager.repositories.FlowRepository;
import it.cnr.isti.workflow.manager.repositories.NodeDefinitionRepository;
import it.cnr.isti.workflow.manager.services.TransformerService;
@SpringBootTest
@TestPropertySource(locations = "classpath:test.properties")
@Import(Configurations.class)
public class FlowTest {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(FlowTest.class);
@ -44,6 +35,8 @@ public class FlowTest {
@Autowired
TransformerService transformerService;
@Autowired
private TestFlowCreator testFlowCreator;
@Autowired
NodeDefinitionRepository nodeDefinitionRepository;
@ -51,71 +44,7 @@ public class FlowTest {
@Test
void transform() throws Exception {
Translator inputFieldtransaltor = Translator.builder().translation("translate the following phrase : ${{phrase}} in french, return only the translation").build();
NodeDefinition nFrenchTranslator = UserNodeDefinition.builder().name("FrenchTranslator")
.executor("GENERIC-AI").category("Translators").createdBy("lucio.lelii").input("phrase", IOType.TEXT)
.output("translated", IOType.TEXT).inputTranslator("prompt",inputFieldtransaltor).build();
nodeDefinitionRepository.save(nFrenchTranslator);
Flow flow = Flow.builder()
.id("testFlow")
.name("Test Flow")
.description("This is a test flow")
.createdBy("lucio.lelii")
.build();
Map<String, Object> parameter = Map.of("LLM", "google-gemini");
String execNodeKey =UUID.randomUUID().toString();
String execInputKey =UUID.randomUUID().toString();
String execOutputKey =UUID.randomUUID().toString();
Node executionNode = Node.builder().key(execNodeKey)
.name("transaltor to french")
.type("FrenchTranslator")
.input(new IOModel(execInputKey, IOType.TEXT.toString(), "phrase"))
.output(new IOModel(execOutputKey, IOType.TEXT.toString(), "translated"))
.parameters(parameter)
.createdBy("lucio.lelii")
.color("#FF0000")
.build();
String inputNodeKey =UUID.randomUUID().toString();
String inputOutputKey =UUID.randomUUID().toString();
Map<String, Object> inputParameter = Map.of("name", "input");
Node inputNode = Node.builder().key(inputNodeKey)
.name("Input Node")
.type("Text Input")
.output(new IOModel(inputOutputKey, IOType.TEXT.toString(), "value"))
.parameters(inputParameter)
.createdBy("lucio.lelii")
.color("#00FF00")
.build();
String outputNodeKey =UUID.randomUUID().toString();
String outputInputKey =UUID.randomUUID().toString();
Map<String, Object> ouputParameter = Map.of("name", "output");
Node outputNode = Node.builder().key(outputNodeKey)
.name("Output Node")
.type("Text Output")
.input(new IOModel(outputInputKey, IOType.TEXT.toString(), "value"))
.parameters(ouputParameter)
.createdBy("lucio.lelii")
.color("#0000FF")
.build();
flow.setNodes(List.of(inputNode, executionNode, outputNode));
flow.setConnections(List.of(
// Connect input node to execution node
new Connection(UUID.randomUUID().toString(), inputOutputKey, execInputKey),
// Connect execution node to output node
new Connection(UUID.randomUUID().toString(), execOutputKey, outputInputKey)
));
Flow flow = testFlowCreator.create();
ExecutionObject execution = transformerService.transform(flow);
assertNotNull(execution.getInputSteps());

View File

@ -0,0 +1,97 @@
package it.cnr.isti.workflow.manager;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import it.cnr.isti.workflow.manager.model.flows.Connection;
import it.cnr.isti.workflow.manager.model.flows.Flow;
import it.cnr.isti.workflow.manager.model.flows.IOModel;
import it.cnr.isti.workflow.manager.model.flows.Node;
import it.cnr.isti.workflow.manager.model.types.IOType;
import it.cnr.isti.workflow.manager.model.types.Translator;
import it.cnr.isti.workflow.manager.model.types.nodes.definitions.NodeDefinition;
import it.cnr.isti.workflow.manager.model.types.nodes.definitions.UserNodeDefinition;
import it.cnr.isti.workflow.manager.repositories.NodeDefinitionRepository;
public class TestFlowCreator {
private final NodeDefinitionRepository nodeDefinitionRepository;
public static final String INPUT_KEY = "phrase";
public TestFlowCreator(NodeDefinitionRepository nodeDefinitionRepository) {
this.nodeDefinitionRepository = nodeDefinitionRepository;
}
public Flow create(){
Translator inputFieldtransaltor = Translator.builder().translation("translate the following phrase : ${{phrase}} in french, return only the translation").build();
NodeDefinition nFrenchTranslator = UserNodeDefinition.builder().name("FrenchTranslator")
.executor("GENERIC-AI").category("Translators").createdBy("lucio.lelii").input("phrase", IOType.TEXT)
.output("translated", IOType.TEXT).inputTranslator("prompt",inputFieldtransaltor).build();
nodeDefinitionRepository.save(nFrenchTranslator);
Flow flow = Flow.builder()
.id("testFlow")
.name("Test Flow")
.description("This is a test flow")
.createdBy("lucio.lelii")
.build();
Map<String, Object> parameter = Map.of("LLM", "google-gemini");
String execNodeKey =UUID.randomUUID().toString();
String execInputKey =UUID.randomUUID().toString();
String execOutputKey =UUID.randomUUID().toString();
Node executionNode = Node.builder().key(execNodeKey)
.name("transaltor to french")
.type("FrenchTranslator")
.input(new IOModel(execInputKey, IOType.TEXT.toString(), "phrase"))
.output(new IOModel(execOutputKey, IOType.TEXT.toString(), "translated"))
.parameters(parameter)
.createdBy("lucio.lelii")
.color("#FF0000")
.build();
String inputNodeKey =INPUT_KEY;
String inputOutputKey =UUID.randomUUID().toString();
Map<String, Object> inputParameter = Map.of("name", "input");
Node inputNode = Node.builder().key(inputNodeKey)
.name("Input Node")
.type("Text Input")
.output(new IOModel(inputOutputKey, IOType.TEXT.toString(), "value"))
.parameters(inputParameter)
.createdBy("lucio.lelii")
.color("#00FF00")
.build();
String outputNodeKey =UUID.randomUUID().toString();
String outputInputKey =UUID.randomUUID().toString();
Map<String, Object> ouputParameter = Map.of("name", "output");
Node outputNode = Node.builder().key(outputNodeKey)
.name("Output Node")
.type("Text Output")
.input(new IOModel(outputInputKey, IOType.TEXT.toString(), "value"))
.parameters(ouputParameter)
.createdBy("lucio.lelii")
.color("#0000FF")
.build();
flow.setNodes(List.of(inputNode, executionNode, outputNode));
flow.setConnections(List.of(
// Connect input node to execution node
new Connection(UUID.randomUUID().toString(), inputOutputKey, execInputKey),
// Connect execution node to output node
new Connection(UUID.randomUUID().toString(), execOutputKey, outputInputKey)
));
return flow;
}
}

View File

@ -1,255 +1,158 @@
{
"id": "2d3c532f-a8be-46c3-a601-495fc6de21f1",
"createdBy": "lucio.lelii",
"name": "testgen",
"name": "myFlow",
"description": null,
"nodes": [
{
"key": "3b0b2489-61a5-4024-98fb-42cdfca2dafa",
"key": "e5f1f8d6-7717-4e32-ab57-f25f38f55401",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "b38c0c63-4ac5-4225-b5b6-d1e1b7434842",
"key": "2967ca92-3977-44ad-8e19-318b9a71d227",
"type": "text",
"name": "value"
}
],
"inputs": [],
"color": "#A8E6CF",
"position": {
"x": -270,
"y": -16
},
"parameters": {
"name": "interview\n"
},
"description": null,
"type": "Text Input"
},
{
"key": "1a4d1254-2c44-49fa-8aee-3865d1be9f95",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "f36c7ae1-78da-4d71-8b44-58a1f87f17cb",
"type": "text",
"name": "requirements"
}
],
"inputs": [
{
"key": "7860945a-506b-45a3-97b6-cbf08023e421",
"type": "text",
"name": "interview"
}
],
"color": "#A8E6CF",
"position": {
"x": -6,
"y": -22
},
"parameters": {
"LLM": "llama3.1:8b"
},
"description": null,
"type": "Requirement Generator"
},
{
"key": "394f3a84-f8b0-4cf6-92c7-042e6be03a26",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "a73eb6d8-9010-428e-a0cd-0831fcba6c42",
"type": "text",
"name": "corrected-requirements"
}
],
"inputs": [
{
"key": "e83aebf3-05dd-4588-b9a3-03fd7253e5fc",
"type": "text",
"name": "requirement-smells"
}
],
"color": "#A8E6CF",
"position": {
"x": 321,
"y": -21
},
"parameters": {
"LLM": "gemma3:12b"
},
"description": null,
"type": "Requirements Corrector"
},
{
"key": "511a2b09-dde6-4877-97ed-92819da4b778",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "96750771-855b-4013-9959-ac8b3fd17133",
"type": "text",
"name": "requirement-smells"
}
],
"inputs": [
{
"key": "b254b9d1-71cf-4c87-9875-eeddf47b89a5",
"key": "059dad32-a3ea-4a34-b77e-f747c2baf864",
"type": "text",
"name": "requirements"
}
],
"color": "#A8E6CF",
"position": {
"x": -199,
"y": 562
"x": 707,
"y": -22
},
"parameters": {
"LLM": "google-gemini"
"LLM": "codellama:latest"
},
"description": null,
"type": "Requirements Analyzer"
},
{
"key": "2bfc55bf-1e15-4e14-8e75-0f1c1cb305f5",
"key": "fce51437-94c9-453e-aced-c303b08dcca7",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "e0fe597b-712d-496e-9780-d3c4a6eb729b",
"type": "text",
"name": "corrected-requirements"
}
],
"outputs": [],
"inputs": [
{
"key": "0e7016a9-43ef-4ce5-9e54-403811061e2c",
"key": "696fb55c-afd7-4fd5-a77c-08ea6377d186",
"type": "text",
"name": "requirement-smells"
"name": "value"
}
],
"color": "#A8E6CF",
"position": {
"x": 398,
"y": -113
"x": 1073,
"y": 13
},
"parameters": {
"LLM": "google-gemini"
"name": "output1"
},
"description": null,
"type": "Requirements Corrector"
},
{
"key": "a1412e6e-0c32-4615-af3e-c318f8b609f1",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "a7eaf186-5fc9-48b0-b76f-fdcad73e4d7a",
"type": "text",
"name": "output"
}
],
"inputs": [
{
"key": "11a14440-8d94-420d-99dc-79bc6fcbab3f",
"type": "text",
"name": "input"
}
],
"color": "#A8E6CF",
"position": {
"x": -186.00000000000003,
"y": -105.19140625000011
},
"parameters": null,
"description": null,
"type": "InputDispatcher"
},
{
"key": "8d3e4cf7-5dc0-48ef-b94e-98d8f0a8ccc7",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "caaa6d9a-af43-4501-968e-1bba415818d4",
"type": "text",
"name": "plant-uml"
}
],
"inputs": [
{
"key": "b31f2183-c35e-4a7b-871c-a6fe553687c0",
"type": "text",
"name": "corrected-requirements"
},
{
"key": "296d4535-8082-4b90-9814-306201887cae",
"type": "text",
"name": "interview-script"
}
],
"color": "#A8E6CF",
"position": {
"x": 541,
"y": 270
},
"parameters": {
"LLM": "google-gemini"
},
"description": null,
"type": "Class Modeller (UML)"
},
{
"key": "252071ea-2a74-46af-b9e7-08f02771c6c6",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "6c9465a6-e1f6-4c76-94fe-eddaf3671250",
"type": "text",
"name": "plantuml-sequence-diagram"
}
],
"inputs": [
{
"key": "94064079-0d19-4cec-9391-6ab1ac6e1e18",
"type": "text",
"name": "interview"
},
{
"key": "a5bf84d5-7a15-422a-820a-a8490943404c",
"type": "text",
"name": "plantuml-class-diagram"
},
{
"key": "83a47422-033a-45c9-aac6-ecd4de4b2b9c",
"type": "text",
"name": "corrected-requirements"
}
],
"color": "#A8E6CF",
"position": {
"x": 999,
"y": 461
},
"parameters": {
"LLM": "google-gemini"
},
"description": null,
"type": "Sequence Modeler"
},
{
"key": "d44d8b30-ab97-4a9c-9475-1f7b2c54a581",
"name": "newNode",
"createdBy": null,
"outputs": [
{
"key": "6d37eb52-3bc2-4dd9-8985-0b17f8db92ba",
"type": "text",
"name": "source-code"
}
],
"inputs": [
{
"key": "87c429c4-c876-48df-a1f8-c772e3da63f1",
"type": "text",
"name": "corrected-requirements"
},
{
"key": "edf43f01-fbe9-4bc3-ae8b-43c5ac3ba0c8",
"type": "text",
"name": "class-diagram"
},
{
"key": "f0546984-491e-420e-97c2-a54a330c8ba2",
"type": "text",
"name": "sequence-diagram"
}
],
"color": "#A8E6CF",
"position": {
"x": 313,
"y": 564
},
"parameters": {
"LLM": "google-gemini"
},
"description": null,
"type": "Code Generator"
"type": "Text Output"
}
],
"connections": [
{
"key": "8829a219-4985-40e4-8453-c725e2f3c608",
"from": "b38c0c63-4ac5-4225-b5b6-d1e1b7434842",
"to": "0e7016a9-43ef-4ce5-9e54-403811061e2c"
"key": "f8b4dbaa-a9cc-4470-89a2-7b999d905d9b",
"from": "2967ca92-3977-44ad-8e19-318b9a71d227",
"to": "7860945a-506b-45a3-97b6-cbf08023e421"
},
{
"key": "359be251-dfad-4c0f-8759-251fd36b0005",
"from": "e0fe597b-712d-496e-9780-d3c4a6eb729b",
"to": "b31f2183-c35e-4a7b-871c-a6fe553687c0"
"key": "ec5ed95b-e546-4ee2-957b-039649f3fac4",
"from": "a73eb6d8-9010-428e-a0cd-0831fcba6c42",
"to": "059dad32-a3ea-4a34-b77e-f747c2baf864"
},
{
"key": "9aa48a8c-d56d-49db-bf5f-9ebec0d750ea",
"from": "a7eaf186-5fc9-48b0-b76f-fdcad73e4d7a",
"to": "296d4535-8082-4b90-9814-306201887cae"
},
{
"key": "4923b0de-5885-4e17-bd8f-ccf3177278a9",
"from": "e0fe597b-712d-496e-9780-d3c4a6eb729b",
"to": "83a47422-033a-45c9-aac6-ecd4de4b2b9c"
},
{
"key": "a16d869b-7eb6-45d5-8549-53b2c74e9378",
"from": "caaa6d9a-af43-4501-968e-1bba415818d4",
"to": "a5bf84d5-7a15-422a-820a-a8490943404c"
},
{
"key": "80e8947e-fc2e-4e35-84a0-f4810504bcaa",
"from": "a7eaf186-5fc9-48b0-b76f-fdcad73e4d7a",
"to": "94064079-0d19-4cec-9391-6ab1ac6e1e18"
},
{
"key": "13861a56-c812-47d1-85d6-9edb55918d6e",
"from": "e0fe597b-712d-496e-9780-d3c4a6eb729b",
"to": "87c429c4-c876-48df-a1f8-c772e3da63f1"
},
{
"key": "a81ea345-7e44-435b-b9a3-3e875e0305ff",
"from": "caaa6d9a-af43-4501-968e-1bba415818d4",
"to": "edf43f01-fbe9-4bc3-ae8b-43c5ac3ba0c8"
},
{
"key": "d2ac98b4-66be-4734-919b-753fcd04dd17",
"from": "6c9465a6-e1f6-4c76-94fe-eddaf3671250",
"to": "f0546984-491e-420e-97c2-a54a330c8ba2"
"key": "f588626b-8e2d-4ca4-94c9-04ce25c9c1b8",
"from": "96750771-855b-4013-9959-ac8b3fd17133",
"to": "696fb55c-afd7-4fd5-a77c-08ea6377d186"
}
],
"startNode": "a1412e6e-0c32-4615-af3e-c318f8b609f1",
"endNode": "d44d8b30-ab97-4a9c-9475-1f7b2c54a581",
"public": true
"public": false
}