package watcher_test import ( "slices" "testing" "sneak.berlin/go/dnswatcher/internal/config" "sneak.berlin/go/dnswatcher/internal/state" "sneak.berlin/go/dnswatcher/internal/watcher" ) // TestSkipRecordNotificationsAlerts runs the hostname change detection // for two names on the same check: nsA's address changes, so that nsA // now differs from nsB, and nsC stops answering. The name in // SkipRecordNotifications gets only the NS Failure; the other name also // gets the Record Change and the Inconsistency. func TestSkipRecordNotificationsAlerts(t *testing.T) { t.Parallel() const skipped = "skipped.example.net" prev := saved(map[string]*state.NameserverRecordState{ nsA: answered(map[string][]string{"A": {ip1}}), nsB: answered(map[string][]string{"A": {ip1}}), nsC: answered(map[string][]string{"A": {ip1}}), }) current := saved(map[string]*state.NameserverRecordState{ nsA: answered(map[string][]string{"A": {ip2}}), nsB: answered(map[string][]string{"A": {ip1}}), nsC: failed(), }) cfg := &config.Config{ Hostnames: []string{host, skipped}, SkipRecordNotifications: []string{skipped}, } // The hostname change detection uses only the configuration and the // notifier. notifier := &mockNotifier{} w := watcher.NewForTest(cfg, nil, nil, nil, nil, notifier) w.DetectHostnameChanges(t.Context(), host, prev, current) w.DetectHostnameChanges(t.Context(), skipped, prev, current) sent := notifier.getNotifications() titles := make([]string, 0, len(sent)) for _, n := range sent { titles = append(titles, n.Title) } slices.Sort(titles) want := []string{ "Inconsistency: " + host, "NS Failure: " + skipped, "NS Failure: " + host, "Record Change: " + host, } if !slices.Equal(titles, want) { t.Errorf("sent %v, want %v", titles, want) } } // TestSkipRecordNotificationsCheck checks testHost, which is in // SkipRecordNotifications, from a saved state in which every nameserver // live DNS lists answered with an address live DNS never returns. No // Record Change and no Inconsistency is sent, and the check still saves // what the nameservers answer. func TestSkipRecordNotificationsCheck(t *testing.T) { t.Parallel() cfg := defaultTestConfig(t) cfg.Hostnames = []string{testHost} cfg.SkipRecordNotifications = []string{testHost} nameservers := lookupNameservers(t, testHost) _, deps := runChecks(t, cfg, func(deps *testDeps) { byNameserver := make(map[string]*state.NameserverRecordState) for _, ns := range nameservers { byNameserver[ns] = answered(map[string][]string{"A": {oldIP}}) } deps.state.SetHostnameState(testHost, saved(byNameserver)) }) for _, title := range []string{ "Record Change: " + testHost, "Inconsistency: " + testHost, } { if n := countNotifications(deps, title); n != 0 { t.Errorf("sent %d %q, want 0", n, title) } } // A nameserver whose query for A failed keeps oldIP, so the check // is that some address live DNS gave was saved. hs, _ := deps.state.GetHostnameState(testHost) fromLiveDNS := func(ip string) bool { return ip != oldIP } if !slices.ContainsFunc(addresses(hs), fromLiveDNS) { t.Errorf("saved addresses %v, want those live DNS gave", addresses(hs)) } }