Loading plugins/org.etsi.mts.tdl.execution.java.codegen/src/org/etsi/mts/tdl/execution/java/codegen/JUnitTestGenerator.java +148 −1 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; Loading Loading @@ -1171,7 +1172,153 @@ public class JUnitTestGenerator extends Renderer { } // Multiple blocks else if (b instanceof AlternativeBehaviour) { // XXX String altsListName = "callables_" + getElementName(b); line("List<ExecutionCallable> " + altsListName + " = new java.util.LinkedList<>();"); // Collect info for each alternative block List<FutureInfo> altCallables = new LinkedList<>(); List<Behaviour> altTriggers = new LinkedList<>(); List<Integer> altTriggerIndices = new LinkedList<>(); List<Block> altBlocks = new LinkedList<>(); List<Block> blocks = ((AlternativeBehaviour) b).getBlock(); for (int blockIdx = 0; blockIdx < blocks.size(); blockIdx++) { Block bl = blocks.get(blockIdx); // Find first participating tester-input in this block Behaviour triggerBehaviour = null; int triggerIndex = -1; for (int i = 0; i < bl.getBehaviour().size(); i++) { Behaviour beh = bl.getBehaviour().get(i); if (isParticipating(beh)) { if (!isTesterInput(beh)) throw new RuntimeException( "Alternative block should start with tester input: " + getMessage(beh)); triggerBehaviour = beh; triggerIndex = i; break; } } if (triggerBehaviour == null) continue; lineComment("Alternative " + blockIdx); // Handle guard Optional<LocalExpression> guard = bl.getGuard().stream() .filter(le -> isCurrentComponentInstance(le.getComponentInstance())).findFirst(); if (guard.isPresent()) { DataUse g = guard.get().getExpression(); initializeDataUse(g, dataUseVariables); append("if ("); write(g, dataUseVariables); append(") "); } // Create callable (without submitting) FutureInfo callable = writeTesterInput(triggerBehaviour, dataUseVariables, false, false); line(altsListName + ".add(" + callable.varName + ");"); newLine(); altCallables.add(callable); altTriggers.add(triggerBehaviour); altTriggerIndices.add(triggerIndex); altBlocks.add(bl); } if (!altCallables.isEmpty()) { newLine(); // Submit all alternatives (with batch mode on ReceiverHubs) String futuresName = "altFutures_" + getElementName(b); line("List<Future<ExecutionResult>> " + futuresName + " = " + COMPONENT_FIELD + ".executeAlternatives(" + altsListName + ");"); // Submit exceptionals String excName = "altExc_" + getElementName(b); line("List<Future<ExecutionResult>> " + excName + " = " + COMPONENT_FIELD + ".executeExceptionals();"); newLine(); // Wait for first completion String winnerName = "altWinner_" + getElementName(b); line("Future<ExecutionResult> " + winnerName + " = " + COMPONENT_FIELD + ".next();"); newLine(); append("try "); blockOpen(); // If/else for each alternative for (int i = 0; i < altCallables.size(); i++) { FutureInfo f = altCallables.get(i); Behaviour trigger = altTriggers.get(i); int trigIdx = altTriggerIndices.get(i); Block bl = altBlocks.get(i); if (i > 0) append(" else "); append("if (" + futuresName + ".get(" + i + ") == " + winnerName + ")"); blockOpen(); // Get result line(f.kind + " result = (" + f.kind + ") " + futuresName + ".get(" + i + ").get();"); // Handle InteractionResult (value assignments from receive) if (f.kind.equals("InteractionResult") && trigger instanceof Interaction) { Optional<Target> localTargetOpt = ((Interaction) trigger).getTarget().stream() .filter(t -> isCurrentComponentInstance(t.getTargetGate().getComponent())) .findFirst(); if (localTargetOpt.isPresent() && trigger instanceof Message) { for (ValueAssignment va : localTargetOpt.get().getValueAssignment()) { lineComment("ValueAssignment"); Variable var = va.getVariable(); append(COMPONENT_FIELD + "." + getElementName(var)); append(" = "); append("(" + getElementName(var.getDataType()) + ")"); line("result.data.getValue();"); } } } // Write remaining behaviours of this block for (int j = trigIdx + 1; j < bl.getBehaviour().size(); j++) { write(bl.getBehaviour().get(j), dataUseVariables, null, thrownExceptions); newLine(); } blockClose(); } // Exceptional behaviour fallback append(" else "); blockOpen(); line("ExceptionalBehaviour exceptionalBehaviour = " + COMPONENT_FIELD + ".getExceptionalBehaviour(" + winnerName + ");"); append("if (exceptionalBehaviour != null) "); blockOpen(); line("exceptionalBehaviour.behaviour.execute();"); blockClose(); blockClose(); thrownExceptions.add(STOP_EXCEPTION); blockClose(); append("finally "); blockOpen(); // Cleanup: disable batch mode, cancel futures line(COMPONENT_FIELD + ".cleanupAlternatives(" + altsListName + ");"); line(futuresName + ".forEach(f -> " + COMPONENT_FIELD + ".stop(f));"); line(excName + ".forEach(f -> " + COMPONENT_FIELD + ".stop(f));"); blockClose(); thrownExceptions.add(INTERRUPTED_EXCEPTION); thrownExceptions.add(FUTURE_EXECUTION_EXCEPTION); newLine(); } } else if (b instanceof ConditionalBehaviour) { List<Block> blocks = ((ConditionalBehaviour) b).getBlock(); Loading plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/rt/core/ReceiverHub.java +32 −3 Original line number Diff line number Diff line Loading @@ -22,6 +22,9 @@ public class ReceiverHub { private List<Expectable> expecting = Collections.synchronizedList(new ArrayList<>()); private ExceptionalBehaviour anyReceiver; private int batchSize = 0; private int batchCount = 0; public ReceiverHub(SystemAdapter systemAdapter, Connection connection, NamedElement testerComponent) { this.systemAdapter = systemAdapter; this.connection = connection; Loading @@ -40,12 +43,28 @@ public class ReceiverHub { this.anyReceiver = anyReceiver; } public void enableBatch(int size) { synchronized (expecting) { this.batchSize = size; this.batchCount = 0; } } public void disableBatch() { synchronized (expecting) { this.batchSize = 0; this.batchCount = 0; expecting.notifyAll(); } } private synchronized void run() { int currentlyExpectingIndex = 0; while (!stopped) { Expectable currentlyExpecting = null; synchronized (expecting) { while (expecting.size() <= currentlyExpectingIndex) while (expecting.size() <= currentlyExpectingIndex || (batchSize > 0 && batchCount < batchSize)) try { expecting.wait(); } catch (InterruptedException e) { Loading @@ -63,7 +82,8 @@ public class ReceiverHub { synchronized (expecting) { for (Expectable e: expecting) if (!e.ignoreUnmatched) { currentlyExpecting = expecting.get(0); // currentlyExpecting = expecting.get(0); currentlyExpecting = e; break; } } Loading Loading @@ -93,8 +113,17 @@ public class ReceiverHub { Expectable expectable = new Expectable(expected, ignoreUntil); synchronized (expecting) { expecting.add(expectable); if (batchSize > 0) { batchCount++; if (batchCount >= batchSize) { batchSize = 0; batchCount = 0; expecting.notifyAll(); } } else { expecting.notifyAll(); } } try { synchronized (expectable) { try { Loading plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/rt/core/TestControl.java +38 −2 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; Loading Loading @@ -187,6 +188,37 @@ public class TestControl { } } public abstract class InteractionCallable extends ExecutionCallableWithDefaults { public abstract ReceiverHub getReceiver(); } public List<Future<ExecutionResult>> executeAlternatives(List<ExecutionCallable> callables) { // Count InteractionCallables per hub and enable batch mode Map<ReceiverHub, Integer> hubCounts = new HashMap<>(); for (ExecutionCallable c : callables) { if (c instanceof InteractionCallable) { ReceiverHub hub = ((InteractionCallable) c).getReceiver(); hubCounts.merge(hub, 1, Integer::sum); } } hubCounts.forEach((hub, count) -> hub.enableBatch(count)); // Submit all callables List<Future<ExecutionResult>> futures = new ArrayList<>(); for (ExecutionCallable c : callables) { futures.add(c.execute()); } return futures; } public void cleanupAlternatives(List<ExecutionCallable> callables) { for (ExecutionCallable c : callables) { if (c instanceof InteractionCallable) { ((InteractionCallable) c).getReceiver().disableBatch(); } } } public List<Future<ExecutionResult>> executeExceptionals() { List<Future<ExecutionResult>> futures = new ArrayList<>(); exceptionalBehaviours.forEach(exc -> futures.add(exc.execute())); Loading Loading @@ -257,10 +289,14 @@ public class TestControl { } public ExecutionCallable receive(Data expected, Connection connection, boolean isTrigger) { ExecutionCallableWithDefaults c = new ExecutionCallableWithDefaults() { InteractionCallable c = new InteractionCallable() { @Override public ReceiverHub getReceiver() { return TestControl.this.getReceiver(connection); } @Override public ExecutionResult call() throws Exception { Data data = getReceiver(connection).receive(expected, isTrigger); Data data = getReceiver().receive(expected, isTrigger); return data != null ? new InteractionResult(data) : null; } }; Loading Loading
plugins/org.etsi.mts.tdl.execution.java.codegen/src/org/etsi/mts/tdl/execution/java/codegen/JUnitTestGenerator.java +148 −1 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; Loading Loading @@ -1171,7 +1172,153 @@ public class JUnitTestGenerator extends Renderer { } // Multiple blocks else if (b instanceof AlternativeBehaviour) { // XXX String altsListName = "callables_" + getElementName(b); line("List<ExecutionCallable> " + altsListName + " = new java.util.LinkedList<>();"); // Collect info for each alternative block List<FutureInfo> altCallables = new LinkedList<>(); List<Behaviour> altTriggers = new LinkedList<>(); List<Integer> altTriggerIndices = new LinkedList<>(); List<Block> altBlocks = new LinkedList<>(); List<Block> blocks = ((AlternativeBehaviour) b).getBlock(); for (int blockIdx = 0; blockIdx < blocks.size(); blockIdx++) { Block bl = blocks.get(blockIdx); // Find first participating tester-input in this block Behaviour triggerBehaviour = null; int triggerIndex = -1; for (int i = 0; i < bl.getBehaviour().size(); i++) { Behaviour beh = bl.getBehaviour().get(i); if (isParticipating(beh)) { if (!isTesterInput(beh)) throw new RuntimeException( "Alternative block should start with tester input: " + getMessage(beh)); triggerBehaviour = beh; triggerIndex = i; break; } } if (triggerBehaviour == null) continue; lineComment("Alternative " + blockIdx); // Handle guard Optional<LocalExpression> guard = bl.getGuard().stream() .filter(le -> isCurrentComponentInstance(le.getComponentInstance())).findFirst(); if (guard.isPresent()) { DataUse g = guard.get().getExpression(); initializeDataUse(g, dataUseVariables); append("if ("); write(g, dataUseVariables); append(") "); } // Create callable (without submitting) FutureInfo callable = writeTesterInput(triggerBehaviour, dataUseVariables, false, false); line(altsListName + ".add(" + callable.varName + ");"); newLine(); altCallables.add(callable); altTriggers.add(triggerBehaviour); altTriggerIndices.add(triggerIndex); altBlocks.add(bl); } if (!altCallables.isEmpty()) { newLine(); // Submit all alternatives (with batch mode on ReceiverHubs) String futuresName = "altFutures_" + getElementName(b); line("List<Future<ExecutionResult>> " + futuresName + " = " + COMPONENT_FIELD + ".executeAlternatives(" + altsListName + ");"); // Submit exceptionals String excName = "altExc_" + getElementName(b); line("List<Future<ExecutionResult>> " + excName + " = " + COMPONENT_FIELD + ".executeExceptionals();"); newLine(); // Wait for first completion String winnerName = "altWinner_" + getElementName(b); line("Future<ExecutionResult> " + winnerName + " = " + COMPONENT_FIELD + ".next();"); newLine(); append("try "); blockOpen(); // If/else for each alternative for (int i = 0; i < altCallables.size(); i++) { FutureInfo f = altCallables.get(i); Behaviour trigger = altTriggers.get(i); int trigIdx = altTriggerIndices.get(i); Block bl = altBlocks.get(i); if (i > 0) append(" else "); append("if (" + futuresName + ".get(" + i + ") == " + winnerName + ")"); blockOpen(); // Get result line(f.kind + " result = (" + f.kind + ") " + futuresName + ".get(" + i + ").get();"); // Handle InteractionResult (value assignments from receive) if (f.kind.equals("InteractionResult") && trigger instanceof Interaction) { Optional<Target> localTargetOpt = ((Interaction) trigger).getTarget().stream() .filter(t -> isCurrentComponentInstance(t.getTargetGate().getComponent())) .findFirst(); if (localTargetOpt.isPresent() && trigger instanceof Message) { for (ValueAssignment va : localTargetOpt.get().getValueAssignment()) { lineComment("ValueAssignment"); Variable var = va.getVariable(); append(COMPONENT_FIELD + "." + getElementName(var)); append(" = "); append("(" + getElementName(var.getDataType()) + ")"); line("result.data.getValue();"); } } } // Write remaining behaviours of this block for (int j = trigIdx + 1; j < bl.getBehaviour().size(); j++) { write(bl.getBehaviour().get(j), dataUseVariables, null, thrownExceptions); newLine(); } blockClose(); } // Exceptional behaviour fallback append(" else "); blockOpen(); line("ExceptionalBehaviour exceptionalBehaviour = " + COMPONENT_FIELD + ".getExceptionalBehaviour(" + winnerName + ");"); append("if (exceptionalBehaviour != null) "); blockOpen(); line("exceptionalBehaviour.behaviour.execute();"); blockClose(); blockClose(); thrownExceptions.add(STOP_EXCEPTION); blockClose(); append("finally "); blockOpen(); // Cleanup: disable batch mode, cancel futures line(COMPONENT_FIELD + ".cleanupAlternatives(" + altsListName + ");"); line(futuresName + ".forEach(f -> " + COMPONENT_FIELD + ".stop(f));"); line(excName + ".forEach(f -> " + COMPONENT_FIELD + ".stop(f));"); blockClose(); thrownExceptions.add(INTERRUPTED_EXCEPTION); thrownExceptions.add(FUTURE_EXECUTION_EXCEPTION); newLine(); } } else if (b instanceof ConditionalBehaviour) { List<Block> blocks = ((ConditionalBehaviour) b).getBlock(); Loading
plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/rt/core/ReceiverHub.java +32 −3 Original line number Diff line number Diff line Loading @@ -22,6 +22,9 @@ public class ReceiverHub { private List<Expectable> expecting = Collections.synchronizedList(new ArrayList<>()); private ExceptionalBehaviour anyReceiver; private int batchSize = 0; private int batchCount = 0; public ReceiverHub(SystemAdapter systemAdapter, Connection connection, NamedElement testerComponent) { this.systemAdapter = systemAdapter; this.connection = connection; Loading @@ -40,12 +43,28 @@ public class ReceiverHub { this.anyReceiver = anyReceiver; } public void enableBatch(int size) { synchronized (expecting) { this.batchSize = size; this.batchCount = 0; } } public void disableBatch() { synchronized (expecting) { this.batchSize = 0; this.batchCount = 0; expecting.notifyAll(); } } private synchronized void run() { int currentlyExpectingIndex = 0; while (!stopped) { Expectable currentlyExpecting = null; synchronized (expecting) { while (expecting.size() <= currentlyExpectingIndex) while (expecting.size() <= currentlyExpectingIndex || (batchSize > 0 && batchCount < batchSize)) try { expecting.wait(); } catch (InterruptedException e) { Loading @@ -63,7 +82,8 @@ public class ReceiverHub { synchronized (expecting) { for (Expectable e: expecting) if (!e.ignoreUnmatched) { currentlyExpecting = expecting.get(0); // currentlyExpecting = expecting.get(0); currentlyExpecting = e; break; } } Loading Loading @@ -93,8 +113,17 @@ public class ReceiverHub { Expectable expectable = new Expectable(expected, ignoreUntil); synchronized (expecting) { expecting.add(expectable); if (batchSize > 0) { batchCount++; if (batchCount >= batchSize) { batchSize = 0; batchCount = 0; expecting.notifyAll(); } } else { expecting.notifyAll(); } } try { synchronized (expectable) { try { Loading
plugins/org.etsi.mts.tdl.execution.java.runtime/src/org/etsi/mts/tdl/execution/java/rt/core/TestControl.java +38 −2 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; Loading Loading @@ -187,6 +188,37 @@ public class TestControl { } } public abstract class InteractionCallable extends ExecutionCallableWithDefaults { public abstract ReceiverHub getReceiver(); } public List<Future<ExecutionResult>> executeAlternatives(List<ExecutionCallable> callables) { // Count InteractionCallables per hub and enable batch mode Map<ReceiverHub, Integer> hubCounts = new HashMap<>(); for (ExecutionCallable c : callables) { if (c instanceof InteractionCallable) { ReceiverHub hub = ((InteractionCallable) c).getReceiver(); hubCounts.merge(hub, 1, Integer::sum); } } hubCounts.forEach((hub, count) -> hub.enableBatch(count)); // Submit all callables List<Future<ExecutionResult>> futures = new ArrayList<>(); for (ExecutionCallable c : callables) { futures.add(c.execute()); } return futures; } public void cleanupAlternatives(List<ExecutionCallable> callables) { for (ExecutionCallable c : callables) { if (c instanceof InteractionCallable) { ((InteractionCallable) c).getReceiver().disableBatch(); } } } public List<Future<ExecutionResult>> executeExceptionals() { List<Future<ExecutionResult>> futures = new ArrayList<>(); exceptionalBehaviours.forEach(exc -> futures.add(exc.execute())); Loading Loading @@ -257,10 +289,14 @@ public class TestControl { } public ExecutionCallable receive(Data expected, Connection connection, boolean isTrigger) { ExecutionCallableWithDefaults c = new ExecutionCallableWithDefaults() { InteractionCallable c = new InteractionCallable() { @Override public ReceiverHub getReceiver() { return TestControl.this.getReceiver(connection); } @Override public ExecutionResult call() throws Exception { Data data = getReceiver(connection).receive(expected, isTrigger); Data data = getReceiver().receive(expected, isTrigger); return data != null ? new InteractionResult(data) : null; } }; Loading