pve-exporter/collector/client_test.go
Davíð Steinn Geirsson 210e22e030 feat: add PVE API client with multi-host failover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 11:25:48 +00:00

118 lines
3.3 KiB
Go

package collector
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestClientGetAuthHeader(t *testing.T) {
var gotAuth string
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotAuth = r.Header.Get("Authorization")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"data":[]}`))
}))
defer server.Close()
client := NewClient([]string{server.URL}, "user@pam!token=secret-value", false, 5)
client.httpClient = server.Client()
body, err := client.Get("/cluster/resources")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if string(body) != `{"data":[]}` {
t.Errorf("unexpected body: %s", body)
}
expectedAuth := "PVEAPIToken=user@pam!token=secret-value"
if gotAuth != expectedAuth {
t.Errorf("expected auth header %q, got %q", expectedAuth, gotAuth)
}
}
func TestClientGetRequestPath(t *testing.T) {
var gotPath string
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotPath = r.URL.Path
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{}`))
}))
defer server.Close()
client := NewClient([]string{server.URL}, "tok", false, 5)
client.httpClient = server.Client()
_, err := client.Get("/nodes/pve1/status")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expected := "/api2/json/nodes/pve1/status"
if gotPath != expected {
t.Errorf("expected path %q, got %q", expected, gotPath)
}
}
func TestClientFailover(t *testing.T) {
callCount := 0
// First server returns 500
server1 := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
callCount++
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("error"))
}))
defer server1.Close()
// Second server succeeds
server2 := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
callCount++
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"data":"ok"}`))
}))
defer server2.Close()
// Both test servers use different TLS certs; we need a client that trusts both.
// Since httptest servers each have their own CA, we create an insecure client.
client := NewClient([]string{server1.URL, server2.URL}, "tok", true, 5)
body, err := client.Get("/test")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if string(body) != `{"data":"ok"}` {
t.Errorf("unexpected body: %s", body)
}
if callCount != 2 {
t.Errorf("expected 2 calls (one failed, one succeeded), got %d", callCount)
}
}
func TestClientAllHostsFail(t *testing.T) {
server1 := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer server1.Close()
server2 := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadGateway)
}))
defer server2.Close()
client := NewClient([]string{server1.URL, server2.URL}, "tok", true, 5)
_, err := client.Get("/test")
if err == nil {
t.Fatal("expected error when all hosts fail")
}
if !strings.Contains(err.Error(), "all PVE hosts failed") {
t.Errorf("unexpected error message: %v", err)
}
}
func TestClientMaxConcurrent(t *testing.T) {
client := NewClient([]string{"https://localhost"}, "tok", false, 10)
if client.MaxConcurrent() != 10 {
t.Errorf("expected MaxConcurrent=10, got %d", client.MaxConcurrent())
}
}