package config import ( "encoding/json" "os" "path/filepath" "testing" "banger/internal/paths" "banger/internal/runtimebundle" ) func TestLoadDerivesArtifactPathsFromRuntimeDir(t *testing.T) { runtimeDir := t.TempDir() meta := runtimebundle.BundleMetadata{ FirecrackerBin: "bin/firecracker", SSHKeyPath: "keys/id_ed25519", NamegenPath: "bin/namegen", CustomizeScript: "scripts/customize.sh", VSockPingHelperPath: "bin/banger-vsock-pingd", DefaultPackages: "config/packages.apt", DefaultRootfs: "images/rootfs-docker.ext4", DefaultKernel: "kernels/vmlinux", DefaultInitrd: "kernels/initrd.img", DefaultModulesDir: "modules/current", } for _, rel := range []string{ meta.FirecrackerBin, meta.SSHKeyPath, meta.NamegenPath, meta.CustomizeScript, meta.VSockPingHelperPath, meta.DefaultPackages, meta.DefaultRootfs, meta.DefaultKernel, meta.DefaultInitrd, filepath.Join(meta.DefaultModulesDir, "modules.dep"), } { path := filepath.Join(runtimeDir, rel) if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatalf("mkdir %s: %v", filepath.Dir(path), err) } if err := os.WriteFile(path, []byte("test"), 0o644); err != nil { t.Fatalf("write %s: %v", path, err) } } data, err := json.Marshal(meta) if err != nil { t.Fatalf("Marshal: %v", err) } if err := os.WriteFile(filepath.Join(runtimeDir, runtimebundle.BundleMetadataFile), data, 0o644); err != nil { t.Fatalf("write bundle metadata: %v", err) } t.Setenv("BANGER_RUNTIME_DIR", runtimeDir) cfg, err := Load(paths.Layout{ConfigDir: t.TempDir()}) if err != nil { t.Fatalf("Load: %v", err) } if cfg.RuntimeDir != runtimeDir { t.Fatalf("RuntimeDir = %q, want %q", cfg.RuntimeDir, runtimeDir) } if cfg.FirecrackerBin != filepath.Join(runtimeDir, meta.FirecrackerBin) { t.Fatalf("FirecrackerBin = %q", cfg.FirecrackerBin) } if cfg.SSHKeyPath != filepath.Join(runtimeDir, meta.SSHKeyPath) { t.Fatalf("SSHKeyPath = %q", cfg.SSHKeyPath) } if cfg.NamegenPath != filepath.Join(runtimeDir, meta.NamegenPath) { t.Fatalf("NamegenPath = %q", cfg.NamegenPath) } if cfg.CustomizeScript != filepath.Join(runtimeDir, meta.CustomizeScript) { t.Fatalf("CustomizeScript = %q", cfg.CustomizeScript) } if cfg.VSockPingHelperPath != filepath.Join(runtimeDir, meta.VSockPingHelperPath) { t.Fatalf("VSockPingHelperPath = %q", cfg.VSockPingHelperPath) } if cfg.DefaultRootfs != filepath.Join(runtimeDir, meta.DefaultRootfs) { t.Fatalf("DefaultRootfs = %q", cfg.DefaultRootfs) } if cfg.DefaultBaseRootfs != filepath.Join(runtimeDir, meta.DefaultRootfs) { t.Fatalf("DefaultBaseRootfs = %q", cfg.DefaultBaseRootfs) } if cfg.DefaultKernel != filepath.Join(runtimeDir, meta.DefaultKernel) { t.Fatalf("DefaultKernel = %q", cfg.DefaultKernel) } if cfg.DefaultInitrd != filepath.Join(runtimeDir, meta.DefaultInitrd) { t.Fatalf("DefaultInitrd = %q", cfg.DefaultInitrd) } if cfg.DefaultModulesDir != filepath.Join(runtimeDir, meta.DefaultModulesDir) { t.Fatalf("DefaultModulesDir = %q", cfg.DefaultModulesDir) } if cfg.DefaultPackagesFile != filepath.Join(runtimeDir, meta.DefaultPackages) { t.Fatalf("DefaultPackagesFile = %q", cfg.DefaultPackagesFile) } } func TestLoadFallsBackToLegacyRuntimeLayoutWithoutBundleMetadata(t *testing.T) { runtimeDir := t.TempDir() for _, rel := range []string{ "firecracker", "id_ed25519", "namegen", "customize.sh", "banger-vsock-pingd", "packages.apt", "rootfs-docker.ext4", "wtf/root/boot/vmlinux-6.8.0-94-generic", "wtf/root/boot/initrd.img-6.8.0-94-generic", "wtf/root/lib/modules/6.8.0-94-generic/modules.dep", } { path := filepath.Join(runtimeDir, rel) if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatalf("mkdir %s: %v", filepath.Dir(path), err) } if err := os.WriteFile(path, []byte("test"), 0o644); err != nil { t.Fatalf("write %s: %v", path, err) } } t.Setenv("BANGER_RUNTIME_DIR", runtimeDir) cfg, err := Load(paths.Layout{ConfigDir: t.TempDir()}) if err != nil { t.Fatalf("Load: %v", err) } if cfg.FirecrackerBin != filepath.Join(runtimeDir, "firecracker") { t.Fatalf("FirecrackerBin = %q", cfg.FirecrackerBin) } if cfg.VSockPingHelperPath != filepath.Join(runtimeDir, "banger-vsock-pingd") { t.Fatalf("VSockPingHelperPath = %q", cfg.VSockPingHelperPath) } if cfg.DefaultKernel != filepath.Join(runtimeDir, "wtf/root/boot/vmlinux-6.8.0-94-generic") { t.Fatalf("DefaultKernel = %q", cfg.DefaultKernel) } } func TestLoadAppliesLogLevelEnvOverride(t *testing.T) { t.Setenv("BANGER_LOG_LEVEL", "debug") cfg, err := Load(paths.Layout{ConfigDir: t.TempDir()}) if err != nil { t.Fatalf("Load: %v", err) } if cfg.LogLevel != "debug" { t.Fatalf("LogLevel = %q", cfg.LogLevel) } } func TestLoadDefaultsLogLevelToInfo(t *testing.T) { cfg, err := Load(paths.Layout{ConfigDir: t.TempDir()}) if err != nil { t.Fatalf("Load: %v", err) } if cfg.LogLevel != "info" { t.Fatalf("LogLevel = %q, want info", cfg.LogLevel) } }