infra/blueprint-test/pkg/utils/poll.go (59 lines of code) (raw):

/** * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package utils import ( "fmt" "time" "github.com/mitchellh/go-testing-interface" ) // Polls on a particular condition function while the returns true. // It fails the test if the condition is not met within numRetries. func Poll(t testing.TB, condition func() (bool, error), numRetries int, interval time.Duration) { err := PollE(t, condition, numRetries, interval) if err != nil { t.Fatalf("failed to pull provided condition after %d retries, last error: %v", numRetries, err) } } // Polls on a particular condition function while the returns true. // Returns an error if the condition is not met within numRetries. func PollE(t testing.TB, condition func() (bool, error), numRetries int, interval time.Duration) error { if numRetries < 0 { return &PollParameterError{"invalid value for numRetries. Must be >= 0"} } if interval <= 0 { return &PollParameterError{"invalid value for interval. Must be > 0"} } retry, err := condition() for count := 0; retry && count <= numRetries; count++ { time.Sleep(interval) if err != nil { GetLoggerFromT().Logf(t, "Received error while polling: %v", err) } GetLoggerFromT().Logf(t, "Retrying... %d", count+1) retry, err = condition() } if err != nil { return &PollConditionError{err: err, numRetries: numRetries} } if retry { return &PollRetryLimitExceededError{interval: interval, numRetries: numRetries} } return nil } // PollParameterError is returend by PollE when input parameters are invalid. type PollParameterError struct { msg string } func (e *PollParameterError) Error() string { return e.msg } // PollRetryLimitExceededError is returned by PollE when retries exceed numRetries. type PollRetryLimitExceededError struct { numRetries int interval time.Duration } func (e *PollRetryLimitExceededError) Error() string { return fmt.Sprintf("polling timed out after %d retries with %.2f second intervals", e.numRetries, e.interval.Seconds()) } // PollConditionError is an error returned on the final PollE attempt. type PollConditionError struct { err error numRetries int } func (e *PollConditionError) Error() string { return fmt.Sprintf("failed to pull provided condition after %d retries, last error: %v", e.numRetries, e.err) } func (e *PollConditionError) Unwrap() error { return e.err }