package config import ( "os" "testing" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/rawbytes" "github.com/knadh/koanf/v2" "github.com/stretchr/testify/assert" ) var stringEnvConfigYaml = ` PageTitle: ${{ INPUT }} ` var stringEnvInterpolationConfigYaml = ` PageTitle: Olivetin - ${{ INPUT }} ` var boolEnvConfigYaml = ` CheckForUpdates: ${{ INPUT }} ` var numericEnvConfigYaml = ` LogHistoryPageSize: ${{ INPUT }} ` var argsSyntaxConfigYaml = ` actions: - title: Ping host id: ping_host shell: ping {{ host }} -c ${{ INPUT }} icon: ping timeout: 100 popupOnStart: execution-dialog-stdout-only arguments: - name: host title: Host type: ascii_identifier default: example.com description: The host that you want to ping ` func pageTitleSelector(cfg *Config) any { return cfg.PageTitle } func checkForUpdatesSelector(cfg *Config) any { return cfg.CheckForUpdates } func logHistoryPageSizeSelector(cfg *Config) any { return cfg.LogHistoryPageSize } var envConfigTests = []struct { yaml string input string output any selector func(*Config) any }{ // Test that it works for string type config fields, both standalone and as part of a larger string value. {stringEnvConfigYaml, "A Nice Title", "A Nice Title", pageTitleSelector}, {stringEnvInterpolationConfigYaml, "A Nice Title", "Olivetin - A Nice Title", pageTitleSelector}, // Test that unset variables turn into empty strings. {stringEnvConfigYaml, "", "", pageTitleSelector}, // Test that it works for bool type config fields for intuitive bool->string conversions. {boolEnvConfigYaml, "FALSE", false, checkForUpdatesSelector}, {boolEnvConfigYaml, "false", false, checkForUpdatesSelector}, {boolEnvConfigYaml, "False", false, checkForUpdatesSelector}, {boolEnvConfigYaml, "TRUE", true, checkForUpdatesSelector}, {boolEnvConfigYaml, "true", true, checkForUpdatesSelector}, {boolEnvConfigYaml, "True", true, checkForUpdatesSelector}, {boolEnvConfigYaml, "0", false, checkForUpdatesSelector}, {boolEnvConfigYaml, "1", true, checkForUpdatesSelector}, // Test that unset variables turn into false bools. {boolEnvConfigYaml, "", false, checkForUpdatesSelector}, // Test that it works for numeric type config fields. {numericEnvConfigYaml, "2048", int64(2048), logHistoryPageSizeSelector}, // Test that unset variables turn into zero numbers. {numericEnvConfigYaml, "", int64(0), logHistoryPageSizeSelector}, // Test that it doesn't interfere with similar arguments {argsSyntaxConfigYaml, "5", "ping {{ host }} -c 5", func(cfg *Config) any { if len(cfg.Actions) > 0 { return cfg.Actions[0].Shell } return "" }}, } func setTestEnvInput(t *testing.T, input string) { t.Helper() if input != "" { if err := os.Setenv("INPUT", input); err != nil { t.Fatalf("Setenv INPUT: %v", err) } return } if err := os.Unsetenv("INPUT"); err != nil { t.Fatalf("Unsetenv INPUT: %v", err) } } func loadConfigFromYAML(t *testing.T, yamlStr string, cfg *Config) bool { t.Helper() k := koanf.New(".") if err := k.Load(rawbytes.Provider([]byte(yamlStr)), yaml.Parser()); err != nil { t.Errorf("Error loading YAML: %v", err) return false } return unmarshalRoot(k, cfg) } func TestEnvInConfig(t *testing.T) { originalInput, hadInput := os.LookupEnv("INPUT") t.Cleanup(func() { if hadInput { setTestEnvInput(t, originalInput) return } setTestEnvInput(t, "") }) for _, tt := range envConfigTests { cfg := DefaultConfig() setTestEnvInput(t, tt.input) if !loadConfigFromYAML(t, tt.yaml, cfg) { t.Errorf("Error unmarshalling config for env=%q", tt.input) continue } field := tt.selector(cfg) assert.Equal(t, tt.output, field, "Unmarshaled config field doesn't match expected value: env=%q", tt.input) } }