From 4ec2df50715bd36ae8f18fc161cc491671d060b6 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Thu, 5 Feb 2026 11:42:35 +0000 Subject: [PATCH] Add cluster membership and not-implemented coverage --- .../cluster_client_additional_api7_test.go | 63 +++++++++++++++++++ pkg/proxmox/cluster_client_more_test.go | 25 ++++++++ 2 files changed, 88 insertions(+) create mode 100644 pkg/proxmox/cluster_client_additional_api7_test.go diff --git a/pkg/proxmox/cluster_client_additional_api7_test.go b/pkg/proxmox/cluster_client_additional_api7_test.go new file mode 100644 index 000000000..bce7c9d02 --- /dev/null +++ b/pkg/proxmox/cluster_client_additional_api7_test.go @@ -0,0 +1,63 @@ +package proxmox + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "testing" +) + +func TestClusterClient_IsClusterMember_NodeCountFallback(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + if r.URL.Path == "/api2/json/nodes" { + fmt.Fprint(w, `{"data":[{"node":"node1","status":"online"},{"node":"node2","status":"online"}]}`) + return + } + if r.URL.Path == "/api2/json/cluster/status" { + fmt.Fprint(w, `{"data":[{"type":"node","name":"node1"},{"type":"node","name":"node2"}]}`) + return + } + w.WriteHeader(http.StatusNotFound) + })) + defer server.Close() + + cfg := ClientConfig{Host: server.URL, TokenName: "u@p!t", TokenValue: "v"} + cc := NewClusterClient("test", cfg, []string{server.URL}, nil) + + member, err := cc.IsClusterMember(context.Background()) + if err != nil { + t.Fatalf("IsClusterMember failed: %v", err) + } + if !member { + t.Fatal("expected cluster membership to be true via node count fallback") + } +} + +func TestClusterClient_IsClusterMember_SingleNode(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + if r.URL.Path == "/api2/json/nodes" { + fmt.Fprint(w, `{"data":[{"node":"node1","status":"online"}]}`) + return + } + if r.URL.Path == "/api2/json/cluster/status" { + fmt.Fprint(w, `{"data":[{"type":"node","name":"node1"}]}`) + return + } + w.WriteHeader(http.StatusNotFound) + })) + defer server.Close() + + cfg := ClientConfig{Host: server.URL, TokenName: "u@p!t", TokenValue: "v"} + cc := NewClusterClient("test", cfg, []string{server.URL}, nil) + + member, err := cc.IsClusterMember(context.Background()) + if err != nil { + t.Fatalf("IsClusterMember failed: %v", err) + } + if member { + t.Fatal("expected cluster membership to be false for single-node response") + } +} diff --git a/pkg/proxmox/cluster_client_more_test.go b/pkg/proxmox/cluster_client_more_test.go index 08979b1f8..22092f59b 100644 --- a/pkg/proxmox/cluster_client_more_test.go +++ b/pkg/proxmox/cluster_client_more_test.go @@ -110,3 +110,28 @@ func TestExecuteWithFailoverClearsErrorOnSuccess(t *testing.T) { t.Fatal("expected lastError to be cleared") } } + +func TestExecuteWithFailoverNotImplementedDoesNotMarkUnhealthy(t *testing.T) { + cc := &ClusterClient{ + name: "cluster", + endpoints: []string{"node1"}, + clients: map[string]*Client{"node1": {}}, + nodeHealth: map[string]bool{"node1": true}, + lastError: make(map[string]string), + lastHealthCheck: map[string]time.Time{"node1": time.Now()}, + rateLimitUntil: make(map[string]time.Time), + } + + err := cc.executeWithFailover(context.Background(), func(*Client) error { + return fmt.Errorf("not implemented status 501") + }) + if err == nil { + t.Fatal("expected error") + } + if !cc.nodeHealth["node1"] { + t.Fatal("expected node to remain healthy for not implemented error") + } + if len(cc.lastError) != 0 { + t.Fatalf("expected no lastError, got %+v", cc.lastError) + } +}