- 实现 MIoT 客户端核心功能(MQTT 连接、设备管理、属性读写) - 支持云端 API 调用与局域网设备发现(mDNS) - 集成国际化(i18n)多语言支持 - 添加 MIoT 设备规约解析器(spec_parser) - 包含单元测试与使用示例
194 lines
4.6 KiB
Go
194 lines
4.6 KiB
Go
// Package miot provides white-box tests for miot_client_prop.go property refresh.
|
|
package miot
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// ============================================================================
|
|
// RequestRefreshProp — queue and timer
|
|
// ============================================================================
|
|
|
|
func TestRequestRefreshProp_QueuesProperty(t *testing.T) {
|
|
c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud)
|
|
|
|
c.RequestRefreshProp("did1", 2, 1)
|
|
|
|
c.mu.Lock()
|
|
key := fmt.Sprintf("%s|%d|%d", "did1", 2, 1)
|
|
_, exists := c.refreshPropsList[key]
|
|
queueLen := len(c.refreshPropsList)
|
|
timer := c.refreshPropsTimer
|
|
c.mu.Unlock()
|
|
|
|
if !exists {
|
|
t.Error("property should be in refreshPropsList")
|
|
}
|
|
if queueLen != 1 {
|
|
t.Errorf("queue len = %d, want 1", queueLen)
|
|
}
|
|
if timer == nil {
|
|
t.Error("refreshPropsTimer should be created")
|
|
}
|
|
|
|
// Clean up
|
|
if timer != nil {
|
|
timer.Stop()
|
|
}
|
|
c.refreshPropsList = make(map[string]map[string]interface{})
|
|
}
|
|
|
|
func TestRequestRefreshProp_DuplicateSkipped(t *testing.T) {
|
|
c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud)
|
|
|
|
c.RequestRefreshProp("did1", 2, 1)
|
|
c.RequestRefreshProp("did1", 2, 1) // duplicate
|
|
|
|
c.mu.Lock()
|
|
queueLen := len(c.refreshPropsList)
|
|
timer := c.refreshPropsTimer
|
|
c.mu.Unlock()
|
|
|
|
if queueLen != 1 {
|
|
t.Errorf("queue len should be 1 after duplicate, got %d", queueLen)
|
|
}
|
|
|
|
if timer != nil {
|
|
timer.Stop()
|
|
}
|
|
c.refreshPropsList = make(map[string]map[string]interface{})
|
|
}
|
|
|
|
func TestRequestRefreshProp_MultipleProperties(t *testing.T) {
|
|
c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud)
|
|
|
|
c.RequestRefreshProp("did1", 2, 1)
|
|
c.RequestRefreshProp("did1", 2, 2)
|
|
c.RequestRefreshProp("did2", 3, 1)
|
|
|
|
c.mu.Lock()
|
|
queueLen := len(c.refreshPropsList)
|
|
timer := c.refreshPropsTimer
|
|
c.mu.Unlock()
|
|
|
|
if queueLen != 3 {
|
|
t.Errorf("queue len = %d, want 3", queueLen)
|
|
}
|
|
|
|
if timer != nil {
|
|
timer.Stop()
|
|
}
|
|
c.refreshPropsList = make(map[string]map[string]interface{})
|
|
}
|
|
|
|
func TestRequestRefreshProp_ReusesTimer(t *testing.T) {
|
|
c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud)
|
|
|
|
c.RequestRefreshProp("did1", 2, 1)
|
|
|
|
c.mu.Lock()
|
|
firstTimer := c.refreshPropsTimer
|
|
c.mu.Unlock()
|
|
|
|
c.RequestRefreshProp("did2", 3, 1)
|
|
|
|
c.mu.Lock()
|
|
secondTimer := c.refreshPropsTimer
|
|
c.mu.Unlock()
|
|
|
|
if firstTimer != secondTimer {
|
|
t.Error("second RequestRefreshProp should reuse the same timer")
|
|
}
|
|
|
|
if firstTimer != nil {
|
|
firstTimer.Stop()
|
|
}
|
|
c.refreshPropsList = make(map[string]map[string]interface{})
|
|
}
|
|
|
|
// ============================================================================
|
|
// refreshPropsHandler — empty queue and no HTTP
|
|
// ============================================================================
|
|
|
|
func TestRefreshPropsHandler_EmptyQueue(t *testing.T) {
|
|
c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud)
|
|
|
|
// Handler with empty queue should return immediately
|
|
c.mu.Lock()
|
|
c.refreshPropsList = make(map[string]map[string]interface{})
|
|
c.mu.Unlock()
|
|
|
|
// Should not panic
|
|
c.refreshPropsHandler()
|
|
}
|
|
|
|
func TestRefreshPropsHandler_NoHTTP(t *testing.T) {
|
|
c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud)
|
|
|
|
c.mu.Lock()
|
|
c.refreshPropsList["did1|2|1"] = map[string]interface{}{
|
|
"did": "did1",
|
|
"siid": 2,
|
|
"piid": 1,
|
|
}
|
|
c.mu.Unlock()
|
|
|
|
// Should not panic, just return due to no HTTP
|
|
c.refreshPropsHandler()
|
|
|
|
// Queue should be cleared
|
|
c.mu.Lock()
|
|
queueLen := len(c.refreshPropsList)
|
|
c.mu.Unlock()
|
|
|
|
if queueLen != 0 {
|
|
t.Errorf("queue should be cleared after handler, got %d items", queueLen)
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// RequestRefreshProp — cancellation
|
|
// ============================================================================
|
|
|
|
func TestRequestRefreshProp_CancelTimer(t *testing.T) {
|
|
c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud)
|
|
|
|
c.RequestRefreshProp("did1", 2, 1)
|
|
|
|
c.mu.Lock()
|
|
timer := c.refreshPropsTimer
|
|
c.mu.Unlock()
|
|
|
|
// Cancel the timer manually
|
|
if timer != nil {
|
|
timer.Stop()
|
|
}
|
|
|
|
// Clear to avoid timer firing after Stop
|
|
c.mu.Lock()
|
|
c.refreshPropsList = make(map[string]map[string]interface{})
|
|
c.refreshPropsTimer = nil
|
|
c.mu.Unlock()
|
|
|
|
// Give timer a moment (should be stopped, no action)
|
|
time.Sleep(50 * time.Millisecond)
|
|
}
|
|
|
|
// ============================================================================
|
|
// refreshRetryCount
|
|
// ============================================================================
|
|
|
|
func TestRefreshProps_InitialRetryCount(t *testing.T) {
|
|
c := NewMIoTClient("test", nil, "uid", "cn", CtrlModeCloud)
|
|
|
|
c.mu.Lock()
|
|
retry := c.refreshRetryCount
|
|
c.mu.Unlock()
|
|
|
|
if retry != 0 {
|
|
t.Errorf("initial retry count = %d, want 0", retry)
|
|
}
|
|
}
|