From d3b697218773eaa5a3dd368705184726dbc0fa38 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 21 Jun 2025 15:54:07 +0300 Subject: Implement headless testing framework for DS-Sim protocol simulations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .../java/examples/CreateWorkingRaftSimulation.java | 152 +++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/main/java/examples/CreateWorkingRaftSimulation.java (limited to 'src/main/java/examples/CreateWorkingRaftSimulation.java') diff --git a/src/main/java/examples/CreateWorkingRaftSimulation.java b/src/main/java/examples/CreateWorkingRaftSimulation.java new file mode 100644 index 0000000..0bc5df4 --- /dev/null +++ b/src/main/java/examples/CreateWorkingRaftSimulation.java @@ -0,0 +1,152 @@ +package examples; + +import simulator.*; +import core.*; +import prefs.*; +import events.*; +import events.internal.*; +import events.implementations.*; +import serialize.VSSerialize; +import java.io.*; +import java.lang.reflect.*; + +/** + * Creates a working Raft simulation by properly setting up the event queue + * and ensuring protocols are activated through the normal event system. + */ +public class CreateWorkingRaftSimulation { + + private static final String RAFT_PROTOCOL = "protocols.implementations.VSRaftProtocol"; + + public static void main(String[] args) throws Exception { + System.out.println("=== Creating Working Raft Simulation ===\n"); + + // Initialize + VSDefaultPrefs prefs = new VSDefaultPrefs(); + prefs.fillWithDefaults(); + VSRegisteredEvents.init(prefs); + + // Create simulator with frame + VSSimulatorFrame frame = new VSSimulatorFrame(prefs, null); + VSSimulator simulator = new VSSimulator(prefs, frame); + frame.addSimulator(simulator); + + // Access visualization + Field vizField = VSSimulator.class.getDeclaredField("simulatorVisualization"); + vizField.setAccessible(true); + VSSimulatorVisualization viz = (VSSimulatorVisualization) vizField.get(simulator); + + // Add 5 processes (3 servers + 2 clients) + Method addProcessMethod = VSSimulatorVisualization.class.getDeclaredMethod("addProcess"); + addProcessMethod.setAccessible(true); + System.out.println("Adding 5 processes..."); + for (int i = 0; i < 5; i++) { + addProcessMethod.invoke(viz); + } + + VSTaskManager taskManager = viz.getTaskManager(); + + // Schedule Raft server activations at time 0 + System.out.println("\nScheduling Raft server activations:"); + for (int i = 0; i < 3; i++) { + VSProtocolEvent serverEvent = new VSProtocolEvent(); + serverEvent.setProtocolClassname(RAFT_PROTOCOL); + serverEvent.isClientProtocol(false); // Server mode + serverEvent.isProtocolActivation(true); // This is an activation + + VSTask task = new VSTask(0, viz.getProcess(i), serverEvent, false); + taskManager.addTask(task); + System.out.println(" - Server " + i + " activation scheduled at time 0"); + } + + // Schedule Raft client activations with slight delay + System.out.println("\nScheduling Raft client activations:"); + for (int i = 3; i < 5; i++) { + VSProtocolEvent clientEvent = new VSProtocolEvent(); + clientEvent.setProtocolClassname(RAFT_PROTOCOL); + clientEvent.isClientProtocol(true); // Client mode + clientEvent.isProtocolActivation(true); // This is an activation + + // Start clients after servers have initialized + long startTime = 500 + (i - 3) * 200; + VSTask task = new VSTask(startTime, viz.getProcess(i), clientEvent, false); + taskManager.addTask(task); + System.out.println(" - Client " + (i-3) + " activation scheduled at time " + startTime); + } + + // Add some interesting events + System.out.println("\nAdding crash/recovery events:"); + + // Process 0 crashes at time 2000 and recovers at 3000 + VSProcessCrashEvent crash1 = new VSProcessCrashEvent(); + taskManager.addTask(new VSTask(2000, viz.getProcess(0), crash1, false)); + System.out.println(" - Server 0 crash scheduled at time 2000"); + + VSProcessRecoverEvent recover1 = new VSProcessRecoverEvent(); + taskManager.addTask(new VSTask(3000, viz.getProcess(0), recover1, false)); + System.out.println(" - Server 0 recovery scheduled at time 3000"); + + // Process 1 crashes at time 4000 and recovers at 5000 + VSProcessCrashEvent crash2 = new VSProcessCrashEvent(); + taskManager.addTask(new VSTask(4000, viz.getProcess(1), crash2, false)); + System.out.println(" - Server 1 crash scheduled at time 4000"); + + VSProcessRecoverEvent recover2 = new VSProcessRecoverEvent(); + taskManager.addTask(new VSTask(5000, viz.getProcess(1), recover2, false)); + System.out.println(" - Server 1 recovery scheduled at time 5000"); + + // Save simulation + File outputFile = new File("saved-simulations/raft-working.dat"); + outputFile.getParentFile().mkdirs(); + + System.out.println("\nSaving simulation..."); + VSSerialize serialize = new VSSerialize(); + serialize.saveSimulator(outputFile.getAbsolutePath(), simulator); + + frame.dispose(); + + System.out.println("\nāœ“ Simulation saved to: " + outputFile.getAbsolutePath()); + + // Create instruction file + File instructionFile = new File("saved-simulations/README-raft.txt"); + try (PrintWriter writer = new PrintWriter(instructionFile)) { + writer.println("RAFT CONSENSUS SIMULATION"); + writer.println("========================"); + writer.println(); + writer.println("This directory contains Raft consensus protocol simulations:"); + writer.println(); + writer.println("1. raft-working.dat - Full working simulation with:"); + writer.println(" - 3 Raft servers (processes 0-2)"); + writer.println(" - 2 Raft clients (processes 3-4)"); + writer.println(" - Server crash/recovery events"); + writer.println(); + writer.println("To run the simulation:"); + writer.println("1. java -jar target/ds-sim-1.0.1-SNAPSHOT.jar"); + writer.println("2. File → Open → saved-simulations/raft-working.dat"); + writer.println("3. Click Run (ā–¶) button"); + writer.println(); + writer.println("What to look for:"); + writer.println("- Leader election (REQUEST_VOTE messages)"); + writer.println("- Heartbeats from leader (APPEND_ENTRIES)"); + writer.println("- Client requests and responses"); + writer.println("- Re-election when servers crash"); + writer.println(); + writer.println("Timeline:"); + writer.println("- Time 0: Servers start, begin leader election"); + writer.println("- Time 500-700: Clients start"); + writer.println("- Time 2000: Server 0 crashes"); + writer.println("- Time 3000: Server 0 recovers"); + writer.println("- Time 4000: Server 1 crashes"); + writer.println("- Time 5000: Server 1 recovers"); + } + + System.out.println("āœ“ Instructions saved to: " + instructionFile.getAbsolutePath()); + + System.out.println("\n=== Success! ==="); + System.out.println("\nThe Raft simulation has been created with the following setup:"); + System.out.println("- 3 servers implementing Raft consensus"); + System.out.println("- 2 clients that will send requests"); + System.out.println("- Crash/recovery events to test fault tolerance"); + System.out.println("\nRun the simulator and load the file to see it in action!"); + } +} \ No newline at end of file -- cgit v1.2.3