From 147428971be43eed90a79f3849f15000d3855390 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期一, 28 九月 2026 15:15:22 +0800
Subject: [PATCH] 实现新威 7.6 直连取数与逐行接收

---
 battery-device-api/src/test/java/com/battery/device/api/registry/DeviceAdapterRegistryTest.java |  135 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 135 insertions(+), 0 deletions(-)

diff --git a/battery-device-api/src/test/java/com/battery/device/api/registry/DeviceAdapterRegistryTest.java b/battery-device-api/src/test/java/com/battery/device/api/registry/DeviceAdapterRegistryTest.java
index 56e6c7e..05e1c91 100644
--- a/battery-device-api/src/test/java/com/battery/device/api/registry/DeviceAdapterRegistryTest.java
+++ b/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,

--
Gitblit v1.7.1