github.com/martinohmann/rfoutlet@v1.2.1-0.20220707195255-8a66aa411105/internal/controller/controller_test.go (about) 1 package controller 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 "time" 8 9 "github.com/martinohmann/rfoutlet/internal/command" 10 "github.com/martinohmann/rfoutlet/internal/outlet" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 type fakeSwitcher struct{} 15 16 func (fakeSwitcher) Switch(*outlet.Outlet, outlet.State) error { return nil } 17 18 type testBroadcaster chan []byte 19 20 func (b testBroadcaster) Broadcast(msg []byte) { 21 b <- msg 22 } 23 24 type testCommand struct { 25 context command.Context 26 doneCh chan struct{} 27 broadcast bool 28 err error 29 } 30 31 func (c *testCommand) Execute(context command.Context) (bool, error) { 32 c.context = context 33 close(c.doneCh) 34 return c.broadcast, c.err 35 } 36 37 func TestController(t *testing.T) { 38 tests := []struct { 39 name string 40 broadcast bool 41 commandErr error 42 }{ 43 { 44 name: "no broadcast", 45 }, 46 { 47 name: "broadcast", 48 broadcast: true, 49 }, 50 { 51 name: "broadcast, but error -> do not broadcast", 52 broadcast: true, 53 commandErr: errors.New("whoops"), 54 }, 55 } 56 57 for _, test := range tests { 58 t.Run(test.name, func(t *testing.T) { 59 queue := make(chan command.Command) 60 b := make(testBroadcaster) 61 s := &fakeSwitcher{} 62 63 stopCh := make(chan struct{}) 64 defer close(stopCh) 65 66 c := &Controller{ 67 Registry: outlet.NewRegistry(), 68 Switcher: s, 69 Broadcaster: b, 70 CommandQueue: queue, 71 } 72 73 go c.Run(stopCh) 74 75 ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) 76 defer cancel() 77 78 doneCh := make(chan struct{}) 79 cmd := &testCommand{ 80 doneCh: doneCh, 81 broadcast: test.broadcast, 82 err: test.commandErr, 83 } 84 85 go func() { queue <- cmd }() 86 87 select { 88 case <-ctx.Done(): 89 t.Fatal("timeout exceeded") 90 case <-doneCh: 91 expectedCtx := command.Context{ 92 Registry: c.Registry, 93 Switcher: c.Switcher, 94 } 95 assert.Equal(t, expectedCtx, cmd.context) 96 97 if test.broadcast && test.commandErr == nil { 98 select { 99 case <-ctx.Done(): 100 t.Fatal("timeout exceeded waiting for broadcast") 101 case <-b: 102 } 103 } 104 } 105 }) 106 } 107 }