build: update golangci-lint to v2.12.2 with org-standard v2 config
All checks were successful
check / check (push) Successful in 33s

Pin golangci-lint to commit c0d3ddc9cf3faa61a4e378e879ece580256d76e5
(v2.12.2) in Dockerfile and script/bootstrap.

Set .golangci.yml to the org-standard v2-schema config already used
across the org's repos (owner-authorized; the same file is being
landed as canonical via a prompts-repo PR). Lint settings live under
linters.settings, so the lll, funlen, cyclop, and dupl thresholds are
actually applied. The informational gomodguard deprecation warning
this config can emit under v2.12 is accepted.

Fix all findings surfaced by the now-active thresholds:

- goconst: shared constants for repeated status, priority, and DNS
  fixture strings in watcher.go and the notify, state, and watcher
  tests
- dupl: consolidate duplicated ntfy/slack HTTP-error tests and
  SendNotification endpoint-error tests behind shared helpers
- lll: wrap long test table entries and comments; shorten one inline
  nolint justification
This commit is contained in:
2026-08-07 17:08:04 +00:00
parent f79cd98107
commit 9054db8d86
11 changed files with 332 additions and 292 deletions

View File

@@ -1,5 +1,9 @@
version: "2" version: "2"
# Config schema uses the golangci-lint v2 layout (settings live under
# linters.settings, not top-level linters-settings) so that the
# thresholds below are actually applied by golangci-lint >= v2.
run: run:
timeout: 5m timeout: 5m
modules-download-mode: readonly modules-download-mode: readonly
@@ -14,19 +18,17 @@ linters:
- wsl # Deprecated, replaced by wsl_v5 - wsl # Deprecated, replaced by wsl_v5
- wrapcheck # Too verbose for internal packages - wrapcheck # Too verbose for internal packages
- varnamelen # Short names like db, id are idiomatic Go - varnamelen # Short names like db, id are idiomatic Go
settings:
linters-settings: lll:
lll: line-length: 88
line-length: 88 funlen:
funlen: lines: 80
lines: 80 statements: 50
statements: 50 cyclop:
cyclop: max-complexity: 15
max-complexity: 15 dupl:
dupl: threshold: 100
threshold: 100
issues: issues:
exclude-use-default: false
max-issues-per-linter: 0 max-issues-per-linter: 0
max-same-issues: 0 max-same-issues: 0

View File

@@ -4,8 +4,8 @@ FROM golang@sha256:f6751d823c26342f9506c03797d2527668d095b0a15f1862cddb4d927a7a4
RUN apk add --no-cache git make gcc musl-dev binutils-gold RUN apk add --no-cache git make gcc musl-dev binutils-gold
# golangci-lint v2.10.1 # golangci-lint v2.12.2, 2026-08-07
RUN go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@5d1e709b7be35cb2025444e19de266b056b7b7ee RUN go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@c0d3ddc9cf3faa61a4e378e879ece580256d76e5
# goimports v0.42.0 # goimports v0.42.0
RUN go install golang.org/x/tools/cmd/goimports@009367f5c17a8d4c45a961a3a509277190a9a6f0 RUN go install golang.org/x/tools/cmd/goimports@009367f5c17a8d4c45a961a3a509277190a9a6f0

View File

