summaryrefslogtreecommitdiff
path: root/src/test/java/testing/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/testing/protocols')
-rw-r--r--src/test/java/testing/protocols/AllProtocolsTestSuite.java34
-rw-r--r--src/test/java/testing/protocols/BaseProtocolTest.java45
-rw-r--r--src/test/java/testing/protocols/BasicMulticastProtocolTest.java89
-rw-r--r--src/test/java/testing/protocols/BerkeleyProtocolTest.java78
-rw-r--r--src/test/java/testing/protocols/BroadcastProtocolTest.java93
-rw-r--r--src/test/java/testing/protocols/CommitProtocolTest.java83
-rw-r--r--src/test/java/testing/protocols/PingPongProtocolTest.java141
-rw-r--r--src/test/java/testing/protocols/PingPongSturmProtocolTest.java64
-rw-r--r--src/test/java/testing/protocols/ReliableMulticastProtocolTest.java86
-rw-r--r--src/test/java/testing/protocols/SlowConnectionProtocolTest.java90
-rw-r--r--src/test/java/testing/protocols/TimeSynchronizationProtocolTest.java83
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