github.com/observiq/bindplane-agent@v1.51.0/internal/service/service_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/internal/service/mocks" 24 "github.com/stretchr/testify/mock" 25 "github.com/stretchr/testify/require" 26 "go.uber.org/zap" 27 ) 28 29 func TestRunServiceInteractive(t *testing.T) { 30 t.Run("Normal start/stop", func(t *testing.T) { 31 svc := &mocks.MockRunnableService{} 32 33 ctx, cancel := context.WithCancel(context.Background()) 34 35 svc.On("Start", mock.Anything).Return(nil) 36 svc.On("Error").Return((<-chan error)(make(chan error))) 37 svc.On("Stop", mock.Anything).Return(nil) 38 39 var err error 40 svcDone := make(chan struct{}) 41 go func() { 42 err = runServiceInteractive(ctx, zap.NewNop(), svc) 43 close(svcDone) 44 }() 45 46 <-time.After(500 * time.Millisecond) 47 cancel() 48 49 select { 50 case <-svcDone: // OK 51 case <-time.After(1 * time.Second): 52 t.Fatalf("Timed out waiting for service done") 53 } 54 55 require.NoError(t, err) 56 }) 57 58 t.Run("Start fails", func(t *testing.T) { 59 svc := &mocks.MockRunnableService{} 60 61 startErr := errors.New("failed to start") 62 63 svc.On("Start", mock.Anything).Return(startErr) 64 65 ctx, cancel := context.WithCancel(context.Background()) 66 defer cancel() 67 68 var err error 69 svcDone := make(chan struct{}) 70 go func() { 71 err = runServiceInteractive(ctx, zap.NewNop(), svc) 72 close(svcDone) 73 }() 74 75 select { 76 case <-svcDone: // OK 77 case <-time.After(1 * time.Second): 78 t.Fatalf("Timed out waiting for service done") 79 } 80 81 require.Error(t, err) 82 require.ErrorIs(t, err, startErr) 83 }) 84 85 t.Run("Service errors", func(t *testing.T) { 86 svc := &mocks.MockRunnableService{} 87 88 svcErr := errors.New("service unexpectedly failed") 89 errChan := make(chan error, 1) 90 errChan <- svcErr 91 92 svc.On("Start", mock.Anything).Return(nil) 93 svc.On("Error").Return((<-chan error)(errChan)) 94 svc.On("Stop", mock.Anything).Return(nil) 95 96 ctx, cancel := context.WithCancel(context.Background()) 97 defer cancel() 98 99 var err error 100 svcDone := make(chan struct{}) 101 go func() { 102 err = runServiceInteractive(ctx, zap.NewNop(), svc) 103 close(svcDone) 104 }() 105 106 select { 107 case <-svcDone: // OK 108 case <-time.After(1 * time.Second): 109 t.Fatalf("Timed out waiting for service done") 110 } 111 112 require.Error(t, err) 113 require.ErrorIs(t, err, svcErr) 114 }) 115 116 t.Run("Stop errors", func(t *testing.T) { 117 svc := &mocks.MockRunnableService{} 118 119 stopErr := errors.New("Stop failed") 120 121 svc.On("Start", mock.Anything).Return(nil) 122 svc.On("Error").Return((<-chan error)(make(chan error))) 123 svc.On("Stop", mock.Anything).Return(stopErr) 124 125 ctx, cancel := context.WithCancel(context.Background()) 126 127 var err error 128 svcDone := make(chan struct{}) 129 go func() { 130 err = runServiceInteractive(ctx, zap.NewNop(), svc) 131 close(svcDone) 132 }() 133 134 <-time.After(500 * time.Millisecond) 135 cancel() 136 137 select { 138 case <-svcDone: // OK 139 case <-time.After(1 * time.Second): 140 t.Fatalf("Timed out waiting for service done") 141 } 142 143 require.Error(t, err) 144 require.ErrorIs(t, err, stopErr) 145 }) 146 147 t.Run("Stop errors after error returned", func(t *testing.T) { 148 svc := &mocks.MockRunnableService{} 149 150 stopErr := errors.New("Stop failed") 151 svcErr := errors.New("service unexpectedly failed") 152 errChan := make(chan error, 1) 153 errChan <- svcErr 154 155 svc.On("Start", mock.Anything).Return(nil) 156 svc.On("Error").Return((<-chan error)(errChan)) 157 svc.On("Stop", mock.Anything).Return(stopErr) 158 159 ctx, cancel := context.WithCancel(context.Background()) 160 defer cancel() 161 162 var err error 163 svcDone := make(chan struct{}) 164 go func() { 165 err = runServiceInteractive(ctx, zap.NewNop(), svc) 166 close(svcDone) 167 }() 168 169 select { 170 case <-svcDone: // OK 171 case <-time.After(1 * time.Second): 172 t.Fatalf("Timed out waiting for service done") 173 } 174 175 require.Error(t, err) 176 require.ErrorIs(t, err, stopErr) 177 }) 178 }