Skip to content

Commit

Permalink
Adapt inputs and outputs when turning a Spec into an Activity
Browse files Browse the repository at this point in the history
  • Loading branch information
echebbi committed Mar 19, 2019
1 parent 7e13576 commit 6eca9bf
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,36 @@
package fr.kazejiyu.ekumi.spec2workflow;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.eclipse.emf.common.util.EList;

import fr.kazejiyu.ekumi.EKumiPlugin;
import fr.kazejiyu.ekumi.model.datatypes.DataType;
import fr.kazejiyu.ekumi.model.datatypes.DataTypeFactory;
import fr.kazejiyu.ekumi.model.datatypes.exceptions.DataTypeUnserializationException;
import fr.kazejiyu.ekumi.model.scripting.ScriptingLanguage;
import fr.kazejiyu.ekumi.model.scripting.ScriptingLanguageFactory;
import fr.kazejiyu.ekumi.model.spec.ActivityAdapter;
import fr.kazejiyu.ekumi.model.spec.Divergence;
import fr.kazejiyu.ekumi.model.spec.ExternalTask;
import fr.kazejiyu.ekumi.model.spec.Node;
import fr.kazejiyu.ekumi.model.spec.ParallelSplit;
import fr.kazejiyu.ekumi.model.spec.Start;
import fr.kazejiyu.ekumi.model.spec.Synchronization;
import fr.kazejiyu.ekumi.model.spec.ActivityAdapter;
import fr.kazejiyu.ekumi.model.spec.util.SpecSwitch;
import fr.kazejiyu.ekumi.model.workflow.Activity;
import fr.kazejiyu.ekumi.model.workflow.ScriptedTask;
import fr.kazejiyu.ekumi.model.workflow.Sequence;
import fr.kazejiyu.ekumi.model.workflow.Variable;
import fr.kazejiyu.ekumi.model.workflow.WorkflowFactory;

