package jmri.jmrit.logix; import java.io.File; import java.io.IOException; import java.util.List; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; import jmri.*; import jmri.util.JmriJFrame; import jmri.util.JUnitAppender; import jmri.util.JUnitUtil; import jmri.util.ThreadingUtil; import jmri.util.junit.annotations.DisabledIfHeadless; import org.junit.jupiter.api.*; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import org.junit.jupiter.api.io.TempDir; import org.netbeans.jemmy.operators.JFrameOperator; import static org.junit.jupiter.api.Assertions.*; /** * Tests for running multiple Warrants * * @author Pete Cressman 2015 */ @Timeout(120) @DisabledIfHeadless @DisabledIfSystemProperty(named ="jmri.skipLinkedWarrantTest", matches ="true") public class LinkedWarrantTest { private OBlockManager _OBlockMgr; private SensorManager _sensorMgr; private WarrantManager _warrantMgr; // tests a warrant launching itself. (origin, destination the same to make continuous loop) @Test public void testLoopedWarrant() { // load and display File f = new File("java/test/jmri/jmrit/logix/valid/ShortBlocksTest.xml"); assertDoesNotThrow( () -> { InstanceManager.getDefault(ConfigureManager.class).load(f); }, ("Exception loading "+ f)); JUnitAppender.suppressErrorMessage("Portal elem = null"); Sensor sensor1 = _sensorMgr.getBySystemName("IS12"); assertNotNull(sensor1,"Senor IS12 not found"); NXFrameTest.setAndConfirmSensorAction(sensor1, Sensor.ACTIVE, _OBlockMgr.getBySystemName("OB12")); WarrantTableFrame tableFrame = ThreadingUtil.runOnGUIwithReturn( () -> WarrantTableFrame.getDefault()); assertNotNull(tableFrame,"tableFrame"); Warrant warrant = _warrantMgr.getWarrant("LoopDeLoop"); assertNotNull(warrant,"warrant"); // OBlock of route String[] route = {"OB12", "OB1", "OB3", "OB5", "OB6", "OB7", "OB9", "OB11", "OB12"}; OBlock block = _OBlockMgr.getOBlock("OB12"); assertNotNull(block); AtomicInteger startCount = new AtomicInteger(0); warrant.addPropertyChangeListener(Warrant.PROPERTY_WARRANT_START, evt -> startCount.incrementAndGet()); // WarrantTable.runTrain() returns a string that is not null if the // warrant can't be started assertNull(tableFrame.runTrain(warrant, Warrant.MODE_RUN),"Warrant starts"); // start run String lookingFor = Bundle.getMessage("warrantStart", warrant.getTrainName(), warrant.getDisplayName(), block.getDisplayName()); JUnitUtil.waitFor(() -> { return lookingFor.equals(tableFrame.getStatus()); }, "LoopDeLoop started first leg expected \"" + lookingFor + "\" but was \"" + tableFrame.getStatus()+"\""); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(warrant, 8), "Loopy 1 starts to move at 8th command"); // Run the train, then checks end location assertDoesNotThrow( () -> { assertEquals(block.getSensor(), NXFrameTest.runtimes(route, _OBlockMgr), "LoopDeLoop Completes first Leg"); }, ("LoopDeLoop after first leg Exception")); // It takes 600+ milliseconds per block to execute NXFrameTest.runtimes() // i.e. wait at least 600 * route.length for return JUnitUtil.waitFor(() -> startCount.get() >= 2, "Loopy 2 started"); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(warrant, 8), "Loopy 2 starts to move at 8th command"); assertDoesNotThrow( () -> { assertEquals(block.getSensor(), NXFrameTest.runtimes(route, _OBlockMgr), "LoopDeLoop Completes Second Leg"); }, ("LoopDeLoop after Second leg Exception")); JUnitUtil.waitFor(() -> startCount.get() >= 3, "LoopDeLoop finished second leg"); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(warrant, 8), "Loopy 3 starts to move at 8th command"); assertDoesNotThrow( () -> { assertEquals(block.getSensor(), NXFrameTest.runtimes(route, _OBlockMgr), "LoopDeLoop Completes third Leg"); }, ("LoopDeLoop after third leg Exception")); JUnitUtil.waitFor(() -> { String m = tableFrame.getStatus(); // Train "Loopy" ends warrant "LoopDeLoop". Now occupying block "LoopConnector". String msg = Bundle.getMessage("warrantComplete", warrant.getTrainName(), warrant.getDisplayName(), block.getDisplayName()); return m.equals(msg); }, () -> "LoopDeLoop finished third leg: " + tableFrame.getStatus()); warrant.dispose(); JFrameOperator jfo = new JFrameOperator(WarrantTableFrame.getDefault()); jfo.requestClose(); jfo.waitClosed(); // JFrameOperator requestClose just hides panel, not disposing of it. // disposing this way allows test to be rerun (i.e. reload panel file) multiple times Boolean retVal = ThreadingUtil.runOnGUIwithReturn(() -> { JmriJFrame.getFrame("LinkedWarrantsTest").dispose(); return true; }); assertTrue(retVal); } // Tests warrant launching a different warrant with different address. Origin location cannot be destination of the other) @Test public void testLinkedWarrant() { // load and display File f = new File("java/test/jmri/jmrit/logix/valid/ShortBlocksTest.xml"); assertDoesNotThrow( () -> { InstanceManager.getDefault(ConfigureManager.class).load(f); }, ("Exception loading "+ f)); JUnitAppender.suppressErrorMessage("Portal elem = null"); final Sensor sensor12 = _sensorMgr.getBySystemName("IS12"); assertNotNull(sensor12,"Sensor IS12 not found"); Sensor sensor1 = _sensorMgr.getBySystemName("IS1"); assertNotNull(sensor1,"Senor IS1 not found"); NXFrameTest.setAndConfirmSensorAction(sensor12, Sensor.ACTIVE, _OBlockMgr.getBySystemName("OB12")); final Warrant warrant = _warrantMgr.getWarrant("Loop&Fred"); assertNotNull(warrant,"warrant"); WarrantTableFrame tableFrame = ThreadingUtil.runOnGUIwithReturn(() -> WarrantTableFrame.getDefault()); // WarrantTable.runTrain() returns a string that is not null if the // warrant can't be started assertNull( ThreadingUtil.runOnGUIwithReturn(() -> tableFrame.runTrain(warrant, Warrant.MODE_RUN)),"Warrant starts"); // start run JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(warrant, 8), () -> "Train starts to move at 8th command, but running message was " + warrant.getRunningMessage()); // OBlock of route String[] route1 = {"OB12", "OB1", "OB3", "OB5", "OB6", "OB7", "OB9", "OB11", "OB12"}; OBlock lastBlockInRoute1 = _OBlockMgr.getOBlock("OB12"); assertNotNull(lastBlockInRoute1); // It takes 500+ milliseconds per block to execute NXFrameTest.runtimes() // "Loop&Fred" links to "WestToEast". Get start for "WestToEast" occupied quickly // midway through the route we need to set OB1 occupied so that Fred can be auto-started Sensor runFred = NXFrameTest.runtimesActionPenultimate(route1, sensor1, "OB1", _OBlockMgr); // Run the train, then checks end location assertEquals(lastBlockInRoute1.getSensor(), runFred, "Train after first leg"); Warrant ww = _warrantMgr.getWarrant("WestToEast"); assertNotNull(ww,"warrant WestToEast exists"); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(ww, 9), () -> "Train Fred starts to move at 9th command, was: " + ww.getRunningMessage()); String[] route2 = {"OB1", "OB3", "OB5", "OB6", "OB7", "OB9", "OB11"}; final OBlock block = _OBlockMgr.getOBlock("OB11"); assertNotNull(block); assertDoesNotThrow( () -> { assertEquals(block.getSensor(), NXFrameTest.runtimes(route2, _OBlockMgr), "Train after second leg"); }, ("Exception running route2")); ww.dispose(); JFrameOperator jfo = new JFrameOperator(WarrantTableFrame.getDefault()); jfo.requestClose(); jfo.waitClosed(); // JFrameOperator requestClose just hides panel, not disposing of it. // disposing this way allows test to be rerun (i.e. reload panel file) multiple times Boolean retVal = ThreadingUtil.runOnGUIwithReturn(() -> { JmriJFrame.getFrame("LinkedWarrantsTest").dispose(); return true; }); assertTrue(retVal); JUnitUtil.waitThreadTerminated("WestToEast Killer"); } // tests a warrant running a train out and launching a return train // Both warrants have the same address and origin of each is destination of the other @Test public void testBackAndForth() { // load and display File f = new File("java/test/jmri/jmrit/logix/valid/ShortBlocksTest.xml"); Assertions.assertDoesNotThrow( () -> { InstanceManager.getDefault(ConfigureManager.class).load(f); }, ("Exception loading "+ f)); JUnitAppender.suppressErrorMessage("Portal elem = null"); WarrantPreferences.getDefault().setShutdown(WarrantPreferences.Shutdown.NO_MERGE); final Sensor sensor1 = _sensorMgr.getBySystemName("IS1"); assertNotNull(sensor1,"Senor IS1 not found"); NXFrameTest.setAndConfirmSensorAction(sensor1, Sensor.ACTIVE, _OBlockMgr.getBySystemName("OB1")); WarrantTableFrame tableFrame = ThreadingUtil.runOnGUIwithReturn( () -> WarrantTableFrame.getDefault()); assertNotNull(tableFrame,"tableFrame"); Warrant outWarrant = _warrantMgr.getWarrant("WestToEastLink"); assertNotNull(outWarrant,"WestWarrant"); Warrant backWarrant = _warrantMgr.getWarrant("EastToWestLink"); OBlock block1 = _OBlockMgr.getOBlock("OB1"); assertNotNull(block1); OBlock block11 = _OBlockMgr.getOBlock("OB11"); assertNotNull(block11); // OBlock of route String[] routeOut = {"OB1", "OB3", "OB5", "OB6", "OB7", "OB9", "OB11"}; Sensor outEndSensor = block11.getSensor(); String[] routeBack = {"OB11", "OB9", "OB7", "OB6", "OB5", "OB3", "OB1"}; Sensor backEndSensor = block1.getSensor(); AtomicInteger outStartCount = new AtomicInteger(0); outWarrant.addPropertyChangeListener(Warrant.PROPERTY_WARRANT_START, evt -> outStartCount.incrementAndGet()); AtomicInteger backStartCount = new AtomicInteger(0); backWarrant.addPropertyChangeListener(Warrant.PROPERTY_WARRANT_START, evt -> backStartCount.incrementAndGet()); // WarrantTable.runTrain() returns a string that is not null if the // warrant can't be started assertNull(ThreadingUtil.runOnGUIwithReturn( () -> tableFrame.runTrain(outWarrant, Warrant.MODE_RUN)),"Warrant starts"); // start run JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(outWarrant, 8), "WestToEastLink starts to move at 8th command"); // Run the train, then checks end location assertDoesNotThrow( () -> { assertEquals(outEndSensor, NXFrameTest.runtimes(routeOut, _OBlockMgr), "Train after first leg"); }, ("Exception running routeOut")); // It takes 500+ milliseconds per block to execute NXFrameTest.runtimes() // i.e. wait at least 600 * (route.length - 1) for return String outBlockName = block11.getDisplayName(); JUnitUtil.waitFor(() -> { String m = tableFrame.getStatus(); return m.equals(Bundle.getMessage("warrantComplete", outWarrant.getTrainName(), outWarrant.getDisplayName(), outBlockName)); }, "WestToEastLink finished first leg out"); JUnitUtil.waitFor(() -> backStartCount.get() >= 1, "EastToWestLink started"); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(backWarrant, 8), "EastToWestLink starts to move at 8th command"); assertDoesNotThrow( () -> { assertEquals(backEndSensor, NXFrameTest.runtimes(routeBack, _OBlockMgr), "Train after second leg"); }, ("Exception running routeBack")); // It takes 500+ milliseconds per block to execute NXFrameTest.runtimes() JUnitUtil.waitFor(() -> { String m = tableFrame.getStatus(); return m.equals(Bundle.getMessage("warrantComplete", backWarrant.getTrainName(), backWarrant.getDisplayName(), block1.getDisplayName())); }, "EastToWestLink finished second leg back"); JUnitUtil.waitFor(() -> outStartCount.get() >= 2, "WestToEastLink started second run"); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(outWarrant, 8), "WestToEastLink starts to move at 8th command"); assertDoesNotThrow( () -> { assertEquals(outEndSensor, NXFrameTest.runtimes(routeOut, _OBlockMgr), "Train after third leg"); }, ("Exception running routeOut 3")); // It takes 500+ milliseconds per block to execute NXFrameTest.runtimes() JUnitUtil.waitFor(() -> { String m = tableFrame.getStatus(); return m.equals(Bundle.getMessage("warrantComplete", outWarrant.getTrainName(), outWarrant.getDisplayName(), outBlockName)); }, "WestToEastLink finished third leg"); JUnitUtil.waitFor(() -> backStartCount.get() >= 2, "EastToWestLink started second run"); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(backWarrant, 8), "EastToWestLink starts to move at 8th command"); assertDoesNotThrow( () -> { assertEquals(backEndSensor, NXFrameTest.runtimes(routeBack, _OBlockMgr), "Train after fourth leg"); }, ("Exception running routeBack 4")); // It takes 600+ milliseconds per block to execute NXFrameTest.runtimes() outWarrant.stopWarrant(true, false); backWarrant.stopWarrant(true, false); JFrameOperator jfo = new JFrameOperator(WarrantTableFrame.getDefault()); jfo.requestClose(); jfo.waitClosed(); // JFrameOperator requestClose just hides panel, not disposing of it. // disposing this way allows test to be rerun (i.e. reload panel file) multiple times Boolean retVal = ThreadingUtil.runOnGUIwithReturn(() -> { JmriJFrame.getFrame("LinkedWarrantsTest").dispose(); return true; }); assertTrue(retVal); } // Tests warrant launching 3 different warrants mid script - tinker to Evers to Chance (1910 Chicago Cubs) @Test public void testLinkedMidScript() { // load and display File f = new File("java/test/jmri/jmrit/logix/valid/NXWarrantTest.xml"); assertDoesNotThrow( () -> { InstanceManager.getDefault(ConfigureManager.class).load(f); }, ("Exception loading "+ f)); JUnitAppender.suppressErrorMessage("Portal elem = null"); // Tinker start block Sensor sensor0 = _sensorMgr.getBySystemName("IS0"); assertNotNull(sensor0,"Senor IS0 not found"); // wait block OB0 occupied NXFrameTest.setAndConfirmSensorAction(sensor0, Sensor.ACTIVE, _OBlockMgr.getBySystemName("OB0")); // Evers start block Sensor sensor7 = _sensorMgr.getBySystemName("IS7"); assertNotNull(sensor7,"Senor IS7 not found"); // wait block OB7 occupied NXFrameTest.setAndConfirmSensorAction(sensor7, Sensor.ACTIVE, _OBlockMgr.getBySystemName("OB7")); // Chance start block Sensor sensor6 = _sensorMgr.getBySystemName("IS6"); assertNotNull(sensor6,"Senor IS6 not found"); NXFrameTest.setAndConfirmSensorAction(sensor6, Sensor.ACTIVE, _OBlockMgr.getBySystemName("OB6")); Warrant w = _warrantMgr.getWarrant("Tinker"); assertNotNull(w,"warrant"); WarrantTableFrame tableFrame = ThreadingUtil.runOnGUIwithReturn( () -> WarrantTableFrame.getDefault()); // WarrantTable.runTrain() returns a string that is not null if the // warrant can't be started assertNull(tableFrame.runTrain(w, Warrant.MODE_RUN),"Warrant starts"); // start run JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(w, 8), () -> "Tinker starts to move at 8th command but was: " + w.getRunningMessage()); // OBlock of route String[] route1 = {"OB0", "OB1", "OB2", "OB3", "OB4", "OB5", "OB10"}; OBlock block10 = _OBlockMgr.getOBlock("OB10"); assertNotNull(block10); // Run the train, then checks end location assertDoesNotThrow( () -> { assertEquals(block10.getSensor(), NXFrameTest.runtimes(route1, _OBlockMgr), "Tinker after first leg"); }, ("Exception running route1")); // It takes 600+ milliseconds per block to execute NXFrameTest.runtimes() // i.e. wait at least 600 * route.length for return Warrant ww = _warrantMgr.getWarrant("Evers"); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(ww, 8), () -> "Evers starts to move at 8th command but was: " + ww.getRunningMessage()); String[] route2 = {"OB7", "OB3", "OB2", "OB1"}; OBlock block1 = _OBlockMgr.getOBlock("OB1"); assertNotNull(block1); assertDoesNotThrow( () -> { assertEquals(block1.getSensor(), NXFrameTest.runtimes(route2, _OBlockMgr), "Evers after second leg"); }, ("Exception running route2")); // It takes 600+ milliseconds per block to execute NXFrameTest.runtimes() Warrant www = _warrantMgr.getWarrant("Chance"); JUnitUtil.waitFor(() -> WarrantTest.atOrPastCommand(www, 8), () -> "Chance starts to move at 8th command but was: " + www.getRunningMessage()); String[] route3 = {"OB6", "OB3", "OB4", "OB5"}; OBlock block5 = _OBlockMgr.getOBlock("OB5"); assertNotNull(block5); assertDoesNotThrow( () -> { assertEquals(block5.getSensor(), NXFrameTest.runtimes(route3, _OBlockMgr), "Chance after third leg"); }, ("Exception running route3")); // It takes 600+ milliseconds per block to execute NXFrameTest.runtimes() JFrameOperator jfo = new JFrameOperator(WarrantTableFrame.getDefault()); jfo.requestClose(); jfo.waitClosed(); // JFrameOperator requestClose just hides panel, not disposing of it. // disposing this way allows test to be rerun (i.e. reload panel file) multiple times Boolean retVal = ThreadingUtil.runOnGUIwithReturn(() -> { JmriJFrame.getFrame("NXWarrantTest").dispose(); return true; }); assertTrue(retVal); w.dispose(); ww.dispose(); www.dispose(); JUnitUtil.waitFor( () -> w.getState() == -1, "tinker warrant terminated"); } @BeforeEach public void setUp(@TempDir File tempDir) throws IOException { JUnitUtil.setUp(); JUnitUtil.resetInstanceManager(); JUnitUtil.resetProfileManager(new jmri.profile.NullProfile(tempDir)); JUnitUtil.initConfigureManager(); JUnitUtil.initInternalTurnoutManager(); JUnitUtil.initInternalLightManager(); JUnitUtil.initInternalSensorManager(); JUnitUtil.initInternalSignalHeadManager(); JUnitUtil.initLayoutBlockManager(); JUnitUtil.initDebugPowerManager(); JUnitUtil.initDebugThrottleManager(); JUnitUtil.initMemoryManager(); JUnitUtil.initOBlockManager(); JUnitUtil.initLogixManager(); JUnitUtil.initConditionalManager(); JUnitUtil.initWarrantManager(); WarrantPreferences.getDefault().setShutdown(WarrantPreferences.Shutdown.NO_MERGE); _OBlockMgr = InstanceManager.getDefault(OBlockManager.class); _sensorMgr = InstanceManager.getDefault(SensorManager.class); _warrantMgr = InstanceManager.getDefault(WarrantManager.class); } @AfterEach public void tearDown() { JUnitUtil.removeMatchingThreads("Engineer("); // CheckForTermination calls runTrain() on finish, poisoning the next test's WarrantTableFrame.lastClicktime; evict after they complete JUnitUtil.waitFor(() -> Thread.getAllStackTraces().keySet().stream() .noneMatch(t -> t.isAlive() && t.getName().startsWith("CheckForTermination")), "CheckForTermination threads to terminate"); WarrantTableFrame wtf = InstanceManager.getNullableDefault(WarrantTableFrame.class); if (wtf != null) { InstanceManager.deregister(wtf, WarrantTableFrame.class); } _warrantMgr.dispose(); _warrantMgr = null; InstanceManager.getDefault(WarrantManager.class).dispose(); _OBlockMgr.dispose(); _OBlockMgr = null; _sensorMgr.dispose(); _sensorMgr = null; JUnitUtil.deregisterBlockManagerShutdownTask(); if (InstanceManager.containsDefault(ShutDownManager.class)) { List list = new ArrayList<>(); ShutDownManager sm = InstanceManager.getDefault(ShutDownManager.class); for (Runnable r : sm.getRunnables()) { if (r instanceof jmri.jmrit.logix.WarrantShutdownTask) { list.add((ShutDownTask)r); } } for ( ShutDownTask t : list) { sm.deregister(t); } } JUnitUtil.tearDown(); } }