mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
The DisableDockerUpdateActions setting was being saved to disk but not updated in h.config, causing the UI toggle to appear to revert on page refresh since the API returned the stale runtime value. Related to #1023
792 lines
18 KiB
Go
792 lines
18 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/hostagent"
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
func TestGatherTags(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
env string
|
|
flags []string
|
|
expected []string
|
|
}{
|
|
// Empty inputs
|
|
{
|
|
name: "empty env and flags returns empty slice",
|
|
env: "",
|
|
flags: nil,
|
|
expected: []string{},
|
|
},
|
|
{
|
|
name: "empty env and empty flags returns empty slice",
|
|
env: "",
|
|
flags: []string{},
|
|
expected: []string{},
|
|
},
|
|
|
|
// Environment only
|
|
{
|
|
name: "single env tag",
|
|
env: "prod",
|
|
flags: nil,
|
|
expected: []string{"prod"},
|
|
},
|
|
{
|
|
name: "multiple env tags comma separated",
|
|
env: "prod,us-west",
|
|
flags: nil,
|
|
expected: []string{"prod", "us-west"},
|
|
},
|
|
{
|
|
name: "env tags with whitespace trimmed",
|
|
env: " prod , us-west ",
|
|
flags: nil,
|
|
expected: []string{"prod", "us-west"},
|
|
},
|
|
{
|
|
name: "env empty items filtered",
|
|
env: "prod,,us-west,",
|
|
flags: nil,
|
|
expected: []string{"prod", "us-west"},
|
|
},
|
|
{
|
|
name: "env whitespace-only items filtered",
|
|
env: "prod, ,us-west",
|
|
flags: nil,
|
|
expected: []string{"prod", "us-west"},
|
|
},
|
|
|
|
// Flags only
|
|
{
|
|
name: "single flag tag",
|
|
env: "",
|
|
flags: []string{"staging"},
|
|
expected: []string{"staging"},
|
|
},
|
|
{
|
|
name: "multiple flag tags",
|
|
env: "",
|
|
flags: []string{"staging", "eu-central"},
|
|
expected: []string{"staging", "eu-central"},
|
|
},
|
|
{
|
|
name: "flag tags with whitespace trimmed",
|
|
env: "",
|
|
flags: []string{" staging ", " eu-central "},
|
|
expected: []string{"staging", "eu-central"},
|
|
},
|
|
{
|
|
name: "flag empty items filtered",
|
|
env: "",
|
|
flags: []string{"staging", "", "eu-central"},
|
|
expected: []string{"staging", "eu-central"},
|
|
},
|
|
{
|
|
name: "flag whitespace-only items filtered",
|
|
env: "",
|
|
flags: []string{"staging", " ", "eu-central"},
|
|
expected: []string{"staging", "eu-central"},
|
|
},
|
|
|
|
// Both env and flags (env first, then flags)
|
|
{
|
|
name: "env tags come before flags",
|
|
env: "prod",
|
|
flags: []string{"app1"},
|
|
expected: []string{"prod", "app1"},
|
|
},
|
|
{
|
|
name: "multiple env and multiple flags",
|
|
env: "prod,us-west",
|
|
flags: []string{"app1", "critical"},
|
|
expected: []string{"prod", "us-west", "app1", "critical"},
|
|
},
|
|
{
|
|
name: "duplicates preserved (no dedup)",
|
|
env: "prod,prod",
|
|
flags: []string{"prod"},
|
|
expected: []string{"prod", "prod", "prod"},
|
|
},
|
|
|
|
// Edge cases
|
|
{
|
|
name: "only commas in env",
|
|
env: ",,,",
|
|
flags: nil,
|
|
expected: []string{},
|
|
},
|
|
{
|
|
name: "single comma",
|
|
env: ",",
|
|
flags: nil,
|
|
expected: []string{},
|
|
},
|
|
{
|
|
name: "env with tabs",
|
|
env: "\tprod\t,\tstaging\t",
|
|
flags: nil,
|
|
expected: []string{"prod", "staging"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := gatherTags(tt.env, tt.flags)
|
|
if !reflect.DeepEqual(got, tt.expected) {
|
|
t.Fatalf("expected %v, got %v", tt.expected, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseLogLevel(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
wantLevel zerolog.Level
|
|
wantErr bool
|
|
errSubstr string
|
|
}{
|
|
// Valid levels
|
|
{
|
|
name: "debug level",
|
|
input: "debug",
|
|
wantLevel: zerolog.DebugLevel,
|
|
},
|
|
{
|
|
name: "info level",
|
|
input: "info",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
{
|
|
name: "warn level",
|
|
input: "warn",
|
|
wantLevel: zerolog.WarnLevel,
|
|
},
|
|
{
|
|
name: "error level",
|
|
input: "error",
|
|
wantLevel: zerolog.ErrorLevel,
|
|
},
|
|
|
|
// Case insensitivity
|
|
{
|
|
name: "uppercase DEBUG",
|
|
input: "DEBUG",
|
|
wantLevel: zerolog.DebugLevel,
|
|
},
|
|
{
|
|
name: "mixed case Info",
|
|
input: "Info",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
{
|
|
name: "uppercase WARN",
|
|
input: "WARN",
|
|
wantLevel: zerolog.WarnLevel,
|
|
},
|
|
{
|
|
name: "uppercase ERROR",
|
|
input: "ERROR",
|
|
wantLevel: zerolog.ErrorLevel,
|
|
},
|
|
|
|
// Whitespace handling
|
|
{
|
|
name: "leading whitespace",
|
|
input: " debug",
|
|
wantLevel: zerolog.DebugLevel,
|
|
},
|
|
{
|
|
name: "trailing whitespace",
|
|
input: "warn ",
|
|
wantLevel: zerolog.WarnLevel,
|
|
},
|
|
{
|
|
name: "both whitespace",
|
|
input: " error ",
|
|
wantLevel: zerolog.ErrorLevel,
|
|
},
|
|
{
|
|
name: "tabs",
|
|
input: "\tinfo\t",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
|
|
// Empty string defaults to info
|
|
{
|
|
name: "empty string defaults to info",
|
|
input: "",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
{
|
|
name: "whitespace only defaults to info",
|
|
input: " ",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
{
|
|
name: "tabs only defaults to info",
|
|
input: "\t\t",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
|
|
// Invalid levels
|
|
{
|
|
name: "invalid level returns error",
|
|
input: "invalid",
|
|
wantLevel: zerolog.InfoLevel,
|
|
wantErr: true,
|
|
errSubstr: "invalid log level",
|
|
},
|
|
{
|
|
name: "typo returns error",
|
|
input: "debuf",
|
|
wantLevel: zerolog.InfoLevel,
|
|
wantErr: true,
|
|
errSubstr: "must be debug, info, warn, or error",
|
|
},
|
|
{
|
|
name: "verbose returns error",
|
|
input: "verbose",
|
|
wantLevel: zerolog.InfoLevel,
|
|
wantErr: true,
|
|
errSubstr: "invalid log level",
|
|
},
|
|
|
|
// Trace level is outside allowed range (DebugLevel to ErrorLevel)
|
|
{
|
|
name: "trace level rejected (outside allowed range)",
|
|
input: "trace",
|
|
wantLevel: zerolog.InfoLevel,
|
|
wantErr: true,
|
|
errSubstr: "must be debug, info, warn, or error",
|
|
},
|
|
|
|
// Fatal/panic levels are outside allowed range
|
|
{
|
|
name: "fatal level rejected (outside allowed range)",
|
|
input: "fatal",
|
|
wantLevel: zerolog.InfoLevel,
|
|
wantErr: true,
|
|
errSubstr: "must be debug, info, warn, or error",
|
|
},
|
|
{
|
|
name: "panic level rejected (outside allowed range)",
|
|
input: "panic",
|
|
wantLevel: zerolog.InfoLevel,
|
|
wantErr: true,
|
|
errSubstr: "must be debug, info, warn, or error",
|
|
},
|
|
|
|
// Numeric values (zerolog supports these)
|
|
{
|
|
name: "numeric 0 maps to debug level",
|
|
input: "0",
|
|
wantLevel: zerolog.DebugLevel,
|
|
},
|
|
{
|
|
name: "numeric 1 maps to info level",
|
|
input: "1",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
{
|
|
name: "numeric 2 maps to warn level",
|
|
input: "2",
|
|
wantLevel: zerolog.WarnLevel,
|
|
},
|
|
{
|
|
name: "numeric 3 maps to error level",
|
|
input: "3",
|
|
wantLevel: zerolog.ErrorLevel,
|
|
},
|
|
{
|
|
name: "numeric -1 is trace (rejected - outside range)",
|
|
input: "-1",
|
|
wantLevel: zerolog.InfoLevel,
|
|
wantErr: true,
|
|
errSubstr: "must be debug, info, warn, or error",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
level, err := parseLogLevel(tt.input)
|
|
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
if tt.errSubstr != "" && !strings.Contains(err.Error(), tt.errSubstr) {
|
|
t.Fatalf("expected error containing %q, got %q", tt.errSubstr, err.Error())
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
if level != tt.wantLevel {
|
|
t.Fatalf("expected level %v, got %v", tt.wantLevel, level)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDefaultLogLevel(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
envValue string
|
|
expected string
|
|
}{
|
|
// Empty returns "info"
|
|
{
|
|
name: "empty string returns info",
|
|
envValue: "",
|
|
expected: "info",
|
|
},
|
|
{
|
|
name: "whitespace only returns info",
|
|
envValue: " ",
|
|
expected: "info",
|
|
},
|
|
{
|
|
name: "tabs only returns info",
|
|
envValue: "\t\t",
|
|
expected: "info",
|
|
},
|
|
{
|
|
name: "newline only returns info",
|
|
envValue: "\n",
|
|
expected: "info",
|
|
},
|
|
|
|
// Non-empty returns as-is (no validation)
|
|
{
|
|
name: "debug returns debug",
|
|
envValue: "debug",
|
|
expected: "debug",
|
|
},
|
|
{
|
|
name: "error returns error",
|
|
envValue: "error",
|
|
expected: "error",
|
|
},
|
|
{
|
|
name: "invalid value passed through",
|
|
envValue: "invalid",
|
|
expected: "invalid",
|
|
},
|
|
{
|
|
name: "mixed case passed through",
|
|
envValue: "DEBUG",
|
|
expected: "DEBUG",
|
|
},
|
|
{
|
|
name: "value with surrounding whitespace NOT trimmed",
|
|
envValue: " debug ",
|
|
expected: " debug ",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := defaultLogLevel(tt.envValue)
|
|
if got != tt.expected {
|
|
t.Fatalf("expected %q, got %q", tt.expected, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMultiValue(t *testing.T) {
|
|
t.Run("String joins with comma", func(t *testing.T) {
|
|
mv := multiValue{"a", "b", "c"}
|
|
if got := mv.String(); got != "a,b,c" {
|
|
t.Fatalf("expected %q, got %q", "a,b,c", got)
|
|
}
|
|
})
|
|
|
|
t.Run("String empty slice returns empty string", func(t *testing.T) {
|
|
mv := multiValue{}
|
|
if got := mv.String(); got != "" {
|
|
t.Fatalf("expected %q, got %q", "", got)
|
|
}
|
|
})
|
|
|
|
t.Run("String single item no comma", func(t *testing.T) {
|
|
mv := multiValue{"single"}
|
|
if got := mv.String(); got != "single" {
|
|
t.Fatalf("expected %q, got %q", "single", got)
|
|
}
|
|
})
|
|
|
|
t.Run("Set appends values", func(t *testing.T) {
|
|
mv := multiValue{}
|
|
if err := mv.Set("first"); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if err := mv.Set("second"); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if err := mv.Set("third"); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
expected := multiValue{"first", "second", "third"}
|
|
if !reflect.DeepEqual(mv, expected) {
|
|
t.Fatalf("expected %v, got %v", expected, mv)
|
|
}
|
|
})
|
|
|
|
t.Run("Set preserves empty strings", func(t *testing.T) {
|
|
mv := multiValue{}
|
|
_ = mv.Set("")
|
|
_ = mv.Set("value")
|
|
_ = mv.Set("")
|
|
|
|
if len(mv) != 3 {
|
|
t.Fatalf("expected 3 items, got %d", len(mv))
|
|
}
|
|
})
|
|
|
|
t.Run("Set always returns nil error", func(t *testing.T) {
|
|
mv := multiValue{}
|
|
// Set always returns nil, testing various inputs
|
|
inputs := []string{"", "normal", "with spaces", "special!@#$%", "unicode日本語"}
|
|
for _, input := range inputs {
|
|
if err := mv.Set(input); err != nil {
|
|
t.Fatalf("expected nil error for input %q, got %v", input, err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRunAsWindowsServiceStub(t *testing.T) {
|
|
// This tests the non-windows stub
|
|
cfg := Config{}
|
|
logger := zerolog.Nop()
|
|
err := runAsWindowsService(cfg, logger)
|
|
if err != nil {
|
|
t.Fatalf("expected nil error from stub, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParseConfig(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args []string
|
|
env map[string]string
|
|
wantURL string
|
|
wantToken string
|
|
wantLevel zerolog.Level
|
|
wantVersion bool
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "defaults with token",
|
|
args: []string{"--token", "test-token"},
|
|
env: nil,
|
|
wantURL: "http://localhost:7655",
|
|
wantToken: "test-token",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
{
|
|
name: "env vars",
|
|
args: []string{},
|
|
env: map[string]string{
|
|
"PULSE_TOKEN": "env-token",
|
|
"PULSE_URL": "http://env-url",
|
|
"LOG_LEVEL": "debug",
|
|
},
|
|
wantURL: "http://env-url",
|
|
wantToken: "env-token",
|
|
wantLevel: zerolog.DebugLevel,
|
|
},
|
|
{
|
|
name: "flags override env",
|
|
args: []string{"--url", "http://flag-url", "--log-level", "error"},
|
|
env: map[string]string{"PULSE_TOKEN": "token", "PULSE_URL": "http://env-url"},
|
|
wantURL: "http://flag-url",
|
|
wantToken: "token",
|
|
wantLevel: zerolog.ErrorLevel,
|
|
},
|
|
{
|
|
name: "show version",
|
|
args: []string{"--version"},
|
|
wantVersion: true,
|
|
},
|
|
{
|
|
name: "missing token returns error",
|
|
args: []string{"--url", "http://localhost"},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "invalid log level returns error",
|
|
args: []string{"--token", "t", "--log-level", "invalid"},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "invalid interval returns error",
|
|
args: []string{"--token", "t", "--interval", "invalid"},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "invalid flag returns error",
|
|
args: []string{"--invalid"},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "help flag",
|
|
args: []string{"--help"},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "env interval",
|
|
args: []string{"--token", "t"},
|
|
env: map[string]string{
|
|
"PULSE_INTERVAL": "10s",
|
|
},
|
|
wantURL: "http://localhost:7655",
|
|
wantToken: "t",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
{
|
|
name: "invalid env interval defaults to 30s",
|
|
args: []string{"--token", "t"},
|
|
env: map[string]string{
|
|
"PULSE_INTERVAL": "invalid",
|
|
},
|
|
wantURL: "http://localhost:7655",
|
|
wantToken: "t",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
{
|
|
name: "negative interval defaults to 30s",
|
|
args: []string{"--token", "t", "--interval", "-10s"},
|
|
wantURL: "http://localhost:7655",
|
|
wantToken: "t",
|
|
wantLevel: zerolog.InfoLevel,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
getenv := func(k string) string {
|
|
if tt.env == nil {
|
|
return ""
|
|
}
|
|
return tt.env[k]
|
|
}
|
|
|
|
cfg, showVersion, err := parseConfig("pulse-host-agent", tt.args, getenv)
|
|
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
if showVersion != tt.wantVersion {
|
|
t.Fatalf("expected showVersion %v, got %v", tt.wantVersion, showVersion)
|
|
}
|
|
|
|
if !showVersion {
|
|
if cfg.HostConfig.PulseURL != tt.wantURL {
|
|
t.Fatalf("expected URL %q, got %q", tt.wantURL, cfg.HostConfig.PulseURL)
|
|
}
|
|
if cfg.HostConfig.APIToken != tt.wantToken {
|
|
t.Fatalf("expected Token %q, got %q", tt.wantToken, cfg.HostConfig.APIToken)
|
|
}
|
|
if cfg.HostConfig.LogLevel != tt.wantLevel {
|
|
t.Fatalf("expected Level %v, got %v", tt.wantLevel, cfg.HostConfig.LogLevel)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
// Custom TestMain if needed, but we can just use regular tests
|
|
m.Run()
|
|
}
|
|
|
|
func TestMainFunc(t *testing.T) {
|
|
origArgs := os.Args
|
|
origExit := osExit
|
|
origRun := runFunc
|
|
defer func() {
|
|
os.Args = origArgs
|
|
osExit = origExit
|
|
runFunc = origRun
|
|
}()
|
|
|
|
tests := []struct {
|
|
name string
|
|
args []string
|
|
runErr error
|
|
wantExit int
|
|
}{
|
|
{
|
|
name: "help exits 0",
|
|
args: []string{"pulse-host-agent", "--help"},
|
|
wantExit: 0,
|
|
},
|
|
{
|
|
name: "version exits 0",
|
|
args: []string{"pulse-host-agent", "--version"},
|
|
wantExit: 0,
|
|
},
|
|
{
|
|
name: "invalid flag exits 1",
|
|
args: []string{"pulse-host-agent", "--invalid-flag"},
|
|
wantExit: 1,
|
|
},
|
|
{
|
|
name: "missing token exits 1",
|
|
args: []string{"pulse-host-agent"},
|
|
wantExit: 1,
|
|
},
|
|
{
|
|
name: "run success exits normally",
|
|
args: []string{"pulse-host-agent", "--token", "test"},
|
|
runErr: nil,
|
|
wantExit: 100, // custom exit to signal success of main and return
|
|
},
|
|
{
|
|
name: "run failure exits 1",
|
|
args: []string{"pulse-host-agent", "--token", "test"},
|
|
runErr: fmt.Errorf("run failed"),
|
|
wantExit: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
os.Args = tt.args
|
|
runFunc = func(ctx context.Context, cfg Config) error {
|
|
return tt.runErr
|
|
}
|
|
|
|
var exitCode int
|
|
var exited bool
|
|
osExit = func(code int) {
|
|
exitCode = code
|
|
exited = true
|
|
panic("exited")
|
|
}
|
|
|
|
// For the "success" case, we want to see it reach the end of main
|
|
// Actually, main doesn't call osExit(0) at the very end, it just returns.
|
|
// But if runFunc returns nil, main returns.
|
|
|
|
if tt.wantExit == 100 {
|
|
// Special case: we expect it NOT to exit via osExit
|
|
defer func() {
|
|
_ = recover()
|
|
if exited {
|
|
t.Errorf("expected main not to call osExit, but it called with %d", exitCode)
|
|
}
|
|
}()
|
|
main()
|
|
return
|
|
}
|
|
|
|
defer func() {
|
|
_ = recover()
|
|
if !exited {
|
|
t.Errorf("expected osExit to be called")
|
|
}
|
|
if exitCode != tt.wantExit {
|
|
t.Errorf("expected exit code %d, got %d", tt.wantExit, exitCode)
|
|
}
|
|
}()
|
|
|
|
main()
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRunFunc(t *testing.T) {
|
|
origService := runAsWindowsServiceFunc
|
|
defer func() {
|
|
runAsWindowsServiceFunc = origService
|
|
}()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
|
defer cancel()
|
|
|
|
t.Run("windows service failure", func(t *testing.T) {
|
|
runAsWindowsServiceFunc = func(cfg Config, logger zerolog.Logger) error {
|
|
return fmt.Errorf("service failed")
|
|
}
|
|
err := run(ctx, Config{})
|
|
if err == nil || !strings.Contains(err.Error(), "Windows service failed") {
|
|
t.Fatalf("expected service failure error, got %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("invalid config fails hostagent.New", func(t *testing.T) {
|
|
runAsWindowsServiceFunc = origService
|
|
cfg := Config{
|
|
HostConfig: hostagent.Config{
|
|
PulseURL: "http://localhost",
|
|
APIToken: "", // Empty token fails New
|
|
},
|
|
}
|
|
err := run(ctx, cfg)
|
|
if err == nil || !strings.Contains(err.Error(), "failed to initialise host agent") {
|
|
t.Fatalf("expected hostagent init error, got %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("run once finishes", func(t *testing.T) {
|
|
runAsWindowsServiceFunc = origService
|
|
cfg := Config{
|
|
HostConfig: hostagent.Config{
|
|
PulseURL: "http://localhost:1",
|
|
APIToken: "test",
|
|
RunOnce: true,
|
|
},
|
|
DisableAutoUpdate: true,
|
|
}
|
|
shortCtx, shortCancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
|
defer shortCancel()
|
|
|
|
_ = run(shortCtx, cfg)
|
|
})
|
|
|
|
t.Run("host agent terminated with error (deadline)", func(t *testing.T) {
|
|
runAsWindowsServiceFunc = origService
|
|
cfg := Config{
|
|
HostConfig: hostagent.Config{
|
|
PulseURL: "http://localhost:1",
|
|
APIToken: "test",
|
|
},
|
|
DisableAutoUpdate: true,
|
|
}
|
|
// Using a short timeout that will definitely trigger before the agent finishes (which is never in this config)
|
|
timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
|
defer timeoutCancel()
|
|
|
|
err := run(timeoutCtx, cfg)
|
|
if err == nil || !strings.Contains(err.Error(), "host agent terminated with error") {
|
|
t.Fatalf("expected termination error, got %v", err)
|
|
}
|
|
})
|
|
}
|