summaryrefslogtreecommitdiff
path: root/src/main/java/testing/SimpleProtocolTestRunner.java
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-06-21 20:10:38 +0300
committerPaul Buetow <paul@buetow.org>2025-06-21 20:10:38 +0300
commit695adc1f6bfb0a0eeef4dd6c035475ea2826871f (patch)
tree945fc0552d4f7f1ef1f468f6030e9925970fa72b /src/main/java/testing/SimpleProtocolTestRunner.java
parentd3b697218773eaa5a3dd368705184726dbc0fa38 (diff)
Complete GUI decoupling implementation for headless testing
- Implement MessageHandler pattern to decouple message sending from visualization - Add HeadlessLoader to load simulations without GUI components - Create HeadlessProtocolRunner for clean protocol test execution - Update VSInternalProcess to use MessageHandler for message routing - Add null checks in VSSimulator for headless mode compatibility - Update VSSimulatorVisualization paint() to check for headless mode - Remove obsolete test scripts and documentation - Update test-protocols.sh to remove GUI error suppression options - Consolidate testing documentation in docs/testing-guide.md All protocol tests now run cleanly in headless mode without GUI errors, enabling proper CI/CD integration and automated testing. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'src/main/java/testing/SimpleProtocolTestRunner.java')
-rw-r--r--src/main/java/testing/SimpleProtocolTestRunner.java163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/main/java/testing/SimpleProtocolTestRunner.java b/src/main/java/testing/SimpleProtocolTestRunner.java
new file mode 100644
index 0000000..02a0ed9
--- /dev/null
+++ b/src/main/java/testing/SimpleProtocolTestRunner.java
@@ -0,0 +1,163 @@
+package testing;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Simple runner for protocol tests that shows detailed output.
+ */
+public class SimpleProtocolTestRunner {
+
+ private static final String ANSI_GREEN = "\u001B[32m";
+ private static final String ANSI_RED = "\u001B[31m";
+ private static final String ANSI_YELLOW = "\u001B[33m";
+ private static final String ANSI_BLUE = "\u001B[34m";
+ private static final String ANSI_RESET = "\u001B[0m";
+
+ public static void main(String[] args) {
+ System.out.println("=== DS-Sim Protocol Test Runner ===\n");
+
+ // Check if saved simulations exist
+ File savedDir = new File("saved-simulations");
+ if (!savedDir.exists()) {
+ System.err.println("ERROR: saved-simulations directory not found!");
+ System.err.println("Please ensure you're running from the project root directory.");
+ System.exit(1);
+ }
+
+ // List of all protocol test simulations
+ Map<String, TestInfo> tests = new LinkedHashMap<>();
+ tests.put("Ping-Pong Protocol", new TestInfo("saved-simulations/ping-pong.dat", 5000,
+ Arrays.asList("Ping", "Pong", "message:", "counter")));
+ tests.put("Berkeley Time Protocol", new TestInfo("saved-simulations/berkeley.dat", 5000,
+ Arrays.asList("Time synchronization", "Berkeley", "adjustment")));
+ tests.put("Broadcast Protocol", new TestInfo("saved-simulations/broadcast.dat", 3000,
+ Arrays.asList("broadcast", "received", "message")));
+ tests.put("Basic Multicast Protocol", new TestInfo("saved-simulations/basic-multicast.dat", 3000,
+ Arrays.asList("multicast", "group", "received")));
+ tests.put("Reliable Multicast Protocol", new TestInfo("saved-simulations/reliable-multicast.dat", 5000,
+ Arrays.asList("reliable", "multicast", "ACK", "resend")));
+ tests.put("External Time Sync", new TestInfo("saved-simulations/external-time-sync.dat", 5000,
+ Arrays.asList("external", "time", "sync", "adjustment")));
+ tests.put("Internal Time Sync", new TestInfo("saved-simulations/internal-time-sync.dat", 5000,
+ Arrays.asList("internal", "time", "sync", "average")));
+ tests.put("One-Phase Commit Protocol", new TestInfo("saved-simulations/one-phase-commit.dat", 3000,
+ Arrays.asList("commit", "vote", "decision")));
+ tests.put("Two-Phase Commit Protocol", new TestInfo("saved-simulations/two-phase-commit.dat", 5000,
+ Arrays.asList("prepare", "commit", "vote", "decision")));
+ tests.put("Slow Connection Protocol", new TestInfo("saved-simulations/slow-connection.dat", 8000,
+ Arrays.asList("slow", "connection", "delay")));
+ tests.put("Ping-Pong Sturm Protocol", new TestInfo("saved-simulations/ping-pong-sturm.dat", 5000,
+ Arrays.asList("Sturm", "ping", "pong")));
+
+ int passed = 0;
+ int failed = 0;
+ int skipped = 0;
+
+ // Create headless runner with logs enabled
+ HeadlessSimulationRunner runner = new HeadlessSimulationRunner();
+ runner.setPrintLogs(true);
+
+ // Run each test
+ for (Map.Entry<String, TestInfo> entry : tests.entrySet()) {
+ String testName = entry.getKey();
+ TestInfo info = entry.getValue();
+
+ System.out.println("\n" + ANSI_YELLOW + "Testing: " + testName + ANSI_RESET);
+ System.out.println("Simulation file: " + info.simulationFile);
+ System.out.println("Duration: " + info.duration + "ms");
+ System.out.println("Expected patterns: " + info.expectedPatterns);
+
+ // Check if simulation file exists
+ File simFile = new File(info.simulationFile);
+ if (!simFile.exists()) {
+ System.out.println(ANSI_RED + "✗ SKIPPED - Simulation file not found" + ANSI_RESET);
+ skipped++;
+ continue;
+ }
+
+ try {
+ // Add log listener to capture output
+ final List<String> capturedLogs = new ArrayList<>();
+ LogListener listener = new LogListener() {
+ @Override
+ public void onLogEntry(LogEntry entry) {
+ String log = entry.getMessage();
+ capturedLogs.add(log);
+ // Print interesting logs in blue
+ for (String pattern : info.expectedPatterns) {
+ if (log.toLowerCase().contains(pattern.toLowerCase())) {
+ System.out.println(ANSI_BLUE + " [LOG] " + log + ANSI_RESET);
+ break;
+ }
+ }
+ }
+ };
+
+ System.out.println("\nRunning simulation...");
+ SimulationResult result = runner.runSimulation(info.simulationFile, info.duration, listener);
+
+ // Verify expected patterns
+ System.out.println("\nVerifying patterns:");
+ boolean allPatternsFound = true;
+ for (String pattern : info.expectedPatterns) {
+ boolean found = capturedLogs.stream()
+ .anyMatch(log -> log.toLowerCase().contains(pattern.toLowerCase()));
+ if (found) {
+ System.out.println(ANSI_GREEN + " ✓ Found: " + pattern + ANSI_RESET);
+ } else {
+ System.out.println(ANSI_RED + " ✗ Missing: " + pattern + ANSI_RESET);
+ allPatternsFound = false;
+ }
+ }
+
+ // Check result
+ System.out.println("\nResult summary:");
+ System.out.println(" Total logs captured: " + result.getAllLogs().size());
+ System.out.println(" Processes: " + result.getMetrics().getNumProcesses());
+ System.out.println(" Message counts: " + result.getMetrics().getProcessMessageCounts());
+
+ if (allPatternsFound && result.getAllLogs().size() > 0) {
+ System.out.println(ANSI_GREEN + "✓ PASSED" + ANSI_RESET);
+ passed++;
+ } else {
+ System.out.println(ANSI_RED + "✗ FAILED - Not all patterns found or no logs captured" + ANSI_RESET);
+ failed++;
+ }
+
+ } catch (Exception e) {
+ System.out.println(ANSI_RED + "✗ FAILED: " + e.getMessage() + ANSI_RESET);
+ e.printStackTrace();
+ failed++;
+ }
+ }
+
+ // Cleanup
+ runner.shutdown();
+
+ // Print summary
+ System.out.println("\n" + "=".repeat(50));
+ System.out.println("Test Summary:");
+ System.out.println(ANSI_GREEN + " Passed: " + passed + ANSI_RESET);
+ System.out.println(ANSI_RED + " Failed: " + failed + ANSI_RESET);
+ System.out.println(ANSI_YELLOW + " Skipped: " + skipped + ANSI_RESET);
+ System.out.println(" Total: " + tests.size());
+ System.out.println("=".repeat(50));
+
+ // Exit with appropriate code
+ System.exit(failed > 0 ? 1 : 0);
+ }
+
+ // Helper class to store test information
+ static class TestInfo {
+ final String simulationFile;
+ final long duration;
+ final List<String> expectedPatterns;
+
+ TestInfo(String simulationFile, long duration, List<String> expectedPatterns) {
+ this.simulationFile = simulationFile;
+ this.duration = duration;
+ this.expectedPatterns = expectedPatterns;
+ }
+ }
+} \ No newline at end of file