Get follows spec entry 9's check order (lock and unknown status before the name, suspended is Stopped after the name and mark checks), reads status/current so paused is Stopped, and maps the three agent messages of entry 7. ListByTag reads one config per candidate and fails whole only on the resources call or an ended ctx. waitTask polls the UPID's node every budgets.poll, logs failed tasks at V(1) and counts "WARNINGS: <n>" as success; waitUnlocked serves Create's ownership check. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
104 lines
2.7 KiB
Go
104 lines
2.7 KiB
Go
package proxmox
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider"
|
|
)
|
|
|
|
const (
|
|
testProvider = "proxmox-home"
|
|
testUID = "0b9c6f3e-2d4a-4e1b-9c7f-5a8d3e2f1b60"
|
|
testVMID = 150042
|
|
)
|
|
|
|
var (
|
|
testName = provider.NameFromUID(testUID)
|
|
testCreatedAt = time.Date(2026, 9, 23, 10, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
// fixture is a Provider over fakeAPI, logging into a capture, with every
|
|
// budget shrunk so waits take milliseconds.
|
|
type fixture struct {
|
|
t *testing.T
|
|
p *Provider
|
|
fake *fakeAPI
|
|
logs *logCapture
|
|
ctx context.Context
|
|
}
|
|
|
|
func newFixture(t *testing.T, verbosity int) *fixture {
|
|
t.Helper()
|
|
fx := &fixture{t: t, fake: newFakeAPI(), logs: &logCapture{}}
|
|
fx.p = newProvider(testProvider, testConfig(), fx.fake)
|
|
fx.p.budgets = testBudgets()
|
|
fx.ctx = fx.logs.context(verbosity)
|
|
return fx
|
|
}
|
|
|
|
func testBudgets() budgets {
|
|
return budgets{
|
|
clone: time.Second,
|
|
upload: time.Second,
|
|
resize: time.Second,
|
|
start: time.Second,
|
|
stop: time.Second,
|
|
destroy: time.Second,
|
|
seedDelete: time.Second,
|
|
running: time.Second,
|
|
poll: time.Millisecond,
|
|
}
|
|
}
|
|
|
|
// addOurVM places a VM carrying the mark for testUID and the tag, as
|
|
// Create leaves it.
|
|
func (fx *fixture) addOurVM(vmid int, name, status string) *fakeVM {
|
|
fx.t.Helper()
|
|
vm := fx.fake.addVM(vmid, name, status)
|
|
vm.config["description"] = formatDescription(testUID, testCreatedAt)
|
|
vm.config["tags"] = proxyTag
|
|
return vm
|
|
}
|
|
|
|
// id is the providerID of the VM addOurVM(testVMID, testName, …) places.
|
|
func (fx *fixture) id() string { return formatProviderID(testVMID, testName) }
|
|
|
|
func (fx *fixture) get(id string) *provider.Instance {
|
|
fx.t.Helper()
|
|
inst, err := fx.p.Get(fx.ctx, id)
|
|
if err != nil {
|
|
fx.t.Fatalf("Get(%s) error = %v", id, err)
|
|
}
|
|
return inst
|
|
}
|
|
|
|
// assertProviderError checks that err is a *provider.Error from this
|
|
// provider for op, in class and in no other class.
|
|
func assertProviderError(t *testing.T, err error, op string, class error) {
|
|
t.Helper()
|
|
if err == nil {
|
|
t.Fatalf("error = nil, want op %s class %v", op, class)
|
|
}
|
|
var pe *provider.Error
|
|
if !errors.As(err, &pe) {
|
|
t.Fatalf("error = %T (%v), want *provider.Error", err, err)
|
|
}
|
|
if pe.Provider != testProvider {
|
|
t.Errorf("error.Provider = %q, want %q", pe.Provider, testProvider)
|
|
}
|
|
if pe.Op != op {
|
|
t.Errorf("error.Op = %q, want %q", pe.Op, op)
|
|
}
|
|
if !errors.Is(err, class) {
|
|
t.Errorf("error = %v, want class %v", err, class)
|
|
}
|
|
for _, other := range []error{provider.ErrNotFound, provider.ErrQuotaExceeded, provider.ErrPermanent, provider.ErrTransient} {
|
|
if other != class && errors.Is(err, other) {
|
|
t.Errorf("error = %v, also matches %v", err, other)
|
|
}
|
|
}
|
|
}
|