mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 09:40:12 +00:00
155 lines
5.3 KiB
Go
155 lines
5.3 KiB
Go
//go:build linux
|
|
|
|
package scenario
|
|
|
|
import "fmt"
|
|
|
|
func validateStressPreparedBinaries(evidence StressPreparedBinaries) error {
|
|
if evidence.DashboardBuildCount != 1 || !evidence.DashboardPathReused || evidence.AgentBuildCount != 1 || !evidence.AgentPathReused {
|
|
return fmt.Errorf("prepared binaries=%+v: %w", evidence, ErrStressEvidence)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateStressWarmups(warmups []StressWarmupEvidence, agentCount int) error {
|
|
if len(warmups) != agentCount {
|
|
return fmt.Errorf("warmups=%d want=%d: %w", len(warmups), agentCount, ErrStressEvidence)
|
|
}
|
|
seen := make(map[int]struct{}, len(warmups))
|
|
for _, warmup := range warmups {
|
|
if _, duplicate := seen[warmup.Agent.Int()]; duplicate || !warmup.Exec || !warmup.Filesystem || !warmup.Terminal || !warmup.NAT || !warmup.FM {
|
|
return fmt.Errorf("warmup=%+v: %w", warmup, ErrStressEvidence)
|
|
}
|
|
seen[warmup.Agent.Int()] = struct{}{}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateStressSessions(sessions []StressSessionEvidence, plan []StressSessionPlan, countPerKind int) error {
|
|
if len(sessions) != countPerKind*3 {
|
|
return fmt.Errorf("sessions=%d want=%d: %w", len(sessions), countPerKind*3, ErrStressEvidence)
|
|
}
|
|
if len(plan) != len(sessions) {
|
|
return fmt.Errorf("session plan=%d evidence=%d: %w", len(plan), len(sessions), ErrStressEvidence)
|
|
}
|
|
expected := make(map[StressSessionID]StressSessionPlan, len(plan))
|
|
for _, session := range plan {
|
|
expected[session.ID] = session
|
|
}
|
|
counts := make(map[StressSessionKind]int, 3)
|
|
seen := make(map[StressSessionID]struct{}, len(sessions))
|
|
for _, session := range sessions {
|
|
planned, exists := expected[session.ID]
|
|
_, duplicate := seen[session.ID]
|
|
if !exists || planned.Kind != session.Kind || duplicate || !session.Succeeded {
|
|
return fmt.Errorf("session=%+v: %w", session, ErrStressEvidence)
|
|
}
|
|
seen[session.ID] = struct{}{}
|
|
counts[session.Kind]++
|
|
}
|
|
for _, kind := range []StressSessionKind{StressSessionTerminal, StressSessionNAT, StressSessionFM} {
|
|
if counts[kind] != countPerKind {
|
|
return fmt.Errorf("session kind=%s count=%d want=%d: %w", kind, counts[kind], countPerKind, ErrStressEvidence)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateStressIteration(plan StressPlan, evidence StressIterationEvidence, iteration int, faultAware bool) (int, error) {
|
|
if evidence.Iteration != iteration || len(evidence.Rounds) != len(plan.Rounds) || len(evidence.Resources) != 1+canonicalAgentCount(plan) {
|
|
return 0, fmt.Errorf("iteration=%+v: %w", evidence, ErrStressEvidence)
|
|
}
|
|
failed := 0
|
|
for index, round := range evidence.Rounds {
|
|
matched, err := matchStressRoundEvidence(plan.Rounds[index], round)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
for _, operation := range matched {
|
|
if !operation.Succeeded || operation.Error != "" {
|
|
failed++
|
|
if !faultAware || !isStressFaultOperation(plan.Rounds[index], operation, iteration) {
|
|
return 0, fmt.Errorf("unexpected failed operation=%s: %w", operation.ID.String(), ErrStressFault)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if err := validateStressResourceIdentities(plan, evidence.Resources); err != nil {
|
|
return 0, err
|
|
}
|
|
for _, windows := range evidence.Resources {
|
|
if _, err := EvaluateStressResource(windows); err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
return failed, nil
|
|
}
|
|
|
|
func validateStressFault(target *StressFaultTarget, failed int, faultAware bool) error {
|
|
if !faultAware {
|
|
if target != nil || failed != 0 {
|
|
return ErrStressFault
|
|
}
|
|
return nil
|
|
}
|
|
want := StressWorkerFaultTarget()
|
|
if target == nil || *target != want || failed != 1 {
|
|
return fmt.Errorf("target=%+v failed=%d want=%+v/1: %w", target, failed, want, ErrStressFault)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func isStressFaultOperation(plan StressRoundPlan, evidence StressOperationEvidence, iteration int) bool {
|
|
target := StressWorkerFaultTarget()
|
|
if iteration != target.Iteration || plan.Round != target.Round {
|
|
return false
|
|
}
|
|
for _, operation := range plan.Operations {
|
|
if operation.ID == evidence.ID {
|
|
return operation.Agent == target.Agent && operation.Kind == target.Kind
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func planAgentCount(plan StressPlan) int {
|
|
return canonicalAgentCount(plan)
|
|
}
|
|
|
|
func canonicalAgentCount(plan StressPlan) int {
|
|
if len(plan.Rounds) == 0 {
|
|
return 0
|
|
}
|
|
return len(plan.Rounds[0].Operations) / 2
|
|
}
|
|
|
|
func validateStressResourceIdentities(plan StressPlan, resources []StressProcessWindows) error {
|
|
wantAgents := planAgentCount(plan)
|
|
if len(resources) != wantAgents+1 {
|
|
return fmt.Errorf("resources=%d want=%d: %w", len(resources), wantAgents+1, ErrStressEvidence)
|
|
}
|
|
dashboardCount := 0
|
|
seenAgents := make(map[int]struct{}, wantAgents)
|
|
for _, resource := range resources {
|
|
switch resource.Process.Kind {
|
|
case StressProcessDashboard:
|
|
dashboardCount++
|
|
case StressProcessAgent:
|
|
ordinal := resource.Process.Agent.Int()
|
|
if ordinal < 1 || ordinal > wantAgents {
|
|
return fmt.Errorf("unknown agent ordinal=%d: %w", ordinal, ErrStressEvidence)
|
|
}
|
|
if _, duplicate := seenAgents[ordinal]; duplicate {
|
|
return fmt.Errorf("duplicate agent ordinal=%d: %w", ordinal, ErrStressEvidence)
|
|
}
|
|
seenAgents[ordinal] = struct{}{}
|
|
default:
|
|
return fmt.Errorf("unknown process kind=%q: %w", resource.Process.Kind, ErrStressEvidence)
|
|
}
|
|
}
|
|
if dashboardCount != 1 || len(seenAgents) != wantAgents {
|
|
return fmt.Errorf("dashboard=%d agents=%d want=1/%d: %w", dashboardCount, len(seenAgents), wantAgents, ErrStressEvidence)
|
|
}
|
|
return nil
|
|
}
|