backend: Faster remote backend tests

The remote backend tests spent most of their execution time sleeping in
various polling and backoff waits. This is unnecessary when testing
against a mock server, so reduce all of these delays when under test to
much lower values.

Only one remaining test has an artificial delay: verifying the discovery
of services against an unknown hostname. This times out at DNS
resolution, which is more difficult to fix than seems worth it at this
time.
This commit is contained in:
Alisdair McDiarmid 2020-11-18 15:35:48 -05:00
parent db82b80c9d
commit eee57280f6
6 changed files with 31 additions and 15 deletions

View File

@ -542,8 +542,8 @@ func TestRemote_applyApprovedExternally(t *testing.T) {
t.Fatalf("error starting operation: %v", err) t.Fatalf("error starting operation: %v", err)
} }
// Wait 2 seconds to make sure the run started. // Wait 50 milliseconds to make sure the run started.
time.Sleep(2 * time.Second) time.Sleep(50 * time.Millisecond)
wl, err := b.client.Workspaces.List( wl, err := b.client.Workspaces.List(
ctx, ctx,
@ -617,8 +617,8 @@ func TestRemote_applyDiscardedExternally(t *testing.T) {
t.Fatalf("error starting operation: %v", err) t.Fatalf("error starting operation: %v", err)
} }
// Wait 2 seconds to make sure the run started. // Wait 50 milliseconds to make sure the run started.
time.Sleep(2 * time.Second) time.Sleep(50 * time.Millisecond)
wl, err := b.client.Workspaces.List( wl, err := b.client.Workspaces.List(
ctx, ctx,
@ -871,7 +871,7 @@ func TestRemote_applyLockTimeout(t *testing.T) {
"approve": "yes", "approve": "yes",
}) })
op.StateLockTimeout = 5 * time.Second op.StateLockTimeout = 50 * time.Millisecond
op.UIIn = input op.UIIn = input
op.UIOut = b.CLI op.UIOut = b.CLI
op.Workspace = backend.DefaultStateName op.Workspace = backend.DefaultStateName
@ -887,8 +887,8 @@ func TestRemote_applyLockTimeout(t *testing.T) {
case <-sigint: case <-sigint:
// Stop redirecting SIGINT signals. // Stop redirecting SIGINT signals.
signal.Stop(sigint) signal.Stop(sigint)
case <-time.After(10 * time.Second): case <-time.After(200 * time.Millisecond):
t.Fatalf("expected lock timeout after 5 seconds, waited 10 seconds") t.Fatalf("expected lock timeout after 50 milliseconds, waited 200 milliseconds")
} }
if len(input.answers) != 2 { if len(input.answers) != 2 {

View File

@ -24,6 +24,13 @@ var (
errRunOverridden = errors.New("overridden using the UI or API") errRunOverridden = errors.New("overridden using the UI or API")
) )
var (
backoffMin = 1000.0
backoffMax = 3000.0
runPollInterval = 3 * time.Second
)
// backoff will perform exponential backoff based on the iteration and // backoff will perform exponential backoff based on the iteration and
// limited by the provided min and max (in milliseconds) durations. // limited by the provided min and max (in milliseconds) durations.
func backoff(min, max float64, iter int) time.Duration { func backoff(min, max float64, iter int) time.Duration {
@ -43,7 +50,7 @@ func (b *Remote) waitForRun(stopCtx, cancelCtx context.Context, op *backend.Oper
return r, stopCtx.Err() return r, stopCtx.Err()
case <-cancelCtx.Done(): case <-cancelCtx.Done():
return r, cancelCtx.Err() return r, cancelCtx.Err()
case <-time.After(backoff(1000, 3000, i)): case <-time.After(backoff(backoffMin, backoffMax, i)):
// Timer up, show status // Timer up, show status
} }
@ -260,7 +267,7 @@ func (b *Remote) costEstimate(stopCtx, cancelCtx context.Context, op *backend.Op
return stopCtx.Err() return stopCtx.Err()
case <-cancelCtx.Done(): case <-cancelCtx.Done():
return cancelCtx.Err() return cancelCtx.Err()
case <-time.After(1 * time.Second): case <-time.After(backoff(backoffMin, backoffMax, i)):
} }
// Retrieve the cost estimate to get its current status. // Retrieve the cost estimate to get its current status.
@ -454,7 +461,7 @@ func (b *Remote) confirm(stopCtx context.Context, op *backend.Operation, opts *t
return return
case <-stopCtx.Done(): case <-stopCtx.Done():
return return
case <-time.After(3 * time.Second): case <-time.After(runPollInterval):
// Retrieve the run again to get its current status. // Retrieve the run again to get its current status.
r, err := b.client.Runs.Read(stopCtx, r.ID) r, err := b.client.Runs.Read(stopCtx, r.ID)
if err != nil { if err != nil {

View File

@ -360,7 +360,7 @@ func (m *mockLogReader) Read(l []byte) (int, error) {
if written, err := m.read(l); err != io.ErrNoProgress { if written, err := m.read(l); err != io.ErrNoProgress {
return written, err return written, err
} }
time.Sleep(500 * time.Millisecond) time.Sleep(1 * time.Millisecond)
} }
} }

View File

@ -20,6 +20,8 @@ import (
"github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/tfdiags"
) )
var planConfigurationVersionsPollInterval = 500 * time.Millisecond
func (b *Remote) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) { func (b *Remote) opPlan(stopCtx, cancelCtx context.Context, op *backend.Operation, w *tfe.Workspace) (*tfe.Run, error) {
log.Printf("[INFO] backend/remote: starting Plan operation") log.Printf("[INFO] backend/remote: starting Plan operation")
@ -213,7 +215,7 @@ in order to capture the filesystem context the remote workspace expects:
return nil, context.Canceled return nil, context.Canceled
case <-cancelCtx.Done(): case <-cancelCtx.Done():
return nil, context.Canceled return nil, context.Canceled
case <-time.After(500 * time.Millisecond): case <-time.After(planConfigurationVersionsPollInterval):
cv, err = b.client.ConfigurationVersions.Read(stopCtx, cv.ID) cv, err = b.client.ConfigurationVersions.Read(stopCtx, cv.ID)
if err != nil { if err != nil {
return nil, generalError("Failed to retrieve configuration version", err) return nil, generalError("Failed to retrieve configuration version", err)

View File

@ -620,7 +620,7 @@ func TestRemote_planLockTimeout(t *testing.T) {
"approve": "yes", "approve": "yes",
}) })
op.StateLockTimeout = 5 * time.Second op.StateLockTimeout = 50 * time.Millisecond
op.UIIn = input op.UIIn = input
op.UIOut = b.CLI op.UIOut = b.CLI
op.Workspace = backend.DefaultStateName op.Workspace = backend.DefaultStateName
@ -636,8 +636,8 @@ func TestRemote_planLockTimeout(t *testing.T) {
case <-sigint: case <-sigint:
// Stop redirecting SIGINT signals. // Stop redirecting SIGINT signals.
signal.Stop(sigint) signal.Stop(sigint)
case <-time.After(10 * time.Second): case <-time.After(200 * time.Millisecond):
t.Fatalf("expected lock timeout after 5 seconds, waited 10 seconds") t.Fatalf("expected lock timeout after 50 milliseconds, waited 200 milliseconds")
} }
if len(input.answers) != 2 { if len(input.answers) != 2 {

View File

@ -4,6 +4,7 @@ import (
"flag" "flag"
"os" "os"
"testing" "testing"
"time"
_ "github.com/hashicorp/terraform/internal/logging" _ "github.com/hashicorp/terraform/internal/logging"
) )
@ -14,5 +15,11 @@ func TestMain(m *testing.M) {
// Make sure TF_FORCE_LOCAL_BACKEND is unset // Make sure TF_FORCE_LOCAL_BACKEND is unset
os.Unsetenv("TF_FORCE_LOCAL_BACKEND") os.Unsetenv("TF_FORCE_LOCAL_BACKEND")
// Reduce delays to make tests run faster
backoffMin = 1.0
backoffMax = 1.0
planConfigurationVersionsPollInterval = 1 * time.Millisecond
runPollInterval = 1 * time.Millisecond
os.Exit(m.Run()) os.Exit(m.Run())
} }