package httpapi import ( "context" "errors" "testing" "github.com/wangjia/pangolin/server/internal/nodes" ) type fakeLoadReader struct { load *nodes.NodeLoad ok bool err error } func (f fakeLoadReader) Get(context.Context, string) (*nodes.NodeLoad, bool, error) { return f.load, f.ok, f.err } // TestDataPlaneHealthy: unknown (nil reader / missing / error) defaults to healthy // (agent liveness gates); a present load returns its reported flag. func TestDataPlaneHealthy(t *testing.T) { ctx := context.Background() cases := []struct { name string api *NodeAPI want bool }{ {"nil reader → healthy", &NodeAPI{}, true}, {"missing load → healthy", &NodeAPI{load: fakeLoadReader{ok: false}}, true}, {"read error → healthy", &NodeAPI{load: fakeLoadReader{err: errors.New("boom")}}, true}, {"present healthy", &NodeAPI{load: fakeLoadReader{load: &nodes.NodeLoad{DataPlaneHealthy: true}, ok: true}}, true}, {"present unhealthy → false", &NodeAPI{load: fakeLoadReader{load: &nodes.NodeLoad{DataPlaneHealthy: false}, ok: true}}, false}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { if got := c.api.dataPlaneHealthy(ctx, "n1"); got != c.want { t.Errorf("dataPlaneHealthy = %v, want %v", got, c.want) } }) } } // TestEffectiveNodeStatus guards the "don't show a node healthy when it can't // serve" fix: a DB-'up' node reports "down" when its agent is offline OR its data // plane (sing-box) is unhealthy. func TestEffectiveNodeStatus(t *testing.T) { cases := []struct { name string db string online bool healthy bool want string }{ {"up + agent online + healthy", "up", true, true, "up"}, {"up + agent offline → down", "up", false, true, "down"}, // agent-liveness fix {"up + agent online + dp unhealthy → down", "up", true, false, "down"}, // data-plane fix {"up + offline + unhealthy → down", "up", false, false, "down"}, {"draining untouched", "draining", false, false, "draining"}, {"down stays down", "down", true, true, "down"}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { if got := effectiveNodeStatus(c.db, c.online, c.healthy); got != c.want { t.Errorf("effectiveNodeStatus(%q, %v, %v) = %q, want %q", c.db, c.online, c.healthy, got, c.want) } }) } }