Commit edd0401d authored by Martti Käärik's avatar Martti Käärik
Browse files

Improved handling in execution framework and generated code + receiver hub...

Improved handling in execution framework and generated code + receiver hub suspension (instead of cleanup)
parent f97f9acb
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -1054,7 +1054,6 @@ public class JUnitTestGenerator extends Renderer {
					FutureInfo futureInfo = writeTesterInput(b, dataUseVariables, true, true);
					myFutures.add(futureInfo);
					thrownExceptions.add(INTERRUPTED_EXCEPTION);
					thrownExceptions.add(FUTURE_EXECUTION_EXCEPTION);

				} else {

@@ -1303,6 +1302,11 @@ public class JUnitTestGenerator extends Renderer {
					blockClose();
					thrownExceptions.add(STOP_EXCEPTION);

					blockClose();
					append("catch (" + FUTURE_EXECUTION_EXCEPTION + " e) ");
					blockOpen();
					line("if (e.getCause() instanceof RuntimeException) throw (RuntimeException) e.getCause();");
					line("throw new RuntimeException(e.getCause());");
					blockClose();
					append("finally ");
					blockOpen();
@@ -1311,11 +1315,11 @@ public class JUnitTestGenerator extends Renderer {
					line(COMPONENT_FIELD + ".cleanupAlternatives(" + altsListName + ");");
					line(futuresName + ".forEach(f -> " + COMPONENT_FIELD + ".stop(f));");
					line(excName + ".forEach(f -> " + COMPONENT_FIELD + ".stop(f));");
					line(COMPONENT_FIELD + ".resumeReceiving();");

					blockClose();

					thrownExceptions.add(INTERRUPTED_EXCEPTION);
					thrownExceptions.add(FUTURE_EXECUTION_EXCEPTION);

					newLine();
				}
@@ -1396,6 +1400,11 @@ public class JUnitTestGenerator extends Renderer {
				blockClose();
				thrownExceptions.add(STOP_EXCEPTION);

				blockClose();
				append("catch (" + FUTURE_EXECUTION_EXCEPTION + " e) ");
				blockOpen();
				line("if (e.getCause() instanceof RuntimeException) throw (RuntimeException) e.getCause();");
				line("throw new RuntimeException(e.getCause());");
				blockClose();
				append("finally ");
				blockOpen();
@@ -1409,6 +1418,7 @@ public class JUnitTestGenerator extends Renderer {
						line("_exceptionals.forEach(f -> " + COMPONENT_FIELD + ".stop(f));");
					}
				});
				line(COMPONENT_FIELD + ".resumeReceiving();");

				blockClose();

+48 −16
Original line number Diff line number Diff line
@@ -2,7 +2,9 @@ package org.etsi.mts.tdl.execution.java.rt.core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.etsi.mts.tdl.execution.java.tri.Argument;
import org.etsi.mts.tdl.execution.java.tri.Connection;
@@ -24,6 +26,7 @@ public class ReceiverHub {

	private int batchSize = 0;
	private int batchCount = 0;
	private boolean suspended = false;

	public ReceiverHub(SystemAdapter systemAdapter, Connection connection, NamedElement testerComponent) {
		this.systemAdapter = systemAdapter;
@@ -58,38 +61,55 @@ public class ReceiverHub {
		}
	}

	public void resume() {
		synchronized (expecting) {
			this.suspended = false;
			expecting.notifyAll();
		}
	}

	private synchronized void run() {
		int currentlyExpectingIndex = 0;
		// Track tried expectables by identity rather than positional index,
		// since the expecting list is mutated concurrently by other threads.
		// Stale entries after resume are harmless — each hub.receive() call
		// creates a new Expectable instance with distinct identity, so stale
		// entries from previous cycles never match newly added expectables.
		Set<Expectable> tried = new HashSet<>();
		while (!stopped) {
			Expectable currentlyExpecting = null;
			synchronized (expecting) {
				while (expecting.size() <= currentlyExpectingIndex
						|| (batchSize > 0 && batchCount < batchSize))
				currentlyExpecting = null;
				while (currentlyExpecting == null) {
					if (!suspended && !(batchSize > 0 && batchCount < batchSize))
						for (Expectable e : expecting)
							if (!tried.contains(e)) {
								currentlyExpecting = e;
								break;
							}
					if (currentlyExpecting == null)
						try {
							expecting.wait();
						} catch (InterruptedException e) {
							return;
						}
				currentlyExpecting = expecting.get(currentlyExpectingIndex);
				currentlyExpectingIndex++;
				}
			}
			try {
				Data data = systemAdapter.receive(currentlyExpecting.expected, connection, testerComponent);
				if (data != null) {
					currentlyExpectingIndex = 0;
					tried.clear();
					if (currentlyExpecting.anyReceiver) {
						// Switch to the first one for reporting
						synchronized (expecting) {
							for (Expectable e: expecting)
								if (!e.ignoreUnmatched) {
//									currentlyExpecting = expecting.get(0);
									currentlyExpecting = e;
									break;
								}
						}
					}
					// XXX this is not correct
					expecting.clear();
					expecting.remove(currentlyExpecting);
					suspended = true;
					synchronized (currentlyExpecting) {
						currentlyExpecting.received = data;
						currentlyExpecting.notifyAll();
@@ -98,8 +118,16 @@ public class ReceiverHub {
			} catch (InterruptedException e) {

			} catch (AssertionError e) {
				tried.add(currentlyExpecting);
				if (!currentlyExpecting.ignoreUnmatched)
					currentlyExpecting.error = e;
			} catch (RuntimeException e) {
				currentlyExpecting.error = e;
				expecting.remove(currentlyExpecting);
				suspended = true;
				synchronized (currentlyExpecting) {
					currentlyExpecting.notifyAll();
				}
			}
		}
	}
@@ -131,8 +159,12 @@ public class ReceiverHub {
				} catch (InterruptedException e) {
					return null;
				}
				if (expectable.error instanceof AssertionError)
					throw (AssertionError) expectable.error;
				if (expectable.error instanceof RuntimeException)
					throw (RuntimeException) expectable.error;
				if (expectable.error != null)
					throw expectable.error;
					throw new RuntimeException(expectable.error);
				return expectable.received;
			}
		} finally {
@@ -148,7 +180,7 @@ public class ReceiverHub {
	class Expectable {
		Data expected;
		Data received;
		AssertionError error;
		Throwable error;
		boolean ignoreUnmatched = false;
		boolean anyReceiver = false;

+22 −2
Original line number Diff line number Diff line
@@ -107,8 +107,17 @@ public class TestControl {
			anyReceiver.callable = new ExecutionCallable() {
				@Override
				public ExecutionResult call() throws Exception {
					try {
						Data data = hub.receive(null, false);
						return data != null ? new InteractionResult(data) : null;
					} catch (RuntimeException e) {
						// Propagate SA errors through the behaviour execution path:
						// complete the future normally so that the test code can handle
						// it as an exceptional behaviour, but replace the behaviour
						// to rethrow the real exception.
						anyReceiver.behaviour = () -> { throw e; };
						return null;
					}
				}

			};
@@ -219,6 +228,10 @@ public class TestControl {
		}
	}

	public void resumeReceiving() {
		receiverHubs.values().forEach(hub -> hub.resume());
	}

	public List<Future<ExecutionResult>> executeExceptionals() {
		List<Future<ExecutionResult>> futures = new ArrayList<>();
		exceptionalBehaviours.forEach(exc -> futures.add(exc.execute()));
@@ -355,6 +368,13 @@ public class TestControl {
					return b;
			}
		}
		// Also check hub anyReceivers — these are implicit exceptional behaviours
		// for TDL's default verdict logic, not part of the user-defined list.
		for (ReceiverHub hub : this.receiverHubs.values()) {
			ExceptionalBehaviour anyReceiver = hub.getAnyReceiver();
			if (anyReceiver != null && anyReceiver.isFuture(future))
				return anyReceiver;
		}
		return null;
	}