| | |
| | | package com.battery.device.api.registry; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertFalse; |
| | | import static org.junit.jupiter.api.Assertions.assertSame; |
| | | import static org.junit.jupiter.api.Assertions.assertThrows; |
| | |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | import org.junit.jupiter.api.Test; |
| | | import com.battery.device.api.DeviceAdapter; |
| | | import com.battery.device.api.TestDataObservationAdapter; |
| | | import com.battery.device.api.model.AdapterCapabilities; |
| | | import com.battery.device.api.model.ChannelIdentity; |
| | | import com.battery.device.api.model.DeviceControlCommand; |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 多来源实例:取数按适配器编码解析到各自实例;实例缺失时明确失败,不回退到其他实例。 |
| | | */ |
| | | @Test |
| | | void routesTestDataObservationToTheInstanceNamedByTheChannelAndFailsWithoutFallback() |
| | | { |
| | | try (DeviceAdapterRegistry registry = new DeviceAdapterRegistry(List.of(new ObservableFactory()))) |
| | | { |
| | | registry.register(observableConfig("source-a", 1000), new ObservableAdapter("source-a", 1000L)); |
| | | registry.register(observableConfig("source-b", 2000), new ObservableAdapter("source-b", 2000L)); |
| | | |
| | | assertEquals(1000L, registry.executeTestData("source-a", |
| | | adapter -> adapter.latestCabinet(channel("source-a")).sequenceId()).longValue()); |
| | | assertEquals(2000L, registry.executeTestData("source-b", |
| | | adapter -> adapter.latestCabinet(channel("source-b")).sequenceId()).longValue()); |
| | | |
| | | // 实例缺失或未提供扩展观测契约时明确失败,不能落到别的实例上。 |
| | | assertThrows(AdapterRegistryException.class, |
| | | () -> registry.executeTestData("source-c", adapter -> adapter.latestCabinet(channel("source-a")))); |
| | | assertThrows(AdapterRegistryException.class, |
| | | () -> registry.executeTestData("lab-bts", adapter -> adapter.adapterCode())); |
| | | } |
| | | } |
| | | |
| | | /** 代码装配的实例与工厂实例共用同一份实例表,发现与取数因此按同一编码解析。 */ |
| | | @Test |
| | | void codeAssembledInstanceIsVisibleToBothAccessors() |
| | | { |
| | | try (DeviceAdapterRegistry registry = new DeviceAdapterRegistry(List.of())) |
| | | { |
| | | ObservableAdapter assembled = new ObservableAdapter("assembled", 42L); |
| | | registry.register(observableConfig("assembled", 3000), assembled); |
| | | |
| | | assertSame(assembled, registry.execute("assembled", adapter -> adapter)); |
| | | assertSame(assembled, registry.executeTestData("assembled", adapter -> adapter)); |
| | | } |
| | | } |
| | | |
| | | private static ChannelIdentity channel(String adapterCode) |
| | | { |
| | | return new ChannelIdentity(adapterCode, 22, 1, 1, 1); |
| | | } |
| | | |
| | | private static AdapterInstanceConfig observableConfig(String adapterCode, int pollIntervalMs) |
| | | { |
| | | return new AdapterInstanceConfig(adapterCode, "NEWARE_MYSQL", "127.0.0.1", 3306, pollIntervalMs, |
| | | "Asia/Hong_Kong", true, AdapterCapabilities.observeOnly()); |
| | | } |
| | | |
| | | private static final class ObservableFactory implements DeviceAdapterFactory |
| | | { |
| | | @Override |
| | | public String adapterType() |
| | | { |
| | | return "NEWARE_MYSQL"; |
| | | } |
| | | |
| | | @Override |
| | | public DeviceAdapter create(AdapterInstanceConfig config) |
| | | { |
| | | return new ObservableAdapter(config.adapterCode(), 0L); |
| | | } |
| | | } |
| | | |
| | | /** 同时实现发现与测试数据观测契约的最小实例,用于验证按编码路由。 */ |
| | | private static final class ObservableAdapter implements DeviceAdapter, TestDataObservationAdapter |
| | | { |
| | | private final String code; |
| | | private final long sequenceId; |
| | | |
| | | private ObservableAdapter(String code, long sequenceId) |
| | | { |
| | | this.code = code; |
| | | this.sequenceId = sequenceId; |
| | | } |
| | | |
| | | @Override |
| | | public String adapterCode() |
| | | { |
| | | return code; |
| | | } |
| | | |
| | | @Override |
| | | public AdapterCapabilities capabilities() |
| | | { |
| | | return AdapterCapabilities.observeOnly(); |
| | | } |
| | | |
| | | @Override |
| | | public List<com.battery.device.api.model.DetectedChannel> discoverChannels() |
| | | { |
| | | return List.of(); |
| | | } |
| | | |
| | | @Override |
| | | public java.util.Map<ChannelIdentity, com.battery.device.api.model.RealtimeSnapshot> inquire( |
| | | java.util.Set<ChannelIdentity> channels) |
| | | { |
| | | return java.util.Map.of(); |
| | | } |
| | | |
| | | @Override |
| | | public TestDataObservationAdapter.CabinetRealtime latestCabinet(ChannelIdentity channel) |
| | | { |
| | | return new TestDataObservationAdapter.CabinetRealtime(sequenceId, java.time.Instant.EPOCH, 0, 0, 0, 0, |
| | | 0, 0, null, null, java.time.Instant.EPOCH, null, "Asia/Hong_Kong", null); |
| | | } |
| | | |
| | | @Override |
| | | public TestDataObservationAdapter.CollectorRealtime latestCollector(String adapterCode, String collectorCode) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public List<TestDataObservationAdapter.StepRecord> stepRecords(ChannelIdentity channel) |
| | | { |
| | | return List.of(); |
| | | } |
| | | |
| | | @Override |
| | | public List<TestDataObservationAdapter.CycleRecord> cycleRecords(ChannelIdentity channel) |
| | | { |
| | | return List.of(); |
| | | } |
| | | |
| | | @Override |
| | | public long persistenceIntervalMillis(ChannelIdentity channel) |
| | | { |
| | | return 60000L; |
| | | } |
| | | } |
| | | |
| | | private static AdapterInstanceConfig config(String host, boolean enabled) |
| | | { |
| | | return new AdapterInstanceConfig("lab-bts", "BTS", host, 502, 5000, |