@@ -25,6 +25,14 @@ confirm make check still passes.
# Completed Steps # Completed Steps
- 2026-08-07: golangci-lint bumped to v2.12.2 (commit-pinned installs
in `Dockerfile` and `script/bootstrap`); `.golangci.yml` set to the
org-standard v2-schema config used across the org's repos
(owner-authorized; same file is being landed as canonical via prompts
PR #24), with settings under `linters.settings` so the
lll/funlen/cyclop/dupl thresholds apply; fixed the resulting
`goconst`, `dupl`, and `lll` findings; the informational `gomodguard`
deprecation warning under this config is accepted
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, - 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints,
Makefile shims, README Entrypoints section Makefile shims, README Entrypoints section
- 2026-02-20: iterative DNS resolver implemented; tests made hermetic - 2026-02-20: iterative DNS resolver implemented; tests made hermetic

View File

@@ -17,13 +17,33 @@ func TestClassifyDNSName(t *testing.T) {
}{ }{
{name: "apex domain simple", input: "example.com", want: config.DNSNameTypeDomain}, {name: "apex domain simple", input: "example.com", want: config.DNSNameTypeDomain},
{name: "hostname simple", input: "www.example.com", want: config.DNSNameTypeHostname}, {name: "hostname simple", input: "www.example.com", want: config.DNSNameTypeHostname},
{name: "apex domain multi-part TLD", input: "example.co.uk", want: config.DNSNameTypeDomain}, {
{name: "hostname multi-part TLD", input: "api.example.co.uk", want: config.DNSNameTypeHostname}, name: "apex domain multi-part TLD",
input: "example.co.uk",
want: config.DNSNameTypeDomain,
},
{
name: "hostname multi-part TLD",
input: "api.example.co.uk",
want: config.DNSNameTypeHostname,
},
{name: "public suffix itself", input: "co.uk", wantErr: true}, {name: "public suffix itself", input: "co.uk", wantErr: true},
{name: "empty string", input: "", wantErr: true}, {name: "empty string", input: "", wantErr: true},
{name: "deeply nested hostname", input: "a.b.c.example.com", want: config.DNSNameTypeHostname}, {
{name: "trailing dot stripped", input: "example.com.", want: config.DNSNameTypeDomain}, name: "deeply nested hostname",
{name: "uppercase normalized", input: "WWW.Example.COM", want: config.DNSNameTypeHostname}, input: "a.b.c.example.com",
want: config.DNSNameTypeHostname,
},
{
name: "trailing dot stripped",
input: "example.com.",
want: config.DNSNameTypeDomain,
},
{
name: "uppercase normalized",
input: "WWW.Example.COM",
want: config.DNSNameTypeHostname,
},
} }
for _, tt := range tests { for _, tt := range tests {

View File

@@ -25,6 +25,20 @@ const (
colorDefault = "#6c757d" colorDefault = "#6c757d"
) )
// Priority strings used across multiple tests.
const (
prioError = "error"
prioWarning = "warning"
prioSuccess = "success"
prioInfo = "info"
prioUnknown = "unknown"
prioDefault = "default"
prioUrgent = "urgent"
)
// testHost is the hostname used in request construction tests.
const testHost = "example.com"
// errSimulated is a static error for transport failures. // errSimulated is a static error for transport failures.
var errSimulated = errors.New("simulated transport failure") var errSimulated = errors.New("simulated transport failure")
@@ -101,13 +115,13 @@ func TestNtfyPriority(t *testing.T) {
input string input string
want string want string
}{ }{
{"error", "urgent"}, {prioError, prioUrgent},
{"warning", "high"}, {prioWarning, "high"},
{"success", "default"}, {prioSuccess, prioDefault},
{"info", "low"}, {prioInfo, "low"},
{"", "default"}, {"", prioDefault},
{"unknown", "default"}, {prioUnknown, prioDefault},
{"critical", "default"}, {"critical", prioDefault},
} }
for _, tc := range cases { for _, tc := range cases {
@@ -134,12 +148,12 @@ func TestSlackColor(t *testing.T) {
input string input string
want string want string
}{ }{
{"error", colorError}, {prioError, colorError},
{"warning", colorWarning}, {prioWarning, colorWarning},
{"success", colorSuccess}, {prioSuccess, colorSuccess},
{"info", colorInfo}, {prioInfo, colorInfo},
{"", colorDefault}, {"", colorDefault},
{"unknown", colorDefault}, {prioUnknown, colorDefault},
{"critical", colorDefault}, {"critical", colorDefault},
} }
@@ -165,7 +179,7 @@ func TestNewRequest(t *testing.T) {
target := &url.URL{ target := &url.URL{
Scheme: "https", Scheme: "https",
Host: "example.com", Host: testHost,
Path: "/webhook", Path: "/webhook",
} }
body := bytes.NewBufferString("hello") body := bytes.NewBufferString("hello")
@@ -187,9 +201,9 @@ func TestNewRequest(t *testing.T) {
) )
} }
if req.Host != "example.com" { if req.Host != testHost {
t.Errorf( t.Errorf(
"Host = %q, want %q", req.Host, "example.com", "Host = %q, want %q", req.Host, testHost,
) )
} }
@@ -217,7 +231,7 @@ func TestNewRequestPreservesContext(t *testing.T) {
ctxKey("k"), ctxKey("k"),
"v", "v",
) )
target := &url.URL{Scheme: "https", Host: "example.com"} target := &url.URL{Scheme: "https", Host: testHost}
req := notify.NewRequestForTest( req := notify.NewRequestForTest(
ctx, http.MethodGet, target, http.NoBody, ctx, http.MethodGet, target, http.NoBody,
@@ -289,10 +303,10 @@ func TestSendNtfyHeaders(t *testing.T) {
) )
} }
if captured.priority != "urgent" { if captured.priority != prioUrgent {
t.Errorf( t.Errorf(
"Priority header = %q, want %q", "Priority header = %q, want %q",
captured.priority, "urgent", captured.priority, prioUrgent,
) )
} }
@@ -311,10 +325,10 @@ func TestSendNtfyAllPriorities(t *testing.T) {
input string input string
want string want string
}{ }{
{"error", "urgent"}, {prioError, prioUrgent},
{"warning", "high"}, {prioWarning, "high"},
{"success", "default"}, {prioSuccess, prioDefault},
{"info", "low"}, {prioInfo, "low"},
} }
for _, tc := range priorities { for _, tc := range priorities {
@@ -356,56 +370,69 @@ func TestSendNtfyAllPriorities(t *testing.T) {
} }
} }
func TestSendNtfyClientError(t *testing.T) { // assertSendStatusError verifies that send returns an error
t.Parallel() // wrapping wantErr when the server responds with status.
func assertSendStatusError(
t *testing.T,
status int,
wantErr error,
send func(*notify.Service, *url.URL) error,
) {
t.Helper()
srv := httptest.NewServer( srv := httptest.NewServer(
http.HandlerFunc( http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) { func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusForbidden) w.WriteHeader(status)
}), }),
) )
defer srv.Close() defer srv.Close()
svc := notify.NewTestService(srv.Client().Transport) svc := notify.NewTestService(srv.Client().Transport)
topicURL, _ := url.Parse(srv.URL) target, _ := url.Parse(srv.URL)
err := svc.SendNtfy( err := send(svc, target)
context.Background(), topicURL, "t", "m", "info",
)
if err == nil { if err == nil {
t.Fatal("expected error for 403 response") t.Fatalf("expected error for %d response", status)
} }
if !errors.Is(err, notify.ErrNtfyFailed) { if !errors.Is(err, wantErr) {
t.Errorf("error = %v, want ErrNtfyFailed", err) t.Errorf("error = %v, want %v", err, wantErr)
} }
} }
func sendNtfyInfo(
svc *notify.Service, target *url.URL,
) error {
return svc.SendNtfy(
context.Background(), target, "t", "m", prioInfo,
)
}
func sendSlackInfo(
svc *notify.Service, target *url.URL,
) error {
return svc.SendSlack(
context.Background(), target, "t", "m", prioInfo,
)
}
func TestSendNtfyClientError(t *testing.T) {
t.Parallel()
assertSendStatusError(
t, http.StatusForbidden,
notify.ErrNtfyFailed, sendNtfyInfo,
)
}
func TestSendNtfyServerError(t *testing.T) { func TestSendNtfyServerError(t *testing.T) {
t.Parallel() t.Parallel()
srv := httptest.NewServer( assertSendStatusError(
http.HandlerFunc( t, http.StatusInternalServerError,
func(w http.ResponseWriter, _ *http.Request) { notify.ErrNtfyFailed, sendNtfyInfo,
w.WriteHeader(http.StatusInternalServerError)
}),
) )
defer srv.Close()
svc := notify.NewTestService(srv.Client().Transport)
topicURL, _ := url.Parse(srv.URL)
err := svc.SendNtfy(
context.Background(), topicURL, "t", "m", "info",
)
if err == nil {
t.Fatal("expected error for 500 response")
}
if !errors.Is(err, notify.ErrNtfyFailed) {
t.Errorf("error = %v, want ErrNtfyFailed", err)
}
} }
func TestSendNtfySuccess(t *testing.T) { func TestSendNtfySuccess(t *testing.T) {
@@ -550,11 +577,11 @@ func TestSendSlackAllColors(t *testing.T) {
priority string priority string
want string want string
}{ }{
{"error", colorError}, {prioError, colorError},
{"warning", colorWarning}, {prioWarning, colorWarning},
{"success", colorSuccess}, {prioSuccess, colorSuccess},
{"info", colorInfo}, {prioInfo, colorInfo},
{"unknown", colorDefault}, {prioUnknown, colorDefault},
} }
for _, tc := range colors { for _, tc := range colors {
@@ -606,53 +633,19 @@ func TestSendSlackAllColors(t *testing.T) {
func TestSendSlackClientError(t *testing.T) { func TestSendSlackClientError(t *testing.T) {
t.Parallel() t.Parallel()
srv := httptest.NewServer( assertSendStatusError(
http.HandlerFunc( t, http.StatusBadRequest,
func(w http.ResponseWriter, _ *http.Request) { notify.ErrSlackFailed, sendSlackInfo,
w.WriteHeader(http.StatusBadRequest)
}),
) )
defer srv.Close()
svc := notify.NewTestService(srv.Client().Transport)
webhookURL, _ := url.Parse(srv.URL)
err := svc.SendSlack(
context.Background(), webhookURL, "t", "m", "info",
)
if err == nil {
t.Fatal("expected error for 400 response")
}
if !errors.Is(err, notify.ErrSlackFailed) {
t.Errorf("error = %v, want ErrSlackFailed", err)
}
} }
func TestSendSlackServerError(t *testing.T) { func TestSendSlackServerError(t *testing.T) {
t.Parallel() t.Parallel()
srv := httptest.NewServer( assertSendStatusError(
http.HandlerFunc( t, http.StatusBadGateway,
func(w http.ResponseWriter, _ *http.Request) { notify.ErrSlackFailed, sendSlackInfo,
w.WriteHeader(http.StatusBadGateway)
}),
) )
defer srv.Close()
svc := notify.NewTestService(srv.Client().Transport)
webhookURL, _ := url.Parse(srv.URL)
err := svc.SendSlack(
context.Background(), webhookURL, "t", "m", "error",
)
if err == nil {
t.Fatal("expected error for 502 response")
}
if !errors.Is(err, notify.ErrSlackFailed) {
t.Errorf("error = %v, want ErrSlackFailed", err)
}
} }
func TestSendSlackNetworkError(t *testing.T) { func TestSendSlackNetworkError(t *testing.T) {
@@ -977,74 +970,62 @@ func TestSendNotificationMattermostOnly(t *testing.T) {
} }
} }
func TestSendNotificationNtfyError(t *testing.T) { // assertSendNotificationTolerates verifies SendNotification
t.Parallel() // neither panics nor blocks when the endpoint configured by
// setURL responds with status.
func assertSendNotificationTolerates(
t *testing.T,
status int,
priority string,
setURL func(*notify.Service, *url.URL),
) {
t.Helper()
srv := httptest.NewServer( srv := httptest.NewServer(
http.HandlerFunc( http.HandlerFunc(
func(w http.ResponseWriter, _ *http.Request) { func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(status)
}), }),
) )
defer srv.Close() defer srv.Close()
ntfyURL, _ := url.Parse(srv.URL) target, _ := url.Parse(srv.URL)
svc := notify.NewTestService(http.DefaultTransport) svc := notify.NewTestService(http.DefaultTransport)
svc.SetNtfyURL(ntfyURL) setURL(svc, target)
// Should not panic or block.
svc.SendNotification( svc.SendNotification(
context.Background(), "t", "m", "error", context.Background(), "t", "m", priority,
) )
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
} }
func TestSendNotificationNtfyError(t *testing.T) {
t.Parallel()
assertSendNotificationTolerates(
t, http.StatusInternalServerError, prioError,
(*notify.Service).SetNtfyURL,
)
}
func TestSendNotificationSlackError(t *testing.T) { func TestSendNotificationSlackError(t *testing.T) {
t.Parallel() t.Parallel()
srv := httptest.NewServer( assertSendNotificationTolerates(
http.HandlerFunc( t, http.StatusForbidden, prioError,
func(w http.ResponseWriter, _ *http.Request) { (*notify.Service).SetSlackWebhookURL,
w.WriteHeader(http.StatusForbidden)
}),
) )
defer srv.Close()
slackURL, _ := url.Parse(srv.URL)
svc := notify.NewTestService(http.DefaultTransport)
svc.SetSlackWebhookURL(slackURL)
svc.SendNotification(
context.Background(), "t", "m", "error",
)
time.Sleep(100 * time.Millisecond)
} }
func TestSendNotificationMattermostError(t *testing.T) { func TestSendNotificationMattermostError(t *testing.T) {
t.Parallel() t.Parallel()
srv := httptest.NewServer( assertSendNotificationTolerates(
http.HandlerFunc( t, http.StatusBadGateway, prioWarning,
func(w http.ResponseWriter, _ *http.Request) { (*notify.Service).SetMattermostWebhookURL,
w.WriteHeader(http.StatusBadGateway)
}),
) )
defer srv.Close()
mmURL, _ := url.Parse(srv.URL)
svc := notify.NewTestService(http.DefaultTransport)
svc.SetMattermostWebhookURL(mmURL)
svc.SendNotification(
context.Background(), "t", "m", "warning",
)
time.Sleep(100 * time.Millisecond)
} }
// ── SlackPayload JSON marshaling ────────────────────────── // ── SlackPayload JSON marshaling ──────────────────────────

View File

@@ -29,14 +29,14 @@ func TestAlertHistoryAddAndRecent(t *testing.T) {
Timestamp: now.Add(-2 * time.Minute), Timestamp: now.Add(-2 * time.Minute),
Title: "first", Title: "first",
Message: "msg1", Message: "msg1",
Priority: "info", Priority: prioInfo,
}) })
h.Add(notify.AlertEntry{ h.Add(notify.AlertEntry{
Timestamp: now.Add(-1 * time.Minute), Timestamp: now.Add(-1 * time.Minute),
Title: "second", Title: "second",
Message: "msg2", Message: "msg2",
Priority: "warning", Priority: prioWarning,
}) })
entries := h.Recent() entries := h.Recent()

