package config import ( "os" "path/filepath" "testing" "time" "banger/internal/paths" ) func TestLoadDefaultsResolveFirecrackerAndGenerateSSHKey(t *testing.T) { configDir := t.TempDir() binDir := t.TempDir() firecrackerPath := filepath.Join(binDir, "firecracker") if err := os.WriteFile(firecrackerPath, []byte("#!/bin/sh\nexit 0\n"), 0o755); err != nil { t.Fatalf("write firecracker: %v", err) } t.Setenv("PATH", binDir) cfg, err := Load(paths.Layout{ConfigDir: configDir}) if err != nil { t.Fatalf("Load: %v", err) } if cfg.FirecrackerBin != firecrackerPath { t.Fatalf("FirecrackerBin = %q, want %q", cfg.FirecrackerBin, firecrackerPath) } wantKey := filepath.Join(configDir, "ssh", "id_ed25519") if cfg.SSHKeyPath != wantKey { t.Fatalf("SSHKeyPath = %q, want %q", cfg.SSHKeyPath, wantKey) } for _, path := range []string{wantKey, wantKey + ".pub"} { if _, err := os.Stat(path); err != nil { t.Fatalf("stat %s: %v", path, err) } } if cfg.DefaultImageName != "default" { t.Fatalf("DefaultImageName = %q, want default", cfg.DefaultImageName) } if cfg.WebListenAddr != "127.0.0.1:7777" { t.Fatalf("WebListenAddr = %q", cfg.WebListenAddr) } } func TestLoadAppliesConfigOverrides(t *testing.T) { configDir := t.TempDir() data := []byte(` log_level = "debug" web_listen_addr = "" firecracker_bin = "/opt/firecracker" ssh_key_path = "/tmp/custom-key" default_image_name = "void-exp" auto_stop_stale_after = "1h" stats_poll_interval = "15s" metrics_poll_interval = "30s" bridge_name = "br-test" bridge_ip = "10.0.0.1" cidr = "25" tap_pool_size = 8 default_dns = "9.9.9.9" `) if err := os.WriteFile(filepath.Join(configDir, "config.toml"), data, 0o644); err != nil { t.Fatalf("write config.toml: %v", err) } cfg, err := Load(paths.Layout{ConfigDir: configDir}) if err != nil { t.Fatalf("Load: %v", err) } if cfg.LogLevel != "debug" { t.Fatalf("LogLevel = %q", cfg.LogLevel) } if cfg.WebListenAddr != "" { t.Fatalf("WebListenAddr = %q, want empty", cfg.WebListenAddr) } if cfg.FirecrackerBin != "/opt/firecracker" { t.Fatalf("FirecrackerBin = %q", cfg.FirecrackerBin) } if cfg.SSHKeyPath != "/tmp/custom-key" { t.Fatalf("SSHKeyPath = %q", cfg.SSHKeyPath) } if cfg.DefaultImageName != "void-exp" { t.Fatalf("DefaultImageName = %q", cfg.DefaultImageName) } if cfg.AutoStopStaleAfter != time.Hour { t.Fatalf("AutoStopStaleAfter = %s", cfg.AutoStopStaleAfter) } if cfg.StatsPollInterval != 15*time.Second { t.Fatalf("StatsPollInterval = %s", cfg.StatsPollInterval) } if cfg.MetricsPollInterval != 30*time.Second { t.Fatalf("MetricsPollInterval = %s", cfg.MetricsPollInterval) } if cfg.BridgeName != "br-test" || cfg.BridgeIP != "10.0.0.1" || cfg.CIDR != "25" { t.Fatalf("bridge config = %+v", cfg) } if cfg.TapPoolSize != 8 { t.Fatalf("TapPoolSize = %d", cfg.TapPoolSize) } if cfg.DefaultDNS != "9.9.9.9" { t.Fatalf("DefaultDNS = %q", cfg.DefaultDNS) } } func TestLoadAppliesLogLevelEnvOverride(t *testing.T) { t.Setenv("BANGER_LOG_LEVEL", "warn") cfg, err := Load(paths.Layout{ConfigDir: t.TempDir()}) if err != nil { t.Fatalf("Load: %v", err) } if cfg.LogLevel != "warn" { t.Fatalf("LogLevel = %q, want warn", cfg.LogLevel) } }