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>
58 lines
1.5 KiB
Go
58 lines
1.5 KiB
Go
package proxmox
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// capture is one response recorded from the real host in Phase 0: the
|
|
// status, the reason phrase after the status code, and the raw body.
|
|
type capture struct {
|
|
Status int `json:"status"`
|
|
Reason string `json:"reason"`
|
|
Body string `json:"body"`
|
|
}
|
|
|
|
// readCapture loads testdata/<name>.json and fails the test when it is
|
|
// missing, so every string a test relies on is backed by a real response.
|
|
func readCapture(t *testing.T, name string) capture {
|
|
t.Helper()
|
|
raw, err := os.ReadFile(filepath.Join("testdata", name+".json"))
|
|
if err != nil {
|
|
t.Fatalf("reading capture %s: %v", name, err)
|
|
}
|
|
var c capture
|
|
if err := json.Unmarshal(raw, &c); err != nil {
|
|
t.Fatalf("parsing capture %s: %v", name, err)
|
|
}
|
|
return c
|
|
}
|
|
|
|
// loadAPIError turns an error capture into the apiError the client builds.
|
|
func loadAPIError(t *testing.T, name string) *apiError {
|
|
t.Helper()
|
|
c := readCapture(t, name)
|
|
if c.Status < 400 {
|
|
t.Fatalf("capture %s has status %d, want an error status", name, c.Status)
|
|
}
|
|
return newAPIError(c.Status, c.Reason, []byte(c.Body))
|
|
}
|
|
|
|
// decodeData decodes the "data" member of a successful capture into T.
|
|
func decodeData[T any](t *testing.T, name string) T {
|
|
t.Helper()
|
|
c := readCapture(t, name)
|
|
if c.Status != 200 {
|
|
t.Fatalf("capture %s has status %d, want 200", name, c.Status)
|
|
}
|
|
var env struct {
|
|
Data T `json:"data"`
|
|
}
|
|
if err := json.Unmarshal([]byte(c.Body), &env); err != nil {
|
|
t.Fatalf("decoding capture %s: %v", name, err)
|
|
}
|
|
return env.Data
|
|
}
|