158 lines
4.4 KiB
Go
158 lines
4.4 KiB
Go
package clusteradmin
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"net/http"
|
|
"net/http/httptest"
|
|
|
|
"forgejo.digital-droplets.de/philschlo/proxui/platform/cluster"
|
|
)
|
|
|
|
func TestCreateClusterDoesNotReturnTokenSecret(t *testing.T) {
|
|
repository := newStubRepository()
|
|
handler := NewHandler(repository)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/internal/clusters", strings.NewReader(`{
|
|
"name": "Lab",
|
|
"api_endpoint": "https://pve.example.test:8006/api2/json",
|
|
"tls_fingerprint": "AA:BB",
|
|
"token_id": "root@pam!proxui",
|
|
"token_secret": "secret-token"
|
|
}`))
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.CreateCluster(rec, req)
|
|
|
|
if rec.Code != http.StatusCreated {
|
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusCreated)
|
|
}
|
|
if repository.saved.TokenSecret != "secret-token" {
|
|
t.Fatalf("saved token secret = %q", repository.saved.TokenSecret)
|
|
}
|
|
if bytes.Contains(rec.Body.Bytes(), []byte("secret-token")) {
|
|
t.Fatal("response contains token secret")
|
|
}
|
|
|
|
var response clusterResponse
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &response); err != nil {
|
|
t.Fatalf("unmarshal response: %v", err)
|
|
}
|
|
if response.TokenID != "root@pam!proxui" {
|
|
t.Fatalf("TokenID = %q, want root@pam!proxui", response.TokenID)
|
|
}
|
|
}
|
|
|
|
func TestUpdateClusterUsesPathIDAndRotatesToken(t *testing.T) {
|
|
repository := newStubRepository()
|
|
handler := NewHandler(repository)
|
|
|
|
req := httptest.NewRequest(http.MethodPut, "/internal/clusters/cluster-1", strings.NewReader(`{
|
|
"name": "Lab",
|
|
"api_endpoint": "https://pve.example.test:8006/api2/json",
|
|
"tls_fingerprint": "AA:BB",
|
|
"token_id": "root@pam!proxui",
|
|
"token_secret": "rotated-token",
|
|
"status": "active"
|
|
}`))
|
|
req.SetPathValue("clusterID", "cluster-1")
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.UpdateCluster(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
|
|
}
|
|
if repository.saved.ID != "cluster-1" {
|
|
t.Fatalf("saved ID = %q, want cluster-1", repository.saved.ID)
|
|
}
|
|
if repository.saved.TokenSecret != "rotated-token" {
|
|
t.Fatalf("saved token secret = %q", repository.saved.TokenSecret)
|
|
}
|
|
if bytes.Contains(rec.Body.Bytes(), []byte("rotated-token")) {
|
|
t.Fatal("response contains rotated token secret")
|
|
}
|
|
}
|
|
|
|
func TestSetClusterStatus(t *testing.T) {
|
|
repository := newStubRepository()
|
|
handler := NewHandler(repository)
|
|
|
|
req := httptest.NewRequest(http.MethodPatch, "/internal/clusters/cluster-1/status", strings.NewReader(`{"status":"disabled"}`))
|
|
req.SetPathValue("clusterID", "cluster-1")
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.SetClusterStatus(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
|
|
}
|
|
if repository.statusID != "cluster-1" {
|
|
t.Fatalf("status ID = %q, want cluster-1", repository.statusID)
|
|
}
|
|
if repository.status != "disabled" {
|
|
t.Fatalf("status = %q, want disabled", repository.status)
|
|
}
|
|
}
|
|
|
|
func TestSetClusterStatusReturnsNotFound(t *testing.T) {
|
|
repository := newStubRepository()
|
|
repository.statusFound = false
|
|
handler := NewHandler(repository)
|
|
|
|
req := httptest.NewRequest(http.MethodPatch, "/internal/clusters/missing/status", strings.NewReader(`{"status":"disabled"}`))
|
|
req.SetPathValue("clusterID", "missing")
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.SetClusterStatus(rec, req)
|
|
|
|
if rec.Code != http.StatusNotFound {
|
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusNotFound)
|
|
}
|
|
}
|
|
|
|
type stubRepository struct {
|
|
saved cluster.Cluster
|
|
statusID string
|
|
status string
|
|
statusFound bool
|
|
}
|
|
|
|
func newStubRepository() *stubRepository {
|
|
return &stubRepository{statusFound: true}
|
|
}
|
|
|
|
func (s *stubRepository) UpsertCluster(_ context.Context, cluster cluster.Cluster) (cluster.Cluster, error) {
|
|
s.saved = cluster
|
|
if cluster.ID == "" {
|
|
cluster.ID = "cluster-1"
|
|
}
|
|
if cluster.Status == "" {
|
|
cluster.Status = "active"
|
|
}
|
|
cluster.CreatedAt = time.Date(2026, 6, 11, 12, 0, 0, 0, time.UTC)
|
|
return cluster, nil
|
|
}
|
|
|
|
func (s *stubRepository) SetClusterStatus(_ context.Context, id string, status string) (cluster.Cluster, bool, error) {
|
|
s.statusID = id
|
|
s.status = status
|
|
if !s.statusFound {
|
|
return cluster.Cluster{}, false, nil
|
|
}
|
|
return cluster.Cluster{
|
|
ID: id,
|
|
Name: "Lab",
|
|
APIEndpoint: "https://pve.example.test:8006/api2/json",
|
|
TLSFingerprint: "AA:BB",
|
|
TokenID: "root@pam!proxui",
|
|
Status: status,
|
|
CreatedAt: time.Date(2026, 6, 11, 12, 0, 0, 0, time.UTC),
|
|
}, true, nil
|
|
}
|