package cluster import ( "testing" "webui4frpc/internal/store" ) func newNode(id string, mem float64) Node { return Node{ID: id, Addr: id + ":7500", Alive: true, Load: Load{MemPct: mem, NetPct: 10}} } func TestRingSuccessors(t *testing.T) { s := &State{} s.InsertAfter("", newNode("a", 50)) s.InsertAfter("a", newNode("b", 40)) s.InsertAfter("b", newNode("c", 30)) if got, _ := s.AliveSuccessor("a"); got != "b" { t.Fatalf("succ(a)=%s want b", got) } if got, _ := s.AliveSuccessor("c"); got != "a" { t.Fatalf("succ(c)=%s want a (wrap)", got) } s.MarkOffline("b") if got, _ := s.AliveSuccessor("a"); got != "c" { t.Fatalf("succ(a) after b down =%s want c", got) } if got, _ := s.AlivePredecessor("a"); got != "c" { t.Fatalf("pred(a)=%s want c", got) } } func TestLowestLoadClaimsTask(t *testing.T) { s := &State{} s.InsertAfter("", newNode("a", 90)) s.InsertAfter("a", newNode("b", 20)) // idle t1 := s.AddPending(store.Local{Name: "l1"}, store.Remote{Name: "r1"}, store.Link{}) low := s.LowestAlive() if low == nil || low.ID != "b" { t.Fatalf("lowest = %+v want b", low) } // b claims + establishes topology claimed := s.ClaimPending(t1.ID) if claimed == nil { t.Fatal("claim should succeed") } if len(s.PendingList()) != 0 { t.Fatalf("pending after claim = %+v", s.PendingList()) } s.AddTopology(claimed, "b") if len(s.TopologyList()) != 1 || s.TopologyList()[0].OwnerID != "b" { t.Fatalf("topology = %+v", s.TopologyList()) } } func TestOfflineReassignTopology(t *testing.T) { s := &State{} s.InsertAfter("", newNode("a", 50)) // a establishes two forwards for _, ln := range []string{"l1", "l2"} { p := s.AddPending(store.Local{Name: ln}, store.Remote{Name: "r1"}, store.Link{}) s.ClaimPending(p.ID) s.AddTopology(p, "a") } if len(s.TopologyList()) != 2 { t.Fatalf("topology = %+v", s.TopologyList()) } // a goes offline: forwards re-attached as pending reattached := s.OfflineReassign("a") if len(reattached) != 2 { t.Fatalf("reattached=%v want 2", reattached) } if len(s.TopologyList()) != 0 { t.Fatalf("topology after reassign = %+v", s.TopologyList()) } if len(s.PendingList()) != 2 { t.Fatalf("pending after reassign = %+v", s.PendingList()) } } func TestInsertAfterReorders(t *testing.T) { s := &State{} s.InsertAfter("", newNode("a", 50)) s.InsertAfter("a", newNode("b", 50)) s.InsertAfter("a", newNode("new", 50)) // new lands after a, b pushed after new var order []string for _, n := range s.Nodes { order = append(order, n.ID) } if order[0] != "a" || order[1] != "new" || order[2] != "b" { t.Fatalf("order = %v want [a new b]", order) } }