View File

@@ -69,7 +69,7 @@ func (rc RetryConfig) backoff(attempt int) time.Duration {
lo := raw * (1 - jitterFraction) lo := raw * (1 - jitterFraction)
hi := raw * (1 + jitterFraction) hi := raw * (1 + jitterFraction)
jittered := lo + rand.Float64()*(hi-lo) //nolint:gosec // jitter does not need crypto/rand jittered := lo + rand.Float64()*(hi-lo) //nolint:gosec // jitter needs no crypto/rand
return time.Duration(jittered) return time.Duration(jittered)
} }

View File

@@ -13,6 +13,16 @@ import (
const testHostname = "www.example.com" const testHostname = "www.example.com"
// Shared fixture values used across tests.
const (
testNS1 = "ns1.example.com."
testNS2 = "ns2.example.com."
testAltNS1 = "ns1.test.com."
testIPv4 = "93.184.216.34"
testIP = "1.2.3.4"
statusError = "error"
)
// populateState fills a State with representative test data across all categories. // populateState fills a State with representative test data across all categories.
func populateState(t *testing.T, s *state.State) { func populateState(t *testing.T, s *state.State) {
t.Helper() t.Helper()
@@ -20,7 +30,7 @@ func populateState(t *testing.T, s *state.State) {
now := time.Now().UTC().Truncate(time.Second) now := time.Now().UTC().Truncate(time.Second)
s.SetDomainState("example.com", &state.DomainState{ s.SetDomainState("example.com", &state.DomainState{
Nameservers: []string{"ns1.example.com.", "ns2.example.com."}, Nameservers: []string{testNS1, testNS2},
LastChecked: now, LastChecked: now,
}) })
@@ -31,17 +41,17 @@ func populateState(t *testing.T, s *state.State) {
s.SetHostnameState(testHostname, &state.HostnameState{ s.SetHostnameState(testHostname, &state.HostnameState{
RecordsByNameserver: map[string]*state.NameserverRecordState{ RecordsByNameserver: map[string]*state.NameserverRecordState{
"ns1.example.com.": { testNS1: {
Records: map[string][]string{ Records: map[string][]string{
"A": {"93.184.216.34"}, "A": {testIPv4},
"AAAA": {"2606:2800:220:1:248:1893:25c8:1946"}, "AAAA": {"2606:2800:220:1:248:1893:25c8:1946"},
}, },
Status: "ok", Status: "ok",
LastChecked: now, LastChecked: now,
}, },
"ns2.example.com.": { testNS2: {
Records: map[string][]string{ Records: map[string][]string{
"A": {"93.184.216.34"}, "A": {testIPv4},
}, },
Status: "ok", Status: "ok",
LastChecked: now, LastChecked: now,
@@ -152,13 +162,13 @@ func TestSaveLoadRoundTrip_Hostnames(t *testing.T) {
func verifyNS1Records(t *testing.T, hn *state.HostnameState) { func verifyNS1Records(t *testing.T, hn *state.HostnameState) {
t.Helper() t.Helper()
ns1, ok := hn.RecordsByNameserver["ns1.example.com."] ns1, ok := hn.RecordsByNameserver[testNS1]
if !ok { if !ok {
t.Fatal("missing nameserver ns1.example.com.") t.Fatal("missing nameserver ns1.example.com.")
} }
aRecords := ns1.Records["A"] aRecords := ns1.Records["A"]
if len(aRecords) != 1 || aRecords[0] != "93.184.216.34" { if len(aRecords) != 1 || aRecords[0] != testIPv4 {
t.Errorf("ns1 A records: got %v", aRecords) t.Errorf("ns1 A records: got %v", aRecords)
} }
@@ -213,7 +223,8 @@ func TestSaveLoadRoundTrip_Ports(t *testing.T) {
} }
} }
// TestSaveLoadRoundTrip_Certificates verifies certificate data survives a save/load cycle. // TestSaveLoadRoundTrip_Certificates verifies certificate data
// survives a save/load cycle.
func TestSaveLoadRoundTrip_Certificates(t *testing.T) { func TestSaveLoadRoundTrip_Certificates(t *testing.T) {
t.Parallel() t.Parallel()
@@ -653,7 +664,7 @@ func TestDomainState_GetSet(t *testing.T) {
now := time.Now().UTC().Truncate(time.Second) now := time.Now().UTC().Truncate(time.Second)
ds := &state.DomainState{ ds := &state.DomainState{
Nameservers: []string{"ns1.test.com."}, Nameservers: []string{testAltNS1},
LastChecked: now, LastChecked: now,
} }
@@ -664,7 +675,7 @@ func TestDomainState_GetSet(t *testing.T) {
t.Fatal("expected true for existing domain") t.Fatal("expected true for existing domain")
} }
if len(got.Nameservers) != 1 || got.Nameservers[0] != "ns1.test.com." { if len(got.Nameservers) != 1 || got.Nameservers[0] != testAltNS1 {
t.Errorf("nameservers: got %v", got.Nameservers) t.Errorf("nameservers: got %v", got.Nameservers)
} }
@@ -674,7 +685,7 @@ func TestDomainState_GetSet(t *testing.T) {
// Overwrite. // Overwrite.
ds2 := &state.DomainState{ ds2 := &state.DomainState{
Nameservers: []string{"ns1.test.com.", "ns2.test.com."}, Nameservers: []string{testAltNS1, "ns2.test.com."},
LastChecked: now.Add(time.Hour), LastChecked: now.Add(time.Hour),
} }
@@ -704,8 +715,8 @@ func TestHostnameState_GetSet(t *testing.T) {
now := time.Now().UTC().Truncate(time.Second) now := time.Now().UTC().Truncate(time.Second)
hs := &state.HostnameState{ hs := &state.HostnameState{
RecordsByNameserver: map[string]*state.NameserverRecordState{ RecordsByNameserver: map[string]*state.NameserverRecordState{
"ns1.example.com.": { testNS1: {
Records: map[string][]string{"A": {"1.2.3.4"}}, Records: map[string][]string{"A": {testIP}},
Status: "ok", Status: "ok",
LastChecked: now, LastChecked: now,
}, },
@@ -720,7 +731,7 @@ func TestHostnameState_GetSet(t *testing.T) {
t.Fatal("expected true for existing hostname") t.Fatal("expected true for existing hostname")
} }
nsState, ok := got.RecordsByNameserver["ns1.example.com."] nsState, ok := got.RecordsByNameserver[testNS1]
if !ok { if !ok {
t.Fatal("missing nameserver entry") t.Fatal("missing nameserver entry")
} }
@@ -730,7 +741,7 @@ func TestHostnameState_GetSet(t *testing.T) {
} }
aRecords := nsState.Records["A"] aRecords := nsState.Records["A"]
if len(aRecords) != 1 || aRecords[0] != "1.2.3.4" { if len(aRecords) != 1 || aRecords[0] != testIP {
t.Errorf("A records: got %v", aRecords) t.Errorf("A records: got %v", aRecords)
} }
} }
@@ -869,7 +880,7 @@ func TestCertificateState_ErrorField(t *testing.T) {
now := time.Now().UTC().Truncate(time.Second) now := time.Now().UTC().Truncate(time.Second)
cs := &state.CertificateState{ cs := &state.CertificateState{
Status: "error", Status: statusError,
Error: "connection refused", Error: "connection refused",
LastChecked: now, LastChecked: now,
} }
@@ -893,8 +904,8 @@ func TestCertificateState_ErrorField(t *testing.T) {
t.Fatal("missing certificate after load") t.Fatal("missing certificate after load")
} }
if got.Status != "error" { if got.Status != statusError {
t.Errorf("status: got %q, want %q", got.Status, "error") t.Errorf("status: got %q, want %q", got.Status, statusError)
} }
if got.Error != "connection refused" { if got.Error != "connection refused" {
@@ -912,9 +923,9 @@ func TestHostnameState_ErrorField(t *testing.T) {
now := time.Now().UTC().Truncate(time.Second) now := time.Now().UTC().Truncate(time.Second)
hs := &state.HostnameState{ hs := &state.HostnameState{
RecordsByNameserver: map[string]*state.NameserverRecordState{ RecordsByNameserver: map[string]*state.NameserverRecordState{
"ns1.example.com.": { testNS1: {
Records: nil, Records: nil,
Status: "error", Status: statusError,
Error: "SERVFAIL", Error: "SERVFAIL",
LastChecked: now, LastChecked: now,
}, },
@@ -941,9 +952,9 @@ func TestHostnameState_ErrorField(t *testing.T) {
t.Fatal("missing hostname after load") t.Fatal("missing hostname after load")
} }
nsState := got.RecordsByNameserver["ns1.example.com."] nsState := got.RecordsByNameserver[testNS1]
if nsState.Status != "error" { if nsState.Status != statusError {
t.Errorf("status: got %q, want %q", nsState.Status, "error") t.Errorf("status: got %q, want %q", nsState.Status, statusError)
} }
if nsState.Error != "SERVFAIL" { if nsState.Error != "SERVFAIL" {
@@ -1062,7 +1073,8 @@ func TestConcurrentGetSet(t *testing.T) {
wg.Wait() wg.Wait()
} }
// runConcurrentOps performs a series of get/set/delete operations for concurrency testing. // runConcurrentOps performs a series of get/set/delete
// operations for concurrency testing.
func runConcurrentOps(s *state.State, key string, now time.Time) { func runConcurrentOps(s *state.State, key string, now time.Time) {
const iterations = 50 const iterations = 50
@@ -1085,7 +1097,7 @@ func runConcurrentOps(s *state.State, key string, now time.Time) {
s.SetHostnameState(key+".example.com", &state.HostnameState{ s.SetHostnameState(key+".example.com", &state.HostnameState{
RecordsByNameserver: map[string]*state.NameserverRecordState{ RecordsByNameserver: map[string]*state.NameserverRecordState{
"ns1.test.": { "ns1.test.": {
Records: map[string][]string{"A": {"1.2.3.4"}}, Records: map[string][]string{"A": {testIP}},
Status: "ok", Status: "ok",
LastChecked: now, LastChecked: now,
}, },

View File

@@ -26,6 +26,12 @@ const tlsPort = 443
// hoursPerDay converts days to hours for duration calculations. // hoursPerDay converts days to hours for duration calculations.
const hoursPerDay = 24 const hoursPerDay = 24
// Status values recorded for nameserver and certificate checks.
const (
statusOK = "ok"
statusError = "error"
)
// Params contains dependencies for Watcher. // Params contains dependencies for Watcher.
type Params struct { type Params struct {
fx.In fx.In
@@ -344,7 +350,7 @@ func buildHostnameState(
for ns, recs := range records { for ns, recs := range records {
hs.RecordsByNameserver[ns] = &state.NameserverRecordState{ hs.RecordsByNameserver[ns] = &state.NameserverRecordState{
Records: recs, Records: recs,
Status: "ok", Status: statusOK,
LastChecked: now, LastChecked: now,
} }
} }
@@ -402,7 +408,7 @@ func (w *Watcher) detectNSDisappearances(
current map[string]map[string][]string, current map[string]map[string][]string,
) { ) {
for ns, prevNS := range prev.RecordsByNameserver { for ns, prevNS := range prev.RecordsByNameserver {
if _, ok := current[ns]; ok || prevNS.Status != "ok" { if _, ok := current[ns]; ok || prevNS.Status != statusOK {
continue continue
} }
@@ -421,7 +427,7 @@ func (w *Watcher) detectNSDisappearances(
for ns := range current { for ns := range current {
prevNS, ok := prev.RecordsByNameserver[ns] prevNS, ok := prev.RecordsByNameserver[ns]
if !ok || prevNS.Status != "error" { if !ok || prevNS.Status != statusError {
continue continue
} }
@@ -705,7 +711,7 @@ func (w *Watcher) handleTLSError(
now time.Time, now time.Time,
err error, err error,
) { ) {
if hasPrev && !w.firstRun && prev.Status == "ok" { if hasPrev && !w.firstRun && prev.Status == statusOK {
msg := fmt.Sprintf( msg := fmt.Sprintf(
"Host: %s\nIP: %s\nError: %s", "Host: %s\nIP: %s\nError: %s",
hostname, ip, err, hostname, ip, err,
@@ -721,7 +727,7 @@ func (w *Watcher) handleTLSError(
w.state.SetCertificateState( w.state.SetCertificateState(
certKey, &state.CertificateState{ certKey, &state.CertificateState{
Status: "error", Status: statusError,
Error: err.Error(), Error: err.Error(),
LastChecked: now, LastChecked: now,
}, },
@@ -748,7 +754,7 @@ func (w *Watcher) handleTLSSuccess(
Issuer: cert.Issuer, Issuer: cert.Issuer,
NotAfter: cert.NotAfter, NotAfter: cert.NotAfter,
SubjectAlternativeNames: cert.SubjectAlternativeNames, SubjectAlternativeNames: cert.SubjectAlternativeNames,
Status: "ok", Status: statusOK,
LastChecked: now, LastChecked: now,
}, },
) )
@@ -760,7 +766,7 @@ func (w *Watcher) detectTLSChanges(
prev *state.CertificateState, prev *state.CertificateState,
cert *tlscheck.CertificateInfo, cert *tlscheck.CertificateInfo,
) { ) {
if prev.Status == "error" { if prev.Status == statusError {
msg := fmt.Sprintf( msg := fmt.Sprintf(
"Host: %s\nIP: %s\nTLS recovered", "Host: %s\nIP: %s\nTLS recovered",
hostname, ip, hostname, ip,

View File

@@ -18,6 +18,17 @@ import (
// errNotFound is returned when mock data is missing. // errNotFound is returned when mock data is missing.
var errNotFound = errors.New("not found") var errNotFound = errors.New("not found")
// Fixture values shared across tests.
const (
testDomain = "example.com"
testHost = "www.example.com"
testNS1 = "ns1.example.com."
testNS2 = "ns2.example.com."
testIPv4 = "93.184.216.34"
testIP = "1.2.3.4"
testIssuer = "DigiCert"
)
// --- Mock implementations --- // --- Mock implementations ---
type mockResolver struct { type mockResolver struct {
@@ -256,8 +267,8 @@ func TestFirstRunBaseline(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Domains = []string{"example.com"} cfg.Domains = []string{testDomain}
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
setupBaselineMocks(deps) setupBaselineMocks(deps)
@@ -269,37 +280,37 @@ func TestFirstRunBaseline(t *testing.T) {
} }
func setupBaselineMocks(deps *testDeps) { func setupBaselineMocks(deps *testDeps) {
deps.resolver.nsRecords["example.com"] = []string{ deps.resolver.nsRecords[testDomain] = []string{
"ns1.example.com.", testNS1,
"ns2.example.com.", testNS2,
} }
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"93.184.216.34"}}, testNS1: {"A": {testIPv4}},
"ns2.example.com.": {"A": {"93.184.216.34"}}, testNS2: {"A": {testIPv4}},
} }
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testHost] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"93.184.216.34"}}, testNS1: {"A": {testIPv4}},
"ns2.example.com.": {"A": {"93.184.216.34"}}, testNS2: {"A": {testIPv4}},
} }
deps.resolver.ipAddresses["www.example.com"] = []string{ deps.resolver.ipAddresses[testHost] = []string{
"93.184.216.34", testIPv4,
} }
deps.portChecker.results["93.184.216.34:80"] = true deps.portChecker.results["93.184.216.34:80"] = true
deps.portChecker.results["93.184.216.34:443"] = true deps.portChecker.results["93.184.216.34:443"] = true
deps.tlsChecker.certs["93.184.216.34:www.example.com"] = &tlscheck.CertificateInfo{ deps.tlsChecker.certs["93.184.216.34:www.example.com"] = &tlscheck.CertificateInfo{
CommonName: "www.example.com", CommonName: testHost,
Issuer: "DigiCert", Issuer: testIssuer,
NotAfter: time.Now().Add(90 * 24 * time.Hour), NotAfter: time.Now().Add(90 * 24 * time.Hour),
SubjectAlternativeNames: []string{ SubjectAlternativeNames: []string{
"www.example.com", testHost,
}, },
} }
deps.tlsChecker.certs["93.184.216.34:example.com"] = &tlscheck.CertificateInfo{ deps.tlsChecker.certs["93.184.216.34:example.com"] = &tlscheck.CertificateInfo{
CommonName: "example.com", CommonName: testDomain,
Issuer: "DigiCert", Issuer: testIssuer,
NotAfter: time.Now().Add(90 * 24 * time.Hour), NotAfter: time.Now().Add(90 * 24 * time.Hour),
SubjectAlternativeNames: []string{ SubjectAlternativeNames: []string{
"example.com", testDomain,
}, },
} }
} }
@@ -348,24 +359,24 @@ func TestDomainPortAndTLSChecks(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Domains = []string{"example.com"} cfg.Domains = []string{testDomain}
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
deps.resolver.nsRecords["example.com"] = []string{ deps.resolver.nsRecords[testDomain] = []string{
"ns1.example.com.", testNS1,
} }
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"93.184.216.34"}}, testNS1: {"A": {testIPv4}},
} }
deps.portChecker.results["93.184.216.34:80"] = true deps.portChecker.results["93.184.216.34:80"] = true
deps.portChecker.results["93.184.216.34:443"] = true deps.portChecker.results["93.184.216.34:443"] = true
deps.tlsChecker.certs["93.184.216.34:example.com"] = &tlscheck.CertificateInfo{ deps.tlsChecker.certs["93.184.216.34:example.com"] = &tlscheck.CertificateInfo{
CommonName: "example.com", CommonName: testDomain,
Issuer: "DigiCert", Issuer: testIssuer,
NotAfter: time.Now().Add(90 * 24 * time.Hour), NotAfter: time.Now().Add(90 * 24 * time.Hour),
SubjectAlternativeNames: []string{ SubjectAlternativeNames: []string{
"example.com", testDomain,
}, },
} }
@@ -406,17 +417,17 @@ func TestNSChangeDetection(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Domains = []string{"example.com"} cfg.Domains = []string{testDomain}
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
deps.resolver.nsRecords["example.com"] = []string{ deps.resolver.nsRecords[testDomain] = []string{
"ns1.example.com.", testNS1,
"ns2.example.com.", testNS2,
} }
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"1.2.3.4"}}, testNS1: {"A": {testIP}},
"ns2.example.com.": {"A": {"1.2.3.4"}}, testNS2: {"A": {testIP}},
} }
deps.portChecker.results["1.2.3.4:80"] = false deps.portChecker.results["1.2.3.4:80"] = false
deps.portChecker.results["1.2.3.4:443"] = false deps.portChecker.results["1.2.3.4:443"] = false
@@ -425,13 +436,13 @@ func TestNSChangeDetection(t *testing.T) {
w.RunOnce(ctx) w.RunOnce(ctx)
deps.resolver.mu.Lock() deps.resolver.mu.Lock()
deps.resolver.nsRecords["example.com"] = []string{ deps.resolver.nsRecords[testDomain] = []string{
"ns1.example.com.", testNS1,
"ns3.example.com.", "ns3.example.com.",
} }
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"1.2.3.4"}}, testNS1: {"A": {testIP}},
"ns3.example.com.": {"A": {"1.2.3.4"}}, "ns3.example.com.": {"A": {testIP}},
} }
deps.resolver.mu.Unlock() deps.resolver.mu.Unlock()
@@ -459,15 +470,15 @@ func TestRecordChangeDetection(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testHost] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"93.184.216.34"}}, testNS1: {"A": {testIPv4}},
} }
deps.resolver.ipAddresses["www.example.com"] = []string{ deps.resolver.ipAddresses[testHost] = []string{
"93.184.216.34", testIPv4,
} }
deps.portChecker.results["93.184.216.34:80"] = false deps.portChecker.results["93.184.216.34:80"] = false
deps.portChecker.results["93.184.216.34:443"] = false deps.portChecker.results["93.184.216.34:443"] = false
@@ -476,10 +487,10 @@ func TestRecordChangeDetection(t *testing.T) {
w.RunOnce(ctx) w.RunOnce(ctx)
deps.resolver.mu.Lock() deps.resolver.mu.Lock()
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testHost] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"93.184.216.35"}}, testNS1: {"A": {"93.184.216.35"}},
} }
deps.resolver.ipAddresses["www.example.com"] = []string{ deps.resolver.ipAddresses[testHost] = []string{
"93.184.216.35", "93.184.216.35",
} }
deps.resolver.mu.Unlock() deps.resolver.mu.Unlock()
@@ -501,24 +512,24 @@ func TestPortStateChange(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testHost] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"1.2.3.4"}}, testNS1: {"A": {testIP}},
} }
deps.resolver.ipAddresses["www.example.com"] = []string{ deps.resolver.ipAddresses[testHost] = []string{
"1.2.3.4", testIP,
} }
deps.portChecker.results["1.2.3.4:80"] = true deps.portChecker.results["1.2.3.4:80"] = true
deps.portChecker.results["1.2.3.4:443"] = true deps.portChecker.results["1.2.3.4:443"] = true
deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{ deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{
CommonName: "www.example.com", CommonName: testHost,
Issuer: "DigiCert", Issuer: testIssuer,
NotAfter: time.Now().Add(90 * 24 * time.Hour), NotAfter: time.Now().Add(90 * 24 * time.Hour),
SubjectAlternativeNames: []string{ SubjectAlternativeNames: []string{
"www.example.com", testHost,
}, },
} }
@@ -541,24 +552,24 @@ func TestTLSExpiryWarning(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testHost] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"1.2.3.4"}}, testNS1: {"A": {testIP}},
} }
deps.resolver.ipAddresses["www.example.com"] = []string{ deps.resolver.ipAddresses[testHost] = []string{
"1.2.3.4", testIP,
} }
deps.portChecker.results["1.2.3.4:80"] = true deps.portChecker.results["1.2.3.4:80"] = true
deps.portChecker.results["1.2.3.4:443"] = true deps.portChecker.results["1.2.3.4:443"] = true
deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{ deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{
CommonName: "www.example.com", CommonName: testHost,
Issuer: "DigiCert", Issuer: testIssuer,
NotAfter: time.Now().Add(3 * 24 * time.Hour), NotAfter: time.Now().Add(3 * 24 * time.Hour),
SubjectAlternativeNames: []string{ SubjectAlternativeNames: []string{
"www.example.com", testHost,
}, },
} }
@@ -592,25 +603,25 @@ func TestTLSExpiryWarningDedup(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
cfg.TLSInterval = 24 * time.Hour cfg.TLSInterval = 24 * time.Hour
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testHost] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"1.2.3.4"}}, testNS1: {"A": {testIP}},
} }
deps.resolver.ipAddresses["www.example.com"] = []string{ deps.resolver.ipAddresses[testHost] = []string{
"1.2.3.4", testIP,
} }
deps.portChecker.results["1.2.3.4:80"] = true deps.portChecker.results["1.2.3.4:80"] = true
deps.portChecker.results["1.2.3.4:443"] = true deps.portChecker.results["1.2.3.4:443"] = true
deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{ deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{
CommonName: "www.example.com", CommonName: testHost,
Issuer: "DigiCert", Issuer: testIssuer,
NotAfter: time.Now().Add(3 * 24 * time.Hour), NotAfter: time.Now().Add(3 * 24 * time.Hour),
SubjectAlternativeNames: []string{ SubjectAlternativeNames: []string{
"www.example.com", testHost,
}, },
} }
@@ -647,17 +658,17 @@ func TestGracefulShutdown(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Domains = []string{"example.com"} cfg.Domains = []string{testDomain}
cfg.DNSInterval = 100 * time.Millisecond cfg.DNSInterval = 100 * time.Millisecond
cfg.TLSInterval = 100 * time.Millisecond cfg.TLSInterval = 100 * time.Millisecond
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
deps.resolver.nsRecords["example.com"] = []string{ deps.resolver.nsRecords[testDomain] = []string{
"ns1.example.com.", testNS1,
} }
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"1.2.3.4"}}, testNS1: {"A": {testIP}},
} }
deps.portChecker.results["1.2.3.4:80"] = false deps.portChecker.results["1.2.3.4:80"] = false
deps.portChecker.results["1.2.3.4:443"] = false deps.portChecker.results["1.2.3.4:443"] = false
@@ -687,13 +698,13 @@ func setupHostnameIP(
hostname, ip string, hostname, ip string,
) { ) {
deps.resolver.allRecords[hostname] = map[string]map[string][]string{ deps.resolver.allRecords[hostname] = map[string]map[string][]string{
"ns1.example.com.": {"A": {ip}}, testNS1: {"A": {ip}},
} }
deps.portChecker.results[ip+":80"] = true deps.portChecker.results[ip+":80"] = true
deps.portChecker.results[ip+":443"] = true deps.portChecker.results[ip+":443"] = true
deps.tlsChecker.certs[ip+":"+hostname] = &tlscheck.CertificateInfo{ deps.tlsChecker.certs[ip+":"+hostname] = &tlscheck.CertificateInfo{
CommonName: hostname, CommonName: hostname,
Issuer: "DigiCert", Issuer: testIssuer,
NotAfter: time.Now().Add(90 * 24 * time.Hour), NotAfter: time.Now().Add(90 * 24 * time.Hour),
SubjectAlternativeNames: []string{hostname}, SubjectAlternativeNames: []string{hostname},
} }
@@ -702,7 +713,7 @@ func setupHostnameIP(
func updateHostnameIP(deps *testDeps, hostname, ip string) { func updateHostnameIP(deps *testDeps, hostname, ip string) {
deps.resolver.mu.Lock() deps.resolver.mu.Lock()
deps.resolver.allRecords[hostname] = map[string]map[string][]string{ deps.resolver.allRecords[hostname] = map[string]map[string][]string{
"ns1.example.com.": {"A": {ip}}, testNS1: {"A": {ip}},
} }
deps.resolver.mu.Unlock() deps.resolver.mu.Unlock()
@@ -714,7 +725,7 @@ func updateHostnameIP(deps *testDeps, hostname, ip string) {
deps.tlsChecker.mu.Lock() deps.tlsChecker.mu.Lock()
deps.tlsChecker.certs[ip+":"+hostname] = &tlscheck.CertificateInfo{ deps.tlsChecker.certs[ip+":"+hostname] = &tlscheck.CertificateInfo{
CommonName: hostname, CommonName: hostname,
Issuer: "DigiCert", Issuer: testIssuer,
NotAfter: time.Now().Add(90 * 24 * time.Hour), NotAfter: time.Now().Add(90 * 24 * time.Hour),
SubjectAlternativeNames: []string{hostname}, SubjectAlternativeNames: []string{hostname},
} }
@@ -725,11 +736,11 @@ func TestDNSRunsBeforePortAndTLSChecks(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
setupHostnameIP(deps, "www.example.com", "10.0.0.1") setupHostnameIP(deps, testHost, "10.0.0.1")
ctx := t.Context() ctx := t.Context()
w.RunOnce(ctx) w.RunOnce(ctx)
@@ -740,7 +751,7 @@ func TestDNSRunsBeforePortAndTLSChecks(t *testing.T) {
} }
// DNS changes to a new IP; port and TLS must pick it up. // DNS changes to a new IP; port and TLS must pick it up.
updateHostnameIP(deps, "www.example.com", "10.0.0.2") updateHostnameIP(deps, testHost, "10.0.0.2")
w.RunOnce(ctx) w.RunOnce(ctx)
@@ -760,8 +771,8 @@ func TestSendTestNotification_Enabled(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Domains = []string{"example.com"} cfg.Domains = []string{testDomain}
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
cfg.SendTestNotification = true cfg.SendTestNotification = true
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
@@ -786,8 +797,8 @@ func TestSendTestNotification_ViaRun(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Domains = []string{"example.com"} cfg.Domains = []string{testDomain}
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
cfg.SendTestNotification = true cfg.SendTestNotification = true
cfg.DNSInterval = 24 * time.Hour cfg.DNSInterval = 24 * time.Hour
cfg.TLSInterval = 24 * time.Hour cfg.TLSInterval = 24 * time.Hour
@@ -833,8 +844,8 @@ func TestSendTestNotification_Disabled(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Domains = []string{"example.com"} cfg.Domains = []string{testDomain}
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
cfg.SendTestNotification = false cfg.SendTestNotification = false
cfg.DNSInterval = 24 * time.Hour cfg.DNSInterval = 24 * time.Hour
cfg.TLSInterval = 24 * time.Hour cfg.TLSInterval = 24 * time.Hour
@@ -871,16 +882,16 @@ func TestNSFailureAndRecovery(t *testing.T) {
t.Parallel() t.Parallel()
cfg := defaultTestConfig(t) cfg := defaultTestConfig(t)
cfg.Hostnames = []string{"www.example.com"} cfg.Hostnames = []string{testHost}
w, deps := newTestWatcher(t, cfg) w, deps := newTestWatcher(t, cfg)
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testHost] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"1.2.3.4"}}, testNS1: {"A": {testIP}},
"ns2.example.com.": {"A": {"1.2.3.4"}}, testNS2: {"A": {testIP}},
} }
deps.resolver.ipAddresses["www.example.com"] = []string{ deps.resolver.ipAddresses[testHost] = []string{
"1.2.3.4", testIP,
} }
deps.portChecker.results["1.2.3.4:80"] = false deps.portChecker.results["1.2.3.4:80"] = false
deps.portChecker.results["1.2.3.4:443"] = false deps.portChecker.results["1.2.3.4:443"] = false
@@ -890,8 +901,8 @@ func TestNSFailureAndRecovery(t *testing.T) {
w.RunOnce(ctx) w.RunOnce(ctx)
deps.resolver.mu.Lock() deps.resolver.mu.Lock()
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{ deps.resolver.allRecords[testHost] = map[string]map[string][]string{
"ns1.example.com.": {"A": {"1.2.3.4"}}, testNS1: {"A": {testIP}},
} }
deps.resolver.mu.Unlock() deps.resolver.mu.Unlock()

View File

@@ -9,9 +9,9 @@ set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
# Pinned versions, 2026-07-07 (same pins as the Dockerfile) # Pinned versions, 2026-08-07 (same pins as the Dockerfile)
# golangci-lint v2.10.1 # golangci-lint v2.12.2
GOLANGCI_LINT_REF="github.com/golangci/golangci-lint/v2/cmd/golangci-lint@5d1e709b7be35cb2025444e19de266b056b7b7ee" GOLANGCI_LINT_REF="github.com/golangci/golangci-lint/v2/cmd/golangci-lint@c0d3ddc9cf3faa61a4e378e879ece580256d76e5"
# goimports v0.42.0 # goimports v0.42.0
GOIMPORTS_REF="golang.org/x/tools/cmd/goimports@009367f5c17a8d4c45a961a3a509277190a9a6f0" GOIMPORTS_REF="golang.org/x/tools/cmd/goimports@009367f5c17a8d4c45a961a3a509277190a9a6f0"