summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-27 15:43:46 +0200
committerPaul Buetow <paul@buetow.org>2026-03-27 15:43:46 +0200
commit73567cc1e5a3a02d4c60c534122e8db9e8a82949 (patch)
tree31ffd4831ad86dda22b950ac33239149b3d13202
parent63b658f8fba0790aa5b6bf94d4c89012f552a7ca (diff)
Narrow replay task visibility fix
-rw-r--r--saved-simulations/raft.datbin15305 -> 15305 bytes
-rw-r--r--src/main/java/core/VSTaskManager.java7
-rw-r--r--src/main/java/simulator/builder/SimulationBuilder.java2
-rw-r--r--src/test/java/core/VSTaskManagerCrashRecoveryIntegrationTest.java88
4 files changed, 90 insertions, 7 deletions
diff --git a/saved-simulations/raft.dat b/saved-simulations/raft.dat
index c54c0c5..9f6c7ad 100644
--- a/saved-simulations/raft.dat
+++ b/saved-simulations/raft.dat
Binary files differ
diff --git a/src/main/java/core/VSTaskManager.java b/src/main/java/core/VSTaskManager.java
index c78af5b..bd95a4e 100644
--- a/src/main/java/core/VSTaskManager.java
+++ b/src/main/java/core/VSTaskManager.java
@@ -553,12 +553,7 @@ public class VSTaskManager implements VSSerializable {
for (int i = 0; i < numTasks; ++i) {
VSTask task = new VSTask(serialize, objectInputStream);
- /*
- * Serialized tasks define the replay state of a loaded simulation.
- * Register them as programmed so they remain visible in the Event
- * view and survive reset/replay after deserialization.
- */
- addTask(task, PROGRAMMED);
+ addTask(task, task.isProgrammed());
}
/** For later backwards compatibility, to add more stuff */
diff --git a/src/main/java/simulator/builder/SimulationBuilder.java b/src/main/java/simulator/builder/SimulationBuilder.java
index cf5f962..ac78a68 100644
--- a/src/main/java/simulator/builder/SimulationBuilder.java
+++ b/src/main/java/simulator/builder/SimulationBuilder.java
@@ -308,7 +308,7 @@ public class SimulationBuilder {
// Create task
VSTask task = new VSTask(st.time, process, st.event,
st.isGlobalTimed ? VSTask.GLOBAL : VSTask.LOCAL);
- taskManager.addTask(task);
+ taskManager.addTask(task, VSTaskManager.PROGRAMMED);
}
}
diff --git a/src/test/java/core/VSTaskManagerCrashRecoveryIntegrationTest.java b/src/test/java/core/VSTaskManagerCrashRecoveryIntegrationTest.java
index 34908bb..eb4bc7b 100644
--- a/src/test/java/core/VSTaskManagerCrashRecoveryIntegrationTest.java
+++ b/src/test/java/core/VSTaskManagerCrashRecoveryIntegrationTest.java
@@ -4,6 +4,8 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.io.FileOutputStream;
+import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.file.Files;
@@ -15,6 +17,8 @@ import org.junit.jupiter.api.Test;
import events.implementations.VSProcessCrashEvent;
import events.implementations.VSProcessRecoverEvent;
+import prefs.VSSerializablePrefs;
+import serialize.VSSerialize;
import simulator.VSSimulator;
import simulator.VSSimulatorVisualization;
import simulator.builder.SimulationBuilder;
@@ -148,6 +152,57 @@ class VSTaskManagerCrashRecoveryIntegrationTest {
}
@Test
+ @DisplayName("Loading preserves programmed replay tasks but not ordinary runtime tasks")
+ void loadingPreservesProgrammedReplayTasksWithoutPromotingRuntimeTasks()
+ throws Exception {
+ Path replayFile = Files.createTempFile("programmed-replay", ".dat");
+ Path runtimeFile = Files.createTempFile("runtime-task", ".dat");
+
+ VSSimulator replaySimulator = new SimulationBuilder()
+ .withProcesses(3)
+ .withDuration(1000)
+ .addCrashEvent(0, 5)
+ .save(replayFile.toString())
+ .getSimulator();
+ simulatorToStop = replaySimulator;
+
+ HeadlessLoader.LoadedSimulation replayLoaded =
+ HeadlessLoader.load(replayFile.toString(), replaySimulator.getPrefs());
+ loadedSimulatorToStop = replayLoaded.getSimulator();
+
+ VSTaskManager replayTaskManager = replayLoaded.getVisualization().getTaskManager();
+ assertEquals(1, replayTaskManager.getProcessGlobalTasks(
+ replayLoaded.getVisualization().getProcess(0)).size(),
+ "builder-authored replay task should remain visible after load");
+
+ loadedSimulatorToStop.getSimulatorCanvas().stopThread();
+ loadedSimulatorToStop = null;
+
+ VSSimulator runtimeSimulator = new SimulationBuilder()
+ .withProcesses(3)
+ .withDuration(1000)
+ .getSimulator();
+ simulatorToStop = runtimeSimulator;
+
+ VSSimulatorVisualization runtimeVisualization = runtimeSimulator.getSimulatorCanvas();
+ VSInternalProcess runtimeProcess = runtimeVisualization.getProcess(0);
+ VSTask runtimeTask = new VSTask(5, runtimeProcess, new VSProcessCrashEvent(), VSTask.GLOBAL);
+ runtimeVisualization.getTaskManager().addTask(runtimeTask);
+ assertFalse(runtimeTask.isProgrammed(), "runtime task should remain non-programmed before save");
+
+ saveSimulation(runtimeFile, runtimeSimulator);
+
+ HeadlessLoader.LoadedSimulation runtimeLoaded =
+ HeadlessLoader.load(runtimeFile.toString(), runtimeSimulator.getPrefs());
+ loadedSimulatorToStop = runtimeLoaded.getSimulator();
+
+ VSTaskManager runtimeTaskManager = runtimeLoaded.getVisualization().getTaskManager();
+ assertEquals(0, runtimeTaskManager.getProcessGlobalTasks(
+ runtimeLoaded.getVisualization().getProcess(0)).size(),
+ "ordinary non-programmed runtime task must stay hidden after load");
+ }
+
+ @Test
@DisplayName("Live GUI-style event injection supports recover and later crash")
void liveEventInjectionSupportsRecoverAndLaterCrash() throws Exception {
VSSimulator simulator = new SimulationBuilder()
@@ -214,4 +269,37 @@ class VSTaskManagerCrashRecoveryIntegrationTest {
simulator.getSimulatorCanvas().stopThread();
}
}
+
+ private void saveSimulation(Path file, VSSimulator simulator) throws Exception {
+ VSSerialize serialize = new VSSerialize();
+ try (FileOutputStream fos = new FileOutputStream(file.toFile());
+ ObjectOutputStream oos = new ObjectOutputStream(fos)) {
+ VSSerializablePrefs serializablePrefs = new VSSerializablePrefs();
+
+ for (String key : simulator.getPrefs().getIntegerKeySet()) {
+ serializablePrefs.initInteger(key, simulator.getPrefs().getInteger(key));
+ }
+ for (String key : simulator.getPrefs().getBooleanKeySet()) {
+ serializablePrefs.initBoolean(key, simulator.getPrefs().getBoolean(key));
+ }
+ for (String key : simulator.getPrefs().getStringKeySet()) {
+ serializablePrefs.initString(key, simulator.getPrefs().getString(key));
+ }
+ for (String key : simulator.getPrefs().getFloatKeySet()) {
+ serializablePrefs.initFloat(key, simulator.getPrefs().getFloat(key));
+ }
+ for (String key : simulator.getPrefs().getColorKeySet()) {
+ serializablePrefs.initColor(key, simulator.getPrefs().getColor(key));
+ }
+ for (String key : simulator.getPrefs().getVectorKeySet()) {
+ serializablePrefs.initVector(key, simulator.getPrefs().getVector(key));
+ }
+ for (String key : simulator.getPrefs().getLongKeySet()) {
+ serializablePrefs.initLong(key, simulator.getPrefs().getLong(key));
+ }
+
+ serializablePrefs.serialize(serialize, oos);
+ simulator.serialize(serialize, oos);
+ }
+ }
}