- local-agent/server:detector 保留 kn_number(parseScanDevices 可測化、 合成 ID 語意不動)+ DeviceInfo.SerialNumber + Manager serialToLocalID 反查表 + GetDevice 雙查(sessions 先、serial 後,純加法) - visiona-agent:pairing exchange 帶本地裝置清單(DeviceLister 失敗不中斷 配對、timeout 2s、omitempty 舊版相容) - visionA-backend:exchange 收 devices —— R1 取第一顆可用序號、R2 假序號 0x00000000 寫 NULL、R4 同 owner 同序號復用既有 device_id(防 23505)、 pg+mem 兩實作對齊 - 五個 proxy 操作(flash/inference/camera/connect/disconnect)收斂於 GetDevice 單一入口,serial 路由一處涵蓋 - docs:api-spec.md §2 增補 POST /api/pairing/exchange(schema + R1/R2/R4) - 測試:行為級四環節鏈 + dbtest 130 實跑 6/6 + DBOn 回歸 4/4; 三 module build/vet/test 全綠 - review:通過 0C/0M/6Mi/5Sug(.autoflow/05-implementation/review/ wp0-serial-routing-review.md);Minor #1 Rescan stale session 掛 WP-C 前置 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
106 lines
3.1 KiB
Go
106 lines
3.1 KiB
Go
package kneron
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// TestParseScanDevices_WithKnNumber verifies the serial number (kn_number)
|
|
// reported by the Python bridge is preserved into DeviceInfo.SerialNumber
|
|
// while the synthetic local ID stays untouched (ADR-018 serial routing, WP-0).
|
|
func TestParseScanDevices_WithKnNumber(t *testing.T) {
|
|
raw := []interface{}{
|
|
map[string]interface{}{
|
|
"port": "1-2",
|
|
"firmware": "KDP",
|
|
"kn_number": "0x1A2B3C4D",
|
|
"product_id": "0x0100",
|
|
},
|
|
map[string]interface{}{
|
|
"port": "1-3",
|
|
"firmware": "KDP2",
|
|
"kn_number": "0x0E5F6071",
|
|
"product_id": "0x0720",
|
|
},
|
|
}
|
|
|
|
devices := parseScanDevices(raw)
|
|
if len(devices) != 2 {
|
|
t.Fatalf("parseScanDevices() = %d devices, want 2", len(devices))
|
|
}
|
|
|
|
if devices[0].ID != "kl520-0" {
|
|
t.Errorf("devices[0].ID = %q, want kl520-0 (synthetic ID must not change)", devices[0].ID)
|
|
}
|
|
if devices[0].SerialNumber != "0x1A2B3C4D" {
|
|
t.Errorf("devices[0].SerialNumber = %q, want 0x1A2B3C4D", devices[0].SerialNumber)
|
|
}
|
|
if devices[1].ID != "kl720-0" {
|
|
t.Errorf("devices[1].ID = %q, want kl720-0", devices[1].ID)
|
|
}
|
|
if devices[1].SerialNumber != "0x0E5F6071" {
|
|
t.Errorf("devices[1].SerialNumber = %q, want 0x0E5F6071", devices[1].SerialNumber)
|
|
}
|
|
}
|
|
|
|
// TestParseScanDevices_MissingKnNumber verifies a payload without kn_number
|
|
// still yields the full device list (serial empty, no panic, no device drop).
|
|
func TestParseScanDevices_MissingKnNumber(t *testing.T) {
|
|
raw := []interface{}{
|
|
map[string]interface{}{
|
|
"port": "1-2",
|
|
"firmware": "KDP",
|
|
"product_id": "0x0100",
|
|
},
|
|
}
|
|
|
|
devices := parseScanDevices(raw)
|
|
if len(devices) != 1 {
|
|
t.Fatalf("parseScanDevices() = %d devices, want 1 (device must not be dropped)", len(devices))
|
|
}
|
|
if devices[0].SerialNumber != "" {
|
|
t.Errorf("SerialNumber = %q, want empty when kn_number absent", devices[0].SerialNumber)
|
|
}
|
|
if devices[0].ID != "kl520-0" {
|
|
t.Errorf("ID = %q, want kl520-0", devices[0].ID)
|
|
}
|
|
}
|
|
|
|
// TestParseScanDevices_NonStringKnNumber verifies a non-string kn_number
|
|
// (e.g. raw number instead of formatted hex string) does not panic and the
|
|
// device is still registered with an empty serial.
|
|
func TestParseScanDevices_NonStringKnNumber(t *testing.T) {
|
|
raw := []interface{}{
|
|
map[string]interface{}{
|
|
"port": "1-2",
|
|
"kn_number": float64(123456), // JSON number decodes to float64
|
|
"product_id": "0x0200",
|
|
},
|
|
}
|
|
|
|
devices := parseScanDevices(raw)
|
|
if len(devices) != 1 {
|
|
t.Fatalf("parseScanDevices() = %d devices, want 1", len(devices))
|
|
}
|
|
if devices[0].SerialNumber != "" {
|
|
t.Errorf("SerialNumber = %q, want empty for non-string kn_number", devices[0].SerialNumber)
|
|
}
|
|
}
|
|
|
|
// TestParseScanDevices_WhitespaceTrimmed verifies kn_number whitespace is trimmed.
|
|
func TestParseScanDevices_WhitespaceTrimmed(t *testing.T) {
|
|
raw := []interface{}{
|
|
map[string]interface{}{
|
|
"kn_number": " 0x1A2B3C4D ",
|
|
"product_id": "0x0100",
|
|
},
|
|
}
|
|
|
|
devices := parseScanDevices(raw)
|
|
if len(devices) != 1 {
|
|
t.Fatalf("parseScanDevices() = %d devices, want 1", len(devices))
|
|
}
|
|
if devices[0].SerialNumber != "0x1A2B3C4D" {
|
|
t.Errorf("SerialNumber = %q, want trimmed 0x1A2B3C4D", devices[0].SerialNumber)
|
|
}
|
|
}
|