Phase 2 of the proxmox provider plan. Adds the proxmox: config block with its validation, registers the type in the config allow-list and the constructor map, and starts internal/provider/proxmox: the api seam and its data types, providerIDs (vms/<vmid>/<name>) with the UID-derived VMID, the description mark, state mapping, and error classification. Tests read the responses captured from pv1-1 in Phase 0 rather than repeating Proxmox's wording, and every matcher is run against every captured error so none fires on the wrong message. The contract methods are Transient stubs until Phases 5 to 7. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
90 lines
2.6 KiB
Go
90 lines
2.6 KiB
Go
package proxmox
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider"
|
|
)
|
|
|
|
func TestFormatProviderID_roundTrip(t *testing.T) {
|
|
t.Parallel()
|
|
for _, vmid := range []int{100, 150042, 999999999} {
|
|
id := formatProviderID(vmid, "proxy-abcdefghijklmnop")
|
|
gotVMID, gotName, err := parseProviderID(id)
|
|
if err != nil || gotVMID != vmid || gotName != "proxy-abcdefghijklmnop" {
|
|
t.Errorf("parseProviderID(%q) = %d, %q, %v; want %d, proxy-abcdefghijklmnop, nil", id, gotVMID, gotName, err, vmid)
|
|
}
|
|
}
|
|
if got := formatProviderID(150042, "proxy-x"); got != "vms/150042/proxy-x" {
|
|
t.Errorf("formatProviderID() = %q, want vms/150042/proxy-x", got)
|
|
}
|
|
}
|
|
|
|
func TestParseProviderID_malformed(t *testing.T) {
|
|
t.Parallel()
|
|
for _, id := range []string{
|
|
"",
|
|
"vms",
|
|
"vms/150042",
|
|
"vms/150042/",
|
|
"vms//proxy-x",
|
|
"vm/150042/proxy-x",
|
|
"hosts/beelink/domains/proxy-x",
|
|
"vms/150042/proxy-x/extra",
|
|
"vms/abc/proxy-x",
|
|
"vms/0150042/proxy-x",
|
|
"vms/+150042/proxy-x",
|
|
"vms/-5/proxy-x",
|
|
"vms/99/proxy-x",
|
|
"vms/1000000000/proxy-x",
|
|
} {
|
|
t.Run(id, func(t *testing.T) {
|
|
t.Parallel()
|
|
_, _, err := parseProviderID(id)
|
|
if !errors.Is(err, provider.ErrPermanent) {
|
|
t.Errorf("parseProviderID(%q) error = %v, want ErrPermanent", id, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVMIDFor_deterministicAndInRange(t *testing.T) {
|
|
t.Parallel()
|
|
uids := []string{"3f1c2d7e-8a44-4f1b-9a6c-1d2e3f4a5b6c", "00000000-0000-0000-0000-000000000000", "x"}
|
|
for _, uid := range uids {
|
|
first := vmidFor(uid, 100000, 199999, 0)
|
|
if first < 100000 || first > 199999 {
|
|
t.Errorf("vmidFor(%q) = %d, want within 100000..199999", uid, first)
|
|
}
|
|
if again := vmidFor(uid, 100000, 199999, 0); again != first {
|
|
t.Errorf("vmidFor(%q) = %d then %d, want the same VMID every time", uid, first, again)
|
|
}
|
|
}
|
|
if vmidFor(uids[0], 100000, 199999, 0) == vmidFor(uids[1], 100000, 199999, 0) {
|
|
t.Error("two different UIDs got the same first VMID; the hash does not spread")
|
|
}
|
|
}
|
|
|
|
func TestVMIDFor_probesForwardAndWraps(t *testing.T) {
|
|
t.Parallel()
|
|
const min, max = 500, 509
|
|
uid := "3f1c2d7e-8a44-4f1b-9a6c-1d2e3f4a5b6c"
|
|
start := vmidFor(uid, min, max, 0)
|
|
seen := map[int]bool{}
|
|
for attempt := range 10 {
|
|
got := vmidFor(uid, min, max, attempt)
|
|
want := min + (start-min+attempt)%10
|
|
if got != want {
|
|
t.Errorf("attempt %d: vmidFor = %d, want %d (one step forward, wrapping at max)", attempt, got, want)
|
|
}
|
|
seen[got] = true
|
|
}
|
|
if len(seen) != 10 {
|
|
t.Errorf("10 attempts over a range of 10 visited %d VMIDs, want all 10", len(seen))
|
|
}
|
|
if got := vmidFor(uid, min, max, 10); got != start {
|
|
t.Errorf("attempt 10 = %d, want to wrap back to %d", got, start)
|
|
}
|
|
}
|