This commit is contained in:
2026-05-18 21:33:39 +03:00
parent 5096155d83
commit 469fa0e860
94 changed files with 8761 additions and 8003 deletions
@@ -0,0 +1,68 @@
package cluster
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
func TestWriteServiceErrorLegacyRemovalBlockedIncludesBreakdownDetails(t *testing.T) {
recorder := httptest.NewRecorder()
handled := writeServiceError(recorder, &LegacyRemovalBlockedError{
BlockedOperation: "create_breaking_release",
Report: StaleNodeRiskReport{
HeartbeatStaleAfterSeconds: 900,
LegacyRemovalAllowed: false,
BridgeHoldRequired: true,
BridgeHoldNodeIDs: []string{"node-1"},
BridgeHoldReasons: []string{"legacy_contract_overlap"},
BlockedOperations: []string{"create_breaking_release", "target_breaking_update_policy", "remove_recovery_bridge_overlap"},
Nodes: []StaleNodeRiskNode{
{NodeID: "node-1", Blocked: true, RecoveryBridgeRequired: true},
{NodeID: "node-2", Blocked: false},
},
Summary: StaleNodeRiskSummary{
StaleNodes: 1,
BlockedNodes: 1,
ArtifactGapNodes: 0,
UnknownProfileNodes: 0,
WaitingUpdateStatusNodes: 0,
UnknownVersionNodes: 0,
LegacyRecoveryContractNodes: 0,
WaitingRecoveryHeartbeatNodes: 1,
},
},
})
if !handled {
t.Fatalf("writeServiceError returned false")
}
if recorder.Code != http.StatusConflict {
t.Fatalf("status = %d, want %d", recorder.Code, http.StatusConflict)
}
var payload struct {
Error struct {
Details map[string]any `json:"details"`
} `json:"error"`
}
if err := json.Unmarshal(recorder.Body.Bytes(), &payload); err != nil {
t.Fatalf("unmarshal response: %v", err)
}
if payload.Error.Details["blocked_operation"] != "create_breaking_release" {
t.Fatalf("blocked_operation = %v", payload.Error.Details["blocked_operation"])
}
if payload.Error.Details["waiting_recovery_heartbeat_nodes"] != float64(1) {
t.Fatalf("waiting_recovery_heartbeat_nodes = %v", payload.Error.Details["waiting_recovery_heartbeat_nodes"])
}
if payload.Error.Details["bridge_hold_required"] != true {
t.Fatalf("bridge_hold_required = %v", payload.Error.Details["bridge_hold_required"])
}
blockedNodeIDs, ok := payload.Error.Details["blocked_node_ids"].([]any)
if !ok || len(blockedNodeIDs) != 1 || blockedNodeIDs[0] != "node-1" {
t.Fatalf("blocked_node_ids = %#v", payload.Error.Details["blocked_node_ids"])
}
bridgeHoldNodeIDs, ok := payload.Error.Details["bridge_hold_node_ids"].([]any)
if !ok || len(bridgeHoldNodeIDs) != 1 || bridgeHoldNodeIDs[0] != "node-1" {
t.Fatalf("bridge_hold_node_ids = %#v", payload.Error.Details["bridge_hold_node_ids"])
}
}