template: run template tests on Windows where possible (#19856)

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`
This commit is contained in:
Tim Gross
2024-02-02 09:22:03 -05:00
committed by GitHub
parent 556d44cd7a
commit 334c383eb6
4 changed files with 205 additions and 159 deletions

View File

@@ -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

View File

@@ -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)
}

View File

@@ -11,11 +11,9 @@ import (
"path/filepath"
"reflect"
"regexp"
"runtime"
"sort"
"strconv"
"strings"
"syscall"
"testing"
"time"
@@ -36,9 +34,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 (
@@ -442,51 +439,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
@@ -565,6 +517,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"
@@ -611,7 +565,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"
@@ -638,7 +593,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 {
@@ -661,6 +616,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"
@@ -729,7 +686,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"
@@ -749,27 +707,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
@@ -783,14 +741,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):
}
@@ -798,7 +756,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)
@@ -806,7 +764,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
@@ -817,15 +775,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"
@@ -895,6 +855,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"
@@ -993,6 +955,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"
@@ -1092,7 +1056,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"
@@ -1134,12 +1098,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"
@@ -1184,7 +1149,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):
}
@@ -1196,7 +1161,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
@@ -1208,15 +1173,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")
}
}
}
@@ -1225,7 +1190,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"
@@ -1270,7 +1235,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):
}
@@ -1282,7 +1247,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
@@ -1293,15 +1258,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: `
@@ -1349,7 +1315,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):
}
@@ -1363,7 +1329,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) {
@@ -1379,7 +1345,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:
@@ -1388,8 +1354,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)
}
})
@@ -1404,19 +1370,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 {
@@ -1458,21 +1424,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
@@ -1547,7 +1515,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()
@@ -1574,9 +1541,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
@@ -1626,6 +1593,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"
@@ -1737,7 +1706,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()
@@ -1760,18 +1728,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()
@@ -1798,11 +1765,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
@@ -1810,8 +1777,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"
@@ -2037,18 +2008,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)
}
})
@@ -2061,7 +2032,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
@@ -2113,11 +2084,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++ {
@@ -2341,41 +2312,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)
}
})
}
@@ -2407,12 +2378,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)
must.True(t, *k.Wait.Enabled)
must.Eq(t, 5*time.Second, *k.Wait.Min)
must.Eq(t, 10*time.Second, *k.Wait.Max)
}
}
@@ -2444,14 +2415,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)
}
}
}
@@ -2472,7 +2443,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
@@ -2482,7 +2453,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")
}
@@ -2490,20 +2461,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{
@@ -2523,7 +2491,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
@@ -2540,12 +2508,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))
}

View File

@@ -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