From 3b0bd146bcb289ecdbcba49e85c4b81b0c825380 Mon Sep 17 00:00:00 2001 From: hc-github-team-nomad-core <82989552+hc-github-team-nomad-core@users.noreply.github.com> Date: Fri, 2 Feb 2024 09:18:06 -0600 Subject: [PATCH] Backport of template: run template tests on Windows where possible into release/1.5.x #19857 We don't run the whole suite of unit tests on all platforms to keep CI times reasonable, so the only things we've been running on Windows are platform-specific. I'm working on some platform-specific `template` related work and having these tests run on Windows will reduce the risk of regressions. Our Windows CI box doesn't have Consul or Vault, so I've skipped those tests for the time being, and can follow up with that later. There's also a test with assertions looking for specific paths, and the results are different on Windows. I've skipped those for the moment as well and will follow up under a separate PR. Also swap `testify` for `shoenig/test` Co-authored-by: Tim Gross --- .github/workflows/test-windows.yml | 3 +- .../template/template_default_test.go | 69 +++++ .../taskrunner/template/template_test.go | 286 ++++++++---------- client/testutil/driver_compatible.go | 8 + 4 files changed, 206 insertions(+), 160 deletions(-) create mode 100644 client/allocrunner/taskrunner/template/template_default_test.go diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index b9bd35c84fa..e968ea7f742 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -88,7 +88,8 @@ jobs: --junitfile results.xml \ github.com/hashicorp/nomad/drivers/docker \ github.com/hashicorp/nomad/client/lib/fifo \ - github.com/hashicorp/nomad/client/logmon + github.com/hashicorp/nomad/client/logmon \ + github.com/hashicorp/nomad/client/allocrunner/taskrunner/template - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 with: name: results.xml diff --git a/client/allocrunner/taskrunner/template/template_default_test.go b/client/allocrunner/taskrunner/template/template_default_test.go new file mode 100644 index 00000000000..d9a37b9de91 --- /dev/null +++ b/client/allocrunner/taskrunner/template/template_default_test.go @@ -0,0 +1,69 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +//go:build !windows + +package template + +import ( + "os" + "path/filepath" + "syscall" + "testing" + "time" + + "github.com/hashicorp/nomad/ci" + clienttestutil "github.com/hashicorp/nomad/client/testutil" + "github.com/hashicorp/nomad/helper/pointer" + "github.com/hashicorp/nomad/nomad/structs" + "github.com/hashicorp/nomad/testutil" + "github.com/shoenig/test/must" +) + +// TestTaskTemplateManager_Permissions tests that we set file permissions +// correctly. This test won't compile on Windows +func TestTaskTemplateManager_Permissions(t *testing.T) { + ci.Parallel(t) + clienttestutil.RequireRoot(t) + + // Make a template that will render immediately + content := "hello, world!" + file := "my.tmpl" + template := &structs.Template{ + EmbeddedTmpl: content, + DestPath: file, + ChangeMode: structs.TemplateChangeModeNoop, + Perms: "777", + Uid: pointer.Of(503), + Gid: pointer.Of(20), + } + + harness := newTestHarness(t, []*structs.Template{template}, false, false) + harness.start(t) + defer harness.stop() + + // Wait for the unblock + select { + case <-harness.mockHooks.UnblockCh: + case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): + t.Fatalf("Task unblock should have been called") + } + + // Check the file is there + path := filepath.Join(harness.taskDir, file) + fi, err := os.Stat(path) + if err != nil { + t.Fatalf("Failed to stat file: %v", err) + } + + if m := fi.Mode(); m != os.ModePerm { + t.Fatalf("Got mode %v; want %v", m, os.ModePerm) + } + + sys := fi.Sys() + uid := pointer.Of(int(sys.(*syscall.Stat_t).Uid)) + gid := pointer.Of(int(sys.(*syscall.Stat_t).Gid)) + + must.Eq(t, template.Uid, uid) + must.Eq(t, template.Gid, gid) +} diff --git a/client/allocrunner/taskrunner/template/template_test.go b/client/allocrunner/taskrunner/template/template_test.go index 6911fb9fd31..88c14037461 100644 --- a/client/allocrunner/taskrunner/template/template_test.go +++ b/client/allocrunner/taskrunner/template/template_test.go @@ -12,12 +12,10 @@ import ( "path/filepath" "reflect" "regexp" - "runtime" "sort" "strconv" "strings" "sync" - "syscall" "testing" "time" @@ -37,9 +35,8 @@ import ( sconfig "github.com/hashicorp/nomad/nomad/structs/config" "github.com/hashicorp/nomad/testutil" "github.com/kr/pretty" + "github.com/shoenig/test" "github.com/shoenig/test/must" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const ( @@ -516,51 +513,6 @@ func TestTaskTemplateManager_Unblock_Static(t *testing.T) { } } -func TestTaskTemplateManager_Permissions(t *testing.T) { - clienttestutil.RequireRoot(t) - ci.Parallel(t) - // Make a template that will render immediately - content := "hello, world!" - file := "my.tmpl" - template := &structs.Template{ - EmbeddedTmpl: content, - DestPath: file, - ChangeMode: structs.TemplateChangeModeNoop, - Perms: "777", - Uid: pointer.Of(503), - Gid: pointer.Of(20), - } - - harness := newTestHarness(t, []*structs.Template{template}, false, false) - harness.start(t) - defer harness.stop() - - // Wait for the unblock - select { - case <-harness.mockHooks.UnblockCh: - case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): - t.Fatalf("Task unblock should have been called") - } - - // Check the file is there - path := filepath.Join(harness.taskDir, file) - fi, err := os.Stat(path) - if err != nil { - t.Fatalf("Failed to stat file: %v", err) - } - - if m := fi.Mode(); m != os.ModePerm { - t.Fatalf("Got mode %v; want %v", m, os.ModePerm) - } - - sys := fi.Sys() - uid := pointer.Of(int(sys.(*syscall.Stat_t).Uid)) - gid := pointer.Of(int(sys.(*syscall.Stat_t).Gid)) - - must.Eq(t, template.Uid, uid) - must.Eq(t, template.Gid, gid) -} - func TestTaskTemplateManager_Unblock_Static_NomadEnv(t *testing.T) { ci.Parallel(t) // Make a template that will render immediately @@ -639,6 +591,8 @@ func TestTaskTemplateManager_Unblock_Static_AlreadyRendered(t *testing.T) { func TestTaskTemplateManager_Unblock_Consul(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) + // Make a template that will render based on a key in Consul key := "foo" content := "barbaz" @@ -685,7 +639,8 @@ func TestTaskTemplateManager_Unblock_Consul(t *testing.T) { func TestTaskTemplateManager_Unblock_Vault(t *testing.T) { ci.Parallel(t) - require := require.New(t) + clienttestutil.RequireVault(t) + // Make a template that will render based on a key in Vault vaultPath := "secret/data/password" key := "password" @@ -712,7 +667,7 @@ func TestTaskTemplateManager_Unblock_Vault(t *testing.T) { // Write the secret to Vault logical := harness.vault.Client.Logical() _, err := logical.Write(vaultPath, map[string]interface{}{"data": map[string]interface{}{key: content}}) - require.NoError(err) + must.NoError(t, err) // Wait for the unblock select { @@ -735,6 +690,8 @@ func TestTaskTemplateManager_Unblock_Vault(t *testing.T) { func TestTaskTemplateManager_Unblock_Multi_Template(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) + // Make a template that will render immediately staticContent := "hello, world!" staticFile := "my.tmpl" @@ -803,7 +760,8 @@ func TestTaskTemplateManager_Unblock_Multi_Template(t *testing.T) { // restored renders and triggers its change mode if the template has changed func TestTaskTemplateManager_FirstRender_Restored(t *testing.T) { ci.Parallel(t) - require := require.New(t) + clienttestutil.RequireVault(t) + // Make a template that will render based on a key in Vault vaultPath := "secret/data/password" key := "password" @@ -823,27 +781,27 @@ func TestTaskTemplateManager_FirstRender_Restored(t *testing.T) { // Ensure no unblock select { case <-harness.mockHooks.UnblockCh: - require.Fail("Task unblock should not have been called") + t.Fatal("Task unblock should not have been called") case <-time.After(time.Duration(1*testutil.TestMultiplier()) * time.Second): } // Write the secret to Vault logical := harness.vault.Client.Logical() _, err := logical.Write(vaultPath, map[string]interface{}{"data": map[string]interface{}{key: content}}) - require.NoError(err) + must.NoError(t, err) // Wait for the unblock select { case <-harness.mockHooks.UnblockCh: case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): - require.Fail("Task unblock should have been called") + t.Fatal("Task unblock should have been called") } // Check the file is there path := filepath.Join(harness.taskDir, file) raw, err := os.ReadFile(path) - require.NoError(err, "Failed to read rendered template from %q", path) - require.Equal(content, string(raw), "Unexpected template data; got %s, want %q", raw, content) + must.NoError(t, err, must.Sprintf("Failed to read rendered template from %q", path)) + must.Eq(t, content, string(raw), must.Sprintf("Unexpected template data; got %s, want %q", raw, content)) // task is now running harness.mockHooks.hasHandle = true @@ -857,14 +815,14 @@ func TestTaskTemplateManager_FirstRender_Restored(t *testing.T) { select { case <-harness.mockHooks.UnblockCh: case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): - require.Fail("Task unblock should have been called") + t.Fatal("Task unblock should have been called") } select { case <-harness.mockHooks.RestartCh: - require.Fail("should not have restarted", harness.mockHooks) + t.Fatal("should not have restarted", harness.mockHooks) case <-harness.mockHooks.SignalCh: - require.Fail("should not have restarted", harness.mockHooks) + t.Fatal("should not have restarted", harness.mockHooks) case <-time.After(time.Duration(1*testutil.TestMultiplier()) * time.Second): } @@ -872,7 +830,7 @@ func TestTaskTemplateManager_FirstRender_Restored(t *testing.T) { harness.manager.Stop() content = "bazbar" _, err = logical.Write(vaultPath, map[string]interface{}{"data": map[string]interface{}{key: content}}) - require.NoError(err) + must.NoError(t, err) harness.mockHooks.UnblockCh = make(chan struct{}, 1) harness.start(t) @@ -880,7 +838,7 @@ func TestTaskTemplateManager_FirstRender_Restored(t *testing.T) { select { case <-harness.mockHooks.UnblockCh: case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): - require.Fail("Task unblock should have been called") + t.Fatal("Task unblock should have been called") } // Wait for restart @@ -891,15 +849,17 @@ OUTER: case <-harness.mockHooks.RestartCh: break OUTER case <-harness.mockHooks.SignalCh: - require.Fail("Signal with restart policy", harness.mockHooks) + t.Fatal("Signal with restart policy", harness.mockHooks) case <-timeout: - require.Fail("Should have received a restart", harness.mockHooks) + t.Fatal("Should have received a restart", harness.mockHooks) } } } func TestTaskTemplateManager_Rerender_Noop(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) + // Make a template that will render based on a key in Consul key := "foo" content1 := "bar" @@ -969,6 +929,8 @@ func TestTaskTemplateManager_Rerender_Noop(t *testing.T) { func TestTaskTemplateManager_Rerender_Signal(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) + // Make a template that renders based on a key in Consul and sends SIGALRM key1 := "foo" content1_1 := "bar" @@ -1069,6 +1031,8 @@ OUTER: func TestTaskTemplateManager_Rerender_Restart(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) + // Make a template that renders based on a key in Consul and sends restart key1 := "bam" content1_1 := "cat" @@ -1168,7 +1132,7 @@ func TestTaskTemplateManager_Interpolate_Destination(t *testing.T) { func TestTaskTemplateManager_Signal_Error(t *testing.T) { ci.Parallel(t) - require := require.New(t) + clienttestutil.RequireConsul(t) // Make a template that renders based on a key in Consul and sends SIGALRM key1 := "foo" @@ -1210,12 +1174,13 @@ func TestTaskTemplateManager_Signal_Error(t *testing.T) { t.Fatalf("Should have received a signals: %+v", harness.mockHooks) } - require.NotNil(harness.mockHooks.KillEvent) - require.Contains(harness.mockHooks.KillEvent.DisplayMessage, "failed to send signals") + must.NotNil(t, harness.mockHooks.KillEvent) + must.StrContains(t, harness.mockHooks.KillEvent.DisplayMessage, "failed to send signals") } func TestTaskTemplateManager_ScriptExecution(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) // Make a template that renders based on a key in Consul and triggers script key1 := "bam" @@ -1260,7 +1225,7 @@ BAR={{key "bar"}} // Ensure no unblock select { case <-harness.mockHooks.UnblockCh: - require.Fail(t, "Task unblock should not have been called") + t.Fatal(t, "Task unblock should not have been called") case <-time.After(time.Duration(1*testutil.TestMultiplier()) * time.Second): } @@ -1272,7 +1237,7 @@ BAR={{key "bar"}} select { case <-harness.mockHooks.UnblockCh: case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): - require.Fail(t, "Task unblock should have been called") + t.Fatal(t, "Task unblock should have been called") } // Update the keys in Consul @@ -1284,15 +1249,15 @@ OUTER: for { select { case <-harness.mockHooks.RestartCh: - require.Fail(t, "restart not expected") + t.Fatal(t, "restart not expected") case ev := <-harness.mockHooks.EmitEventCh: if strings.Contains(ev.DisplayMessage, t1.ChangeScript.Command) { break OUTER } case <-harness.mockHooks.SignalCh: - require.Fail(t, "signal not expected") + t.Fatal(t, "signal not expected") case <-timeout: - require.Fail(t, "should have received an event") + t.Fatal(t, "should have received an event") } } } @@ -1301,7 +1266,7 @@ OUTER: // task upon script execution failure if that's how it's configured. func TestTaskTemplateManager_ScriptExecutionFailTask(t *testing.T) { ci.Parallel(t) - require := require.New(t) + clienttestutil.RequireConsul(t) // Make a template that renders based on a key in Consul and triggers script key1 := "bam" @@ -1346,7 +1311,7 @@ BAR={{key "bar"}} // Ensure no unblock select { case <-harness.mockHooks.UnblockCh: - require.Fail("Task unblock should not have been called") + t.Fatal("Task unblock should not have been called") case <-time.After(time.Duration(1*testutil.TestMultiplier()) * time.Second): } @@ -1358,7 +1323,7 @@ BAR={{key "bar"}} select { case <-harness.mockHooks.UnblockCh: case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): - require.Fail("Task unblock should have been called") + t.Fatal("Task unblock should have been called") } // Update the keys in Consul @@ -1369,15 +1334,16 @@ BAR={{key "bar"}} case <-harness.mockHooks.KillCh: break case <-time.After(time.Duration(1*testutil.TestMultiplier()) * time.Second): - require.Fail("Should have received a signals: %+v", harness.mockHooks) + t.Fatalf("Should have received a signals: %+v", harness.mockHooks) } - require.NotNil(harness.mockHooks.KillEvent) - require.Contains(harness.mockHooks.KillEvent.DisplayMessage, "task is being killed") + must.NotNil(t, harness.mockHooks.KillEvent) + must.StrContains(t, harness.mockHooks.KillEvent.DisplayMessage, "task is being killed") } func TestTaskTemplateManager_ChangeModeMixed(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) templateRestart := &structs.Template{ EmbeddedTmpl: ` @@ -1425,7 +1391,7 @@ COMMON={{key "common"}} // Ensure no unblock select { case <-harness.mockHooks.UnblockCh: - require.Fail(t, "Task unblock should not have been called") + t.Fatal(t, "Task unblock should not have been called") case <-time.After(time.Duration(1*testutil.TestMultiplier()) * time.Second): } @@ -1439,7 +1405,7 @@ COMMON={{key "common"}} select { case <-harness.mockHooks.UnblockCh: case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): - require.Fail(t, "Task unblock should have been called") + t.Fatal(t, "Task unblock should have been called") } t.Run("restart takes precedence", func(t *testing.T) { @@ -1455,7 +1421,7 @@ COMMON={{key "common"}} case <-harness.mockHooks.RestartCh: // Consume restarts so the channel is clean for other tests. case <-harness.mockHooks.SignalCh: - require.Fail(t, "signal not expected") + t.Fatal(t, "signal not expected") case ev := <-harness.mockHooks.EmitEventCh: events = append(events, ev) case <-timeout: @@ -1464,8 +1430,8 @@ COMMON={{key "common"}} } for _, ev := range events { - require.NotContains(t, ev.DisplayMessage, templateScript.ChangeScript.Command) - require.NotContains(t, ev.Type, structs.TaskSignaling) + must.StrNotContains(t, ev.DisplayMessage, templateScript.ChangeScript.Command) + must.StrNotContains(t, ev.Type, structs.TaskSignaling) } }) @@ -1480,19 +1446,19 @@ COMMON={{key "common"}} for { select { case <-harness.mockHooks.RestartCh: - require.Fail(t, "restart not expected") + t.Fatal(t, "restart not expected") case ev := <-harness.mockHooks.EmitEventCh: if strings.Contains(ev.DisplayMessage, templateScript.ChangeScript.Command) { // Make sure we only run script once. - require.False(t, gotScript) + must.False(t, gotScript) gotScript = true } case <-harness.mockHooks.SignalCh: // Make sure we only signal once. - require.False(t, gotSignal) + must.False(t, gotSignal) gotSignal = true case <-timeout: - require.Fail(t, "timeout waiting for script and signal") + t.Fatal(t, "timeout waiting for script and signal") } if gotScript && gotSignal { @@ -1534,21 +1500,23 @@ TEST_ENV_NOT_FOUND: {{env "` + testenv + `_NOTFOUND" }}` select { case <-harness.mockHooks.UnblockCh: case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): - require.Fail(t, "Task unblock should have been called") + t.Fatal(t, "Task unblock should have been called") } // Check the file is there path := filepath.Join(harness.taskDir, file) raw, err := os.ReadFile(path) - require.NoError(t, err) + must.NoError(t, err) - require.Equal(t, expected, string(raw)) + must.Eq(t, expected, string(raw)) } // TestTaskTemplateManager_Env asserts templates with the env flag set are read // into the task's environment. func TestTaskTemplateManager_Env(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) + template := &structs.Template{ EmbeddedTmpl: ` # Comment lines are ok @@ -1623,7 +1591,6 @@ func TestTaskTemplateManager_Env_Missing(t *testing.T) { // template processing function handles interpolated destinations func TestTaskTemplateManager_Env_InterpolatedDest(t *testing.T) { ci.Parallel(t) - require := require.New(t) d := t.TempDir() @@ -1650,9 +1617,9 @@ func TestTaskTemplateManager_Env_InterpolatedDest(t *testing.T) { d, "") vars, err := loadTemplateEnv(templates, taskEnv) - require.NoError(err) - require.Contains(vars, "FOO") - require.Equal(vars["FOO"], "bar") + must.NoError(t, err) + must.MapContainsKey(t, vars, "FOO") + must.Eq(t, "bar", vars["FOO"]) } // TestTaskTemplateManager_Env_Multi asserts the core env @@ -1702,6 +1669,8 @@ func TestTaskTemplateManager_Env_Multi(t *testing.T) { func TestTaskTemplateManager_Rerender_Env(t *testing.T) { ci.Parallel(t) + clienttestutil.RequireConsul(t) + // Make a template that renders based on a key in Consul and sends restart key1 := "bam" key2 := "bar" @@ -1809,7 +1778,6 @@ func TestTaskTemplateManager_Config_ServerName(t *testing.T) { // propagated to consul-template's configuration. func TestTaskTemplateManager_Config_VaultNamespace(t *testing.T) { ci.Parallel(t) - assert := assert.New(t) testNS := "test-namespace" c := config.DefaultConfig() @@ -1829,18 +1797,17 @@ func TestTaskTemplateManager_Config_VaultNamespace(t *testing.T) { } ctmplMapping, err := parseTemplateConfigs(config) - assert.Nil(err, "Parsing Templates") + must.NoError(t, err, must.Sprint("parsing templates")) ctconf, err := newRunnerConfig(config, ctmplMapping) - assert.Nil(err, "Building Runner Config") - assert.Equal(testNS, *ctconf.Vault.Namespace, "Vault Namespace Value") + must.NoError(t, err, must.Sprint("building runner config")) + must.Eq(t, testNS, *ctconf.Vault.Namespace, must.Sprintf("Vault Namespace Value")) } // TestTaskTemplateManager_Config_VaultNamespace asserts the Vault namespace setting is // propagated to consul-template's configuration. func TestTaskTemplateManager_Config_VaultNamespace_TaskOverride(t *testing.T) { ci.Parallel(t) - assert := assert.New(t) testNS := "test-namespace" c := config.DefaultConfig() @@ -1864,11 +1831,11 @@ func TestTaskTemplateManager_Config_VaultNamespace_TaskOverride(t *testing.T) { } ctmplMapping, err := parseTemplateConfigs(config) - assert.Nil(err, "Parsing Templates") + must.NoError(t, err, must.Sprint("parsing templates")) ctconf, err := newRunnerConfig(config, ctmplMapping) - assert.Nil(err, "Building Runner Config") - assert.Equal(overriddenNS, *ctconf.Vault.Namespace, "Vault Namespace Value") + must.NoError(t, err, must.Sprint("building runner config")) + must.Eq(t, overriddenNS, *ctconf.Vault.Namespace, must.Sprintf("Vault Namespace Value")) } // TestTaskTemplateManager_Escapes asserts that when sandboxing is enabled @@ -1876,8 +1843,12 @@ func TestTaskTemplateManager_Config_VaultNamespace_TaskOverride(t *testing.T) { func TestTaskTemplateManager_Escapes(t *testing.T) { ci.Parallel(t) + // the specific files paths are different on Linux vs Windows + // TODO(tgross): rewrite this test to allow for platform-specific paths + clienttestutil.RequireNotWindows(t) + clientConf := config.DefaultConfig() - require.False(t, clientConf.TemplateConfig.DisableSandbox, "expected sandbox to be disabled") + must.False(t, clientConf.TemplateConfig.DisableSandbox, must.Sprint("expected sandbox to be disabled")) // Set a fake alloc dir to make test output more realistic clientConf.AllocDir = "/fake/allocdir" @@ -2103,18 +2074,18 @@ func TestTaskTemplateManager_Escapes(t *testing.T) { mapping, err := parseTemplateConfigs(config) if tc.Err == nil { // Ok path - require.NoError(t, err) - require.NotNil(t, mapping) - require.Len(t, mapping, 1) + must.NoError(t, err) + must.NotNil(t, mapping) + must.MapLen(t, 1, mapping) for k := range mapping { - require.Equal(t, tc.SourcePath, *k.Source) - require.Equal(t, tc.DestPath, *k.Destination) + must.Eq(t, tc.SourcePath, *k.Source) + must.Eq(t, tc.DestPath, *k.Destination) t.Logf("Rendering %s => %s", *k.Source, *k.Destination) } } else { // Err path - assert.EqualError(t, err, tc.Err.Error()) - require.Nil(t, mapping) + test.EqError(t, err, tc.Err.Error()) + must.Nil(t, mapping) } }) @@ -2127,7 +2098,7 @@ func TestTaskTemplateManager_BlockedEvents(t *testing.T) { // then asserts that templates are still blocked on 3 and 4, // and check that we got the relevant task events ci.Parallel(t) - require := require.New(t) + clienttestutil.RequireConsul(t) // Make a template that will render based on a key in Consul var embedded string @@ -2179,11 +2150,11 @@ func TestTaskTemplateManager_BlockedEvents(t *testing.T) { // Check to see we got a correct message // assert that all 0-4 keys are missing - require.Len(harness.mockHooks.Events, 1) + must.Len(t, 1, harness.mockHooks.Events) t.Logf("first message: %v", harness.mockHooks.Events[0]) missing, more := missingKeys(harness.mockHooks.Events[0]) - require.Equal(5, len(missing)+more) - require.Contains(harness.mockHooks.Events[0].DisplayMessage, "and 2 more") + must.Eq(t, 5, len(missing)+more) + must.StrContains(t, harness.mockHooks.Events[0].DisplayMessage, "and 2 more") // Write 0-2 keys to Consul for i := 0; i < 3; i++ { @@ -2399,41 +2370,41 @@ func TestTaskTemplateManager_ClientTemplateConfig_Set(t *testing.T) { // monkey patch the client config with the version of the ClientTemplateConfig we want to test. _case.TTMConfig.ClientConfig.TemplateConfig = _case.ClientTemplateConfig templateMapping, err := parseTemplateConfigs(_case.TTMConfig) - require.NoError(t, err) + must.NoError(t, err) runnerConfig, err := newRunnerConfig(_case.TTMConfig, templateMapping) - require.NoError(t, err) + must.NoError(t, err) // Direct properties - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.MaxStale, *runnerConfig.MaxStale) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.BlockQueryWaitTime, *runnerConfig.BlockQueryWaitTime) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.MaxStale, *runnerConfig.MaxStale) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.BlockQueryWaitTime, *runnerConfig.BlockQueryWaitTime) // WaitConfig - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.Wait.Min, *runnerConfig.Wait.Min) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.Wait.Max, *runnerConfig.Wait.Max) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.Wait.Min, *runnerConfig.Wait.Min) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.Wait.Max, *runnerConfig.Wait.Max) // Consul Retry - require.NotNil(t, runnerConfig.Consul) - require.NotNil(t, runnerConfig.Consul.Retry) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.ConsulRetry.Attempts, *runnerConfig.Consul.Retry.Attempts) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.ConsulRetry.Backoff, *runnerConfig.Consul.Retry.Backoff) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.ConsulRetry.MaxBackoff, *runnerConfig.Consul.Retry.MaxBackoff) + must.NotNil(t, runnerConfig.Consul) + must.NotNil(t, runnerConfig.Consul.Retry) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.ConsulRetry.Attempts, *runnerConfig.Consul.Retry.Attempts) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.ConsulRetry.Backoff, *runnerConfig.Consul.Retry.Backoff) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.ConsulRetry.MaxBackoff, *runnerConfig.Consul.Retry.MaxBackoff) // Vault Retry - require.NotNil(t, runnerConfig.Vault) - require.NotNil(t, runnerConfig.Vault.Retry) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.VaultRetry.Attempts, *runnerConfig.Vault.Retry.Attempts) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.VaultRetry.Backoff, *runnerConfig.Vault.Retry.Backoff) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.VaultRetry.MaxBackoff, *runnerConfig.Vault.Retry.MaxBackoff) + must.NotNil(t, runnerConfig.Vault) + must.NotNil(t, runnerConfig.Vault.Retry) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.VaultRetry.Attempts, *runnerConfig.Vault.Retry.Attempts) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.VaultRetry.Backoff, *runnerConfig.Vault.Retry.Backoff) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.VaultRetry.MaxBackoff, *runnerConfig.Vault.Retry.MaxBackoff) // Nomad Retry - require.NotNil(t, runnerConfig.Nomad) - require.NotNil(t, runnerConfig.Nomad.Retry) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.NomadRetry.Attempts, *runnerConfig.Nomad.Retry.Attempts) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.NomadRetry.Backoff, *runnerConfig.Nomad.Retry.Backoff) - require.Equal(t, *_case.ExpectedRunnerConfig.TemplateConfig.NomadRetry.MaxBackoff, *runnerConfig.Nomad.Retry.MaxBackoff) + must.NotNil(t, runnerConfig.Nomad) + must.NotNil(t, runnerConfig.Nomad.Retry) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.NomadRetry.Attempts, *runnerConfig.Nomad.Retry.Attempts) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.NomadRetry.Backoff, *runnerConfig.Nomad.Retry.Backoff) + must.Eq(t, *_case.ExpectedRunnerConfig.TemplateConfig.NomadRetry.MaxBackoff, *runnerConfig.Nomad.Retry.MaxBackoff) // Test that wait_bounds are enforced for _, tmpl := range *runnerConfig.Templates { - require.Equal(t, *_case.ExpectedTemplateConfig.Wait.Enabled, *tmpl.Wait.Enabled) - require.Equal(t, *_case.ExpectedTemplateConfig.Wait.Min, *tmpl.Wait.Min) - require.Equal(t, *_case.ExpectedTemplateConfig.Wait.Max, *tmpl.Wait.Max) + must.Eq(t, *_case.ExpectedTemplateConfig.Wait.Enabled, *tmpl.Wait.Enabled) + must.Eq(t, *_case.ExpectedTemplateConfig.Wait.Min, *tmpl.Wait.Min) + must.Eq(t, *_case.ExpectedTemplateConfig.Wait.Max, *tmpl.Wait.Max) } }) } @@ -2465,12 +2436,12 @@ func TestTaskTemplateManager_Template_Wait_Set(t *testing.T) { } templateMapping, err := parseTemplateConfigs(ttmConfig) - require.NoError(t, err) + must.NoError(t, err) - for k := range templateMapping { - require.True(t, *k.Wait.Enabled) - require.Equal(t, 5*time.Second, *k.Wait.Min) - require.Equal(t, 10*time.Second, *k.Wait.Max) + for k, _ := range templateMapping { + must.True(t, *k.Wait.Enabled) + must.Eq(t, 5*time.Second, *k.Wait.Min) + must.Eq(t, 10*time.Second, *k.Wait.Max) } } @@ -2502,14 +2473,14 @@ func TestTaskTemplateManager_Template_ErrMissingKey_Set(t *testing.T) { } templateMapping, err := parseTemplateConfigs(ttmConfig) - require.NoError(t, err) + must.NoError(t, err) for k, tmpl := range templateMapping { if tmpl.EmbeddedTmpl == "test-false" { - require.False(t, *k.ErrMissingKey) + must.False(t, *k.ErrMissingKey) } if tmpl.EmbeddedTmpl == "test-true" { - require.True(t, *k.ErrMissingKey) + must.True(t, *k.ErrMissingKey) } } } @@ -2530,7 +2501,7 @@ func TestTaskTemplateManager_writeToFile_Disabled(t *testing.T) { } harness := newTestHarness(t, []*structs.Template{template}, false, false) - require.NoError(t, harness.startWithErr(), "couldn't setup initial harness") + must.NoError(t, harness.startWithErr(), must.Sprint("couldn't setup initial harness")) defer harness.stop() // Using writeToFile should cause a kill @@ -2540,7 +2511,7 @@ func TestTaskTemplateManager_writeToFile_Disabled(t *testing.T) { case <-harness.mockHooks.EmitEventCh: t.Fatalf("Task event should not have been emitted") case e := <-harness.mockHooks.KillCh: - require.Contains(t, e.DisplayMessage, "writeToFile: function is disabled") + must.StrContains(t, e.DisplayMessage, "writeToFile: function is disabled") case <-time.After(time.Duration(5*testutil.TestMultiplier()) * time.Second): t.Fatalf("timeout") } @@ -2548,20 +2519,17 @@ func TestTaskTemplateManager_writeToFile_Disabled(t *testing.T) { // Check the file is not there path := filepath.Join(harness.taskDir, file) _, err := os.ReadFile(path) - require.Error(t, err) + must.Error(t, err) } // TestTaskTemplateManager_writeToFile asserts the consul-template function // writeToFile can be enabled. func TestTaskTemplateManager_writeToFile(t *testing.T) { - if runtime.GOOS != "linux" { - t.Skip("username and group lookup assume linux platform") - } - ci.Parallel(t) + clienttestutil.RequireLinux(t) cu, err := users.Current() - require.NoError(t, err) + must.NoError(t, err) file := "my.tmpl" template := &structs.Template{ @@ -2581,7 +2549,7 @@ func TestTaskTemplateManager_writeToFile(t *testing.T) { // Enable all funcs harness.config.TemplateConfig.FunctionDenylist = []string{} - require.NoError(t, harness.startWithErr(), "couldn't setup initial harness") + must.NoError(t, harness.startWithErr(), must.Sprint("couldn't setup initial harness")) defer harness.stop() // Using writeToFile should not cause a kill @@ -2598,12 +2566,12 @@ func TestTaskTemplateManager_writeToFile(t *testing.T) { // Check the templated file is there path := filepath.Join(harness.taskDir, file) r, err := os.ReadFile(path) - require.NoError(t, err) - require.True(t, bytes.HasSuffix(r, []byte("...done\n")), string(r)) + must.NoError(t, err) + must.True(t, bytes.HasSuffix(r, []byte("...done\n")), must.Sprint(string(r))) // Check that writeToFile was allowed path = filepath.Join(harness.taskDir, "writetofile.out") r, err = os.ReadFile(path) - require.NoError(t, err) - require.Equal(t, "hello", string(r)) + must.NoError(t, err) + must.Eq(t, "hello", string(r)) } diff --git a/client/testutil/driver_compatible.go b/client/testutil/driver_compatible.go index 7abc9edf216..e139c60d96c 100644 --- a/client/testutil/driver_compatible.go +++ b/client/testutil/driver_compatible.go @@ -52,6 +52,14 @@ func RequireLinux(t *testing.T) { } } +// RequireNotWindows skips tests whenever: +// - running on Window +func RequireNotWindows(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Test requires non-Windows") + } +} + // ExecCompatible skips tests unless: // - running as root // - running on Linux