summaryrefslogtreecommitdiff
path: root/src/test/java/testing
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/testing')
-rw-r--r--src/test/java/testing/RaftSimulationTest.java57
-rw-r--r--src/test/java/testing/protocols/BaseProtocolTest.java10
-rw-r--r--src/test/java/testing/protocols/BroadcastProtocolTest.java3
-rw-r--r--src/test/java/testing/protocols/MessageDeliveryDebug2Test.java88
-rw-r--r--src/test/java/testing/protocols/MessageDeliveryDebug3Test.java87
-rw-r--r--src/test/java/testing/protocols/MessageDeliveryDebug4Test.java83
-rw-r--r--src/test/java/testing/protocols/MessageDeliveryDebugTest.java71
-rw-r--r--src/test/java/testing/protocols/PingPongProtocolTest.java3
-rw-r--r--src/test/java/testing/protocols/RaftProtocolTest.java77
9 files changed, 476 insertions, 3 deletions
diff --git a/src/test/java/testing/RaftSimulationTest.java b/src/test/java/testing/RaftSimulationTest.java
new file mode 100644
index 0000000..b161668
--- /dev/null
+++ b/src/test/java/testing/RaftSimulationTest.java
@@ -0,0 +1,57 @@
+package testing;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeEach;
+import prefs.VSDefaultPrefs;
+import events.VSRegisteredEvents;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Integration test for Raft protocol simulation.
+ * Tests that leader election occurs when running a Raft simulation.
+ */
+class RaftSimulationTest {
+
+ private VSDefaultPrefs prefs;
+
+ @BeforeEach
+ void setUp() {
+ prefs = new VSDefaultPrefs();
+ prefs.fillWithDefaults();
+ VSRegisteredEvents.init(prefs);
+ }
+
+ @Test
+ void testRaftLeaderElection() throws Exception {
+ // This test verifies that the Raft protocol implementation
+ // properly elects a leader when running
+
+ // For now, we verify the protocol can be instantiated and initialized
+ Object raftObj = new utils.VSClassLoader().newInstance("protocols.implementations.VSRaftProtocol");
+ assertNotNull(raftObj, "Raft protocol should be instantiable");
+ assertTrue(raftObj instanceof protocols.VSAbstractProtocol, "Should be a protocol");
+
+ // Verify the protocol has the correct classname set
+ protocols.implementations.VSRaftProtocol raftProtocol =
+ (protocols.implementations.VSRaftProtocol) raftObj;
+ assertNotNull(raftProtocol.getClassname(),
+ "Protocol classname should be set");
+ assertTrue(raftProtocol.getClassname().contains("VSRaftProtocol"),
+ "Protocol classname should contain VSRaftProtocol");
+ }
+
+ @Test
+ void testRaftProtocolRegistration() {
+ // Verify Raft protocol is properly registered
+ assertTrue(VSRegisteredEvents.getProtocolClassnames().contains(
+ "protocols.implementations.VSRaftProtocol"),
+ "Raft protocol should be registered");
+
+ // Verify it has a proper display name (this is set in lang properties)
+ String shortName = VSRegisteredEvents.getShortnameByClassname(
+ "protocols.implementations.VSRaftProtocol");
+ assertNotNull(shortName, "Raft protocol should have a short name");
+ assertEquals("Raft Consensus", shortName);
+ }
+} \ No newline at end of file
diff --git a/src/test/java/testing/protocols/BaseProtocolTest.java b/src/test/java/testing/protocols/BaseProtocolTest.java
index e9cbc81..fcc04fa 100644
--- a/src/test/java/testing/protocols/BaseProtocolTest.java
+++ b/src/test/java/testing/protocols/BaseProtocolTest.java
@@ -26,7 +26,15 @@ public abstract class BaseProtocolTest {
*/
protected SimulationResult runSimulation(String file, long duration) {
try {
- return runner.runSimulation(file, duration);
+ SimulationResult result = runner.runSimulation(file, duration);
+
+ // Check if any messages were sent
+ int totalMessages = result.getMetrics().getTotalMessageCount();
+ if (totalMessages == 0) {
+ throw new AssertionError("Protocol test failed: No messages were sent during simulation of " + file);
+ }
+
+ return result;
} catch (Exception e) {
throw new RuntimeException("Failed to run simulation: " + file, e);
}
diff --git a/src/test/java/testing/protocols/BroadcastProtocolTest.java b/src/test/java/testing/protocols/BroadcastProtocolTest.java
index d0ed6f3..644e6b3 100644
--- a/src/test/java/testing/protocols/BroadcastProtocolTest.java
+++ b/src/test/java/testing/protocols/BroadcastProtocolTest.java
@@ -32,7 +32,8 @@ public class BroadcastProtocolTest {
ProtocolVerifier verifier = new ProtocolVerifier()
.expectLog("Broadcast.*activated")
.expectNoLog("ERROR")
- .expectNoLog("Exception");
+ .expectNoLog("Exception")
+ .expectMessages(); // Broadcast must send messages
VerificationResult verification = verifier.verify(result.getAllLogs());
diff --git a/src/test/java/testing/protocols/MessageDeliveryDebug2Test.java b/src/test/java/testing/protocols/MessageDeliveryDebug2Test.java
new file mode 100644
index 0000000..abebfe0
--- /dev/null
+++ b/src/test/java/testing/protocols/MessageDeliveryDebug2Test.java
@@ -0,0 +1,88 @@
+package testing.protocols;
+
+import testing.*;
+import org.junit.jupiter.api.*;
+import static org.junit.jupiter.api.Assertions.*;
+import java.lang.reflect.Field;
+import core.VSTask;
+import core.VSTaskManager;
+import java.util.*;
+
+/**
+ * Extended debug test to understand why protocols are running twice.
+ */
+public class MessageDeliveryDebug2Test {
+ private HeadlessSimulationRunner runner;
+
+ @BeforeEach
+ public void setup() {
+ runner = new HeadlessSimulationRunner();
+ }
+
+ @AfterEach
+ public void teardown() {
+ runner.shutdown();
+ }
+
+ @Test
+ @DisplayName("Debug why PingPong client sends two messages")
+ public void debugDuplicateMessages() throws Exception {
+ System.out.println("\n=== Starting Duplicate Message Debug Test ===");
+
+ // Custom log listener to trace task execution
+ LogListener listener = new LogListener() {
+ private int messagesSent = 0;
+
+ @Override
+ public void onLogEntry(LogEntry entry) {
+ String msg = entry.getMessage();
+
+ // Track all events
+ if (msg.contains("activated") || msg.contains("Message sent") ||
+ msg.contains("onClientStart") || msg.contains("counter=")) {
+ System.out.println(String.format("[TRACE %5d] P%d: %s",
+ entry.getTimestamp(), entry.getProcessNum(), msg));
+
+ if (msg.contains("Message sent")) {
+ messagesSent++;
+ if (messagesSent == 2) {
+ System.out.println("!!! ISSUE: Second message sent immediately at time " +
+ entry.getTimestamp() + " - protocol likely executed twice!");
+ }
+ }
+ }
+
+ // Look for protocol event execution
+ if (msg.contains("VSProtocolEvent") || msg.contains("VSPingPongProtocol")) {
+ System.out.println(String.format("[EVENT %5d] P%d: %s",
+ entry.getTimestamp(), entry.getProcessNum(), msg));
+ }
+ }
+ };
+
+ SimulationResult result = runner.runSimulation(
+ "saved-simulations/ping-pong.dat",
+ 1000, // Just 1 second is enough to see the issue
+ listener
+ );
+
+ System.out.println("\n=== Analysis ===");
+
+ // Count messages sent at time 0
+ int messagesAtTimeZero = 0;
+ for (LogEntry entry : result.getAllLogs()) {
+ if (entry.getTimestamp() == 0 && entry.getMessage().contains("Message sent")) {
+ messagesAtTimeZero++;
+ System.out.println("Message at time 0: " + entry.getMessage());
+ }
+ }
+
+ System.out.println("\nMessages sent at time 0: " + messagesAtTimeZero);
+
+ if (messagesAtTimeZero > 1) {
+ System.out.println("ERROR: Multiple messages sent at time 0 indicates duplicate protocol execution!");
+ }
+
+ System.out.println("\n=== Test Complete ===");
+ }
+} \ No newline at end of file
diff --git a/src/test/java/testing/protocols/MessageDeliveryDebug3Test.java b/src/test/java/testing/protocols/MessageDeliveryDebug3Test.java
new file mode 100644
index 0000000..3e41a05
--- /dev/null
+++ b/src/test/java/testing/protocols/MessageDeliveryDebug3Test.java
@@ -0,0 +1,87 @@
+package testing.protocols;
+
+import testing.*;
+import org.junit.jupiter.api.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Deep debug test to understand why messages aren't being received.
+ */
+public class MessageDeliveryDebug3Test {
+ private HeadlessSimulationRunner runner;
+
+ @BeforeEach
+ public void setup() {
+ runner = new HeadlessSimulationRunner();
+ runner.setPrintLogs(true);
+ }
+
+ @AfterEach
+ public void teardown() {
+ runner.shutdown();
+ }
+
+ @Test
+ @DisplayName("Debug message delivery with detailed logging")
+ public void debugMessageDelivery() throws Exception {
+ System.out.println("\n=== Starting Message Delivery Deep Debug ===");
+
+ // Run for longer to see if messages eventually get delivered
+ SimulationResult result = runner.runSimulation(
+ "saved-simulations/ping-pong.dat",
+ 10000 // 10 seconds
+ );
+
+ System.out.println("\n=== Analysis ===");
+
+ // Count message types
+ int sentCount = 0;
+ int receivedCount = 0;
+ int scheduledCount = 0;
+
+ for (LogEntry entry : result.getAllLogs()) {
+ String msg = entry.getMessage();
+ if (msg.contains("Message sent")) {
+ sentCount++;
+ System.out.println("SENT at " + entry.getTimestamp() + ": " + msg);
+ } else if (msg.contains("Message received")) {
+ receivedCount++;
+ System.out.println("RECEIVED at " + entry.getTimestamp() + ": " + msg);
+ } else if (msg.contains("scheduled for delivery")) {
+ scheduledCount++;
+ System.out.println("SCHEDULED: " + msg);
+ }
+ }
+
+ System.out.println("\nTotal messages sent: " + sentCount);
+ System.out.println("Total messages received: " + receivedCount);
+ System.out.println("Total messages scheduled: " + scheduledCount);
+
+ // Check if we're getting any server/client activity
+ boolean hasServerActivity = false;
+ boolean hasClientActivity = false;
+
+ for (LogEntry entry : result.getAllLogs()) {
+ String msg = entry.getMessage();
+ if (msg.contains("Server") && msg.contains("activated")) {
+ hasServerActivity = true;
+ }
+ if (msg.contains("Client") && msg.contains("activated")) {
+ hasClientActivity = true;
+ }
+ }
+
+ System.out.println("\nServer activated: " + hasServerActivity);
+ System.out.println("Client activated: " + hasClientActivity);
+
+ // Print all logs for full context
+ System.out.println("\n=== All Logs ===");
+ for (LogEntry entry : result.getAllLogs()) {
+ System.out.println(String.format("[%5d] P%d: %s",
+ entry.getTimestamp(), entry.getProcessNum(), entry.getMessage()));
+ }
+
+ assertTrue(sentCount > 0, "Should have sent at least one message");
+ assertTrue(receivedCount > 0, "Should have received at least one message");
+ }
+} \ No newline at end of file
diff --git a/src/test/java/testing/protocols/MessageDeliveryDebug4Test.java b/src/test/java/testing/protocols/MessageDeliveryDebug4Test.java
new file mode 100644
index 0000000..719bb37
--- /dev/null
+++ b/src/test/java/testing/protocols/MessageDeliveryDebug4Test.java
@@ -0,0 +1,83 @@
+package testing.protocols;
+
+import testing.*;
+import org.junit.jupiter.api.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Test with longer timeout to ensure all messages are delivered.
+ */
+public class MessageDeliveryDebug4Test {
+ private HeadlessSimulationRunner runner;
+
+ @BeforeEach
+ public void setup() {
+ runner = new HeadlessSimulationRunner();
+ }
+
+ @Test
+ @DisplayName("Test counter values with extended timeout")
+ public void testCounterValues() throws Exception {
+ System.out.println("\n=== Testing Counter Values ===");
+
+ // Run for 10 seconds to ensure all messages are exchanged
+ SimulationResult result = runner.runSimulation(
+ "saved-simulations/ping-pong.dat",
+ 10000
+ );
+
+ System.out.println("\n=== Counter Analysis ===");
+
+ // Look for all counter values
+ int maxClientCounter = 0;
+ int maxServerCounter = 0;
+
+ for (LogEntry entry : result.getAllLogs()) {
+ String msg = entry.getMessage();
+ if (msg.contains("counter=")) {
+ int start = msg.indexOf("counter=") + 8;
+ int end = msg.indexOf(";", start);
+ if (end == -1) end = msg.indexOf(" ", start);
+ if (end == -1) end = msg.length();
+
+ try {
+ int counter = Integer.parseInt(msg.substring(start, end));
+ System.out.println("Found counter=" + counter + " at time " + entry.getTimestamp());
+
+ if (msg.contains("fromClient=true")) {
+ maxClientCounter = Math.max(maxClientCounter, counter);
+ } else if (msg.contains("fromServer=true")) {
+ maxServerCounter = Math.max(maxServerCounter, counter);
+ }
+ } catch (NumberFormatException e) {
+ // Ignore
+ }
+ }
+ }
+
+ System.out.println("\nMax client counter: " + maxClientCounter);
+ System.out.println("Max server counter: " + maxServerCounter);
+
+ // Count messages
+ int sentCount = result.countLogs("Message sent");
+ int receivedCount = result.countLogs("Message received");
+
+ System.out.println("\nTotal messages sent: " + sentCount);
+ System.out.println("Total messages received: " + receivedCount);
+
+ // Print timeline
+ System.out.println("\n=== Message Timeline ===");
+ for (LogEntry entry : result.getAllLogs()) {
+ String msg = entry.getMessage();
+ if (msg.contains("Message sent") || msg.contains("Message received") ||
+ msg.contains("activated")) {
+ System.out.println(String.format("[%5d] P%d: %s",
+ entry.getTimestamp(), entry.getProcessNum(),
+ msg.substring(msg.indexOf(";") + 2))); // Skip PID part
+ }
+ }
+
+ assertTrue(maxClientCounter >= 2, "Client should reach at least counter=2");
+ assertTrue(maxServerCounter >= 1, "Server should reach at least counter=1");
+ }
+} \ No newline at end of file
diff --git a/src/test/java/testing/protocols/MessageDeliveryDebugTest.java b/src/test/java/testing/protocols/MessageDeliveryDebugTest.java
new file mode 100644
index 0000000..9f190a1
--- /dev/null
+++ b/src/test/java/testing/protocols/MessageDeliveryDebugTest.java
@@ -0,0 +1,71 @@
+package testing.protocols;
+
+import testing.*;
+import org.junit.jupiter.api.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Debug test to understand message delivery issues in headless mode.
+ */
+public class MessageDeliveryDebugTest {
+ private HeadlessSimulationRunner runner;
+
+ @BeforeEach
+ public void setup() {
+ runner = new HeadlessSimulationRunner();
+ runner.setPrintLogs(true); // Enable log printing for debugging
+ }
+
+ @AfterEach
+ public void teardown() {
+ runner.shutdown();
+ }
+
+ @Test
+ @DisplayName("Debug message delivery in Ping-Pong protocol")
+ public void debugMessageDelivery() throws Exception {
+ System.out.println("\n=== Starting Message Delivery Debug Test ===");
+
+ // Run simulation with log listener to see what's happening
+ LogListener listener = new LogListener() {
+ @Override
+ public void onLogEntry(LogEntry entry) {
+ String msg = entry.getMessage();
+ if (msg.contains("Message sent") || msg.contains("Message received") ||
+ msg.contains("scheduled for delivery") || msg.contains("activated")) {
+ System.out.println(String.format("[DEBUG %5d] P%d: %s",
+ entry.getTimestamp(), entry.getProcessNum(), msg));
+ }
+ }
+ };
+
+ SimulationResult result = runner.runSimulation(
+ "saved-simulations/ping-pong.dat",
+ 5000,
+ listener
+ );
+
+ System.out.println("\n=== Simulation Complete ===");
+ System.out.println("Total logs captured: " + result.getAllLogs().size());
+
+ // Count specific log types
+ int sentCount = result.countLogs("Message sent");
+ int receivedCount = result.countLogs("Message received");
+ int activatedCount = result.countLogs("activated");
+
+ System.out.println("Messages sent: " + sentCount);
+ System.out.println("Messages received: " + receivedCount);
+ System.out.println("Protocols activated: " + activatedCount);
+
+ // Print all logs for analysis
+ System.out.println("\n=== All Logs ===");
+ for (LogEntry entry : result.getAllLogs()) {
+ System.out.println(String.format("[%5d] P%d: %s",
+ entry.getTimestamp(), entry.getProcessNum(), entry.getMessage()));
+ }
+
+ // Basic assertions
+ assertTrue(activatedCount > 0, "At least one protocol should be activated");
+ System.out.println("\n=== Test Complete ===");
+ }
+} \ No newline at end of file
diff --git a/src/test/java/testing/protocols/PingPongProtocolTest.java b/src/test/java/testing/protocols/PingPongProtocolTest.java
index 3396e08..947de54 100644
--- a/src/test/java/testing/protocols/PingPongProtocolTest.java
+++ b/src/test/java/testing/protocols/PingPongProtocolTest.java
@@ -31,7 +31,8 @@ public class PingPongProtocolTest {
ProtocolVerifier verifier = new ProtocolVerifier()
.expectLogExactly("Ping-Pong.*activated", 2)
.expectLog("Ping-Pong Client activated")
- .expectLog("Ping-Pong Server activated");
+ .expectLog("Ping-Pong Server activated")
+ .expectMessages(); // Ensure messages are sent
VerificationResult verification = verifier.verify(result.getAllLogs());
diff --git a/src/test/java/testing/protocols/RaftProtocolTest.java b/src/test/java/testing/protocols/RaftProtocolTest.java
new file mode 100644
index 0000000..b92606d
--- /dev/null
+++ b/src/test/java/testing/protocols/RaftProtocolTest.java
@@ -0,0 +1,77 @@
+package testing.protocols;
+
+import testing.*;
+import org.junit.jupiter.api.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Integration test for Raft consensus protocol.
+ */
+public class RaftProtocolTest extends BaseProtocolTest {
+
+ @Test
+ @DisplayName("Test Raft protocol activation and message sending")
+ public void testRaftActivation() {
+ SimulationResult result = runSimulation(
+ "saved-simulations/raft.dat",
+ 2000 // 2 seconds should be enough for elections
+ );
+
+ ProtocolVerifier verifier = new ProtocolVerifier()
+ .expectLogExactly("Raft Consensus Server activated", 3)
+ .expectLog("FOLLOWER.*initialized")
+ .expectLog("Starting election")
+ .expectLog("CANDIDATE")
+ .expectMessages() // Must have messages
+ .expectAtLeastNMessages(10); // Should have many election messages
+
+ VerificationResult verification = verifier.verify(result.getAllLogs());
+
+ assertTrue(verification.passed(), verification.getFailureMessage());
+ assertEquals(3, result.getMetrics().getNumProcesses(),
+ "Should have 3 processes");
+ }
+
+ @Test
+ @DisplayName("Test Raft election messages")
+ public void testRaftElectionMessages() {
+ SimulationResult result = runSimulation(
+ "saved-simulations/raft.dat",
+ 3000
+ );
+
+ ProtocolVerifier verifier = new ProtocolVerifier()
+ .expectLog("REQUEST_VOTE")
+ .expectLog("Message sent.*REQUEST_VOTE")
+ .expectAtLeastNMessages(15); // Multiple election rounds
+
+ VerificationResult verification = verifier.verify(result.getAllLogs());
+ assertTrue(verification.passed(), verification.getFailureMessage());
+
+ // Verify term progression
+ assertTrue(result.findFirst("term=1").isPresent(), "Should have term 1");
+ assertTrue(result.findFirst("term=2").isPresent(), "Should progress to term 2");
+ }
+
+ @Test
+ @DisplayName("Test Raft with clients")
+ public void testRaftWithClients() {
+ // Skip if file doesn't exist
+ if (!new java.io.File("saved-simulations/raft-with-clients.dat").exists()) {
+ return;
+ }
+
+ SimulationResult result = runSimulation(
+ "saved-simulations/raft-with-clients.dat",
+ 5000
+ );
+
+ ProtocolVerifier verifier = new ProtocolVerifier()
+ .expectLogExactly("Raft Consensus Server activated", 3)
+ .expectLogExactly("Raft Consensus Client activated", 2)
+ .expectMessages(); // Must have messages
+
+ VerificationResult verification = verifier.verify(result.getAllLogs());
+ assertTrue(verification.passed(), verification.getFailureMessage());
+ }
+} \ No newline at end of file