From f82d90123a9fd53584e85c6fa58c0d8e0a90edc0 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 9 Dec 2025 22:32:29 -0700 Subject: [PATCH] Additional tests for wwctl overlay info Signed-off-by: Jonathon Anderson --- internal/app/wwctl/overlay/info/main_test.go | 294 ++++++++++++++++++- 1 file changed, 287 insertions(+), 7 deletions(-) diff --git a/internal/app/wwctl/overlay/info/main_test.go b/internal/app/wwctl/overlay/info/main_test.go index 2b906741..d08c383b 100644 --- a/internal/app/wwctl/overlay/info/main_test.go +++ b/internal/app/wwctl/overlay/info/main_test.go @@ -30,13 +30,12 @@ func Test_Overlay_Variables(t *testing.T) { }, args: []string{"test-overlay", "test.ww"}, expectError: false, - expectedOutput: `First Line -Second Line - -VARIABLE OPTION TYPE HELP --------- ------ ---- ---- -.Node.Tags.bar string -`, + expectedOutput: "First Line\n" + + "Second Line\n" + + "\n" + + "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".Node.Tags.bar string \n", }, { name: "overlay variables no file", @@ -51,6 +50,281 @@ VARIABLE OPTION TYPE HELP args: []string{"no-overlay", "test.ww"}, expectError: true, }, + { + name: "nested fields multiple levels", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/nested.ww": ` +{{ .Kernel.Args }} +{{ .Ipmi.UserName }} +{{ .Ipmi.Ipaddr }} +{{ .Warewulf.Port }} +`, + }, + args: []string{"test-overlay", "nested.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".Ipmi.Ipaddr --ipmiaddr IP Set the IPMI IP address\n" + + ".Ipmi.UserName --ipmiuser string Set the IPMI username\n" + + ".Kernel.Args --kernelargs []string Set kernel arguments\n" + + ".Warewulf.Port int \n", + }, + { + name: "template without variables", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/no-vars.ww": ` +# Static configuration file +# This file has no template variables +static_value=true +`, + }, + args: []string{"test-overlay", "no-vars.ww"}, + expectError: false, + expectedOutput: `VARIABLE OPTION TYPE HELP +-------- ------ ---- ---- +`, + }, + { + name: "only documentation no variables", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/doc-only.ww": ` +{{/* wwdoc: This is just documentation */}} +{{/* wwdoc2: No actual template variables used */}} +Static content here +`, + }, + args: []string{"test-overlay", "doc-only.ww"}, + expectError: false, + expectedOutput: `This is just documentation +No actual template variables used + +VARIABLE OPTION TYPE HELP +-------- ------ ---- ---- +`, + }, + { + name: "template parse error", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/invalid.ww": ` +{{ .Id } +{{ unclosed range .NetDevs }} +`, + }, + args: []string{"test-overlay", "invalid.ww"}, + expectError: true, + }, + { + name: "inline comment documentation", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/inline-doc.ww": ` +{{/* .Id: The unique node identifier */}} +{{/* .Hostname: The node's hostname in DNS */}} +{{/* .Tags.env: Environment tag (prod, dev, test) */}} +{{ .Id }} +{{ .Hostname }} +{{ .Tags.env }} +`, + }, + args: []string{"test-overlay", "inline-doc.ww"}, + expectError: false, + expectedOutput: `VARIABLE OPTION TYPE HELP +-------- ------ ---- ---- +.Hostname string The node's hostname in DNS +.Id string The unique node identifier +.Tags.env string Environment tag (prod, dev, test) +`, + }, + { + name: "complex conditional branches", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/conditionals.ww": ` +{{ if eq .Kernel.Version "5.15" }} +Old kernel +{{ else if gt (len .NetDevs) 0 }} +Has network: {{ .Id }} +{{ else }} +Default: {{ .Hostname }} +{{ end }} +`, + }, + args: []string{"test-overlay", "conditionals.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".Hostname string \n" + + ".Id string \n" + + ".Kernel.Version --kernelversion string Set kernel version\n" + + ".NetDevs map[string]*node.NetDev \n", + }, + { + name: "sprig function pipelines", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/sprig.ww": ` +{{ .Id | upper }} +{{ .Hostname | lower }} +{{ .Kernel.Args | join " " }} +{{ .Tags.foo | default "bar" }} +`, + }, + args: []string{"test-overlay", "sprig.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".Hostname string \n" + + ".Id string \n" + + ".Kernel.Args --kernelargs []string Set kernel arguments\n" + + ".Tags.foo string \n", + }, + { + name: "include function usage", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/include.ww": ` +{{ Include "/etc/passwd" }} +{{ IncludeFrom .ImageName "/etc/group" }} +`, + }, + args: []string{"test-overlay", "include.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".ImageName --image string Set image name\n", + }, + { + name: "mixed documentation types", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/mixed-doc.ww": ` +{{/* wwdoc: Configuration for network interfaces */}} +{{/* wwdoc-details: This template generates network configs */}} +{{/* .NetDevs: Map of network devices by name */}} +{{/* .Id: Node identifier */}} +{{ .Id }} +{{ .NetDevs }} +`, + }, + args: []string{"test-overlay", "mixed-doc.ww"}, + expectError: false, + expectedOutput: "Configuration for network interfaces\n" + + "This template generates network configs\n" + + "\n" + + "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".Id string Node identifier\n" + + ".NetDevs map[string]*node.NetDev Map of network devices by name\n", + }, + { + name: "tag field access", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/tags.ww": ` +{{ .Tags.foo }} +{{ .Ipmi.Tags.vlan }} +{{ .NetDevs }} +`, + }, + args: []string{"test-overlay", "tags.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".Ipmi.Tags.vlan string \n" + + ".NetDevs map[string]*node.NetDev \n" + + ".Tags.foo string \n", + }, + { + name: "dollar sign root context", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/dollar.ww": ` +{{ $.Id }} +{{ $.BuildHost }} +{{ $.Ipaddr }} +`, + }, + args: []string{"test-overlay", "dollar.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + "$.BuildHost string \n" + + "$.Id string \n" + + "$.Ipaddr string \n", + }, + { + name: "range over map basic", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/range-map.ww": ` +{{/* wwdoc: Network device iteration */}} +{{- range $devname, $netdev := .NetDevs }} +Device: {{ $netdev.Device }} +Type: {{ $netdev.Type }} +IP: {{ $netdev.Ipaddr }} +{{- end }} +`, + }, + args: []string{"test-overlay", "range-map.ww"}, + expectError: false, + expectedOutput: "Network device iteration\n" + + "\n" + + "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + "$netdev.Device --netdev string Set the device for given network\n" + + "$netdev.Ipaddr --ipaddr IP IPv4 address in given network\n" + + "$netdev.Type --type string Set device type of given network\n" + + ".NetDevs map[string]*node.NetDev \n", + }, + { + name: "range over map with output verification", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/range-verify.ww": ` +{{- range $devname, $netdev := .NetDevs }} +{{ $devname }} +{{ $netdev.Device }} +{{ $netdev.Type }} +{{- end }} +`, + }, + args: []string{"test-overlay", "range-verify.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + "$netdev.Device --netdev string Set the device for given network\n" + + "$netdev.Type --type string Set device type of given network\n" + + ".NetDevs map[string]*node.NetDev \n", + }, + { + name: "empty collection checks", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/empty.ww": ` +{{ if gt (len .NetDevs) 0 }} +Has devices +{{ end }} +{{ if .FileSystems }} +Has filesystems +{{ end }} +`, + }, + args: []string{"test-overlay", "empty.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".FileSystems map[string]*node.FileSystem \n" + + ".NetDevs map[string]*node.NetDev \n", + }, + { + name: "file and abort directives", + writeFiles: map[string]string{ + "var/lib/warewulf/overlays/test-overlay/control.ww": ` +{{ file "output.conf" }} +{{ if .Tags.enabled }} +Config: {{ .Tags.value }} +{{ else }} +{{ abort }} +{{ end }} +`, + }, + args: []string{"test-overlay", "control.ww"}, + expectError: false, + expectedOutput: "VARIABLE OPTION TYPE HELP\n" + + "-------- ------ ---- ----\n" + + ".Tags.enabled string \n" + + ".Tags.value string \n", + }, } for _, tt := range tests { @@ -80,6 +354,12 @@ VARIABLE OPTION TYPE HELP if tt.expectedOutput != "" { output := buf.String() assert.Equal(t, tt.expectedOutput, output) + } else { + // For tests without expected output, print actual output for debugging + // This helps understand what variables are being detected + if testing.Verbose() { + t.Logf("Output:\n%s", buf.String()) + } } }) }