Files
Lucas Manuel Rodriguez e447a685f0 Rename fleetctl's testing_utils.go to testing_utils_test.go and create separate test package (#45585)
Resolves #45220 (one of several PRs, we are very close)

## Testing

- [X] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Improved test infrastructure for the CLI: consolidated and renamed
test helpers, added a dedicated in-process CLI test helper, and updated
many test cases to use the new helpers.
* Tightened several test assertions and standardized output/error
validation across unit and integration tests to improve reliability.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45585)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-15 11:59:18 -03:00

199 lines
5.5 KiB
Go

package fleetctl
import (
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
)
func TestConfigCommand(t *testing.T) {
t.Run("invalid config set", func(t *testing.T) {
cases := []struct {
desc string
setFlags []string
wantErr string
}{
{
desc: "invalid flag",
setFlags: []string{"--nosuchoption", "xyz"},
wantErr: "flag provided but not defined: -nosuchoption",
},
{
desc: "invalid tls-skip-verify",
setFlags: []string{"--tls-skip-verify=xyz"},
wantErr: `invalid boolean value "xyz" for -tls-skip-verify: parse error`,
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
dir := t.TempDir()
configFile := filepath.Join(dir, "config")
baseFlags := []string{"config", "set", "--config", configFile}
runAppCheckErr(t, append(baseFlags, c.setFlags...), c.wantErr)
})
}
})
t.Run("valid config set", func(t *testing.T) {
cases := []struct {
desc string
context string
setFlags []string
want Context
}{
{
desc: "set email",
context: "",
setFlags: []string{"--email", "a@b.c"},
want: Context{Email: "a@b.c"},
},
{
desc: "set address",
context: "",
setFlags: []string{"--address", "http://localhost"},
want: Context{Address: "http://localhost"},
},
{
desc: "set token",
context: "",
setFlags: []string{"--token", "abc"},
want: Context{Token: "abc"},
},
{
desc: "set tls-skip-verify",
context: "",
setFlags: []string{"--tls-skip-verify"},
want: Context{TLSSkipVerify: true},
},
{
desc: "set rootca",
context: "",
setFlags: []string{"--rootca", "./rootca"},
want: Context{RootCA: "./rootca"},
},
{
desc: "set url-prefix",
context: "",
setFlags: []string{"--url-prefix", "/test"},
want: Context{URLPrefix: "/test"},
},
{
desc: "set custom-headers",
context: "",
setFlags: []string{"--custom-header", "X-Test:1"},
want: Context{CustomHeaders: map[string]string{"X-Test": "1"}},
},
{
desc: "set custom-headers no value",
context: "",
setFlags: []string{"--custom-header", "X-Test"},
want: Context{CustomHeaders: map[string]string{"X-Test": ""}},
},
{
desc: "set custom-headers multiple separators",
context: "",
setFlags: []string{"--custom-header", "X-Test:1:2:3"},
want: Context{CustomHeaders: map[string]string{"X-Test": "1:2:3"}},
},
{
desc: "set multiple custom-headers",
context: "",
setFlags: []string{"--custom-header", "X-Test:1", "--custom-header", "X-Test2:2"},
want: Context{CustomHeaders: map[string]string{"X-Test": "1", "X-Test2": "2"}},
},
{
desc: "set different options in distinct context",
context: "test",
setFlags: []string{"--email", "b@c.d", "--address", "http://localhost", "--custom-header", "X-Test:1", "--custom-header", "X-Test2:2"},
want: Context{
Email: "b@c.d",
Address: "http://localhost",
CustomHeaders: map[string]string{"X-Test": "1", "X-Test2": "2"},
},
},
}
for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
dir := t.TempDir()
configFile := filepath.Join(dir, "config")
baseFlags := []string{"config", "set", "--config", configFile}
if c.context != "" {
baseFlags = append(baseFlags, "--context", c.context)
} else {
c.context = "default"
}
runAppForTest(t, append(baseFlags, c.setFlags...))
cfg, err := readConfig(configFile)
require.NoError(t, err)
cfgCtx, ok := cfg.Contexts[c.context]
require.True(t, ok)
require.Equal(t, c.want, cfgCtx)
})
}
})
}
func TestCustomHeadersConfig(t *testing.T) {
dir := t.TempDir()
configFile := filepath.Join(dir, "config")
// start a server that will receive requests
var called bool
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
called = true
require.Equal(t, "custom", r.Header.Get("X-Fleet-Test"))
require.Equal(t, "another", r.Header.Get("X-Fleet-MoreTest"))
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
t.Setenv("FLEET_SERVER_ADDRESS", srv.URL)
runAppForTest(t, []string{
"config", "set",
"--config", configFile,
"--token", "abcd",
"--custom-header", "X-Fleet-Test:custom",
"--custom-header", "X-Fleet-MoreTest:another",
"--address", srv.URL,
})
runAppNoChecks([]string{"get", "packs", "--config", configFile}) //nolint:errcheck
require.True(t, called)
}
func TestConfigGetShowsHelp(t *testing.T) {
t.Run("config get without args shows help", func(t *testing.T) {
w, err := runAppNoChecks([]string{"config", "get"})
require.NoError(t, err)
output := w.String()
require.Contains(t, output, "NAME:")
require.Contains(t, output, "fleetctl config get")
require.Contains(t, output, "Get a config option")
})
t.Run("config get with invalid key shows help", func(t *testing.T) {
w, err := runAppNoChecks([]string{"config", "get", "invalidkey"})
require.NoError(t, err)
output := w.String()
require.Contains(t, output, "NAME:")
require.Contains(t, output, "fleetctl config get")
require.Contains(t, output, "Get a config option")
})
t.Run("config set without flags shows help", func(t *testing.T) {
w, err := runAppNoChecks([]string{"config", "set"})
require.NoError(t, err)
output := w.String()
require.Contains(t, output, "NAME:")
require.Contains(t, output, "fleetctl config set")
require.Contains(t, output, "Set config options")
})
}