mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 04:06:21 +00:00
173 lines
4.8 KiB
Go
173 lines
4.8 KiB
Go
package api
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
)
|
|
|
|
func TestHandleTestConnection(t *testing.T) {
|
|
tempDir, err := os.MkdirTemp("", "pulse-conn-test")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
cfg := &config.Config{DataPath: tempDir}
|
|
handler := newTestConfigHandlers(t, cfg)
|
|
|
|
tests := []struct {
|
|
name string
|
|
requestBody interface{}
|
|
expectedStatus int
|
|
verifyResponse func(*testing.T, map[string]interface{})
|
|
}{
|
|
{
|
|
name: "fail_invalid_json",
|
|
requestBody: "invalid-json",
|
|
expectedStatus: http.StatusBadRequest,
|
|
},
|
|
{
|
|
name: "fail_missing_host",
|
|
requestBody: map[string]string{
|
|
"type": "pve",
|
|
// no host
|
|
},
|
|
expectedStatus: http.StatusBadRequest,
|
|
},
|
|
{
|
|
name: "fail_invalid_type",
|
|
requestBody: map[string]string{
|
|
"type": "unknown",
|
|
"host": "10.0.0.1",
|
|
},
|
|
expectedStatus: http.StatusBadRequest,
|
|
},
|
|
{
|
|
name: "fail_missing_auth",
|
|
requestBody: map[string]string{
|
|
"type": "pve",
|
|
"host": "10.0.0.1",
|
|
// no user/pass or token
|
|
},
|
|
expectedStatus: http.StatusBadRequest,
|
|
},
|
|
{
|
|
name: "fail_invalid_host_format",
|
|
requestBody: map[string]string{
|
|
"type": "pve",
|
|
"host": "://invalid-url",
|
|
"user": "root@pam",
|
|
"password": "password",
|
|
},
|
|
expectedStatus: http.StatusBadRequest,
|
|
},
|
|
{
|
|
name: "fail_connection_creation",
|
|
requestBody: map[string]string{
|
|
"type": "pve",
|
|
"host": "127.0.0.1:9999", // Unreachable port
|
|
"user": "root@pam",
|
|
"password": "password",
|
|
},
|
|
// Expecting 400 Bad Request because sanitizeErrorMessage wraps it
|
|
expectedStatus: http.StatusBadRequest,
|
|
},
|
|
{
|
|
// Token parsing logic test - should fail authentication if token format is invalid
|
|
// but here we just check if it accepts valid auth params struct.
|
|
// Actual successful connection is hard to test without mocking proxmox client.
|
|
// We can verify "connection refused" or "timeout" which confirms it tried.
|
|
name: "fail_connection_refused",
|
|
requestBody: map[string]string{
|
|
"type": "pve",
|
|
"host": "127.0.0.1:1", // Port 1 likely closed
|
|
"user": "root@pam",
|
|
"password": "password",
|
|
},
|
|
expectedStatus: http.StatusBadRequest,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var body []byte
|
|
var err error
|
|
|
|
if s, ok := tt.requestBody.(string); ok && s == "invalid-json" {
|
|
body = []byte(s)
|
|
} else {
|
|
body, err = json.Marshal(tt.requestBody)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
req := httptest.NewRequest("POST", "/api/config/connection/test", bytes.NewBuffer(body))
|
|
w := httptest.NewRecorder()
|
|
|
|
handler.HandleTestConnection(w, req)
|
|
|
|
if w.Code != tt.expectedStatus {
|
|
t.Errorf("handler returned wrong status code: got %v \nBody: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
if tt.verifyResponse != nil {
|
|
var response map[string]interface{}
|
|
_ = json.NewDecoder(w.Body).Decode(&response)
|
|
tt.verifyResponse(t, response)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestHandleTestNodePBSIsADirectProbeWithoutChangingRuntimeHealth(t *testing.T) {
|
|
var authorization string
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
authorization = r.Header.Get("Authorization")
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_ = json.NewEncoder(w).Encode(map[string]any{"data": []any{}})
|
|
}))
|
|
defer server.Close()
|
|
|
|
cfg := &config.Config{
|
|
DataPath: t.TempDir(),
|
|
PBSInstances: []config.PBSInstance{{
|
|
Name: "backup",
|
|
Host: server.URL,
|
|
TokenName: "root@pam!pulse",
|
|
TokenValue: "rotated-secret",
|
|
}},
|
|
}
|
|
handler := newTestConfigHandlers(t, cfg)
|
|
beforeHealth := handler.defaultMonitor.SchedulerHealth()
|
|
beforeStatuses := handler.defaultMonitor.GetConnectionStatuses()
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/config/nodes/pbs-0/test", nil)
|
|
rec := httptest.NewRecorder()
|
|
handler.HandleTestNode(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("saved PBS test status = %d, body=%s", rec.Code, rec.Body.String())
|
|
}
|
|
if !strings.Contains(authorization, "rotated-secret") {
|
|
t.Fatalf("saved PBS test did not use the current stored token: %q", authorization)
|
|
}
|
|
afterHealth := handler.defaultMonitor.SchedulerHealth()
|
|
if !reflect.DeepEqual(afterHealth.Instances, beforeHealth.Instances) ||
|
|
!reflect.DeepEqual(afterHealth.Breakers, beforeHealth.Breakers) ||
|
|
!reflect.DeepEqual(afterHealth.Staleness, beforeHealth.Staleness) {
|
|
t.Fatalf("direct PBS test mutated canonical scheduler health:\nbefore=%+v\nafter=%+v", beforeHealth, afterHealth)
|
|
}
|
|
if !reflect.DeepEqual(handler.defaultMonitor.GetConnectionStatuses(), beforeStatuses) {
|
|
t.Fatal("direct PBS test mutated the runtime connection projection")
|
|
}
|
|
}
|