Files
Cyrene_v2/backend/plugins/iot-mock/plugin_test.go
T
Aska 750d594055 feat(plugin): add plugin interface system and iot-mock implementation
- internal/plugin: Plugin/IoTProvider/ToolProvider/RAGProvider interfaces
- internal/plugin: Registry with type-safe auto-detection, 11 tests
- plugins/iot-mock: 8 simulated smart home devices, 11 tests
- 63 total tests, build + vet clean
2026-08-09 20:38:37 +08:00

201 lines
4.7 KiB
Go

package iotmock
import (
"context"
"testing"
"git.yeij.top/AskaEth/Cyrene_v2/internal/plugin"
)
func TestNewPlugin(t *testing.T) {
p := New()
if p.Name() != "iot-mock" {
t.Errorf("expected name iot-mock, got %s", p.Name())
}
if p.Version() != "1.0.0" {
t.Errorf("expected version 1.0.0, got %s", p.Version())
}
if !p.Enabled() {
t.Error("plugin should be enabled by default")
}
}
func TestListDevices(t *testing.T) {
p := New()
devices, err := p.ListDevices(context.Background())
if err != nil {
t.Fatalf("ListDevices failed: %v", err)
}
if len(devices) != 8 {
t.Errorf("expected 8 devices, got %d", len(devices))
}
// Verify devices are clones (modifying returned device doesn't affect internal state)
devices[0].State["power"] = true
d, _ := p.GetDevice(context.Background(), "light-livingroom")
if d.State["power"] != false {
t.Error("returned devices should be clones, internal state modified")
}
}
func TestGetDevice(t *testing.T) {
p := New()
d, err := p.GetDevice(context.Background(), "light-livingroom")
if err != nil {
t.Fatalf("GetDevice failed: %v", err)
}
if d.Name != "客厅灯" {
t.Errorf("expected name 客厅灯, got %s", d.Name)
}
if d.Type != plugin.DeviceLight {
t.Errorf("expected type light, got %s", d.Type)
}
// Unknown device
_, err = p.GetDevice(context.Background(), "nonexistent")
if err == nil {
t.Error("expected error for unknown device")
}
}
func TestToggleDevice(t *testing.T) {
p := New()
// Initially off
d, _ := p.GetDevice(context.Background(), "light-livingroom")
if d.State["power"] != false {
t.Error("expected light to be off initially")
}
// Toggle on
err := p.ToggleDevice(context.Background(), "light-livingroom")
if err != nil {
t.Fatalf("ToggleDevice failed: %v", err)
}
d, _ = p.GetDevice(context.Background(), "light-livingroom")
if d.State["power"] != true {
t.Error("expected light to be on after toggle")
}
// Toggle off
p.ToggleDevice(context.Background(), "light-livingroom")
d, _ = p.GetDevice(context.Background(), "light-livingroom")
if d.State["power"] != false {
t.Error("expected light to be off after second toggle")
}
}
func TestSetDevice(t *testing.T) {
p := New()
err := p.SetDevice(context.Background(), "light-livingroom", "brightness", 50)
if err != nil {
t.Fatalf("SetDevice failed: %v", err)
}
d, _ := p.GetDevice(context.Background(), "light-livingroom")
if d.State["brightness"] != 50 {
t.Errorf("expected brightness=50, got %v", d.State["brightness"])
}
// History should have an entry
if len(d.History) != 1 {
t.Errorf("expected 1 history entry, got %d", len(d.History))
}
}
func TestSetDeviceNotFound(t *testing.T) {
p := New()
err := p.SetDevice(context.Background(), "nonexistent", "power", true)
if err == nil {
t.Error("expected error for unknown device")
}
}
func TestSubscribeChanges(t *testing.T) {
p := New()
ch, err := p.SubscribeChanges(context.Background())
if err != nil {
t.Fatalf("SubscribeChanges failed: %v", err)
}
// Toggle should emit an event
go p.ToggleDevice(context.Background(), "light-livingroom")
event := <-ch
if event.DeviceID != "light-livingroom" {
t.Errorf("expected event for light-livingroom, got %s", event.DeviceID)
}
if event.Field != "power" {
t.Errorf("expected event field power, got %s", event.Field)
}
if event.NewValue != true {
t.Errorf("expected new value true, got %v", event.NewValue)
}
}
func TestInitAndClose(t *testing.T) {
p := New()
err := p.Init(context.Background(), plugin.PluginConfig{})
if err != nil {
t.Fatalf("Init failed: %v", err)
}
err = p.Close()
if err != nil {
t.Fatalf("Close failed: %v", err)
}
// Second close should be safe
err = p.Close()
if err != nil {
t.Errorf("second Close should not error: %v", err)
}
}
func TestDeviceHistoryLimit(t *testing.T) {
p := New()
// Generate 25 events (limit is 20)
for i := range 25 {
p.SetDevice(context.Background(), "light-livingroom", "brightness", i)
}
d, _ := p.GetDevice(context.Background(), "light-livingroom")
if len(d.History) > 20 {
t.Errorf("history should be capped at 20, got %d", len(d.History))
}
}
func TestAllDevicesExist(t *testing.T) {
p := New()
expectedIDs := []string{
"light-livingroom", "light-bedroom",
"ac-livingroom", "ac-bedroom",
"curtain-livingroom",
"sensor-temperature", "sensor-humidity",
"lock-door",
}
for _, id := range expectedIDs {
_, err := p.GetDevice(context.Background(), id)
if err != nil {
t.Errorf("expected device %s to exist", id)
}
}
}
func TestPluginInterface(t *testing.T) {
p := New()
// Verify it implements the IoTProvider interface
var _ plugin.IoTProvider = p
// Verify it implements the base Plugin interface
var _ plugin.Plugin = p
}