public class BasicWorkflowAdapter extends SpecSwitch<Activity> implements ActivityAdapter {

@SuppressWarnings("unused") // Will be used as soon as inputs & outputs are handled
private DataTypeFactory datatypes;

private ScriptingLanguageFactory languages;
Expand Down Expand Up @@ -134,6 +142,8 @@ public Activity caseExternalTask(ExternalTask task) {
script.setId(task.getId());
script.setName(task.getName());
script.setScriptPath(task.getScriptId());
script.getInputs().addAll(adapt(script, task.getInputs()));
script.getOutputs().addAll(adapt(script, task.getOutputs()));

Optional<ScriptingLanguage> scriptLanguage = languages.find(task.getLanguageId());
scriptLanguage.ifPresent(script::setLanguage);
Expand All @@ -144,6 +154,36 @@ public Activity caseExternalTask(ExternalTask task) {
return script;
}

private List<Variable> adapt(Activity activity, EList<fr.kazejiyu.ekumi.model.spec.Variable> variables) {
return variables.stream()
.map(this::adapt)
.filter(Objects::nonNull)
.peek(variable -> variable.setOwner(activity))
.collect(toList());
}

private Variable adapt(fr.kazejiyu.ekumi.model.spec.Variable variable) {
Variable adapted = WorkflowFactory.eINSTANCE.createVariable();
adapted.setName(variable.getName());
Optional<DataType<?>> datatype = datatypes.find(variable.getTypeId());

if (! datatype.isPresent()) {
adapted.setValue(null);
}
else {
adapted.setType(datatype.get());
try {
adapted.setValue(datatype.get().unserialize(variable.getValue()));
}
catch (DataTypeUnserializationException e) {
EKumiPlugin.warn(e, "Unable to set value of variable " + variable.getName() + ", setting value to default");
adapted.setValue(datatype.get().getDefaultValue());
}
}

return adapted;
}

@Override
public Activity caseParallelSplit(ParallelSplit spec) {
fr.kazejiyu.ekumi.model.workflow.ParallelSplit split = WorkflowFactory.eINSTANCE.createParallelSplit();
Expand Down Expand Up @@ -189,5 +229,5 @@ public Activity caseSynchronization(Synchronization sync) {
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;

import fr.kazejiyu.ekumi.model.datatypes.DataType;
import fr.kazejiyu.ekumi.model.datatypes.DataTypeFactory;
import fr.kazejiyu.ekumi.model.datatypes.exceptions.DataTypeUnserializationException;
import fr.kazejiyu.ekumi.model.scripting.ScriptingLanguage;
import fr.kazejiyu.ekumi.model.scripting.ScriptingLanguageFactory;
import fr.kazejiyu.ekumi.model.spec.Divergence;
Expand All @@ -33,6 +36,7 @@
import fr.kazejiyu.ekumi.model.workflow.ParallelSplit;
import fr.kazejiyu.ekumi.model.workflow.ScriptedTask;
import fr.kazejiyu.ekumi.model.workflow.Sequence;
import fr.kazejiyu.ekumi.model.workflow.Variable;
import fr.kazejiyu.ekumi.tests.common.mock.MockitoExtension;

@ExtendWith(MockitoExtension.class)
Expand Down Expand Up @@ -286,6 +290,162 @@ void creates_a_ScriptedTask_without_any__ScriptingLanguage() {
}
}

@Nested @DisplayName("that has inputs")
class ThatHasInputs {

private fr.kazejiyu.ekumi.model.spec.Variable input;
private DataType<Double> datatype;

@SuppressWarnings("unchecked")
@BeforeEach
void createInputs() {
input = SpecFactory.eINSTANCE.createVariable();
input.setName("Input 1");
input.setTypeId("mocked-datatype");
input.setValue("mocked-value");
task.getInputs().add(input);

datatype = Mockito.mock(DataType.class);
when (datatypes.find("mocked-datatype")) .thenReturn(Optional.of(datatype));
when (datatype.unserialize("mocked-value")) .thenReturn(5.0);
}

@Test @DisplayName("adapts the inputs")
void adapts_the_inputs() {
Activity adapted = adapter.caseExternalTask(task);

assertThat(adapted.getInputs()).size().isEqualTo(1);

Variable variable = adapted.getInputs().get(0);

SoftAssertions softly = new SoftAssertions();
softly.assertThat(variable.getName()).isEqualTo(input.getName());
softly.assertThat(variable.getOwner()).isEqualTo(adapted);
softly.assertThat(variable.getType()).isEqualTo(datatype);
softly.assertThat(variable.getValue()).isEqualTo(5.0);
softly.assertAll();
}

@Nested @DisplayName("which datatype is unknown")
class WhichDatatypeIsUnknown {

@BeforeEach
void setInputDatatype() {
input.setTypeId("idonotexist");
}

@Test @DisplayName("adapt the input with a null value")
void adapt_the_input_with_a_null_value() {
Activity adapted = adapter.caseExternalTask(task);
Variable adaptedInput = adapted.getInputs().get(0);

assertThat(adaptedInput.getValue()).isNull();
}

}

@Nested @DisplayName("which value cannot be unserialize")
class WhichValueCannotBeUnserialize {

private final static double DEFAULT_VAL = 0d;

@BeforeEach
void makeValueUnserializable() {
input.setValue("unserializable");
when (datatype.unserialize("unserializable")) .thenThrow(DataTypeUnserializationException.class);
when (datatype.getDefaultValue()) .thenReturn(DEFAULT_VAL);
}

@Test @DisplayName("adapt the input with datatype's default value")
void adapt_the_input_with_datatype_default_value() {
Activity adapted = adapter.caseExternalTask(task);
Variable adaptedInput = adapted.getInputs().get(0);

assertThat(adaptedInput.getValue()).isEqualTo(DEFAULT_VAL);
}

}

}

@Nested @DisplayName("that has outputs")
class ThatHasOutputs {

private fr.kazejiyu.ekumi.model.spec.Variable output;

@Mock
private DataType<Double> datatype;

@BeforeEach
void createOutputs() {
output = SpecFactory.eINSTANCE.createVariable();
output.setName("Output 1");
output.setTypeId("mocked-datatype");
output.setValue("mocked-value");
task.getOutputs().add(output);

when (datatypes.find("mocked-datatype")) .thenReturn(Optional.of(datatype));
when (datatype.unserialize("mocked-value")) .thenReturn(5.0);
}

@Test @DisplayName("adapts the outputs")
void adapts_the_outputs() {
Activity adapted = adapter.caseExternalTask(task);

assertThat(adapted.getOutputs()).size().isEqualTo(1);

Variable variable = adapted.getOutputs().get(0);

SoftAssertions softly = new SoftAssertions();
softly.assertThat(variable.getName()).isEqualTo(output.getName());
softly.assertThat(variable.getOwner()).isEqualTo(adapted);
softly.assertThat(variable.getType()).isEqualTo(datatype);
softly.assertThat(variable.getValue()).isEqualTo(5.0);
softly.assertAll();
}

@Nested @DisplayName("which datatype is unknown")
class WhichDatatypeIsUnknown {

@BeforeEach
void setOutputDatatype() {
output.setTypeId("idonotexist");
}

@Test @DisplayName("adapt the output with a null value")
void adapt_the_output_with_a_null_value() {
Activity adapted = adapter.caseExternalTask(task);
Variable adaptedOutput = adapted.getOutputs().get(0);

assertThat(adaptedOutput.getValue()).isNull();
}

}

@Nested @DisplayName("which value cannot be unserialize")
class WhichValueCannotBeUnserialize {

private final static double DEFAULT_VAL = 0d;

@BeforeEach
void makeValueUnserializable() {
output.setValue("unserializable");
when (datatype.unserialize("unserializable")) .thenThrow(DataTypeUnserializationException.class);
when (datatype.getDefaultValue()) .thenReturn(DEFAULT_VAL);
}

@Test @DisplayName("adapt the outputs with datatype's default value")
void adapt_the_outputs_with_datatype_default_value() {
Activity adapted = adapter.caseExternalTask(task);
Variable adaptedOutput = adapted.getOutputs().get(0);

assertThat(adaptedOutput.getValue()).isEqualTo(DEFAULT_VAL);
}

}

}

}

@Nested @DisplayName("when adapting a Synchronization")
Expand Down

0 comments on commit 6eca9bf

Please sign in to comment.