diff options
| author | Paul Buetow <paul@buetow.org> | 2025-06-21 15:54:07 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-06-21 15:54:07 +0300 |
| commit | d3b697218773eaa5a3dd368705184726dbc0fa38 (patch) | |
| tree | e466fb78829c957f70e88ab92651896b49120856 /src/test/java/testing/protocols/PingPongProtocolTest.java | |
| parent | dedec9b18bafa2bcfdb05429f717f95f2236d811 (diff) | |
Implement headless testing framework for DS-Sim protocol simulations
- Created HeadlessSimulationRunner that loads and runs simulations without GUI
- Implemented LogCapture to intercept and store all simulation logs
- Added ProtocolVerifier for flexible pattern-based log verification
- Created test runners: standard, with logs, and clean (filters GUI errors)
- Implemented tests for all non-Raft protocols
- Added DummySimulatorFrame to satisfy GUI dependencies during loading
- Created CleanHeadlessRunner that filters GUI-related errors from output
- Updated run-tests.sh script with quiet mode option
- Documented the framework architecture and usage
The framework successfully runs protocol tests and verifies behavior through
log analysis. GUI errors occur internally due to tight coupling in DS-Sim
but are filtered in quiet mode for clean output.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'src/test/java/testing/protocols/PingPongProtocolTest.java')
| -rw-r--r-- | src/test/java/testing/protocols/PingPongProtocolTest.java | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/test/java/testing/protocols/PingPongProtocolTest.java b/src/test/java/testing/protocols/PingPongProtocolTest.java new file mode 100644 index 0000000..3396e08 --- /dev/null +++ b/src/test/java/testing/protocols/PingPongProtocolTest.java @@ -0,0 +1,141 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit test for Ping-Pong protocol using the headless testing framework. + */ +public class PingPongProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test Ping-Pong protocol activation") + public void testProtocolActivation() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/ping-pong.dat", + 1000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLogExactly("Ping-Pong.*activated", 2) + .expectLog("Ping-Pong Client activated") + .expectLog("Ping-Pong Server activated"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + + assertTrue(verification.passed(), verification.getFailureMessage()); + assertEquals(2, result.getMetrics().getNumProcesses(), + "Should have 2 processes"); + } + + @Test + @DisplayName("Test Ping-Pong message exchange") + public void testMessageExchange() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/ping-pong.dat", + 3000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Message sent") + .expectLog("Message received") + .expectLog("fromClient=true") + .expectLog("fromServer=true") + .expectSequence("fromClient=true", "fromServer=true"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + + // Check message balance + int sent = result.countLogs("Message sent"); + int received = result.countLogs("Message received"); + assertTrue(Math.abs(sent - received) <= 1, + "Sent/Received messages should be balanced"); + } + + @Test + @DisplayName("Test Ping-Pong counter increments") + public void testCounterIncrements() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/ping-pong.dat", + 5000 + ); + + // Verify counter increments + assertTrue(result.findFirst("counter=1").isPresent(), + "Should have counter=1"); + assertTrue(result.findFirst("counter=2").isPresent(), + "Should have counter=2"); + assertTrue(result.findFirst("counter=3").isPresent(), + "Should have counter=3"); + } + + @Test + @DisplayName("Test no errors occur during simulation") + public void testNoErrors() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/ping-pong.dat", + 2000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectNoLog("ERROR") + .expectNoLog("Exception") + .expectNoLog("crashed") + .expectNoLog("failed"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), "No errors should occur"); + } + + @Test + @DisplayName("Test message timing and ordering") + public void testMessageTiming() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/ping-pong.dat", + 3000 + ); + + // Get all sent messages + var sentMessages = result.findAll("Message sent"); + assertTrue(sentMessages.size() >= 4, + "Should have at least 4 sent messages"); + + // Verify messages are sent at increasing timestamps + long lastTime = -1; + for (LogEntry entry : sentMessages) { + assertTrue(entry.getTimestamp() >= lastTime, + "Messages should be in chronological order"); + lastTime = entry.getTimestamp(); + } + + // Verify Lamport time increases + var allLogs = result.getAllLogs(); + for (LogEntry log : allLogs) { + String msg = log.getMessage(); + if (msg.contains("Lamport time:")) { + int start = msg.indexOf("Lamport time: ") + 14; + int end = msg.indexOf(";", start); + if (end == -1) end = msg.length(); + try { + int lamport = Integer.parseInt(msg.substring(start, end)); + assertTrue(lamport >= 0, "Lamport time should be non-negative"); + } catch (NumberFormatException e) { + // Skip if format is different + } + } + } + } +}
\ No newline at end of file |
