package checker import ( "encoding/json" "strings" "testing" "time" sdk "git.happydns.org/checker-sdk-go/checker" ) func TestStatusToSeverity(t *testing.T) { cases := []struct { in sdk.Status want string }{ {sdk.StatusCrit, SeverityCrit}, {sdk.StatusError, SeverityCrit}, {sdk.StatusWarn, SeverityWarn}, {sdk.StatusInfo, SeverityInfo}, {sdk.StatusOK, ""}, {sdk.StatusUnknown, ""}, } for _, c := range cases { if got := statusToSeverity(c.in); got != c.want { t.Errorf("status %v: want %q, got %q", c.in, c.want, got) } } } func TestOverallStatus_NullMX(t *testing.T) { d := &SMTPData{MX: MXLookup{NullMX: true}} label, class := overallStatus(d, nil, nil) if label != "NULL MX" || class != "info" { t.Errorf("got (%q,%q)", label, class) } } func TestOverallStatus_DataOnly(t *testing.T) { d := &SMTPData{} label, class := overallStatus(d, nil, nil) if label != "data only" || class != "muted" { t.Errorf("got (%q,%q)", label, class) } } func TestOverallStatus_FromFixes(t *testing.T) { d := &SMTPData{} states := []sdk.CheckState{{Status: sdk.StatusOK}} cases := []struct { fixes []reportFix wantLabel string wantClass string caseLabel string }{ {[]reportFix{{Severity: SeverityCrit}}, "FAIL", "fail", "crit"}, {[]reportFix{{Severity: SeverityWarn}}, "WARN", "warn", "warn"}, {[]reportFix{{Severity: SeverityInfo}}, "INFO", "info", "info"}, {nil, "OK", "ok", "ok"}, } for _, c := range cases { label, class := overallStatus(d, states, c.fixes) if label != c.wantLabel || class != c.wantClass { t.Errorf("%s: got (%q,%q)", c.caseLabel, label, class) } } } func TestOverallStatus_CritWinsOverWarn(t *testing.T) { d := &SMTPData{} states := []sdk.CheckState{{Status: sdk.StatusOK}} fixes := []reportFix{{Severity: SeverityWarn}, {Severity: SeverityCrit}, {Severity: SeverityInfo}} if label, _ := overallStatus(d, states, fixes); label != "FAIL" { t.Errorf("crit must dominate, got %q", label) } } func TestFixesFromStates_OnlyFindings(t *testing.T) { states := []sdk.CheckState{ {Status: sdk.StatusOK, Code: "skip-me"}, {Status: sdk.StatusUnknown, Code: "skip-me-too"}, {Status: sdk.StatusWarn, Code: "warn-1", Message: "msg", Meta: map[string]any{"fix": "do x", "endpoint": "1.2.3.4:25", "target": "mx"}}, {Status: sdk.StatusCrit, Code: "crit-1", Message: "boom"}, } out := fixesFromStates(states) if len(out) != 2 { t.Fatalf("want 2 fixes, got %d", len(out)) } w := out[0] if w.Severity != SeverityWarn || w.Fix != "do x" || w.Endpoint != "1.2.3.4:25" || w.Target != "mx" { t.Errorf("warn fix wrong: %+v", w) } } func TestFixesFromStates_MetaWrongTypesIgnored(t *testing.T) { states := []sdk.CheckState{ {Status: sdk.StatusWarn, Code: "x", Meta: map[string]any{"fix": 42, "endpoint": nil}}, } out := fixesFromStates(states) if len(out) != 1 { t.Fatalf("got %d", len(out)) } if out[0].Fix != "" || out[0].Endpoint != "" { t.Errorf("non-string meta values must be ignored, got %+v", out[0]) } } func TestIndexTLSByAddress(t *testing.T) { yes := true notAfter := time.Now().Add(30 * 24 * time.Hour) payload := map[string]any{ "host": "mx.example.com", "port": 25, "chain_valid": yes, "hostname_match": yes, "not_after": notAfter, "issues": []map[string]any{ {"code": "x", "severity": "warn", "message": "m"}, {"code": "y", "severity": "bogus"}, // dropped }, } related := []sdk.RelatedObservation{{Data: mustJSON(t, payload), CollectedAt: time.Now()}} idx := indexTLSByAddress(related) posture, ok := idx["mx.example.com:25"] if !ok { t.Fatalf("expected entry, got %+v", idx) } if posture.ChainValid == nil || !*posture.ChainValid { t.Errorf("ChainValid: %+v", posture.ChainValid) } if len(posture.Issues) != 1 { t.Errorf("issues: want 1, got %d", len(posture.Issues)) } } func TestBuildReportData_StatusByEndpoint(t *testing.T) { yes := true relay := true d := &SMTPData{ Domain: "example.com", MX: MXLookup{Records: []MXRecord{{Preference: 10, Target: "mx.example.com", IPv4: []string{"1.2.3.4"}}}}, Endpoints: []EndpointProbe{ // healthy { Target: "mx.example.com", IP: "1.2.3.4", Port: 25, Address: "1.2.3.4:25", TCPConnected: true, BannerReceived: true, BannerCode: 220, EHLOReceived: true, STARTTLSOffered: true, STARTTLSUpgraded: true, NullSenderAccepted: &yes, PostmasterAccepted: &yes, }, // unreachable {Target: "mx.example.com", IP: "1.2.3.5", Port: 25, Address: "1.2.3.5:25"}, // open relay { Target: "mx.example.com", IP: "1.2.3.6", Port: 25, Address: "1.2.3.6:25", TCPConnected: true, BannerReceived: true, BannerCode: 220, EHLOReceived: true, STARTTLSOffered: true, STARTTLSUpgraded: true, OpenRelay: &relay, }, }, } view := buildReportData(d, nil, []sdk.CheckState{{Status: sdk.StatusOK}}) if len(view.Endpoints) != 3 { t.Fatalf("want 3 endpoints, got %d", len(view.Endpoints)) } wantStatuses := []string{"OK", "unreachable", "OPEN RELAY"} for i, want := range wantStatuses { if view.Endpoints[i].StatusLabel != want { t.Errorf("endpoint[%d]: got %q, want %q", i, view.Endpoints[i].StatusLabel, want) } } } func TestBuildReportData_FixesSortedBySeverity(t *testing.T) { d := &SMTPData{Domain: "x"} states := []sdk.CheckState{ {Status: sdk.StatusInfo, Code: "info-1"}, {Status: sdk.StatusCrit, Code: "crit-1"}, {Status: sdk.StatusWarn, Code: "warn-1"}, } view := buildReportData(d, nil, states) if len(view.Fixes) != 3 { t.Fatalf("got %d fixes", len(view.Fixes)) } if view.Fixes[0].Severity != SeverityCrit || view.Fixes[1].Severity != SeverityWarn || view.Fixes[2].Severity != SeverityInfo { t.Errorf("not sorted: %+v", view.Fixes) } } func TestRenderReport_ContainsDomain(t *testing.T) { view := reportData{ Domain: "example.com", StatusLabel: "OK", StatusClass: "ok", } html, err := renderReport(view) if err != nil { t.Fatalf("render: %v", err) } if !strings.Contains(html, "example.com") { t.Errorf("html missing domain") } if !strings.Contains(html, "") { t.Errorf("not an html doc") } } func TestGetHTMLReport_RoundTrip(t *testing.T) { yes := true d := &SMTPData{ Domain: "example.com", RunAt: "2026-01-01T00:00:00Z", MX: MXLookup{Records: []MXRecord{{Preference: 10, Target: "mx.example.com", IPv4: []string{"1.2.3.4"}}}}, Endpoints: []EndpointProbe{{ Target: "mx.example.com", IP: "1.2.3.4", Port: 25, Address: "1.2.3.4:25", TCPConnected: true, BannerReceived: true, BannerCode: 220, EHLOReceived: true, STARTTLSOffered: true, STARTTLSUpgraded: true, NullSenderAccepted: &yes, PostmasterAccepted: &yes, }}, } body, err := json.Marshal(d) if err != nil { t.Fatalf("marshal: %v", err) } rctx := sdk.StaticReportContext(body) p := &smtpProvider{} html, err := p.GetHTMLReport(rctx) if err != nil { t.Fatalf("GetHTMLReport: %v", err) } if !strings.Contains(html, "mx.example.com") { t.Errorf("html missing target hostname") } } func TestGetHTMLReport_BadJSON(t *testing.T) { rctx := sdk.StaticReportContext(json.RawMessage("{not json")) p := &smtpProvider{} if _, err := p.GetHTMLReport(rctx); err == nil { t.Fatal("expected error on bad json") } }