diff options
| author | Paul Buetow <paul@buetow.org> | 2025-06-21 20:10:38 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-06-21 20:10:38 +0300 |
| commit | 695adc1f6bfb0a0eeef4dd6c035475ea2826871f (patch) | |
| tree | 945fc0552d4f7f1ef1f468f6030e9925970fa72b /src/main/java/testing/SimpleProtocolTestRunner.java | |
| parent | d3b697218773eaa5a3dd368705184726dbc0fa38 (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.java | 163 |
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 |
