github.com/iotexproject/iotex-core@v1.14.1-rc1/testutil/wait.go (about) 1 // Copyright (c) 2018 IoTeX 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package testutil 7 8 import ( 9 "time" 10 11 "github.com/pkg/errors" 12 ) 13 14 // ErrTimeout is returned when time is up 15 var ErrTimeout = errors.New("timed out") 16 17 // CheckCondition defines a func type that checks whether a certain condition is satisfied 18 type CheckCondition func() (bool, error) 19 20 // SignalChan returns a channel that will be written every interval until timeout 21 func SignalChan(interval, timeout time.Duration) <-chan struct{} { 22 ch := make(chan struct{}) 23 24 go func() { 25 defer close(ch) 26 tick := time.NewTicker(interval) 27 defer tick.Stop() 28 29 var after <-chan time.Time 30 if timeout != 0 { 31 timer := time.NewTimer(timeout) 32 after = timer.C 33 defer timer.Stop() 34 } 35 // Signal channel every interval time period 36 for { 37 select { 38 case <-tick.C: 39 select { 40 case ch <- struct{}{}: 41 default: 42 } 43 // Timeout 44 case <-after: 45 return 46 } 47 } 48 }() 49 return ch 50 } 51 52 // WaitUntil periodically checks whether the condition specified in CheckCondition function is satisfied 53 // If an error is returned, it either comes from CheckCondition function or time is up before the given 54 // condition is satisfied 55 func WaitUntil(interval, timeout time.Duration, f CheckCondition) error { 56 ch := SignalChan(interval, timeout) 57 for { 58 _, open := <-ch 59 satisfied, err := f() 60 if satisfied { 61 return nil 62 } 63 if err != nil { 64 return err 65 } 66 // If channel is closed, the maximum waiting time is reached and a timeout error is returned 67 if !open { 68 return ErrTimeout 69 } 70 } 71 }