package main import ( "io" "log" "os" "sync" "testing" "git.sr.ht/~michalr/go-satel" "github.com/stretchr/testify/assert" ) func TestSatelEventTypeFiltering(t *testing.T) { testEvents := make(chan satel.Event) receivedEvents := make([]satel.Event, 0) wg := sync.WaitGroup{} go func() { wg.Add(1) for e := range FilterByTypeOrIndex(testEvents, &wg, []satel.ChangeType{satel.ArmedPartition, satel.PartitionFireAlarm}, []int{}) { receivedEvents = append(receivedEvents, e) } wg.Done() }() testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, true) testEvents <- makeTestSatelEvent(satel.DoorOpened, 2, true) testEvents <- makeTestSatelEvent(satel.PartitionAlarm, 3, true) testEvents <- makeTestSatelEvent(satel.PartitionFireAlarm, 4, true) testEvents <- makeTestSatelEvent(satel.TroublePart1, 5, true) testEvents <- makeTestSatelEvent(satel.ZoneTamper, 6, true) close(testEvents) wg.Wait() assert.Len(t, receivedEvents, 2) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 1, true)) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.PartitionFireAlarm, 4, true)) } func TestSatelEventTypeFiltering_NoAllowedEventTypesMeansAllAreAllowed(t *testing.T) { testEvents := make(chan satel.Event) receivedEvents := make([]satel.Event, 0) wg := sync.WaitGroup{} go func() { wg.Add(1) for e := range FilterByTypeOrIndex(testEvents, &wg, []satel.ChangeType{}, []int{}) { receivedEvents = append(receivedEvents, e) } wg.Done() }() for index, ct := range SUPPORTED_CHANGE_TYPES { testEvents <- makeTestSatelEvent(ct, index, true) } close(testEvents) wg.Wait() assert.Len(t, receivedEvents, len(SUPPORTED_CHANGE_TYPES)) for index, ct := range SUPPORTED_CHANGE_TYPES { assert.Contains(t, receivedEvents, makeTestSatelEvent(ct, index, true)) } } func TestSatelIndexFiltering(t *testing.T) { testEvents := make(chan satel.Event) receivedEvents := make([]satel.Event, 0) wg := sync.WaitGroup{} go func() { wg.Add(1) for e := range FilterByTypeOrIndex(testEvents, &wg, []satel.ChangeType{}, []int{1, 3}) { receivedEvents = append(receivedEvents, e) } wg.Done() }() testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, true) testEvents <- makeTestSatelEvent(satel.DoorOpened, 2, true) testEvents <- makeTestSatelEvent(satel.PartitionAlarm, 3, true) testEvents <- makeTestSatelEvent(satel.PartitionFireAlarm, 4, true) testEvents <- makeTestSatelEvent(satel.TroublePart1, 5, true) testEvents <- makeTestSatelEvent(satel.ZoneTamper, 6, true) close(testEvents) wg.Wait() assert.Len(t, receivedEvents, 2) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 1, true)) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.PartitionAlarm, 3, true)) } func TestSatelIndexFiltering_NoAllowedEventTypesMeansAllAreAllowed(t *testing.T) { testEvents := make(chan satel.Event) receivedEvents := make([]satel.Event, 0) wg := sync.WaitGroup{} myReasonableMaxIndex := 100 // I wanted to use math.MaxInt at first, but it's kind of a waste of time here go func() { wg.Add(1) for e := range FilterByTypeOrIndex(testEvents, &wg, []satel.ChangeType{}, []int{}) { receivedEvents = append(receivedEvents, e) } wg.Done() }() for i := 0; i < myReasonableMaxIndex; i++ { testEvents <- makeTestSatelEvent(satel.ArmedPartition, i, true) } close(testEvents) wg.Wait() assert.Len(t, receivedEvents, myReasonableMaxIndex) for i := 0; i < myReasonableMaxIndex; i++ { assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, i, true)) } } func TestSatelLastSeenFiltering(t *testing.T) { f, err := os.CreateTemp("", "TestSatelLastSeenFiltering") assert.NoError(t, err) tempFileName := f.Name() assert.NoError(t, f.Close()) defer os.Remove(f.Name()) testEvents := make(chan satel.Event) receivedEvents := make([]satel.Event, 0) wg := sync.WaitGroup{} fakeLog := log.New(io.Discard, "", log.Ltime) ds := MakeDataStore(fakeLog, tempFileName) go func() { wg.Add(1) for e := range FilterByLastSeen(testEvents, &wg, &ds, fakeLog) { receivedEvents = append(receivedEvents, e) } wg.Done() }() testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 2, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, false) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 2, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, false) close(testEvents) wg.Wait() assert.Len(t, receivedEvents, 3) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 1, true)) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 2, true)) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 1, false)) } func TestSatelLastSeenFilteringWithPersistence(t *testing.T) { f, err := os.CreateTemp("", "TestSatelLastSeenFilteringWithPersistence") assert.NoError(t, err) tempFileName := f.Name() assert.NoError(t, f.Close()) defer os.Remove(f.Name()) testEvents := make(chan satel.Event) receivedEvents := make([]satel.Event, 0) wg := sync.WaitGroup{} fakeLog := log.New(io.Discard, "", log.Ltime) ds := MakeDataStore(fakeLog, tempFileName) go func() { wg.Add(1) for e := range FilterByLastSeen(testEvents, &wg, &ds, fakeLog) { receivedEvents = append(receivedEvents, e) } wg.Done() }() testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 2, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, false) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 2, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, false) close(testEvents) wg.Wait() assert.Len(t, receivedEvents, 3) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 1, true)) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 2, true)) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 1, false)) testEvents = make(chan satel.Event) receivedEvents = make([]satel.Event, 0) ds = MakeDataStore(fakeLog, tempFileName) go func() { wg.Add(1) for e := range FilterByLastSeen(testEvents, &wg, &ds, fakeLog) { receivedEvents = append(receivedEvents, e) } wg.Done() }() receivedEvents = make([]satel.Event, 0) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, false) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, false) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 1, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 2, true) testEvents <- makeTestSatelEvent(satel.ArmedPartition, 2, true) close(testEvents) wg.Wait() assert.Len(t, receivedEvents, 1) assert.Contains(t, receivedEvents, makeTestSatelEvent(satel.ArmedPartition, 1, true)) } type MockSleeper struct { ch *chan<- interface{} callCount int } func (self *MockSleeper) Sleep(ch chan<- interface{}) { if self.ch == nil { self.ch = &ch } self.callCount += 1 } func TestThrottle(t *testing.T) { testEvents := make(chan int) receivedEvents := make([]int, 0) wg := sync.WaitGroup{} fakeLog := log.New(io.Discard, "", log.Ltime) mockSleeper := MockSleeper{nil, 0} go func() { wg.Add(1) for e := range Throttle(testEvents, &wg, &mockSleeper, fakeLog) { receivedEvents = append(receivedEvents, e) } wg.Done() }() testEvents <- 1 testEvents <- 2 testEvents <- 3 *mockSleeper.ch <- nil testEvents <- 4 testEvents <- 5 testEvents <- 6 *mockSleeper.ch <- nil testEvents <- 7 close(testEvents) wg.Wait() assert.Equal(t, 3, mockSleeper.callCount) assert.Len(t, receivedEvents, 3) assert.Contains(t, receivedEvents, 3) assert.Contains(t, receivedEvents, 6) assert.Contains(t, receivedEvents, 7) }