mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
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:
3
.github/workflows/test-windows.yml
vendored
3
.github/workflows/test-windows.yml
vendored
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user