Files
webui4frpc/internal/cluster/ring_revoke_test.go

65 lines
2.2 KiB
Go

package cluster
import (
"context"
"testing"
"webui4frpc/internal/store"
)
// TestRevokeTaskRemovesTopology: a revoke task published to the ring removes
// the forward from topology, calls Handler.Revoke, and logs forward.remove.
func TestRevokeTaskRemovesTopology(t *testing.T) {
revoked := false
eng := NewEngine("n1", "n1:7500", "u", "p", "0.71.0", nil,
&fakeHandler{load: Load{MemPct: 5, NetPct: 5},
revoke: func(ctx context.Context, tk *Task) error { revoked = true; return nil }},
func(ctx context.Context, next string, tk *Token) error { return nil },
"n1:7500", true)
// establish a forward
eng.state.AddPending(store.Local{Name: "web"}, store.Remote{Name: "frps1"}, store.Link{RemotePort: 18081})
// lowest-load is n1 (only node): it claims + builds topology
if err := eng.phase2(context.Background(), &Token{Cycle: 1, Phase: PhaseSync, State: eng.state}); err != nil {
t.Fatal(err)
}
if len(eng.state.TopologyList()) != 1 {
t.Fatalf("topology after claim = %+v", eng.state.TopologyList())
}
// publish a revoke task pointing at the same forward
eng.state.AddRevoke(store.Local{Name: "web"}, store.Remote{Name: "frps1"}, store.Link{RemotePort: 18081})
if err := eng.phase2(context.Background(), &Token{Cycle: 2, Phase: PhaseSync, State: eng.state}); err != nil {
t.Fatal(err)
}
if len(eng.state.TopologyList()) != 0 {
t.Fatalf("topology after revoke = %+v", eng.state.TopologyList())
}
if !revoked {
t.Fatal("Handler.Revoke was not called")
}
// log should contain forward.remove
var sawRemove bool
for _, e := range eng.Log.Snapshot() {
if e.Kind == LogForwardRemove {
sawRemove = true
}
}
if !sawRemove {
t.Fatalf("log missing forward.remove: %+v", eng.Log.Snapshot())
}
}
// TestRevokeIdempotent: revoking an already-missing forward does not error.
func TestRevokeIdempotent(t *testing.T) {
eng := newTestEngine("n1", true)
eng.state.AddRevoke(store.Local{Name: "ghost"}, store.Remote{Name: "frps1"}, store.Link{RemotePort: 1})
if err := eng.phase2(context.Background(), &Token{Cycle: 1, Phase: PhaseSync, State: eng.state}); err != nil {
t.Fatalf("revoke missing: %v", err)
}
// no topology entry, no panic
if len(eng.state.TopologyList()) != 0 {
t.Fatal("should be empty")
}
}