github.com/smartcontractkit/chainlink-testing-framework/libs@v0.0.0-20240227141906-ec710b4eb1a3/docker/test_env/wait_strategies.go (about)

     1  package test_env
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"regexp"
     8  	"time"
     9  
    10  	tcwait "github.com/testcontainers/testcontainers-go/wait"
    11  )
    12  
    13  type LogRegexStrategy struct {
    14  	timeout      *time.Duration
    15  	Pattern      *regexp.Regexp
    16  	Occurrence   int
    17  	PollInterval time.Duration
    18  }
    19  
    20  func NewLogRegexStrategy(pattern *regexp.Regexp) *LogRegexStrategy {
    21  	return &LogRegexStrategy{
    22  		Pattern:      pattern,
    23  		Occurrence:   1,
    24  		PollInterval: defaultPollInterval(),
    25  	}
    26  }
    27  
    28  func (ws *LogRegexStrategy) WithStartupTimeout(timeout time.Duration) *LogRegexStrategy {
    29  	ws.timeout = &timeout
    30  	return ws
    31  }
    32  
    33  // WithPollInterval can be used to override the default polling interval of 100 milliseconds
    34  func (ws *LogRegexStrategy) WithPollInterval(pollInterval time.Duration) *LogRegexStrategy {
    35  	ws.PollInterval = pollInterval
    36  	return ws
    37  }
    38  
    39  func (ws *LogRegexStrategy) WithOccurrence(o int) *LogRegexStrategy {
    40  	// the number of occurrence needs to be positive
    41  	if o <= 0 {
    42  		o = 1
    43  	}
    44  	ws.Occurrence = o
    45  	return ws
    46  }
    47  
    48  // WaitUntilReady implements Strategy.WaitUntilReady
    49  func (ws *LogRegexStrategy) WaitUntilReady(ctx context.Context, target tcwait.StrategyTarget) (err error) {
    50  	timeout := defaultStartupTimeout()
    51  	if ws.timeout != nil {
    52  		timeout = *ws.timeout
    53  	}
    54  
    55  	ctx, cancel := context.WithTimeout(ctx, timeout)
    56  	defer cancel()
    57  
    58  	length := 0
    59  
    60  LOOP:
    61  	for {
    62  		select {
    63  		case <-ctx.Done():
    64  			return ctx.Err()
    65  		default:
    66  			state, err := target.State(ctx)
    67  			if err != nil {
    68  				return err
    69  			}
    70  			if !state.Running {
    71  				return fmt.Errorf("container is not running %s", state.Status)
    72  			}
    73  
    74  			reader, err := target.Logs(ctx)
    75  			if err != nil {
    76  				time.Sleep(ws.PollInterval)
    77  				continue
    78  			}
    79  
    80  			b, err := io.ReadAll(reader)
    81  			if err != nil {
    82  				time.Sleep(ws.PollInterval)
    83  				continue
    84  			}
    85  
    86  			logs := string(b)
    87  			if length == len(logs) && err != nil {
    88  				return err
    89  			} else if len(ws.Pattern.FindAllString(logs, -1)) >= ws.Occurrence {
    90  				break LOOP
    91  			} else {
    92  				length = len(logs)
    93  				time.Sleep(ws.PollInterval)
    94  				continue
    95  			}
    96  		}
    97  	}
    98  
    99  	return nil
   100  }
   101  
   102  func defaultStartupTimeout() time.Duration {
   103  	return 60 * time.Second
   104  }
   105  
   106  func defaultPollInterval() time.Duration {
   107  	return 100 * time.Millisecond
   108  }