package handlers_test import ( "regexp" "strings" "testing" "time" "sneak.berlin/go/dnswatcher/internal/handlers" ) func TestRelTime(t *testing.T) { t.Parallel() tests := []struct { name string dur time.Duration want string }{ {"zero", 0, "never"}, {"seconds", 30 * time.Second, "30s ago"}, {"minutes", 5 * time.Minute, "5m ago"}, {"hours", 2*time.Hour + 15*time.Minute, "2h 15m ago"}, {"days", 48*time.Hour + 3*time.Hour, "2d 3h ago"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var input time.Time if tt.dur > 0 { input = time.Now().Add(-tt.dur) } got := handlers.RelTime(input) if got != tt.want { t.Errorf( "RelTime(%v) = %q, want %q", tt.dur, got, tt.want, ) } }) } } func TestExpiryDays(t *testing.T) { t.Parallel() // 10 days from now. future := time.Now().Add(10 * 24 * time.Hour) days := handlers.ExpiryDays(future) if days < 9 || days > 10 { t.Errorf("expected ~10 days, got %d", days) } // Already expired. past := time.Now().Add(-24 * time.Hour) days = handlers.ExpiryDays(past) if days != 0 { t.Errorf("expected 0 for expired, got %d", days) } } func TestFormatRecords(t *testing.T) { t.Parallel() got := handlers.FormatRecords(nil) if got != "-" { t.Errorf("expected -, got %q", got) } got = handlers.FormatRecords(map[string][]string{ "A": {"1.2.3.4"}, }) if got != "A: 1.2.3.4" { t.Errorf("unexpected format: %q", got) } } // TestFormatRecordsTypeOrder checks that record types are listed in // the README's order (A, AAAA, CNAME, MX, TXT, SRV, CAA, NS), with // any other type after them in alphabetical order. func TestFormatRecordsTypeOrder(t *testing.T) { t.Parallel() got := handlers.FormatRecords(map[string][]string{ "SOA": {"ns1.example.com. hostmaster.example.com. 1 2 3 4 5"}, "NS": {"ns1.example.com.", "ns2.example.com."}, "CAA": {`0 issue "letsencrypt.org"`}, "DNAME": {"example.net."}, "TXT": {"v=spf1 -all"}, "SRV": {"10 5 443 www.example.com."}, "MX": {"10 mail.example.com."}, "CNAME": {"www.example.com."}, "AAAA": {"2001:db8::1"}, "A": {"192.0.2.1"}, }) want := strings.Join([]string{ "A: 192.0.2.1", "AAAA: 2001:db8::1", "CNAME: www.example.com.", "MX: 10 mail.example.com.", "TXT: v=spf1 -all", "SRV: 10 5 443 www.example.com.", `CAA: 0 issue "letsencrypt.org"`, "NS: ns1.example.com.", "NS: ns2.example.com.", "DNAME: example.net.", "SOA: ns1.example.com. hostmaster.example.com. 1 2 3 4 5", }, ", ") if got != want { t.Errorf("FormatRecords lists types out of order:\n got %q\nwant %q", got, want) } } // dashboardRow returns the table row of page that contains name. func dashboardRow(t *testing.T, page string, name string) string { t.Helper() for row := range strings.SplitSeq(page, " "+heading+" ") { return section } } t.Fatalf("dashboard has no section headed %q", heading) return "" } // TestDashboardShowsDomainRecordsUnderDomains checks that the dashboard // shows an apex domain's own records in the Domains section, and // neither lists nor counts the domain as a hostname. func TestDashboardShowsDomainRecordsUnderDomains(t *testing.T) { t.Parallel() page := get(t, newHandlersWithFailures(t).HandleDashboard()) domains := dashboardSection(t, page, "Domains") if !strings.Contains(dashboardRow(t, domains, domainAddress), testDomain) { t.Errorf("row of %s does not name %s", domainAddress, testDomain) } if strings.Contains(dashboardSection(t, page, "Hostnames"), testDomain) { t.Errorf("Hostnames section lists the domain %s", testDomain) } words := strings.Join(strings.Fields(page), " ") footer := "monitoring 1 domains + 1 hostnames" if !strings.Contains(words, footer) { t.Errorf("dashboard does not say %q", footer) } // With the tags taken out, the summary bar starts "Domains 1 // Hostnames 1". text := regexp.MustCompile(`<[^>]*>`).ReplaceAllString(page, " ") summary := "Domains 1 Hostnames 1" if !strings.Contains(strings.Join(strings.Fields(text), " "), summary) { t.Errorf("summary bar does not say %q", summary) } } // rowCells returns the text of each cell of a dashboard table row // whose cells start with tag, "]*>`) parts := strings.Split(row, tag)[1:] cells := make([]string, 0, len(parts)) for _, cell := range parts { text := tags.ReplaceAllString(tag+cell, " ") cells = append(cells, strings.Join(strings.Fields(text), " ")) } return cells } // TestDashboardPortsTellDomainsFromHostnames checks that the Ports // table lists an apex domain under Domains and a hostname under // Hostnames when both resolve to the port's address. func TestDashboardPortsTellDomainsFromHostnames(t *testing.T) { t.Parallel() page := get(t, newHandlersWithFailures(t).HandleDashboard()) ports := dashboardSection(t, page, "Ports") headings := rowCells(dashboardRow(t, ports, "Address"), "