package daemon import ( "context" "path/filepath" "strings" "testing" "banger/internal/model" "banger/internal/paths" ) // TestReserveVMAllowsNameThatPrefixesExistingVM is a regression for a // correctness bug in the name-uniqueness check: reserveVM used to // route through FindVM, which falls back to prefix-matching on both // ids and names. That meant a perfectly valid new name like "beta" // could be rejected simply because an existing VM's id or name // started with "beta". Exact-name lookup via store.GetVMByName fixes // it. The test seeds a VM whose id and name are long strings, then // tries to reserve a new VM with a name that's a prefix of each — // both must succeed. func TestReserveVMAllowsNameThatPrefixesExistingVM(t *testing.T) { ctx := context.Background() tmp := t.TempDir() d := &Daemon{ store: openDaemonStore(t), layout: paths.Layout{VMsDir: filepath.Join(tmp, "vms"), RuntimeDir: filepath.Join(tmp, "runtime")}, config: model.DaemonConfig{BridgeIP: model.DefaultBridgeIP}, } existing := testVM("longname-sandbox-foobar", "image-x", "172.16.0.50") upsertDaemonVM(t, ctx, d.store, existing) image := testImage("image-x") image.ID = "image-x" image.Name = "image-x" if err := d.store.UpsertImage(ctx, image); err != nil { t.Fatalf("UpsertImage: %v", err) } // New VM name is a prefix of the existing id (which is // "longname-sandbox-foobar-id" per testVM). Old FindVM-based check // would reject this. if vm, err := d.reserveVM(ctx, "longname", image, model.VMSpec{VCPUCount: 1, MemoryMiB: 128}); err != nil { t.Fatalf("reserveVM(prefix of id): %v", err) } else if vm.Name != "longname" { t.Fatalf("reserveVM returned name=%q, want longname", vm.Name) } // Prefix of the existing name ("longname-sandbox") must also work. if vm, err := d.reserveVM(ctx, "longname-sandbox", image, model.VMSpec{VCPUCount: 1, MemoryMiB: 128}); err != nil { t.Fatalf("reserveVM(prefix of name): %v", err) } else if vm.Name != "longname-sandbox" { t.Fatalf("reserveVM returned name=%q, want longname-sandbox", vm.Name) } } // TestReserveVMRejectsExactDuplicateName confirms the uniqueness // check still catches actual collisions after the FindVM → GetVMByName // switch. func TestReserveVMRejectsExactDuplicateName(t *testing.T) { ctx := context.Background() tmp := t.TempDir() d := &Daemon{ store: openDaemonStore(t), layout: paths.Layout{VMsDir: filepath.Join(tmp, "vms"), RuntimeDir: filepath.Join(tmp, "runtime")}, config: model.DaemonConfig{BridgeIP: model.DefaultBridgeIP}, } existing := testVM("sandbox", "image-x", "172.16.0.51") upsertDaemonVM(t, ctx, d.store, existing) image := testImage("image-x") image.ID = "image-x" image.Name = "image-x" if err := d.store.UpsertImage(ctx, image); err != nil { t.Fatalf("UpsertImage: %v", err) } _, err := d.reserveVM(ctx, "sandbox", image, model.VMSpec{VCPUCount: 1, MemoryMiB: 128}) if err == nil { t.Fatal("reserveVM with duplicate name should have failed") } if !strings.Contains(err.Error(), "already exists") { t.Fatalf("err = %v, want 'already exists'", err) } }