package daemon import ( "context" "io" "log/slog" "path/filepath" "strings" "testing" "banger/internal/api" "banger/internal/model" ) // newWorkspaceRejectionDaemon returns a running-VM + wired daemon // suitable for the PrepareVMWorkspace rejection tests. No real guest // state — rejection paths return before any SSH I/O, so the fake // firecracker infra the happy-path tests need is unnecessary here. func newWorkspaceRejectionDaemon(t *testing.T) (*Daemon, model.VMRecord) { t.Helper() vm := testVM("rejectbox", "image-reject", "172.16.0.211") vm.State = model.VMStateRunning vm.Runtime.State = model.VMStateRunning d := &Daemon{ store: openDaemonStore(t), config: model.DaemonConfig{SSHKeyPath: filepath.Join(t.TempDir(), "id_ed25519")}, logger: slog.New(slog.NewTextHandler(io.Discard, nil)), } wireServices(d) upsertDaemonVM(t, context.Background(), d.store, vm) // Handle cache entry with a live-looking PID so vmAlive returns // true for the "VM is running" path; the rejection tests that want // the not-running branch clear this override explicitly. d.vm.setVMHandlesInMemory(vm.ID, model.VMHandles{PID: 1}) // init is always alive return d, vm } func TestPrepareVMWorkspace_RejectsMalformedMode(t *testing.T) { d, vm := newWorkspaceRejectionDaemon(t) _, err := d.ws.PrepareVMWorkspace(context.Background(), api.VMWorkspacePrepareParams{ IDOrName: vm.Name, SourcePath: "/tmp/fake", Mode: "bogus_mode", }) if err == nil || !strings.Contains(err.Error(), "unsupported workspace mode") { t.Fatalf("err = %v, want unsupported-mode rejection", err) } } func TestPrepareVMWorkspace_RejectsFromWithoutBranch(t *testing.T) { d, vm := newWorkspaceRejectionDaemon(t) _, err := d.ws.PrepareVMWorkspace(context.Background(), api.VMWorkspacePrepareParams{ IDOrName: vm.Name, SourcePath: "/tmp/fake", From: "HEAD", // Branch deliberately left empty. }) if err == nil || !strings.Contains(err.Error(), "workspace from requires branch") { t.Fatalf("err = %v, want from-without-branch rejection", err) } } func TestPrepareVMWorkspace_RejectsNotRunningVM(t *testing.T) { d, vm := newWorkspaceRejectionDaemon(t) // Clear handles so vmAlive returns false — simulates a VM that's // been stopped or never booted. d.vm.clearVMHandles(vm) _, err := d.ws.PrepareVMWorkspace(context.Background(), api.VMWorkspacePrepareParams{ IDOrName: vm.Name, SourcePath: "/tmp/fake", }) if err == nil || !strings.Contains(err.Error(), "is not running") { t.Fatalf("err = %v, want not-running rejection", err) } } func TestPrepareVMWorkspace_RejectsUnknownVM(t *testing.T) { d, _ := newWorkspaceRejectionDaemon(t) _, err := d.ws.PrepareVMWorkspace(context.Background(), api.VMWorkspacePrepareParams{ IDOrName: "ghost-vm", SourcePath: "/tmp/fake", }) if err == nil || !strings.Contains(err.Error(), "not found") { t.Fatalf("err = %v, want VM-not-found rejection", err) } }