diff options
Diffstat (limited to 'src/main/java/testing')
| -rw-r--r-- | src/main/java/testing/HeadlessProtocolRunner.java | 15 | ||||
| -rw-r--r-- | src/main/java/testing/HeadlessSimulationRunner.java | 55 | ||||
| -rw-r--r-- | src/main/java/testing/LogCapture.java | 29 | ||||
| -rw-r--r-- | src/main/java/testing/ProtocolVerifier.java | 65 | ||||
| -rw-r--r-- | src/main/java/testing/SimulationMetrics.java | 6 |
5 files changed, 156 insertions, 14 deletions
diff --git a/src/main/java/testing/HeadlessProtocolRunner.java b/src/main/java/testing/HeadlessProtocolRunner.java index daf96aa..a6098de 100644 --- a/src/main/java/testing/HeadlessProtocolRunner.java +++ b/src/main/java/testing/HeadlessProtocolRunner.java @@ -50,6 +50,21 @@ public class HeadlessProtocolRunner { System.out.println(" Log entries: " + result.getMetrics().getTotalLogCount()); System.out.println(" Messages per process: " + result.getMetrics().getProcessMessageCounts()); + // Count total messages sent + int totalMessages = result.getMetrics().getTotalMessageCount(); + System.out.println(" Total messages sent: " + totalMessages); + + // Check if any messages were sent + if (totalMessages == 0) { + System.err.println("\nâ ď¸ WARNING: No messages were sent during simulation!"); + System.err.println(" This indicates the protocol may not be functioning correctly."); + if (!verbose) { + System.err.println(" Re-run with -Dds.sim.verbose=true for detailed output."); + } + // Mark as failure + throw new RuntimeException("Protocol test failed: No messages sent"); + } + System.out.println(); } catch (Exception e) { System.err.println("â FAILED: " + e.getMessage()); diff --git a/src/main/java/testing/HeadlessSimulationRunner.java b/src/main/java/testing/HeadlessSimulationRunner.java index 9d2274c..6279fa9 100644 --- a/src/main/java/testing/HeadlessSimulationRunner.java +++ b/src/main/java/testing/HeadlessSimulationRunner.java @@ -26,6 +26,11 @@ public class HeadlessSimulationRunner { public HeadlessSimulationRunner() { this.prefs = new VSDefaultPrefs(); this.prefs.fillWithDefaults(); + + // Set reasonable message delays for testing (10-50ms instead of 500-2000ms) + this.prefs.initLong("message.sendingtime.min", 10); + this.prefs.initLong("message.sendingtime.max", 50); + VSRegisteredEvents.init(prefs); this.executor = Executors.newSingleThreadExecutor(); } @@ -55,14 +60,20 @@ public class HeadlessSimulationRunner { simulator = loaded.getSimulator(); viz = loaded.getVisualization(); + // Update message delays on all processes after loading + for (int i = 0; i < viz.getNumProcesses(); i++) { + VSInternalProcess process = viz.getProcess(i); + if (process != null) { + process.initLong("message.sendingtime.min", 10); + process.initLong("message.sendingtime.max", 50); + } + } + if (simulator == null || viz == null) { throw new IllegalStateException("Failed to load simulation"); } - // Set up headless message handlers for all processes - setupHeadlessMessageHandlers(viz); - - // Install log capture + // Install log capture first logCapture = new LogCapture(); logCapture.setPrintLogs(printLogs); if (listener != null) { @@ -70,6 +81,9 @@ public class HeadlessSimulationRunner { } installLogCapture(); + // Set up headless message handlers for all processes (after log capture is ready) + setupHeadlessMessageHandlers(viz); + // Get the simulation's configured end time long untilTime = viz.getUntilTime(); long actualMaxTime = Math.min(maxTime, untilTime); @@ -187,10 +201,11 @@ public class HeadlessSimulationRunner { lastActiveTime = currentTime; } else { noActivityCount++; - // If no activity for 3000ms (3 seconds) of simulation time, stop - // This accounts for message delivery times of 500-2000ms plus some buffer - if (noActivityCount > 3000 && (currentTime - lastActiveTime) > 3000) { - System.out.println("No activity detected for 3 seconds - simulation complete at time " + simulatorTime); + // If no activity for 5000ms (5 seconds) of simulation time, stop + // This accounts for message delivery times of 500-2000ms plus extra buffer + // to ensure all messages are delivered + if (noActivityCount > 5000 && (currentTime - lastActiveTime) > 5000) { + System.out.println("No activity detected for 5 seconds - simulation complete at time " + simulatorTime); break; } } @@ -208,10 +223,19 @@ public class HeadlessSimulationRunner { private boolean hasPendingActivity(VSTaskManager taskManager, Field globalTasksField, long currentTime) { try { - // Check global tasks + // Check global tasks - but also check if any are scheduled for future times Queue<?> globalTasks = (Queue<?>) globalTasksField.get(taskManager); if (globalTasks != null && !globalTasks.isEmpty()) { - return true; // If any global tasks exist, keep running + // Check if any tasks are scheduled for the future + for (Object obj : globalTasks) { + VSTask task = (VSTask) obj; + if (task.getTaskTime() > currentTime) { + // There's a future task scheduled, keep running + return true; + } + } + // If all tasks are in the past or present, they should execute now + return true; } // Check process-specific tasks @@ -220,12 +244,19 @@ public class HeadlessSimulationRunner { if (process != null) { Queue<VSTask> tasks = process.getTasks(); if (tasks != null && !tasks.isEmpty()) { - return true; // If any process tasks exist, keep running + // Check if any tasks are scheduled for the future + for (VSTask task : tasks) { + if (task.getTaskTime() > process.getTime()) { + return true; + } + } + // If all tasks are ready to run, keep going + return true; } } } - // Check for messages in transit + // Check for messages in transit (visualization lines) Field messageLinesField = VSSimulatorVisualization.class.getDeclaredField("messageLines"); messageLinesField.setAccessible(true); LinkedList<?> messageLines = (LinkedList<?>) messageLinesField.get(viz); diff --git a/src/main/java/testing/LogCapture.java b/src/main/java/testing/LogCapture.java index 97bb127..ddd0ad0 100644 --- a/src/main/java/testing/LogCapture.java +++ b/src/main/java/testing/LogCapture.java @@ -30,6 +30,17 @@ public class LogCapture extends VSLogging { this.printLogs = printLogs; } + public void setSimulatorCanvas(VSSimulatorVisualization viz) { + // Store reference for process count + try { + Field field = VSLogging.class.getDeclaredField("simulatorVisualization"); + field.setAccessible(true); + field.set(this, viz); + } catch (Exception e) { + // Ignore + } + } + public void setLogPrefix(String prefix) { this.logPrefix = prefix; } @@ -136,9 +147,23 @@ public class LogCapture extends VSLogging { public Map<Integer, Integer> getProcessMessageCounts() { Map<Integer, Integer> counts = new HashMap<>(); - for (Map.Entry<Integer, List<LogEntry>> entry : processLogs.entrySet()) { - counts.put(entry.getKey(), entry.getValue().size()); + + // Initialize counts for all processes + VSSimulatorVisualization viz = getSimulatorVisualization(); + if (viz != null) { + for (int i = 0; i < viz.getNumProcesses(); i++) { + counts.put(i, 0); + } } + + // Count messages from all captured logs + for (LogEntry log : capturedLogs) { + if (log.getMessage().contains("Message sent")) { + int processNum = log.getProcessNum(); + counts.put(processNum, counts.getOrDefault(processNum, 0) + 1); + } + } + return counts; } diff --git a/src/main/java/testing/ProtocolVerifier.java b/src/main/java/testing/ProtocolVerifier.java index 19ed1f2..e5338d4 100644 --- a/src/main/java/testing/ProtocolVerifier.java +++ b/src/main/java/testing/ProtocolVerifier.java @@ -80,6 +80,29 @@ public class ProtocolVerifier { } /** + * Expect at least n messages to be sent during the simulation. + */ + public ProtocolVerifier expectAtLeastNMessages(int minMessages) { + rules.add(new MessageCountRule(minMessages, Integer.MAX_VALUE)); + return this; + } + + /** + * Expect exactly n messages to be sent during the simulation. + */ + public ProtocolVerifier expectExactlyNMessages(int count) { + rules.add(new MessageCountRule(count, count)); + return this; + } + + /** + * Expect messages to be sent (at least 1). + */ + public ProtocolVerifier expectMessages() { + return expectAtLeastNMessages(1); + } + + /** * Verify all rules against the provided logs. */ public VerificationResult verify(List<LogEntry> logs) { @@ -240,4 +263,46 @@ public class ProtocolVerifier { return new RuleResult(passed, message, matches); } } + + /** + * Rule that verifies message count. + */ + private static class MessageCountRule implements VerificationRule { + private final int minCount; + private final int maxCount; + private final String description; + + public MessageCountRule(int minCount, int maxCount) { + this.minCount = minCount; + this.maxCount = maxCount; + this.description = String.format( + "Message count should be %s", + minCount == maxCount ? + String.valueOf(minCount) : + minCount + "-" + (maxCount == Integer.MAX_VALUE ? "â" : maxCount) + ); + } + + @Override + public RuleResult verify(List<LogEntry> logs) { + int messageCount = 0; + List<LogEntry> messageLogs = new ArrayList<>(); + + // Count all "Message sent" logs + for (LogEntry log : logs) { + if (log.getMessage().contains("Message sent")) { + messageCount++; + messageLogs.add(log); + } + } + + boolean passed = messageCount >= minCount && messageCount <= maxCount; + String message = String.format( + "%s (found %d messages)", + description, messageCount + ); + + return new RuleResult(passed, message, messageLogs); + } + } }
\ No newline at end of file diff --git a/src/main/java/testing/SimulationMetrics.java b/src/main/java/testing/SimulationMetrics.java index 2b80631..dc8fc39 100644 --- a/src/main/java/testing/SimulationMetrics.java +++ b/src/main/java/testing/SimulationMetrics.java @@ -44,4 +44,10 @@ public class SimulationMetrics { return (double) totalProcessMessages / numProcesses; } + + public int getTotalMessageCount() { + return processMessageCounts.values().stream() + .mapToInt(Integer::intValue) + .sum(); + } }
\ No newline at end of file |
