package com.battery.device.simulator; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import com.battery.device.api.model.ChannelIdentity; import com.battery.device.api.model.DeviceConnectionStatus; import com.battery.device.api.model.DeviceWorkStatus; class SimulatorObservationAdapterContractTest { @Test void configuredChannelFactsSurviveSoftwareFailureAndRestart() throws Exception { var store = new InMemoryBtsSimulatorStateStore(); long firstSequence; try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0, store)) { simulator.updateChannel(1, 1, true, DeviceWorkStatus.PROTECTED); simulator.updateCollectorChannelStatus(1, "S-01", DeviceWorkStatus.UNOBSERVABLE); var collector = simulator.latestCollector(BtsDevelopmentSimulator.ADAPTER_CODE, "dev-sim-collector-1"); assertTrue(collector.measurements().stream().noneMatch(item -> item.channelCode().equals("S-01"))); firstSequence = collector.measurements().get(0).sequenceId(); simulator.setSoftwareAccessible(false); simulator.updateDevice(1, "127.0.0.8", 4, false); assertFalse(simulator.snapshot().softwareAccessible()); } try (BtsDevelopmentSimulator restored = new BtsDevelopmentSimulator(0, store)) { assertFalse(restored.snapshot().softwareAccessible()); assertEquals("127.0.0.8", restored.snapshot().devices().get(0).ip()); assertEquals(DeviceWorkStatus.PROTECTED, restored.snapshot().devices().get(0).channels().get(0).workStatus()); assertTrue(restored.snapshot().collectors().get(0).latestMeasurements().isEmpty()); restored.setSoftwareAccessible(true); assertTrue(restored.latestCollector(BtsDevelopmentSimulator.ADAPTER_CODE, "dev-sim-collector-1").measurements().get(0).sequenceId() > firstSequence); assertEquals(DeviceWorkStatus.UNOBSERVABLE, restored.snapshot().collectors().get(0).channels().get(0).workStatus()); } } @Test void offlineCollectorDoesNotReturnLastSuccessAndStateReadsDoNotSample() throws Exception { try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0)) { assertTrue(simulator.snapshot().collectors().get(0).latestMeasurements().isEmpty()); var first = simulator.collectorRealtime(1); var recent = simulator.snapshot().recentRequests(); assertEquals(recent, simulator.snapshot().recentRequests()); simulator.updateCollector(1, "127.0.1.2", 4, false); assertFalse(simulator.collectorRealtime(1).online()); assertTrue(simulator.collectorRealtime(1).measurements().isEmpty()); simulator.updateCollector(1, "127.0.1.2", 4, true); assertTrue(simulator.collectorRealtime(1).measurements().get(0).sequenceId() > first.measurements().get(0).sequenceId()); var channel = simulator.discoverChannels().get(0).identity(); simulator.updateChannel(1, 1, true, DeviceWorkStatus.UNOBSERVABLE); assertNull(simulator.latestCabinet(channel)); assertEquals(DeviceWorkStatus.UNOBSERVABLE, simulator.observe(java.util.Set.of(channel)).get(channel).workStatus()); } } @Test void softwareFailurePreservesIdentityAndDoesNotReplayMeasurements() throws Exception { try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0)) { var channel = simulator.discoverChannels().get(0).identity(); simulator.updateChannel(1, 1, true, DeviceWorkStatus.WORKING); var first = simulator.latestCabinet(channel); assertNotNull(first); assertFalse(simulator.latestCollector(BtsDevelopmentSimulator.ADAPTER_CODE, "dev-sim-collector-1").measurements().isEmpty()); simulator.setSoftwareAccessible(false); assertEquals(channel, simulator.discoverChannels().get(0).identity()); assertTrue(simulator.snapshot().devices().get(0).online()); assertEquals(DeviceWorkStatus.UNOBSERVABLE, simulator.observe(java.util.Set.of(channel)).get(channel).workStatus()); assertNull(simulator.latestCabinet(channel)); assertTrue(simulator.latestCollector(BtsDevelopmentSimulator.ADAPTER_CODE, "dev-sim-collector-1").measurements().isEmpty()); simulator.setSoftwareAccessible(true); var next = simulator.latestCabinet(channel); assertTrue(next.sequenceId() > first.sequenceId()); assertFalse(next.deviceTime().isBefore(first.deviceTime())); assertTrue(simulator.stepRecords(channel).isEmpty()); assertTrue(simulator.cycleRecords(channel).isEmpty()); assertEquals(60000L, simulator.persistenceIntervalMillis(channel)); } } @Test void persistenceRejectsForeignIdentitiesAndOfflineCachedFacts() throws Exception { try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0)) { ChannelIdentity channel = simulator.discoverChannels().get(0).identity(); simulator.updateChannel(channel.devid(), channel.chlid(), true, DeviceWorkStatus.WORKING); assertNotNull(simulator.latestCabinet(channel)); for (ChannelIdentity foreign : java.util.List.of( new ChannelIdentity("another-adapter", channel.devtype(), channel.devid(), channel.subdevid(), channel.chlid()), new ChannelIdentity(channel.adapterCode(), 999, channel.devid(), channel.subdevid(), channel.chlid()), new ChannelIdentity(channel.adapterCode(), channel.devtype(), channel.devid(), 999, channel.chlid()))) { assertNull(simulator.latestCabinet(foreign)); assertNull(simulator.testPlan(foreign)); assertTrue(simulator.stepRecords(foreign).isEmpty()); assertTrue(simulator.cycleRecords(foreign).isEmpty()); } simulator.updateChannel(channel.devid(), channel.chlid(), false, DeviceWorkStatus.WORKING); assertNull(simulator.latestCabinet(channel)); assertTrue(simulator.stepRecords(channel).isEmpty()); assertTrue(simulator.cycleRecords(channel).isEmpty()); } } @Test void simulatorCanBeUsedDirectlyThroughTheVendorNeutralContract() throws Exception { try (BtsDevelopmentSimulator simulator = new BtsDevelopmentSimulator(0)) { ChannelIdentity channel = simulator.discoverChannels().get(0).identity(); simulator.updateChannel(channel.devid(), channel.chlid(), true, DeviceWorkStatus.WORKING); var observation = simulator.observe(java.util.Set.of(channel)).get(channel); assertEquals("dev-sim", simulator.adapterCode()); assertEquals(DeviceConnectionStatus.ONLINE, observation.connectionStatus()); assertEquals(DeviceWorkStatus.WORKING, observation.workStatus()); } } }