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  }