banger/internal/paths/paths_test.go
Thales Maciel 08ef706e3f
Add vsock-backed SSH session reminders
Remind users when a VM is still running after 	hanger vm ssh exits instead of silently dropping them back to the host shell.\n\nAttach a Firecracker vsock device to each VM, persist the host vsock path/CID,\nadd a new guest-side banger-vsock-pingd responder to the runtime bundle and both\nimage-build paths, and expose a vm.ping RPC that the CLI and TUI call after SSH\nreturns. Doctor and start/build preflight now validate the helper plus\n/dev/vhost-vsock so the feature fails early and clearly.\n\nValidated with go mod tidy, bash -n customize.sh, git diff --check, make build,\nand GOCACHE=/tmp/banger-gocache go test ./... outside the sandbox because the\ndaemon tests need real Unix/UDP sockets. Rebuild the image/rootfs used for new\nVMs so the guest ping service is present.
2026-03-18 20:14:51 -03:00

93 lines
2.6 KiB
Go

package paths
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"banger/internal/runtimebundle"
)
func TestResolveRuntimeDirPrefersEnv(t *testing.T) {
t.Setenv("BANGER_RUNTIME_DIR", "/env/runtime")
if got := ResolveRuntimeDir("/config/runtime", "/deprecated/repo"); got != "/env/runtime" {
t.Fatalf("ResolveRuntimeDir() = %q, want /env/runtime", got)
}
}
func TestResolveRuntimeDirUsesInstalledLayout(t *testing.T) {
root := t.TempDir()
runtimeDir := filepath.Join(root, "lib", "banger")
createRuntimeBundle(t, runtimeDir)
origExecutablePath := executablePath
executablePath = func() (string, error) {
return filepath.Join(root, "bin", "banger"), nil
}
t.Cleanup(func() {
executablePath = origExecutablePath
})
if got := ResolveRuntimeDir("", ""); got != runtimeDir {
t.Fatalf("ResolveRuntimeDir() = %q, want %q", got, runtimeDir)
}
}
func TestResolveRuntimeDirUsesSourceCheckoutRuntimeSubdir(t *testing.T) {
root := t.TempDir()
runtimeDir := filepath.Join(root, "runtime")
createRuntimeBundle(t, runtimeDir)
origExecutablePath := executablePath
executablePath = func() (string, error) {
return filepath.Join(root, "banger"), nil
}
t.Cleanup(func() {
executablePath = origExecutablePath
})
if got := ResolveRuntimeDir("", ""); got != runtimeDir {
t.Fatalf("ResolveRuntimeDir() = %q, want %q", got, runtimeDir)
}
}
func createRuntimeBundle(t *testing.T, runtimeDir string) {
t.Helper()
metadata := 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",
}
for _, rel := range []string{
metadata.FirecrackerBin,
metadata.SSHKeyPath,
metadata.NamegenPath,
metadata.CustomizeScript,
metadata.VSockPingHelperPath,
metadata.DefaultPackages,
metadata.DefaultRootfs,
metadata.DefaultKernel,
} {
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(metadata)
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)
}
}