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
This commit is contained in:
1 parent
7943e290ec
commit
750d594055
8 files changed
+1109
No files matched your search
@@ -0,0 +1,200 @@
|
||||
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
|
||||
}
|
||||
Reference in new issue
Block a user