Gisle Aune
2 years ago
9 changed files with 181 additions and 21 deletions
-
2bus.go
-
2events/device.go
-
3go.mod
-
4internal/color/color.go
-
87internal/testutils/eventlogger.go
-
3services/effectenforcer.go
-
66services/effectenforcer_test.go
-
25services/nanoleaf/client.go
-
2services/scenemap.go
@ -0,0 +1,87 @@ |
|||||
|
package testutils |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
lucifer3 "git.aiterp.net/lucifer3/server" |
||||
|
"log" |
||||
|
"math/rand" |
||||
|
"sync/atomic" |
||||
|
"testing" |
||||
|
) |
||||
|
|
||||
|
type syncEvent struct { |
||||
|
id uint64 |
||||
|
} |
||||
|
|
||||
|
func (s syncEvent) EventDescription() string { |
||||
|
return fmt.Sprintf("syncEvent(%d)", s.id) |
||||
|
} |
||||
|
|
||||
|
type TestEventLogger struct { |
||||
|
entries []any |
||||
|
syncN uint64 |
||||
|
syncCh chan struct{} |
||||
|
} |
||||
|
|
||||
|
func (l *TestEventLogger) Active() bool { |
||||
|
return true |
||||
|
} |
||||
|
|
||||
|
func (l *TestEventLogger) Sync(bus *lucifer3.EventBus) { |
||||
|
l.syncCh = make(chan struct{}) |
||||
|
v := rand.Int63() |
||||
|
atomic.StoreUint64(&l.syncN, uint64(v)) |
||||
|
|
||||
|
bus.RunEvent(syncEvent{id: uint64(v)}) |
||||
|
|
||||
|
<-l.syncCh |
||||
|
} |
||||
|
|
||||
|
func (l *TestEventLogger) AssertEvent(t *testing.T, eventStr string) { |
||||
|
for i, entry := range l.entries { |
||||
|
if event, ok := entry.(lucifer3.Event); ok && eventStr == event.EventDescription() { |
||||
|
l.entries = l.entries[i+1:] |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
t.Errorf("Event not found: %s", eventStr) |
||||
|
} |
||||
|
|
||||
|
func (l *TestEventLogger) AssertCommand(t *testing.T, commandStr string) { |
||||
|
for i, entry := range l.entries { |
||||
|
if cmd, ok := entry.(lucifer3.Command); ok { |
||||
|
log.Println(cmd.CommandDescription() == commandStr) |
||||
|
} |
||||
|
if command, ok := entry.(lucifer3.Command); ok && commandStr == command.CommandDescription() { |
||||
|
l.entries = l.entries[i+1:] |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
t.Errorf("Command not found: %s", commandStr) |
||||
|
} |
||||
|
|
||||
|
func (l *TestEventLogger) HandleEvent(_ *lucifer3.EventBus, event lucifer3.Event) { |
||||
|
if ev, ok := event.(syncEvent); ok { |
||||
|
if atomic.CompareAndSwapUint64(&l.syncN, ev.id, 0) { |
||||
|
close(l.syncCh) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
l.entries = append(l.entries, event) |
||||
|
} |
||||
|
|
||||
|
func (l *TestEventLogger) HandleCommand(_ *lucifer3.EventBus, command lucifer3.Command) { |
||||
|
l.entries = append(l.entries, command) |
||||
|
} |
||||
|
|
||||
|
func evStr(ev any) string { |
||||
|
if ev, ok := ev.(lucifer3.Event); ok { |
||||
|
return ev.EventDescription() |
||||
|
} else if ev, ok := ev.(lucifer3.Command); ok { |
||||
|
return ev.CommandDescription() |
||||
|
} |
||||
|
|
||||
|
panic("Unknown type") |
||||
|
} |
@ -0,0 +1,66 @@ |
|||||
|
package services |
||||
|
|
||||
|
import ( |
||||
|
lucifer3 "git.aiterp.net/lucifer3/server" |
||||
|
"git.aiterp.net/lucifer3/server/commands" |
||||
|
"git.aiterp.net/lucifer3/server/device" |
||||
|
"git.aiterp.net/lucifer3/server/effects" |
||||
|
"git.aiterp.net/lucifer3/server/events" |
||||
|
"git.aiterp.net/lucifer3/server/internal/color" |
||||
|
"git.aiterp.net/lucifer3/server/internal/gentools" |
||||
|
"git.aiterp.net/lucifer3/server/internal/testutils" |
||||
|
"strconv" |
||||
|
"testing" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func TestEffectEnforcer(t *testing.T) { |
||||
|
bus := lucifer3.EventBus{} |
||||
|
resolver := NewResolver() |
||||
|
sceneMap := NewSceneMap(resolver) |
||||
|
logger := &testutils.TestEventLogger{} |
||||
|
|
||||
|
bus.JoinPrivileged(resolver) |
||||
|
bus.JoinPrivileged(sceneMap) |
||||
|
bus.Join(NewEffectEnforcer(resolver, sceneMap)) |
||||
|
bus.Join(logger) |
||||
|
|
||||
|
for i := 1; i <= 9; i += 1 { |
||||
|
bus.RunEvents([]lucifer3.Event{ |
||||
|
events.HardwareState{ |
||||
|
ID: "test:" + strconv.Itoa(i), |
||||
|
InternalName: "Test Device " + strconv.Itoa(i), |
||||
|
SupportFlags: device.SFlagColor | device.SFlagIntensity | device.SFlagPower, |
||||
|
ColorFlags: device.CFlagXY | device.CFlagHS | device.CFlagRGB | device.CFlagKelvin, |
||||
|
ColorGamut: nil, |
||||
|
ColorKelvinRange: nil, |
||||
|
Buttons: nil, |
||||
|
State: device.State{ |
||||
|
Power: gentools.Ptr(false), |
||||
|
Intensity: gentools.Ptr(1.0), |
||||
|
Color: &color.Color{K: gentools.Ptr(2900)}, |
||||
|
}, |
||||
|
BatteryPercentage: nil, |
||||
|
Unreachable: false, |
||||
|
}, |
||||
|
events.DeviceReady{ID: "test:" + strconv.Itoa(i)}, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
bus.RunCommand(commands.Assign{ |
||||
|
Match: "test:*", |
||||
|
Effect: effects.Pattern{ |
||||
|
States: []device.State{ |
||||
|
{Color: &color.Color{XY: &color.XY{X: 0.22, Y: 0.18}}}, |
||||
|
{Color: &color.Color{XY: &color.XY{X: 0.27, Y: 0.23}}}, |
||||
|
}, |
||||
|
}, |
||||
|
}) |
||||
|
|
||||
|
time.Sleep(time.Millisecond * 100) |
||||
|
logger.Sync(&bus) |
||||
|
logger.AssertEvent(t, "DeviceReady(id:test:1)") |
||||
|
logger.AssertEvent(t, "DeviceReady(id:test:9)") |
||||
|
logger.AssertCommand(t, "Assign(test:*, Pattern(states:[(xy:0.2200,0.1800), (xy:0.2700,0.2300)], anim:0ms))") |
||||
|
logger.AssertCommand(t, "SetStateBatch(9 devices)") |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue