diff options
Diffstat (limited to 'src/main/java/testing/HeadlessSimulationRunner.java')
| -rw-r--r-- | src/main/java/testing/HeadlessSimulationRunner.java | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/main/java/testing/HeadlessSimulationRunner.java b/src/main/java/testing/HeadlessSimulationRunner.java new file mode 100644 index 0000000..c3b699e --- /dev/null +++ b/src/main/java/testing/HeadlessSimulationRunner.java @@ -0,0 +1,188 @@ +package testing; + +import simulator.*; +import core.*; +import prefs.*; +import events.*; +import serialize.VSSerialize; +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +/** + * Runs DS-Sim simulations in headless mode without GUI dependencies. + * Captures logs and provides verification capabilities for automated testing. + */ +public class HeadlessSimulationRunner { + private final VSDefaultPrefs prefs; + private VSSimulator simulator; + private VSSimulatorVisualization viz; + private LogCapture logCapture; + private final ExecutorService executor; + private boolean printLogs = false; + + public HeadlessSimulationRunner() { + this.prefs = new VSDefaultPrefs(); + this.prefs.fillWithDefaults(); + VSRegisteredEvents.init(prefs); + this.executor = Executors.newSingleThreadExecutor(); + } + + /** + * Run a simulation from a saved file for a specified duration. + * + * @param simulationFile Path to the saved simulation .dat file + * @param maxTime Maximum simulation time in milliseconds + * @return SimulationResult containing logs and metrics + */ + public SimulationResult runSimulation(String simulationFile, long maxTime) + throws Exception { + return runSimulation(simulationFile, maxTime, null); + } + + /** + * Run a simulation with an optional log listener. + */ + public SimulationResult runSimulation(String simulationFile, long maxTime, LogListener listener) + throws Exception { + System.out.println("Loading simulation: " + simulationFile); + + try { + // Use the new headless loader + HeadlessLoader.LoadedSimulation loaded = HeadlessLoader.load(simulationFile, prefs); + simulator = loaded.getSimulator(); + viz = loaded.getVisualization(); + + // Install log capture + logCapture = new LogCapture(); + logCapture.setPrintLogs(printLogs); + if (listener != null) { + logCapture.addListener(listener); + } + installLogCapture(); + + System.out.println("Running simulation for " + maxTime + "ms..."); + + // Run simulation + Future<Void> runFuture = executor.submit(() -> { + try { + runSimulationSteps(maxTime); + } catch (Exception e) { + System.err.println("Error during simulation: " + e.getMessage()); + e.printStackTrace(); + } + return null; + }); + + // Wait for completion or timeout + try { + runFuture.get(maxTime * 2, TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + System.out.println("Simulation timeout - stopping..."); + runFuture.cancel(true); + } + + System.out.println("Simulation complete. Captured " + + logCapture.getTotalLogCount() + " log entries."); + + return new SimulationResult( + logCapture.getCapturedLogs(), + logCapture.getProcessLogs(), + getSimulationMetrics() + ); + } catch (Exception e) { + System.err.println("Failed to load simulation: " + e.getMessage()); + throw e; + } + } + + private void runSimulationSteps(long maxTime) throws Exception { + VSTaskManager taskManager = viz.getTaskManager(); + + // Get necessary fields via reflection + Field timeField = VSSimulatorVisualization.class + .getDeclaredField("time"); + timeField.setAccessible(true); + + // Find runTasks method with correct signature + Method runTasksMethod = VSTaskManager.class + .getDeclaredMethod("runTasks", long.class, long.class, long.class); + runTasksMethod.setAccessible(true); + + long startTime = timeField.getLong(viz); + long currentTime = startTime; + + while (currentTime - startTime < maxTime) { + // Update time + timeField.setLong(viz, currentTime); + + // Sync process times + for (int i = 0; i < viz.getNumProcesses(); i++) { + viz.getProcess(i).syncTime(currentTime); + } + + // Run tasks (step, offset, lastGlobalTime) + runTasksMethod.invoke(taskManager, currentTime, 0L, currentTime - 1); + + // Advance time by 1ms + currentTime++; + + // Small delay to prevent CPU spinning + Thread.sleep(1); + } + } + + private void installLogCapture() throws Exception { + // Set simulatorVisualization reference in logCapture + logCapture.setSimulatorCanvas(viz); + + // Install on visualization + Field logingField = VSSimulatorVisualization.class + .getDeclaredField("loging"); + logingField.setAccessible(true); + logingField.set(viz, logCapture); + + // Install on all processes + for (int i = 0; i < viz.getNumProcesses(); i++) { + VSInternalProcess process = viz.getProcess(i); + if (process != null) { + Field processLogingField = VSAbstractProcess.class + .getDeclaredField("loging"); + processLogingField.setAccessible(true); + processLogingField.set(process, logCapture); + } + } + } + + private SimulationMetrics getSimulationMetrics() { + return new SimulationMetrics( + viz.getNumProcesses(), + logCapture.getTotalLogCount(), + logCapture.getProcessMessageCounts() + ); + } + + public void setPrintLogs(boolean printLogs) { + this.printLogs = printLogs; + if (logCapture != null) { + logCapture.setPrintLogs(printLogs); + } + } + + public void addLogListener(LogListener listener) { + if (logCapture != null) { + logCapture.addListener(listener); + } + } + + public void shutdown() { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + } + } +}
\ No newline at end of file |
