170 lines
4.6 KiB
Go
170 lines
4.6 KiB
Go
// SPDX-License-Identifier: MIT
|
|
|
|
package checker
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
func TestWorstStatus(t *testing.T) {
|
|
if got := worstStatus(nil); got != sdk.StatusOK {
|
|
t.Errorf("nil states: got %v, want OK", got)
|
|
}
|
|
got := worstStatus([]sdk.CheckState{
|
|
{Status: sdk.StatusOK},
|
|
{Status: sdk.StatusWarn},
|
|
{Status: sdk.StatusCrit},
|
|
{Status: sdk.StatusInfo},
|
|
})
|
|
if got != sdk.StatusCrit {
|
|
t.Errorf("got %v, want Crit", got)
|
|
}
|
|
}
|
|
|
|
func TestTitleAndHint(t *testing.T) {
|
|
title, hint := titleAndHint(sdk.CheckState{
|
|
Message: "fallback",
|
|
Meta: map[string]any{"title": "T", "hint": "H"},
|
|
})
|
|
if title != "T" || hint != "H" {
|
|
t.Errorf("got (%q,%q), want (T,H)", title, hint)
|
|
}
|
|
// Falls back to message when no title in meta.
|
|
title, _ = titleAndHint(sdk.CheckState{Message: "fb"})
|
|
if title != "fb" {
|
|
t.Errorf("expected fallback to Message, got %q", title)
|
|
}
|
|
}
|
|
|
|
func TestGetHTMLReport_EmptyContext(t *testing.T) {
|
|
p := &dnsvizProvider{}
|
|
out, err := p.GetHTMLReport(sdk.StaticReportContext(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(out, "No DNSViz data and no rule states") {
|
|
t.Errorf("expected empty banner, got: %s", out)
|
|
}
|
|
}
|
|
|
|
func TestGetHTMLReport_FullDocument(t *testing.T) {
|
|
data := &DNSVizData{
|
|
Domain: "example.com",
|
|
Order: []string{"example.com.", "com.", "."},
|
|
Zones: map[string]ZoneAnalysis{
|
|
"example.com.": {
|
|
Status: "BOGUS",
|
|
Errors: []Finding{{Code: "RRSIG_EXPIRED", Description: "signature has expired", Servers: []string{"ns1"}}},
|
|
},
|
|
"com.": {Status: "SECURE"},
|
|
".": {Status: "SECURE"},
|
|
},
|
|
Raw: []byte(`{"example.com.": {"status": "BOGUS"}}`),
|
|
ProbeStderr: "probe-warning",
|
|
GrokStderr: "grok-warning",
|
|
}
|
|
rawJSON, _ := json.Marshal(data)
|
|
states := []sdk.CheckState{
|
|
{Status: sdk.StatusCrit, Code: "dnssec_rrsig_expired", Subject: "example.com.", Message: "Signature expired",
|
|
Meta: map[string]any{"title": "Signature expired", "hint": "Re-sign the zone."}},
|
|
{Status: sdk.StatusOK, Code: "dnsviz_overall_status", Message: "ok"},
|
|
}
|
|
p := &dnsvizProvider{}
|
|
out, err := p.GetHTMLReport(sdk.NewReportContext(rawJSON, nil, states))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
wantContains := []string{
|
|
"<title>DNSSEC report: example.com</title>",
|
|
`class="banner s-CRIT"`,
|
|
"Fix these first",
|
|
"Re-sign the zone.",
|
|
"DNS hierarchy",
|
|
"RRSIG_EXPIRED",
|
|
"All rule states",
|
|
"probe-warning",
|
|
"grok-warning",
|
|
}
|
|
for _, sub := range wantContains {
|
|
if !strings.Contains(out, sub) {
|
|
t.Errorf("HTML missing %q", sub)
|
|
}
|
|
}
|
|
// Ensure XSS-prone strings are escaped.
|
|
xssData := &DNSVizData{
|
|
Domain: `<script>alert(1)</script>`,
|
|
Order: []string{"x."},
|
|
Zones: map[string]ZoneAnalysis{"x.": {Status: "SECURE"}},
|
|
}
|
|
rawXSS, _ := json.Marshal(xssData)
|
|
xssOut, _ := p.GetHTMLReport(sdk.StaticReportContext(rawXSS))
|
|
if strings.Contains(xssOut, "<script>alert(1)</script>") {
|
|
t.Errorf("unescaped <script> in report: %s", xssOut)
|
|
}
|
|
}
|
|
|
|
func TestGetHTMLReport_BadJSON(t *testing.T) {
|
|
p := &dnsvizProvider{}
|
|
_, err := p.GetHTMLReport(sdk.StaticReportContext(json.RawMessage("not json")))
|
|
if err == nil {
|
|
t.Fatal("expected error for malformed data")
|
|
}
|
|
}
|
|
|
|
func TestExtractMetrics(t *testing.T) {
|
|
data := &DNSVizData{
|
|
Zones: map[string]ZoneAnalysis{
|
|
"example.com.": {Errors: []Finding{{}, {}}, Warnings: []Finding{{}}},
|
|
"com.": {},
|
|
},
|
|
}
|
|
rawJSON, _ := json.Marshal(data)
|
|
states := []sdk.CheckState{
|
|
{Status: sdk.StatusOK},
|
|
{Status: sdk.StatusCrit},
|
|
{Status: sdk.StatusCrit},
|
|
}
|
|
p := &dnsvizProvider{}
|
|
now := time.Now()
|
|
metrics, err := p.ExtractMetrics(sdk.NewReportContext(rawJSON, nil, states), now)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
byName := map[string]float64{}
|
|
statusCounts := map[string]float64{}
|
|
for _, m := range metrics {
|
|
if !m.Timestamp.Equal(now) {
|
|
t.Errorf("metric %q has wrong timestamp", m.Name)
|
|
}
|
|
if m.Name == "dnsviz.findings.count" {
|
|
statusCounts[m.Labels["status"]] = m.Value
|
|
continue
|
|
}
|
|
byName[m.Name] = m.Value
|
|
}
|
|
if byName["dnsviz.zones.count"] != 2 {
|
|
t.Errorf("zones.count = %v, want 2", byName["dnsviz.zones.count"])
|
|
}
|
|
if byName["dnsviz.errors.count"] != 2 {
|
|
t.Errorf("errors.count = %v, want 2", byName["dnsviz.errors.count"])
|
|
}
|
|
if byName["dnsviz.warnings.count"] != 1 {
|
|
t.Errorf("warnings.count = %v, want 1", byName["dnsviz.warnings.count"])
|
|
}
|
|
if statusCounts["CRIT"] != 2 || statusCounts["OK"] != 1 {
|
|
t.Errorf("findings counts: %v", statusCounts)
|
|
}
|
|
}
|
|
|
|
func TestExtractMetrics_BadJSON(t *testing.T) {
|
|
p := &dnsvizProvider{}
|
|
_, err := p.ExtractMetrics(sdk.StaticReportContext(json.RawMessage("not json")), time.Now())
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
}
|