From 47a00ea34b3b866f2b30a99da8bb495334799bbd Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Wed, 6 Feb 2019 09:36:42 +0100 Subject: [PATCH] backend/remote: cleanup test connections Cleanup test connection to prevent file descriptor issues when running the tests on a Mac. --- backend/remote/backend.go | 5 -- backend/remote/backend_apply_test.go | 74 +++++++++++++++++++--------- backend/remote/backend_mock.go | 5 +- backend/remote/backend_plan_test.go | 65 ++++++++++++++++-------- backend/remote/backend_state_test.go | 3 +- backend/remote/backend_test.go | 30 +++++++---- backend/remote/testing.go | 22 +++++---- svchost/disco/host.go | 4 +- 8 files changed, 132 insertions(+), 76 deletions(-) diff --git a/backend/remote/backend.go b/backend/remote/backend.go index b8d08ebbb..93a78d52b 100644 --- a/backend/remote/backend.go +++ b/backend/remote/backend.go @@ -336,11 +336,6 @@ func (b *Remote) discover() (*url.URL, *disco.Constraints, error) { return nil, nil, err } - // Return early if we are a development build. - if tfversion.Prerelease == "dev" { - return service, nil, err - } - // We purposefully ignore the error and return the previous error, as // checking for version constraints is considered optional. constraints, _ := host.VersionConstraints(tfeServiceID, "terraform") diff --git a/backend/remote/backend_apply_test.go b/backend/remote/backend_apply_test.go index f78d35dd6..c27b747ef 100644 --- a/backend/remote/backend_apply_test.go +++ b/backend/remote/backend_apply_test.go @@ -33,7 +33,8 @@ func testOperationApply(t *testing.T, configDir string) (*backend.Operation, fun } func TestRemote_applyBasic(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply") defer configCleanup() @@ -76,7 +77,8 @@ func TestRemote_applyBasic(t *testing.T) { } func TestRemote_applyWithoutPermissions(t *testing.T) { - b := testBackendNoDefault(t) + b, bCleanup := testBackendNoDefault(t) + defer bCleanup() // Create a named workspace without permissions. w, err := b.client.Workspaces.Create( @@ -114,7 +116,8 @@ func TestRemote_applyWithoutPermissions(t *testing.T) { } func TestRemote_applyWithVCS(t *testing.T) { - b := testBackendNoDefault(t) + b, bCleanup := testBackendNoDefault(t) + defer bCleanup() // Create a named workspace with a VCS. _, err := b.client.Workspaces.Create( @@ -154,7 +157,8 @@ func TestRemote_applyWithVCS(t *testing.T) { } func TestRemote_applyWithParallelism(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply") defer configCleanup() @@ -179,7 +183,8 @@ func TestRemote_applyWithParallelism(t *testing.T) { } func TestRemote_applyWithPlan(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply") defer configCleanup() @@ -207,7 +212,8 @@ func TestRemote_applyWithPlan(t *testing.T) { } func TestRemote_applyWithoutRefresh(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply") defer configCleanup() @@ -232,7 +238,8 @@ func TestRemote_applyWithoutRefresh(t *testing.T) { } func TestRemote_applyWithTarget(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply") defer configCleanup() @@ -262,7 +269,8 @@ func TestRemote_applyWithTarget(t *testing.T) { } func TestRemote_applyWithVariables(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply-variables") defer configCleanup() @@ -287,7 +295,8 @@ func TestRemote_applyWithVariables(t *testing.T) { } func TestRemote_applyNoConfig(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/empty") defer configCleanup() @@ -314,7 +323,8 @@ func TestRemote_applyNoConfig(t *testing.T) { } func TestRemote_applyNoChanges(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply-no-changes") defer configCleanup() @@ -344,7 +354,8 @@ func TestRemote_applyNoChanges(t *testing.T) { } func TestRemote_applyNoApprove(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply") defer configCleanup() @@ -381,7 +392,8 @@ func TestRemote_applyNoApprove(t *testing.T) { } func TestRemote_applyAutoApprove(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply") defer configCleanup() @@ -425,7 +437,8 @@ func TestRemote_applyAutoApprove(t *testing.T) { } func TestRemote_applyWithAutoApply(t *testing.T) { - b := testBackendNoDefault(t) + b, bCleanup := testBackendNoDefault(t) + defer bCleanup() // Create a named workspace that auto applies. _, err := b.client.Workspaces.Create( @@ -488,7 +501,8 @@ func TestRemote_applyForceLocal(t *testing.T) { } defer os.Unsetenv("TF_FORCE_LOCAL_BACKEND") - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply") defer configCleanup() @@ -531,7 +545,9 @@ func TestRemote_applyForceLocal(t *testing.T) { } func TestRemote_applyWorkspaceWithoutOperations(t *testing.T) { - b := testBackendNoDefault(t) + b, bCleanup := testBackendNoDefault(t) + defer bCleanup() + ctx := context.Background() // Create a named workspace that doesn't allow operations. @@ -587,7 +603,9 @@ func TestRemote_applyWorkspaceWithoutOperations(t *testing.T) { } func TestRemote_applyLockTimeout(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() + ctx := context.Background() // Retrieve the workspace used to run this operation in. @@ -659,7 +677,8 @@ func TestRemote_applyLockTimeout(t *testing.T) { } func TestRemote_applyDestroy(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply-destroy") defer configCleanup() @@ -703,7 +722,8 @@ func TestRemote_applyDestroy(t *testing.T) { } func TestRemote_applyDestroyNoConfig(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() input := testInput(t, map[string]string{ "approve": "yes", @@ -736,7 +756,8 @@ func TestRemote_applyDestroyNoConfig(t *testing.T) { } func TestRemote_applyPolicyPass(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply-policy-passed") defer configCleanup() @@ -782,7 +803,8 @@ func TestRemote_applyPolicyPass(t *testing.T) { } func TestRemote_applyPolicyHardFail(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply-policy-hard-failed") defer configCleanup() @@ -833,7 +855,8 @@ func TestRemote_applyPolicyHardFail(t *testing.T) { } func TestRemote_applyPolicySoftFail(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply-policy-soft-failed") defer configCleanup() @@ -880,7 +903,8 @@ func TestRemote_applyPolicySoftFail(t *testing.T) { } func TestRemote_applyPolicySoftFailAutoApprove(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply-policy-soft-failed") defer configCleanup() @@ -932,7 +956,8 @@ func TestRemote_applyPolicySoftFailAutoApprove(t *testing.T) { } func TestRemote_applyPolicySoftFailAutoApply(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() // Create a named workspace that auto applies. _, err := b.client.Workspaces.Create( @@ -992,7 +1017,8 @@ func TestRemote_applyPolicySoftFailAutoApply(t *testing.T) { } func TestRemote_applyWithRemoteError(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationApply(t, "./test-fixtures/apply-with-error") defer configCleanup() diff --git a/backend/remote/backend_mock.go b/backend/remote/backend_mock.go index 636062577..b623c04bd 100644 --- a/backend/remote/backend_mock.go +++ b/backend/remote/backend_mock.go @@ -620,9 +620,8 @@ func (m *mockRuns) List(ctx context.Context, workspaceID string, options tfe.Run return nil, tfe.ErrResourceNotFound } - rl := &tfe.RunList{} - for _, r := range m.workspaces[w.ID] { - rl.Items = append(rl.Items, r) + rl := &tfe.RunList{ + Items: m.workspaces[w.ID], } rl.Pagination = &tfe.Pagination{ diff --git a/backend/remote/backend_plan_test.go b/backend/remote/backend_plan_test.go index 6a5dc3e58..a43c06ae6 100644 --- a/backend/remote/backend_plan_test.go +++ b/backend/remote/backend_plan_test.go @@ -33,7 +33,8 @@ func testOperationPlan(t *testing.T, configDir string) (*backend.Operation, func } func TestRemote_planBasic(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -63,7 +64,8 @@ func TestRemote_planBasic(t *testing.T) { } func TestRemote_planWithoutPermissions(t *testing.T) { - b := testBackendNoDefault(t) + b, bCleanup := testBackendNoDefault(t) + defer bCleanup() // Create a named workspace without permissions. w, err := b.client.Workspaces.Create( @@ -100,7 +102,8 @@ func TestRemote_planWithoutPermissions(t *testing.T) { } func TestRemote_planWithParallelism(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -125,7 +128,8 @@ func TestRemote_planWithParallelism(t *testing.T) { } func TestRemote_planWithPlan(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -153,7 +157,8 @@ func TestRemote_planWithPlan(t *testing.T) { } func TestRemote_planWithPath(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -181,7 +186,8 @@ func TestRemote_planWithPath(t *testing.T) { } func TestRemote_planWithoutRefresh(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -206,7 +212,8 @@ func TestRemote_planWithoutRefresh(t *testing.T) { } func TestRemote_planWithTarget(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -236,7 +243,8 @@ func TestRemote_planWithTarget(t *testing.T) { } func TestRemote_planWithVariables(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan-variables") defer configCleanup() @@ -261,7 +269,8 @@ func TestRemote_planWithVariables(t *testing.T) { } func TestRemote_planNoConfig(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/empty") defer configCleanup() @@ -288,7 +297,8 @@ func TestRemote_planNoConfig(t *testing.T) { } func TestRemote_planNoChanges(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan-no-changes") defer configCleanup() @@ -325,7 +335,8 @@ func TestRemote_planForceLocal(t *testing.T) { } defer os.Unsetenv("TF_FORCE_LOCAL_BACKEND") - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -355,7 +366,8 @@ func TestRemote_planForceLocal(t *testing.T) { } func TestRemote_planWithoutOperationsEntitlement(t *testing.T) { - b := testBackendNoOperations(t) + b, bCleanup := testBackendNoOperations(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -385,7 +397,9 @@ func TestRemote_planWithoutOperationsEntitlement(t *testing.T) { } func TestRemote_planWorkspaceWithoutOperations(t *testing.T) { - b := testBackendNoDefault(t) + b, bCleanup := testBackendNoDefault(t) + defer bCleanup() + ctx := context.Background() // Create a named workspace that doesn't allow operations. @@ -428,7 +442,9 @@ func TestRemote_planWorkspaceWithoutOperations(t *testing.T) { } func TestRemote_planLockTimeout(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() + ctx := context.Background() // Retrieve the workspace used to run this operation in. @@ -497,7 +513,8 @@ func TestRemote_planLockTimeout(t *testing.T) { } func TestRemote_planDestroy(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan") defer configCleanup() @@ -520,7 +537,8 @@ func TestRemote_planDestroy(t *testing.T) { } func TestRemote_planDestroyNoConfig(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/empty") defer configCleanup() @@ -543,7 +561,8 @@ func TestRemote_planDestroyNoConfig(t *testing.T) { } func TestRemote_planWithWorkingDirectory(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() options := tfe.WorkspaceUpdateOptions{ WorkingDirectory: tfe.String("terraform"), @@ -583,7 +602,8 @@ func TestRemote_planWithWorkingDirectory(t *testing.T) { } func TestRemote_planPolicyPass(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan-policy-passed") defer configCleanup() @@ -616,7 +636,8 @@ func TestRemote_planPolicyPass(t *testing.T) { } func TestRemote_planPolicyHardFail(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan-policy-hard-failed") defer configCleanup() @@ -654,7 +675,8 @@ func TestRemote_planPolicyHardFail(t *testing.T) { } func TestRemote_planPolicySoftFail(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan-policy-soft-failed") defer configCleanup() @@ -692,7 +714,8 @@ func TestRemote_planPolicySoftFail(t *testing.T) { } func TestRemote_planWithRemoteError(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() op, configCleanup := testOperationPlan(t, "./test-fixtures/plan-with-error") defer configCleanup() diff --git a/backend/remote/backend_state_test.go b/backend/remote/backend_state_test.go index c68f5e9c8..530fdc88b 100644 --- a/backend/remote/backend_state_test.go +++ b/backend/remote/backend_state_test.go @@ -20,7 +20,8 @@ func TestRemoteClient(t *testing.T) { } func TestRemoteClient_stateLock(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() s1, err := b.StateMgr(backend.DefaultStateName) if err != nil { diff --git a/backend/remote/backend_test.go b/backend/remote/backend_test.go index 7edbd4358..c7f16fc45 100644 --- a/backend/remote/backend_test.go +++ b/backend/remote/backend_test.go @@ -19,14 +19,18 @@ func TestRemote(t *testing.T) { } func TestRemote_backendDefault(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() + backend.TestBackendStates(t, b) backend.TestBackendStateLocks(t, b, b) backend.TestBackendStateForceUnlock(t, b, b) } func TestRemote_backendNoDefault(t *testing.T) { - b := testBackendNoDefault(t) + b, bCleanup := testBackendNoDefault(t) + defer bCleanup() + backend.TestBackendStates(t, b) } @@ -157,8 +161,8 @@ func TestRemote_versionConstraints(t *testing.T) { "prefix": cty.NullVal(cty.String), }), }), - version: "0.10.1", - result: "upgrade Terraform to >= 0.11.8", + version: "0.0.1", + result: "upgrade Terraform to >= 0.1.0", }, "version too new": { config: cty.ObjectVal(map[string]cty.Value{ @@ -170,8 +174,8 @@ func TestRemote_versionConstraints(t *testing.T) { "prefix": cty.NullVal(cty.String), }), }), - version: "0.12.0", - result: "downgrade Terraform to <= 0.11.11", + version: "10.0.1", + result: "downgrade Terraform to <= 10.0.0", }, } @@ -207,7 +211,8 @@ func TestRemote_versionConstraints(t *testing.T) { } func TestRemote_localBackend(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() local, ok := b.local.(*backendLocal.Local) if !ok { @@ -221,7 +226,9 @@ func TestRemote_localBackend(t *testing.T) { } func TestRemote_addAndRemoveWorkspacesDefault(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() + if _, err := b.Workspaces(); err != backend.ErrWorkspacesNotSupported { t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err) } @@ -244,7 +251,9 @@ func TestRemote_addAndRemoveWorkspacesDefault(t *testing.T) { } func TestRemote_addAndRemoveWorkspacesNoDefault(t *testing.T) { - b := testBackendNoDefault(t) + b, bCleanup := testBackendNoDefault(t) + defer bCleanup() + states, err := b.Workspaces() if err != nil { t.Fatal(err) @@ -323,7 +332,8 @@ func TestRemote_addAndRemoveWorkspacesNoDefault(t *testing.T) { } func TestRemote_checkConstraints(t *testing.T) { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() cases := map[string]struct { constraints *disco.Constraints diff --git a/backend/remote/testing.go b/backend/remote/testing.go index c42d6efcb..729cd0ace 100644 --- a/backend/remote/testing.go +++ b/backend/remote/testing.go @@ -40,7 +40,7 @@ func testInput(t *testing.T, answers map[string]string) *mockInput { return &mockInput{answers: answers} } -func testBackendDefault(t *testing.T) *Remote { +func testBackendDefault(t *testing.T) (*Remote, func()) { obj := cty.ObjectVal(map[string]cty.Value{ "hostname": cty.NullVal(cty.String), "organization": cty.StringVal("hashicorp"), @@ -53,7 +53,7 @@ func testBackendDefault(t *testing.T) *Remote { return testBackend(t, obj) } -func testBackendNoDefault(t *testing.T) *Remote { +func testBackendNoDefault(t *testing.T) (*Remote, func()) { obj := cty.ObjectVal(map[string]cty.Value{ "hostname": cty.NullVal(cty.String), "organization": cty.StringVal("hashicorp"), @@ -66,7 +66,7 @@ func testBackendNoDefault(t *testing.T) *Remote { return testBackend(t, obj) } -func testBackendNoOperations(t *testing.T) *Remote { +func testBackendNoOperations(t *testing.T) (*Remote, func()) { obj := cty.ObjectVal(map[string]cty.Value{ "hostname": cty.NullVal(cty.String), "organization": cty.StringVal("no-operations"), @@ -80,16 +80,18 @@ func testBackendNoOperations(t *testing.T) *Remote { } func testRemoteClient(t *testing.T) remote.Client { - b := testBackendDefault(t) + b, bCleanup := testBackendDefault(t) + defer bCleanup() + raw, err := b.StateMgr(backend.DefaultStateName) if err != nil { t.Fatalf("error: %v", err) } - s := raw.(*remote.State) - return s.Client + + return raw.(*remote.State).Client } -func testBackend(t *testing.T, obj cty.Value) *Remote { +func testBackend(t *testing.T, obj cty.Value) (*Remote, func()) { s := testServer(t) b := New(testDisco(s)) @@ -148,7 +150,7 @@ func testBackend(t *testing.T, obj cty.Value) *Remote { } } - return b + return b, s.Close } func testLocalBackend(t *testing.T, remote *Remote) backend.Enhanced { @@ -193,8 +195,8 @@ func testServer(t *testing.T) *httptest.Server { io.WriteString(w, `{ "service": "tfe.v2.1", "product": "terraform", - "minimum": "0.11.8", - "maximum": "0.11.11" + "minimum": "0.1.0", + "maximum": "10.0.0" }`) }) diff --git a/svchost/disco/host.go b/svchost/disco/host.go index 524b2813b..ab9514c4f 100644 --- a/svchost/disco/host.go +++ b/svchost/disco/host.go @@ -201,8 +201,8 @@ func (h *Host) VersionConstraints(id, product string) (*Constraints, error) { // Set a default timeout of 1 sec for the versions request (in milliseconds) timeout := 1000 - if _, err := strconv.Atoi(os.Getenv("CHECKPOINT_TIMEOUT")); err == nil { - timeout, _ = strconv.Atoi(os.Getenv("CHECKPOINT_TIMEOUT")) + if v, err := strconv.Atoi(os.Getenv("CHECKPOINT_TIMEOUT")); err == nil { + timeout = v } client := &http.Client{