package checkdefaults import ( "testing" ) // The attribute shapes here are copied from seeds/inventory.yaml. The original // resolveHost looked for lan_ip / mesh.netbird.ip / mesh_ip, none of which a // service or workstation actually carries — which is why 86 of 89 entities // ended up with no checks. func TestResolveHostAcceptsRealSeedShapes(t *testing.T) { cases := []struct { desc string attrs map[string]any want string }{ {"lxc carries lan_ip", map[string]any{"lan_ip": "192.168.8.246"}, "192.168.8.246"}, { "ws:mac-mini carries only a netbird fqdn", map[string]any{"mesh": map[string]any{"netbird": map[string]any{ "fqdn": "mac-mini-234-17.netbird.selfhosted"}}}, "mac-mini-234-17.netbird.selfhosted", }, { "a netbird ip still wins over the fqdn", map[string]any{"mesh": map[string]any{"netbird": map[string]any{ "ip": "100.122.0.10", "fqdn": "x.netbird.selfhosted"}}}, "100.122.0.10", }, {"public_host as a last resort", map[string]any{"public_host": "media.hubris.network"}, "media.hubris.network"}, {"a service carries no address at all", map[string]any{ "url": "https://media.hubris.network", "port": 8096}, ""}, {"nil attrs", nil, ""}, } for _, c := range cases { if got := resolveHost(c.attrs); got != c.want { t.Errorf("%s: resolveHost = %q, want %q", c.desc, got, c.want) } } } func TestHTTPURLPrefersAttributeThenName(t *testing.T) { cases := []struct { desc string name string attrs map[string]any want string }{ {"explicit url wins", "jellyfin", map[string]any{"url": "https://media.hubris.network"}, "https://media.hubris.network"}, {"public_host becomes https", "jellyfin", map[string]any{"public_host": "media.hubris.network"}, "https://media.hubris.network"}, // Ingress routes carry the hostname as the entity name and usually // declare no attributes at all. {"hostname-shaped name", "media.hubris.network", nil, "https://media.hubris.network"}, {"a bare service name is not a hostname", "jellyfin", nil, ""}, } for _, c := range cases { got := httpURL(Target{Name: c.name}, c.attrs) if got != c.want { t.Errorf("%s: httpURL = %q, want %q", c.desc, got, c.want) } } } func TestBuildKindReportsWhyItSkipped(t *testing.T) { // A declared kind that cannot be built must explain itself rather than // vanish — that silence is what hid the coverage gap. if defs, reason := buildKind(KindPing, Target{}, nil, "", "root", 22); len(defs) != 0 || reason == "" { t.Errorf("ping without a host should skip with a reason, got %d defs / %q", len(defs), reason) } if defs, reason := buildKind(KindProcess, Target{Name: ""}, nil, "10.0.0.1", "root", 22); len(defs) != 0 || reason == "" { t.Errorf("process without a name should skip with a reason, got %d defs / %q", len(defs), reason) } if defs, reason := buildKind("dns", Target{}, nil, "10.0.0.1", "root", 22); len(defs) != 0 || reason == "" { t.Errorf("an unimplemented kind should skip with a reason, got %d defs / %q", len(defs), reason) } } func TestBuildKindProcessPassesTheUnitName(t *testing.T) { // process_check.sh reads $1 and answers "no service name provided" // without it. checkdefaults always wrote args; nothing read them. defs, reason := buildKind(KindProcess, Target{Name: "jellyfin"}, nil, "10.0.0.1", "root", 22) if len(defs) != 1 { t.Fatalf("expected one process check, got %d (%s)", len(defs), reason) } if got := defs[0].config["args"]; got != "jellyfin" { t.Errorf("process check args = %v, want jellyfin", got) } if got := defs[0].config["script"]; got != "process_check.sh" { t.Errorf("process check script = %v", got) } } func TestBuildKindHTTPUsesAStatusRangeNotAnExactCode(t *testing.T) { // Most services sit behind Authentik and answer 302/401. defs, _ := buildKind(KindHTTP, Target{Name: "jellyfin"}, map[string]any{"url": "https://media.hubris.network"}, "", "root", 22) if len(defs) != 1 { t.Fatalf("expected one http check, got %d", len(defs)) } if got := defs[0].config["max_status"]; got != 500 { t.Errorf("max_status = %v, want 500", got) } if _, exact := defs[0].config["expected_status"]; exact { t.Error("default http checks must not pin an exact status") } } func TestBuildKindResourceExpandsToFourScripts(t *testing.T) { defs, _ := buildKind(KindResource, Target{}, nil, "10.0.0.1", "root", 22) if len(defs) != 4 { t.Fatalf("resource should expand to 4 checks, got %d", len(defs)) } for _, d := range defs { if d.kind != "ssh-script" { t.Errorf("resource check kind = %q, want ssh-script", d.kind) } if d.config["host"] != "10.0.0.1" { t.Errorf("resource check lost its host: %v", d.config) } } }