package com.battery.device.bts;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.Duration;
import java.time.ZoneId;
import java.util.Set;
import org.junit.jupiter.api.Test;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.model.ChannelIdentity;
import com.battery.device.model.DeviceConnectionStatus;
import com.battery.device.model.DeviceWorkStatus;
import com.battery.device.model.ObservationFailureReason;
class DeviceObservationSeamContractTest
{
private static final ChannelIdentity CHANNEL = new ChannelIdentity("lab-bts", 22, 1, 1, 1);
@Test
void successfulResponseIsOnlineAndCarriesDeviceTimeAndPlan() throws Exception
{
try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator();
BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(),
Duration.ofSeconds(1), Duration.ofSeconds(1));
DeviceAdapter adapter = new BtsDeviceAdapter("lab-bts", transport,
new BtsXmlCodec("lab-bts", ZoneId.of("Asia/Hong_Kong"))))
{
simulator.enqueue("inquire_resp"
+ ""
+ "
");
var observation = adapter.observe(Set.of(CHANNEL)).get(CHANNEL);
assertEquals(DeviceConnectionStatus.ONLINE, observation.connectionStatus());
assertEquals(DeviceWorkStatus.WORKING, observation.workStatus());
assertEquals("2026-09-04T10:00:00Z", observation.deviceTime().toString());
assertEquals(1, observation.plannedSteps().size());
assertEquals("cc", observation.plannedSteps().get(0).stepType());
assertEquals(null, observation.failureReason());
}
}
@Test
void missingChannelResponseIsOfflineAndUnobservable() throws Exception
{
try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator();
BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(),
Duration.ofSeconds(1), Duration.ofSeconds(1));
DeviceAdapter adapter = new BtsDeviceAdapter("lab-bts", transport,
new BtsXmlCodec("lab-bts", ZoneId.of("Asia/Hong_Kong"))))
{
simulator.enqueue("inquire_resp
");
var observation = adapter.observe(Set.of(CHANNEL)).get(CHANNEL);
assertEquals(DeviceConnectionStatus.OFFLINE, observation.connectionStatus());
assertEquals(DeviceWorkStatus.UNOBSERVABLE, observation.workStatus());
assertEquals(ObservationFailureReason.OFFLINE, observation.failureReason());
}
}
@Test
void timeoutAndParseFailureBecomeStableOfflineReasons() throws Exception
{
try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator();
BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(),
Duration.ofSeconds(1), Duration.ofMillis(50));
DeviceAdapter adapter = new BtsDeviceAdapter("lab-bts", transport,
new BtsXmlCodec("lab-bts", ZoneId.of("Asia/Hong_Kong"))))
{
simulator.enqueueDelayed(Duration.ofMillis(200), "inquire_resp
");
assertEquals(ObservationFailureReason.TIMEOUT, adapter.observe(Set.of(CHANNEL)).get(CHANNEL).failureReason());
}
try (ScriptedBtsTcpSimulator simulator = new ScriptedBtsTcpSimulator();
BtsTcpTransport transport = new BtsTcpTransport("127.0.0.1", simulator.port(),
Duration.ofSeconds(1), Duration.ofSeconds(1));
DeviceAdapter adapter = new BtsDeviceAdapter("lab-bts", transport,
new BtsXmlCodec("lab-bts", ZoneId.of("Asia/Hong_Kong"))))
{
simulator.enqueue("inquire_resp");
assertEquals(ObservationFailureReason.PARSE_FAILED, adapter.observe(Set.of(CHANNEL)).get(CHANNEL).failureReason());
}
}
}