github.com/observiq/bindplane-agent@v1.51.0/internal/service/standalone_test.go (about) 1 // Copyright observIQ, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package service 16 17 import ( 18 "context" 19 "errors" 20 "testing" 21 "time" 22 23 "github.com/observiq/bindplane-agent/collector" 24 "github.com/observiq/bindplane-agent/collector/mocks" 25 "github.com/stretchr/testify/mock" 26 "github.com/stretchr/testify/require" 27 ) 28 29 func TestStandaloneCollectorService(t *testing.T) { 30 t.Run("Collector starts and stops normally", func(t *testing.T) { 31 col := mocks.NewMockCollector(t) 32 ctx, cancel := context.WithCancel(context.Background()) 33 defer cancel() 34 35 col.On("Run", ctx).Return(nil) 36 col.On("Status").Return((<-chan *collector.Status)(make(chan *collector.Status))) 37 col.On("Stop", mock.Anything).Return(nil) 38 39 srv := NewStandaloneCollectorService(col) 40 41 var err error 42 startedChan := make(chan struct{}) 43 go func() { 44 err = srv.Start(ctx) 45 close(startedChan) 46 }() 47 48 select { 49 case <-startedChan: // OK 50 case <-time.After(time.Second): 51 t.Fatalf("Start timed out") 52 } 53 54 require.NoError(t, err) 55 require.Equal(t, 0, len(srv.Error()), "error channel has elements in it!") 56 57 stoppedChan := make(chan struct{}) 58 go func() { 59 err = srv.Stop(context.Background()) 60 close(stoppedChan) 61 }() 62 63 select { 64 case <-stoppedChan: // OK 65 case <-time.After(time.Second): 66 t.Fatalf("Stop timed out") 67 } 68 69 require.NoError(t, err) 70 }) 71 72 t.Run("Collector.Run errors", func(t *testing.T) { 73 col := mocks.NewMockCollector(t) 74 runError := errors.New("run failed") 75 76 ctx, cancel := context.WithCancel(context.Background()) 77 defer cancel() 78 79 col.On("Run", ctx).Return(runError) 80 81 srv := NewStandaloneCollectorService(col) 82 83 var err error 84 startedChan := make(chan struct{}) 85 go func() { 86 err = srv.Start(ctx) 87 close(startedChan) 88 }() 89 90 select { 91 case <-startedChan: // OK 92 case <-time.After(time.Second): 93 t.Fatalf("Start timed out") 94 } 95 96 require.Error(t, err) 97 require.ErrorIs(t, err, runError) 98 require.Equal(t, 0, len(srv.Error()), "error channel has elements in it!") 99 }) 100 101 t.Run("Stop context is cancelled", func(t *testing.T) { 102 col := mocks.NewMockCollector(t) 103 104 ctx, cancel := context.WithCancel(context.Background()) 105 defer cancel() 106 107 col.On("Run", ctx).Return(nil) 108 col.On("Status").Return((<-chan *collector.Status)(make(chan *collector.Status))).Maybe() 109 col.On("Stop", mock.Anything).Run(func(_ mock.Arguments) { time.Sleep(100 * time.Second) }).Maybe() 110 111 srv := NewStandaloneCollectorService(col) 112 113 var err error 114 startedChan := make(chan struct{}) 115 go func() { 116 err = srv.Start(ctx) 117 close(startedChan) 118 }() 119 120 select { 121 case <-startedChan: // OK 122 case <-time.After(time.Second): 123 t.Fatalf("Start timed out") 124 } 125 126 require.NoError(t, err) 127 require.Equal(t, 0, len(srv.Error()), "error channel has elements in it!") 128 129 errChan := make(chan error, 1) 130 go func() { 131 ctx, cancel := context.WithCancel(context.Background()) 132 cancel() 133 134 errChan <- srv.Stop(ctx) 135 }() 136 137 select { 138 case err = <-errChan: // Get error and verify stop has finished 139 case <-time.After(time.Second): 140 t.Fatalf("Stop timed out") 141 } 142 143 require.Error(t, err) 144 require.ErrorIs(t, err, context.Canceled) 145 }) 146 147 t.Run("Collector status has an error", func(t *testing.T) { 148 col := mocks.NewMockCollector(t) 149 colStatusErr := errors.New("Collector errored") 150 colStatus := make(chan *collector.Status, 1) 151 colStatus <- &collector.Status{ 152 Running: false, 153 Err: colStatusErr, 154 } 155 156 ctx, cancel := context.WithCancel(context.Background()) 157 defer cancel() 158 159 col.On("Run", ctx).Return(nil) 160 col.On("Status").Return((<-chan *collector.Status)(colStatus)) 161 col.On("Stop", mock.Anything).Return(nil) 162 163 srv := NewStandaloneCollectorService(col) 164 165 var err error 166 startedChan := make(chan struct{}) 167 go func() { 168 err = srv.Start(ctx) 169 close(startedChan) 170 }() 171 172 select { 173 case <-startedChan: // OK 174 case <-time.After(2 * time.Second): 175 t.Fatalf("Start timed out") 176 } 177 178 require.NoError(t, err) 179 180 defer srv.Stop(context.Background()) 181 182 select { 183 case err := <-srv.Error(): 184 require.Equal(t, colStatusErr, err) 185 case <-time.After(time.Second): 186 t.Fatalf("Timed out waiting for error") 187 } 188 189 require.Equal(t, 0, len(srv.Error()), "error channel has elements in it!") 190 }) 191 192 t.Run("Collector status is not running", func(t *testing.T) { 193 col := mocks.NewMockCollector(t) 194 colStatus := make(chan *collector.Status, 1) 195 colStatus <- &collector.Status{ 196 Running: false, 197 } 198 199 ctx, cancel := context.WithCancel(context.Background()) 200 defer cancel() 201 202 col.On("Run", ctx).Return(nil) 203 col.On("Status").Return((<-chan *collector.Status)(colStatus)) 204 col.On("Stop", mock.Anything).Return(nil) 205 206 srv := NewStandaloneCollectorService(col) 207 208 var err error 209 startedChan := make(chan struct{}) 210 go func() { 211 err = srv.Start(ctx) 212 close(startedChan) 213 }() 214 215 select { 216 case <-startedChan: // OK 217 case <-time.After(2 * time.Second): 218 t.Fatalf("Start timed out") 219 } 220 221 require.NoError(t, err) 222 223 defer srv.Stop(context.Background()) 224 225 select { 226 case err := <-srv.Error(): 227 require.Contains(t, err.Error(), "collector unexpectedly stopped running") 228 case <-time.After(time.Second): 229 t.Fatalf("Timed out waiting for error") 230 } 231 232 require.Equal(t, 0, len(srv.Error()), "error channel has elements in it!") 233 }) 234 }