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  }