github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/testutils/soon.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package testutils
    12  
    13  import (
    14  	"context"
    15  	"runtime/debug"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/util/log"
    20  	"github.com/cockroachdb/cockroach/pkg/util/retry"
    21  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    22  )
    23  
    24  // DefaultSucceedsSoonDuration is the maximum amount of time unittests
    25  // will wait for a condition to become true. See SucceedsSoon().
    26  const DefaultSucceedsSoonDuration = 45 * time.Second
    27  
    28  // SucceedsSoon fails the test (with t.Fatal) unless the supplied
    29  // function runs without error within a preset maximum duration. The
    30  // function is invoked immediately at first and then successively with
    31  // an exponential backoff starting at 1ns and ending at around 1s.
    32  func SucceedsSoon(t testing.TB, fn func() error) {
    33  	t.Helper()
    34  	if err := SucceedsSoonError(fn); err != nil {
    35  		t.Fatalf("condition failed to evaluate within %s: %s\n%s",
    36  			DefaultSucceedsSoonDuration, err, string(debug.Stack()))
    37  	}
    38  }
    39  
    40  // SucceedsSoonError returns an error unless the supplied function runs without
    41  // error within a preset maximum duration. The function is invoked immediately
    42  // at first and then successively with an exponential backoff starting at 1ns
    43  // and ending at around 1s.
    44  func SucceedsSoonError(fn func() error) error {
    45  	tBegin := timeutil.Now()
    46  	wrappedFn := func() error {
    47  		err := fn()
    48  		if timeutil.Since(tBegin) > 3*time.Second && err != nil {
    49  			log.InfofDepth(context.Background(), 4, "SucceedsSoon: %v", err)
    50  		}
    51  		return err
    52  	}
    53  	return retry.ForDuration(DefaultSucceedsSoonDuration, wrappedFn)
    54  }