package checks import ( "testing" "github.com/DeBrosOfficial/network/pkg/inspector" ) func TestCheckNamespace_PerNodeHealthy(t *testing.T) { nd := makeNodeData("1.1.1.1", "node") nd.Namespaces = []inspector.NamespaceData{ { Name: "myapp", PortBase: 10000, RQLiteUp: true, RQLiteState: "Leader", RQLiteReady: true, OlricUp: true, GatewayUp: true, GatewayStatus: 200, }, } data := makeCluster(map[string]*inspector.NodeData{"1.1.1.1": nd}) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.rqlite_up", inspector.StatusPass) expectStatus(t, results, "ns.myapp.rqlite_state", inspector.StatusPass) expectStatus(t, results, "ns.myapp.rqlite_ready", inspector.StatusPass) expectStatus(t, results, "ns.myapp.olric_up", inspector.StatusPass) expectStatus(t, results, "ns.myapp.gateway_up", inspector.StatusPass) } func TestCheckNamespace_RQLiteDown(t *testing.T) { nd := makeNodeData("1.1.1.1", "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "myapp", PortBase: 10000, RQLiteUp: false}, } data := makeCluster(map[string]*inspector.NodeData{"1.1.1.1": nd}) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.rqlite_up", inspector.StatusFail) } func TestCheckNamespace_RQLiteStates(t *testing.T) { tests := []struct { state string status inspector.Status }{ {"Leader", inspector.StatusPass}, {"Follower", inspector.StatusPass}, {"Candidate", inspector.StatusWarn}, {"Unknown", inspector.StatusFail}, } for _, tt := range tests { t.Run(tt.state, func(t *testing.T) { nd := makeNodeData("1.1.1.1", "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "myapp", PortBase: 10000, RQLiteUp: true, RQLiteState: tt.state}, } data := makeCluster(map[string]*inspector.NodeData{"1.1.1.1": nd}) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.rqlite_state", tt.status) }) } } func TestCheckNamespace_RQLiteNotReady(t *testing.T) { nd := makeNodeData("1.1.1.1", "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "myapp", PortBase: 10000, RQLiteUp: true, RQLiteState: "Follower", RQLiteReady: false}, } data := makeCluster(map[string]*inspector.NodeData{"1.1.1.1": nd}) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.rqlite_ready", inspector.StatusFail) } func TestCheckNamespace_OlricDown(t *testing.T) { nd := makeNodeData("1.1.1.1", "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "myapp", OlricUp: false}, } data := makeCluster(map[string]*inspector.NodeData{"1.1.1.1": nd}) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.olric_up", inspector.StatusFail) } func TestCheckNamespace_GatewayDown(t *testing.T) { nd := makeNodeData("1.1.1.1", "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "myapp", GatewayUp: false, GatewayStatus: 0}, } data := makeCluster(map[string]*inspector.NodeData{"1.1.1.1": nd}) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.gateway_up", inspector.StatusFail) } func TestCheckNamespace_CrossNode_AllHealthy(t *testing.T) { nodes := map[string]*inspector.NodeData{} for _, host := range []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} { nd := makeNodeData(host, "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "myapp", RQLiteUp: true, OlricUp: true, GatewayUp: true}, } nodes[host] = nd } data := makeCluster(nodes) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.all_healthy", inspector.StatusPass) expectStatus(t, results, "ns.myapp.quorum", inspector.StatusPass) } func TestCheckNamespace_CrossNode_PartialHealthy(t *testing.T) { nodes := map[string]*inspector.NodeData{} for i, host := range []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} { nd := makeNodeData(host, "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "myapp", RQLiteUp: true, OlricUp: i < 2, GatewayUp: true}, } nodes[host] = nd } data := makeCluster(nodes) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.all_healthy", inspector.StatusFail) // Quorum should still pass (3/3 RQLite up, need 2) expectStatus(t, results, "ns.myapp.quorum", inspector.StatusPass) } func TestCheckNamespace_CrossNode_QuorumLost(t *testing.T) { nodes := map[string]*inspector.NodeData{} rqliteUp := []bool{true, false, false} for i, host := range []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} { nd := makeNodeData(host, "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "myapp", RQLiteUp: rqliteUp[i], OlricUp: true, GatewayUp: true}, } nodes[host] = nd } data := makeCluster(nodes) results := CheckNamespace(data) expectStatus(t, results, "ns.myapp.quorum", inspector.StatusFail) } func TestCheckNamespace_MultipleNamespaces(t *testing.T) { nd := makeNodeData("1.1.1.1", "node") nd.Namespaces = []inspector.NamespaceData{ {Name: "app1", RQLiteUp: true, RQLiteState: "Leader", OlricUp: true, GatewayUp: true}, {Name: "app2", RQLiteUp: false, OlricUp: true, GatewayUp: true}, } data := makeCluster(map[string]*inspector.NodeData{"1.1.1.1": nd}) results := CheckNamespace(data) expectStatus(t, results, "ns.app1.rqlite_up", inspector.StatusPass) expectStatus(t, results, "ns.app2.rqlite_up", inspector.StatusFail) } func TestCheckNamespace_NoNamespaces(t *testing.T) { nd := makeNodeData("1.1.1.1", "node") nd.Namespaces = nil data := makeCluster(map[string]*inspector.NodeData{"1.1.1.1": nd}) results := CheckNamespace(data) // No per-node results, only cross-node (which should be empty since no namespaces) for _, r := range results { t.Errorf("unexpected check: %s", r.ID) } }