yeg
2026-09-28 147428971be43eed90a79f3849f15000d3855390
battery-device-api/src/test/java/com/battery/device/api/registry/DeviceAdapterRegistryTest.java
@@ -1,5 +1,6 @@
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;
@@ -15,6 +16,7 @@
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;
@@ -153,6 +155,139 @@
        }
    }
    /**
     * 多来源实例:取数按适配器编码解析到各自实例;实例缺失时明确失败,不回退到其他实例。
     */
    @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,