github.com/Jeffail/benthos/v3@v3.65.0/lib/broker/try_test.go (about) 1 package broker 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "sync" 8 "sync/atomic" 9 "testing" 10 "time" 11 12 "github.com/Jeffail/benthos/v3/lib/message" 13 "github.com/Jeffail/benthos/v3/lib/metrics" 14 "github.com/Jeffail/benthos/v3/lib/response" 15 "github.com/Jeffail/benthos/v3/lib/types" 16 ) 17 18 var _ types.Consumer = &Try{} 19 var _ types.Closable = &Try{} 20 21 func TestTryDoubleClose(t *testing.T) { 22 oTM, err := NewTry([]types.Output{&MockOutputType{}}, metrics.Noop()) 23 if err != nil { 24 t.Fatal(err) 25 } 26 27 // This shouldn't cause a panic 28 oTM.CloseAsync() 29 oTM.CloseAsync() 30 } 31 32 //------------------------------------------------------------------------------ 33 34 func TestTryHappyPath(t *testing.T) { 35 outputs := []types.Output{} 36 mockOutputs := []*MockOutputType{ 37 {}, 38 {}, 39 {}, 40 } 41 42 for _, o := range mockOutputs { 43 outputs = append(outputs, o) 44 } 45 46 readChan := make(chan types.Transaction) 47 resChan := make(chan types.Response) 48 49 oTM, err := NewTry(outputs, metrics.Noop()) 50 if err != nil { 51 t.Error(err) 52 return 53 } 54 if err = oTM.Consume(readChan); err != nil { 55 t.Error(err) 56 return 57 } 58 59 for i := 0; i < 10; i++ { 60 content := [][]byte{[]byte(fmt.Sprintf("hello world %v", i))} 61 select { 62 case readChan <- types.NewTransaction(message.New(content), resChan): 63 case <-time.After(time.Second): 64 t.Errorf("Timed out waiting for broker send") 65 return 66 } 67 68 go func() { 69 var ts types.Transaction 70 select { 71 case ts = <-mockOutputs[0].TChan: 72 if !bytes.Equal(ts.Payload.Get(0).Get(), content[0]) { 73 t.Errorf("Wrong content returned %s != %s", ts.Payload.Get(0).Get(), content[0]) 74 } 75 case <-mockOutputs[1].TChan: 76 t.Error("Received message in wrong order") 77 return 78 case <-mockOutputs[2].TChan: 79 t.Error("Received message in wrong order") 80 return 81 case <-time.After(time.Second): 82 t.Errorf("Timed out waiting for broker propagate") 83 return 84 } 85 86 select { 87 case ts.ResponseChan <- response.NewAck(): 88 case <-time.After(time.Second): 89 t.Errorf("Timed out responding to broker") 90 return 91 } 92 }() 93 94 select { 95 case res := <-resChan: 96 if res.Error() != nil { 97 t.Error(res.Error()) 98 } 99 case <-time.After(time.Second): 100 t.Errorf("Timed out responding to broker") 101 return 102 } 103 } 104 105 oTM.CloseAsync() 106 if err := oTM.WaitForClose(time.Second * 10); err != nil { 107 t.Error(err) 108 } 109 } 110 111 func TestTryHappyishPath(t *testing.T) { 112 outputs := []types.Output{} 113 mockOutputs := []*MockOutputType{ 114 {}, 115 {}, 116 {}, 117 } 118 119 for _, o := range mockOutputs { 120 outputs = append(outputs, o) 121 } 122 123 readChan := make(chan types.Transaction) 124 resChan := make(chan types.Response) 125 126 oTM, err := NewTry(outputs, metrics.Noop()) 127 if err != nil { 128 t.Error(err) 129 return 130 } 131 if err = oTM.Consume(readChan); err != nil { 132 t.Error(err) 133 return 134 } 135 136 for i := 0; i < 10; i++ { 137 content := [][]byte{[]byte(fmt.Sprintf("hello world %v", i))} 138 select { 139 case readChan <- types.NewTransaction(message.New(content), resChan): 140 case <-time.After(time.Second): 141 t.Errorf("Timed out waiting for broker send") 142 return 143 } 144 145 go func() { 146 var ts types.Transaction 147 select { 148 case ts = <-mockOutputs[0].TChan: 149 if !bytes.Equal(ts.Payload.Get(0).Get(), content[0]) { 150 t.Errorf("Wrong content returned %s != %s", ts.Payload.Get(0).Get(), content[0]) 151 } 152 case <-mockOutputs[1].TChan: 153 t.Error("Received message in wrong order") 154 return 155 case <-mockOutputs[2].TChan: 156 t.Error("Received message in wrong order") 157 return 158 case <-time.After(time.Second): 159 t.Errorf("Timed out waiting for broker propagate") 160 return 161 } 162 163 select { 164 case ts.ResponseChan <- response.NewError(errors.New("test err")): 165 case <-time.After(time.Second): 166 t.Errorf("Timed out responding to broker") 167 return 168 } 169 170 select { 171 case ts = <-mockOutputs[1].TChan: 172 if !bytes.Equal(ts.Payload.Get(0).Get(), content[0]) { 173 t.Errorf("Wrong content returned %s != %s", ts.Payload.Get(0).Get(), content[0]) 174 } 175 case <-mockOutputs[0].TChan: 176 t.Error("Received message in wrong order") 177 return 178 case <-mockOutputs[2].TChan: 179 t.Error("Received message in wrong order") 180 return 181 case <-time.After(time.Second): 182 t.Errorf("Timed out waiting for broker propagate") 183 return 184 } 185 186 select { 187 case ts.ResponseChan <- response.NewAck(): 188 case <-time.After(time.Second): 189 t.Errorf("Timed out responding to broker") 190 return 191 } 192 }() 193 194 select { 195 case res := <-resChan: 196 if res.Error() != nil { 197 t.Error(res.Error()) 198 } 199 case <-time.After(time.Second): 200 t.Errorf("Timed out responding to broker") 201 return 202 } 203 } 204 205 oTM.CloseAsync() 206 if err := oTM.WaitForClose(time.Second * 10); err != nil { 207 t.Error(err) 208 } 209 } 210 211 func TestTryAllFail(t *testing.T) { 212 outputs := []types.Output{} 213 mockOutputs := []*MockOutputType{ 214 {}, 215 {}, 216 {}, 217 } 218 219 for _, o := range mockOutputs { 220 outputs = append(outputs, o) 221 } 222 223 readChan := make(chan types.Transaction) 224 resChan := make(chan types.Response) 225 226 oTM, err := NewTry(outputs, metrics.Noop()) 227 if err != nil { 228 t.Fatal(err) 229 } 230 if err = oTM.Consume(readChan); err != nil { 231 t.Fatal(err) 232 } 233 234 for i := 0; i < 10; i++ { 235 content := [][]byte{[]byte(fmt.Sprintf("hello world %v", i))} 236 select { 237 case readChan <- types.NewTransaction(message.New(content), resChan): 238 case <-time.After(time.Second): 239 t.Fatalf("Timed out waiting for broker send") 240 } 241 242 testErr := errors.New("test error") 243 go func() { 244 for j := 0; j < 3; j++ { 245 var ts types.Transaction 246 select { 247 case ts = <-mockOutputs[j%3].TChan: 248 if !bytes.Equal(ts.Payload.Get(0).Get(), content[0]) { 249 t.Errorf("Wrong content returned %s != %s", ts.Payload.Get(0).Get(), content[0]) 250 } 251 case <-mockOutputs[(j+1)%3].TChan: 252 t.Errorf("Received message in wrong order: %v != %v", j%3, (j+1)%3) 253 return 254 case <-mockOutputs[(j+2)%3].TChan: 255 t.Errorf("Received message in wrong order: %v != %v", j%3, (j+2)%3) 256 return 257 case <-time.After(time.Second): 258 t.Errorf("Timed out waiting for broker propagate") 259 return 260 } 261 262 select { 263 case ts.ResponseChan <- response.NewError(testErr): 264 case <-time.After(time.Second): 265 t.Errorf("Timed out responding to broker") 266 } 267 } 268 }() 269 270 select { 271 case res := <-resChan: 272 if exp, act := testErr, res.Error(); exp != act { 273 t.Errorf("Wrong error returned: %v != %v", act, exp) 274 } 275 case <-time.After(time.Second): 276 t.Fatal("Timed out responding to broker") 277 } 278 } 279 280 oTM.CloseAsync() 281 if err := oTM.WaitForClose(time.Second * 10); err != nil { 282 t.Error(err) 283 } 284 } 285 286 func TestTryAllFailParallel(t *testing.T) { 287 outputs := []types.Output{} 288 mockOutputs := []*MockOutputType{ 289 {}, 290 {}, 291 {}, 292 } 293 294 for _, o := range mockOutputs { 295 outputs = append(outputs, o) 296 } 297 298 readChan := make(chan types.Transaction) 299 300 oTM, err := NewTry(outputs, metrics.Noop()) 301 if err != nil { 302 t.Fatal(err) 303 } 304 oTM = oTM.WithMaxInFlight(50) 305 if err = oTM.Consume(readChan); err != nil { 306 t.Fatal(err) 307 } 308 309 resChans := make([]chan types.Response, 10) 310 for i := range resChans { 311 resChans[i] = make(chan types.Response) 312 } 313 314 tallies := [3]int32{} 315 316 wg, wgStart := sync.WaitGroup{}, sync.WaitGroup{} 317 testErr := errors.New("test error") 318 startChan := make(chan struct{}) 319 for _, resChan := range resChans { 320 wg.Add(1) 321 wgStart.Add(1) 322 go func() { 323 defer wg.Done() 324 for j := 0; j < 3; j++ { 325 var ts types.Transaction 326 var index int 327 select { 328 case ts = <-mockOutputs[j%3].TChan: 329 index = j % 3 330 case ts = <-mockOutputs[(j+1)%3].TChan: 331 index = (j + 1) % 3 332 case ts = <-mockOutputs[(j+2)%3].TChan: 333 index = (j + 2) % 3 334 case <-time.After(time.Second): 335 t.Errorf("Timed out waiting for broker propagate") 336 if j == 0 { 337 wgStart.Done() 338 } 339 return 340 } 341 atomic.AddInt32(&tallies[index], 1) 342 if j == 0 { 343 wgStart.Done() 344 } 345 346 <-startChan 347 348 select { 349 case ts.ResponseChan <- response.NewError(testErr): 350 case <-time.After(time.Second): 351 t.Errorf("Timed out responding to broker") 352 } 353 } 354 }() 355 select { 356 case readChan <- types.NewTransaction(message.New([][]byte{[]byte("foo")}), resChan): 357 case <-time.After(time.Second): 358 t.Fatalf("Timed out waiting for broker send") 359 } 360 } 361 wgStart.Wait() 362 close(startChan) 363 364 for _, resChan := range resChans { 365 select { 366 case res := <-resChan: 367 if exp, act := testErr, res.Error(); exp != act { 368 t.Errorf("Wrong error returned: %v != %v", act, exp) 369 } 370 case <-time.After(time.Second): 371 t.Error("Timed out responding to broker") 372 } 373 } 374 375 wg.Wait() 376 for _, tally := range tallies { 377 if int(tally) != len(resChans) { 378 t.Errorf("Wrong count of propagated messages: %v", tally) 379 } 380 } 381 382 oTM.CloseAsync() 383 if err := oTM.WaitForClose(time.Second * 10); err != nil { 384 t.Error(err) 385 } 386 } 387 388 //------------------------------------------------------------------------------