diff options
Diffstat (limited to 'src/test/java/testing')
11 files changed, 886 insertions, 0 deletions
diff --git a/src/test/java/testing/protocols/AllProtocolsTestSuite.java b/src/test/java/testing/protocols/AllProtocolsTestSuite.java new file mode 100644 index 0000000..dae298b --- /dev/null +++ b/src/test/java/testing/protocols/AllProtocolsTestSuite.java @@ -0,0 +1,34 @@ +package testing.protocols; + +import org.junit.platform.suite.api.*; + +/** + * Test suite that runs all protocol tests. + * This ensures all protocol simulations are tested when running unit tests. + */ +@Suite +@SuiteDisplayName("DS-Sim Protocol Test Suite") +@SelectClasses({ + // Basic protocols + PingPongProtocolTest.class, + PingPongSturmProtocolTest.class, + BroadcastProtocolTest.class, + BasicMulticastProtocolTest.class, + ReliableMulticastProtocolTest.class, + + // Time synchronization protocols + BerkeleyProtocolTest.class, + TimeSynchronizationProtocolTest.class, + + // Commit protocols + CommitProtocolTest.class, + + // Network simulation + SlowConnectionProtocolTest.class + + // Note: Raft tests are excluded as requested +}) +@IncludeClassNamePatterns(".*Test") +public class AllProtocolsTestSuite { + // This class remains empty. It is used only as a holder for the above annotations +}
\ No newline at end of file diff --git a/src/test/java/testing/protocols/BaseProtocolTest.java b/src/test/java/testing/protocols/BaseProtocolTest.java new file mode 100644 index 0000000..e9cbc81 --- /dev/null +++ b/src/test/java/testing/protocols/BaseProtocolTest.java @@ -0,0 +1,45 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; + +/** + * Base class for protocol tests providing common setup and utilities. + */ +public abstract class BaseProtocolTest { + protected HeadlessSimulationRunner runner; + + @BeforeEach + public void baseSetup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void baseTeardown() { + if (runner != null) { + runner.shutdown(); + } + } + + /** + * Run a simulation and get the result with error handling. + */ + protected SimulationResult runSimulation(String file, long duration) { + try { + return runner.runSimulation(file, duration); + } catch (Exception e) { + throw new RuntimeException("Failed to run simulation: " + file, e); + } + } + + /** + * Create a basic verifier that checks for no errors. + */ + protected ProtocolVerifier createBasicVerifier() { + return new ProtocolVerifier() + .expectNoLog("ERROR") + .expectNoLog("Exception") + .expectNoLog("null") + .expectNoLog("NullPointer"); + } +}
\ No newline at end of file diff --git a/src/test/java/testing/protocols/BasicMulticastProtocolTest.java b/src/test/java/testing/protocols/BasicMulticastProtocolTest.java new file mode 100644 index 0000000..e3a03c5 --- /dev/null +++ b/src/test/java/testing/protocols/BasicMulticastProtocolTest.java @@ -0,0 +1,89 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit test for Basic Multicast protocol using the headless testing framework. + */ +@DisplayName("Basic Multicast Protocol Tests") +public class BasicMulticastProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test Basic Multicast protocol activation") + public void testProtocolActivation() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/basic-multicast.dat", + 1000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Basic Multicast.*activated") + .expectLog("Client activated") + .expectLog("Server activated"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + + assertTrue(verification.passed(), verification.getFailureMessage()); + assertTrue(result.getMetrics().getNumProcesses() >= 3, + "Should have at least 3 processes for multicast"); + } + + @Test + @DisplayName("Test multicast message delivery") + public void testMulticastDelivery() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/basic-multicast.dat", + 3000 + ); + + // Verify multicast behavior + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Message sent") + .expectLog("Message received") + .expectLog("Multicast") + .expectNoLog("ERROR") + .expectNoLog("failed"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + + // Check that multiple processes receive messages + int sentCount = result.countLogs("Message sent"); + int receivedCount = result.countLogs("Message received"); + + assertTrue(receivedCount >= sentCount, + "In multicast, received messages should be >= sent messages"); + } + + @Test + @DisplayName("Test message ordering") + public void testMessageOrdering() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/basic-multicast.dat", + 2000 + ); + + // Verify messages are delivered in order + var receivedMessages = result.findAll("Message received"); + + long lastTimestamp = -1; + for (LogEntry entry : receivedMessages) { + assertTrue(entry.getTimestamp() >= lastTimestamp, + "Messages should be received in chronological order"); + lastTimestamp = entry.getTimestamp(); + } + } +}
\ No newline at end of file diff --git a/src/test/java/testing/protocols/BerkeleyProtocolTest.java b/src/test/java/testing/protocols/BerkeleyProtocolTest.java new file mode 100644 index 0000000..9dc144d --- /dev/null +++ b/src/test/java/testing/protocols/BerkeleyProtocolTest.java @@ -0,0 +1,78 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit test for Berkeley time synchronization protocol. + */ +@DisplayName("Berkeley Time Synchronization Protocol Tests") +public class BerkeleyProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test Berkeley protocol activation") + public void testProtocolActivation() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/berkeley.dat", + 1000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Berkley.*activated|Berkeley.*activated") + .expectNoLog("ERROR"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + + assertTrue(verification.passed(), verification.getFailureMessage()); + assertTrue(result.getMetrics().getTotalLogCount() > 0, + "Should have some log activity"); + } + + @Test + @DisplayName("Test time synchronization messages") + public void testTimeSynchronization() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/berkeley.dat", + 5000 + ); + + // Berkeley protocol involves time requests and adjustments + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("time|Time|TIME") + .expectLog("sync|Sync|SYNC") + .expectLog("Message sent") + .expectLog("Message received"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + } + + @Test + @DisplayName("Test master-slave communication") + public void testMasterSlaveCommunication() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/berkeley.dat", + 3000 + ); + + // Berkeley has master and slave nodes + boolean hasMasterActivity = result.countLogs("master|Master|MASTER") > 0; + boolean hasSlaveActivity = result.countLogs("slave|Slave|SLAVE") > 0; + boolean hasTimeExchange = result.countLogs("time|Time") > 0; + + assertTrue(hasMasterActivity || hasSlaveActivity || hasTimeExchange, + "Should have master/slave or time-related activity"); + } +}
\ No newline at end of file diff --git a/src/test/java/testing/protocols/BroadcastProtocolTest.java b/src/test/java/testing/protocols/BroadcastProtocolTest.java new file mode 100644 index 0000000..d0ed6f3 --- /dev/null +++ b/src/test/java/testing/protocols/BroadcastProtocolTest.java @@ -0,0 +1,93 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit test for Broadcast protocol. + */ +@DisplayName("Broadcast Protocol Tests") +public class BroadcastProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test Broadcast protocol activation") + public void testProtocolActivation() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/broadcast.dat", + 1000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Broadcast.*activated") + .expectNoLog("ERROR") + .expectNoLog("Exception"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + + assertTrue(verification.passed(), verification.getFailureMessage()); + } + + @Test + @DisplayName("Test broadcast message delivery to all nodes") + public void testBroadcastDelivery() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/broadcast.dat", + 3000 + ); + + // In broadcast, one message should be received by multiple nodes + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Message sent") + .expectLog("Message received") + .expectLog("Broadcast|broadcast|BROADCAST"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + + // Verify broadcast property: more receives than sends + int sent = result.countLogs("Message sent"); + int received = result.countLogs("Message received"); + + if (sent > 0 && result.getMetrics().getNumProcesses() > 2) { + assertTrue(received > sent, + "Broadcast should deliver to multiple receivers"); + } + } + + @Test + @DisplayName("Test all processes receive broadcast") + public void testAllProcessesReceive() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/broadcast.dat", + 4000 + ); + + // Count how many different processes received messages + var processLogs = result.getProcessLogs(); + int processesWithReceivedMessages = 0; + + for (var entry : processLogs.entrySet()) { + boolean hasReceived = entry.getValue().stream() + .anyMatch(log -> log.getMessage().contains("received")); + if (hasReceived) { + processesWithReceivedMessages++; + } + } + + // In broadcast, multiple processes should receive messages + assertTrue(processesWithReceivedMessages >= 1, + "At least one process should receive messages"); + } +}
\ No newline at end of file diff --git a/src/test/java/testing/protocols/CommitProtocolTest.java b/src/test/java/testing/protocols/CommitProtocolTest.java new file mode 100644 index 0000000..abe9a5d --- /dev/null +++ b/src/test/java/testing/protocols/CommitProtocolTest.java @@ -0,0 +1,83 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit tests for commit protocols (one-phase and two-phase). + */ +@DisplayName("Commit Protocol Tests") +public class CommitProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test One-Phase Commit protocol") + public void testOnePhaseCommit() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/one-phase-commit.dat", + 3000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("1-Phase Commit.*activated|One.*Phase.*activated") + .expectLog("commit|Commit|COMMIT") + .expectLog("Message") + .expectNoLog("ERROR") + .expectNoLog("abort|ABORT"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + } + + @Test + @DisplayName("Test Two-Phase Commit protocol") + public void testTwoPhaseCommit() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/two-phase-commit.dat", + 4000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("2-Phase Commit.*activated|Two.*Phase.*activated") + .expectLog("Message") + .expectNoLog("ERROR"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + + // Two-phase commit should have prepare/vote and commit phases + boolean hasPrepare = result.countLogs("prepare|Prepare|PREPARE|vote|Vote") > 0; + boolean hasCommit = result.countLogs("commit|Commit|COMMIT") > 0; + + assertTrue(hasPrepare || hasCommit, + "Should have prepare/vote or commit messages"); + } + + @Test + @DisplayName("Test commit protocol coordinator behavior") + public void testCoordinatorBehavior() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/two-phase-commit.dat", + 5000 + ); + + // Look for coordinator-specific messages + boolean hasCoordinator = result.countLogs("coordinator|Coordinator|COORDINATOR") > 0; + boolean hasParticipant = result.countLogs("participant|Participant|PARTICIPANT") > 0; + boolean hasTransaction = result.countLogs("transaction|Transaction") > 0; + + assertTrue(hasCoordinator || hasParticipant || hasTransaction, + "Should have coordinator/participant activity"); + } +}
\ No newline at end of file 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 diff --git a/src/test/java/testing/protocols/PingPongSturmProtocolTest.java b/src/test/java/testing/protocols/PingPongSturmProtocolTest.java new file mode 100644 index 0000000..34cf64e --- /dev/null +++ b/src/test/java/testing/protocols/PingPongSturmProtocolTest.java @@ -0,0 +1,64 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit test for Ping-Pong Sturm variant. + */ +@DisplayName("Ping-Pong Sturm Protocol Tests") +public class PingPongSturmProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test Ping-Pong Sturm protocol activation") + public void testProtocolActivation() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/ping-pong-sturm.dat", + 1000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Ping-Pong.*activated") + .expectNoLog("ERROR"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + } + + @Test + @DisplayName("Test Sturm variant message exchange") + public void testSturmMessageExchange() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/ping-pong-sturm.dat", + 3000 + ); + + // Similar to regular ping-pong but may have different patterns + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Message sent") + .expectLog("Message received") + .expectLog("fromClient=true|fromServer=true"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + + // Check for balanced communication + int sent = result.countLogs("Message sent"); + int received = result.countLogs("Message received"); + + assertTrue(Math.abs(sent - received) <= 2, + "Messages should be roughly balanced"); + } +}
\ No newline at end of file diff --git a/src/test/java/testing/protocols/ReliableMulticastProtocolTest.java b/src/test/java/testing/protocols/ReliableMulticastProtocolTest.java new file mode 100644 index 0000000..ae9b4d7 --- /dev/null +++ b/src/test/java/testing/protocols/ReliableMulticastProtocolTest.java @@ -0,0 +1,86 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit test for Reliable Multicast protocol. + */ +@DisplayName("Reliable Multicast Protocol Tests") +public class ReliableMulticastProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test Reliable Multicast protocol activation") + public void testProtocolActivation() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/reliable-multicast.dat", + 1000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Reliable Multicast.*activated") + .expectNoLog("ERROR"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + } + + @Test + @DisplayName("Test reliable delivery guarantees") + public void testReliableDelivery() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/reliable-multicast.dat", + 5000 + ); + + // Reliable multicast should ensure delivery + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Message sent") + .expectLog("Message received") + .expectLog("Multicast|multicast") + .expectNoLog("lost|Lost|LOST") + .expectNoLog("failed delivery"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + + // Check for acknowledgments or reliability mechanisms + boolean hasAck = result.countLogs("ack|ACK|acknowledge|Acknowledge") > 0; + boolean hasSeq = result.countLogs("sequence|Sequence|seq|SEQ") > 0; + boolean hasReliable = result.countLogs("reliable|Reliable") > 0; + + assertTrue(hasAck || hasSeq || hasReliable, + "Should have reliability mechanisms"); + } + + @Test + @DisplayName("Test message ordering in reliable multicast") + public void testMessageOrdering() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/reliable-multicast.dat", + 3000 + ); + + // Verify messages maintain order + var messages = result.findAll("Message received"); + + long lastTime = -1; + for (LogEntry entry : messages) { + assertTrue(entry.getTimestamp() >= lastTime, + "Messages should be in order"); + lastTime = entry.getTimestamp(); + } + } +}
\ No newline at end of file diff --git a/src/test/java/testing/protocols/SlowConnectionProtocolTest.java b/src/test/java/testing/protocols/SlowConnectionProtocolTest.java new file mode 100644 index 0000000..cf17517 --- /dev/null +++ b/src/test/java/testing/protocols/SlowConnectionProtocolTest.java @@ -0,0 +1,90 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit test for Slow Connection simulation. + */ +@DisplayName("Slow Connection Simulation Tests") +public class SlowConnectionProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test slow connection simulation") + public void testSlowConnection() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/slow-connection.dat", + 5000 + ); + + // Slow connection should show delayed message delivery + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("activated") + .expectLog("Message") + .expectNoLog("ERROR"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + } + + @Test + @DisplayName("Test message delays in slow connection") + public void testMessageDelays() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/slow-connection.dat", + 6000 + ); + + // Look for evidence of delays + var sentMessages = result.findAll("Message sent"); + var receivedMessages = result.findAll("Message received"); + + if (!sentMessages.isEmpty() && !receivedMessages.isEmpty()) { + // Calculate average delay + long totalDelay = 0; + int delayCount = 0; + + for (int i = 0; i < Math.min(sentMessages.size(), receivedMessages.size()); i++) { + long sentTime = sentMessages.get(i).getTimestamp(); + long receivedTime = receivedMessages.get(i).getTimestamp(); + if (receivedTime > sentTime) { + totalDelay += (receivedTime - sentTime); + delayCount++; + } + } + + if (delayCount > 0) { + long avgDelay = totalDelay / delayCount; + assertTrue(avgDelay > 0, "Should have message delays in slow connection"); + } + } + } + + @Test + @DisplayName("Test connection characteristics") + public void testConnectionCharacteristics() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/slow-connection.dat", + 4000 + ); + + // Check for slow/delay related messages + boolean hasSlowIndication = result.countLogs("slow|Slow|delay|Delay") > 0; + boolean hasConnection = result.countLogs("connection|Connection") > 0; + + assertTrue(hasSlowIndication || hasConnection || result.getAllLogs().size() > 0, + "Should have some activity indicating slow connection"); + } +}
\ No newline at end of file diff --git a/src/test/java/testing/protocols/TimeSynchronizationProtocolTest.java b/src/test/java/testing/protocols/TimeSynchronizationProtocolTest.java new file mode 100644 index 0000000..d04dab3 --- /dev/null +++ b/src/test/java/testing/protocols/TimeSynchronizationProtocolTest.java @@ -0,0 +1,83 @@ +package testing.protocols; + +import testing.*; +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * JUnit tests for time synchronization protocols (internal and external). + */ +@DisplayName("Time Synchronization Protocol Tests") +public class TimeSynchronizationProtocolTest { + private HeadlessSimulationRunner runner; + + @BeforeEach + public void setup() { + runner = new HeadlessSimulationRunner(); + } + + @AfterEach + public void teardown() { + runner.shutdown(); + } + + @Test + @DisplayName("Test Internal Time Synchronization") + public void testInternalTimeSync() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/int-sync.dat", + 3000 + ); + + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("Internal.*sync.*activated|Internal sync.*activated") + .expectLog("time|Time|sync|Sync") + .expectLog("Message") + .expectNoLog("ERROR"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + } + + @Test + @DisplayName("Test External vs Internal Time Synchronization") + public void testExternalVsInternalSync() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/ext-vs-int-sync.dat", + 4000 + ); + + // This simulation compares external and internal sync + ProtocolVerifier verifier = new ProtocolVerifier() + .expectLog("activated") + .expectLog("sync|Sync|synchron") + .expectNoLog("ERROR") + .expectNoLog("failed"); + + VerificationResult verification = verifier.verify(result.getAllLogs()); + assertTrue(verification.passed(), verification.getFailureMessage()); + + // Check for both internal and external sync activity + boolean hasInternal = result.countLogs("Internal|internal") > 0; + boolean hasExternal = result.countLogs("External|external|Christians") > 0; + + assertTrue(hasInternal || hasExternal, + "Should have time synchronization activity"); + } + + @Test + @DisplayName("Test clock adjustments") + public void testClockAdjustments() throws Exception { + SimulationResult result = runner.runSimulation( + "saved-simulations/int-sync.dat", + 5000 + ); + + // Look for time-related messages + boolean hasTimeMessages = result.countLogs("time|Time|clock|Clock") > 0; + boolean hasAdjustments = result.countLogs("adjust|Adjust|sync") > 0; + + assertTrue(hasTimeMessages || hasAdjustments, + "Should have time-related activity"); + } +}
\ No newline at end of file |
