build: update golangci-lint to v2.12.2 with org-standard v2 config
All checks were successful
check / check (push) Successful in 33s
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:
@@ -1,5 +1,9 @@
|
||||
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:
|
||||
timeout: 5m
|
||||
modules-download-mode: readonly
|
||||
@@ -14,8 +18,7 @@ linters:
|
||||
- wsl # Deprecated, replaced by wsl_v5
|
||||
- wrapcheck # Too verbose for internal packages
|
||||
- varnamelen # Short names like db, id are idiomatic Go
|
||||
|
||||
linters-settings:
|
||||
settings:
|
||||
lll:
|
||||
line-length: 88
|
||||
funlen:
|
||||
@@ -27,6 +30,5 @@ linters-settings:
|
||||
threshold: 100
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
|
||||
@@ -4,8 +4,8 @@ FROM golang@sha256:f6751d823c26342f9506c03797d2527668d095b0a15f1862cddb4d927a7a4
|
||||
|
||||
RUN apk add --no-cache git make gcc musl-dev binutils-gold
|
||||
|
||||
# golangci-lint v2.10.1
|
||||
RUN go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@5d1e709b7be35cb2025444e19de266b056b7b7ee
|
||||
# golangci-lint v2.12.2, 2026-08-07
|
||||
RUN go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@c0d3ddc9cf3faa61a4e378e879ece580256d76e5
|
||||
# goimports v0.42.0
|
||||
RUN go install golang.org/x/tools/cmd/goimports@009367f5c17a8d4c45a961a3a509277190a9a6f0
|
||||
|
||||
|
||||
8
TODO.md
8
TODO.md
@@ -25,6 +25,14 @@ confirm make check still passes.
|
||||
|
||||
# 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,
|
||||
Makefile shims, README Entrypoints section
|
||||
- 2026-02-20: iterative DNS resolver implemented; tests made hermetic
|
||||
|
||||
@@ -17,13 +17,33 @@ func TestClassifyDNSName(t *testing.T) {
|
||||
}{
|
||||
{name: "apex domain simple", input: "example.com", want: config.DNSNameTypeDomain},
|
||||
{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: "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: "uppercase normalized", input: "WWW.Example.COM", want: config.DNSNameTypeHostname},
|
||||
{
|
||||
name: "deeply nested hostname",
|
||||
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 {
|
||||
|
||||
@@ -25,6 +25,20 @@ const (
|
||||
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.
|
||||
var errSimulated = errors.New("simulated transport failure")
|
||||
|
||||
@@ -101,13 +115,13 @@ func TestNtfyPriority(t *testing.T) {
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{"error", "urgent"},
|
||||
{"warning", "high"},
|
||||
{"success", "default"},
|
||||
{"info", "low"},
|
||||
{"", "default"},
|
||||
{"unknown", "default"},
|
||||
{"critical", "default"},
|
||||
{prioError, prioUrgent},
|
||||
{prioWarning, "high"},
|
||||
{prioSuccess, prioDefault},
|
||||
{prioInfo, "low"},
|
||||
{"", prioDefault},
|
||||
{prioUnknown, prioDefault},
|
||||
{"critical", prioDefault},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -134,12 +148,12 @@ func TestSlackColor(t *testing.T) {
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{"error", colorError},
|
||||
{"warning", colorWarning},
|
||||
{"success", colorSuccess},
|
||||
{"info", colorInfo},
|
||||
{prioError, colorError},
|
||||
{prioWarning, colorWarning},
|
||||
{prioSuccess, colorSuccess},
|
||||
{prioInfo, colorInfo},
|
||||
{"", colorDefault},
|
||||
{"unknown", colorDefault},
|
||||
{prioUnknown, colorDefault},
|
||||
{"critical", colorDefault},
|
||||
}
|
||||
|
||||
@@ -165,7 +179,7 @@ func TestNewRequest(t *testing.T) {
|
||||
|
||||
target := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "example.com",
|
||||
Host: testHost,
|
||||
Path: "/webhook",
|
||||
}
|
||||
body := bytes.NewBufferString("hello")
|
||||
@@ -187,9 +201,9 @@ func TestNewRequest(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
if req.Host != "example.com" {
|
||||
if req.Host != testHost {
|
||||
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"),
|
||||
"v",
|
||||
)
|
||||
target := &url.URL{Scheme: "https", Host: "example.com"}
|
||||
target := &url.URL{Scheme: "https", Host: testHost}
|
||||
|
||||
req := notify.NewRequestForTest(
|
||||
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(
|
||||
"Priority header = %q, want %q",
|
||||
captured.priority, "urgent",
|
||||
captured.priority, prioUrgent,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -311,10 +325,10 @@ func TestSendNtfyAllPriorities(t *testing.T) {
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{"error", "urgent"},
|
||||
{"warning", "high"},
|
||||
{"success", "default"},
|
||||
{"info", "low"},
|
||||
{prioError, prioUrgent},
|
||||
{prioWarning, "high"},
|
||||
{prioSuccess, prioDefault},
|
||||
{prioInfo, "low"},
|
||||
}
|
||||
|
||||
for _, tc := range priorities {
|
||||
@@ -356,56 +370,69 @@ func TestSendNtfyAllPriorities(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendNtfyClientError(t *testing.T) {
|
||||
t.Parallel()
|
||||
// assertSendStatusError verifies that send returns an error
|
||||
// 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(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.WriteHeader(status)
|
||||
}),
|
||||
)
|
||||
defer srv.Close()
|
||||
|
||||
svc := notify.NewTestService(srv.Client().Transport)
|
||||
topicURL, _ := url.Parse(srv.URL)
|
||||
target, _ := url.Parse(srv.URL)
|
||||
|
||||
err := svc.SendNtfy(
|
||||
context.Background(), topicURL, "t", "m", "info",
|
||||
)
|
||||
err := send(svc, target)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for 403 response")
|
||||
t.Fatalf("expected error for %d response", status)
|
||||
}
|
||||
|
||||
if !errors.Is(err, notify.ErrNtfyFailed) {
|
||||
t.Errorf("error = %v, want ErrNtfyFailed", err)
|
||||
if !errors.Is(err, wantErr) {
|
||||
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) {
|
||||
t.Parallel()
|
||||
|
||||
srv := httptest.NewServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}),
|
||||
assertSendStatusError(
|
||||
t, http.StatusInternalServerError,
|
||||
notify.ErrNtfyFailed, sendNtfyInfo,
|
||||
)
|
||||
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) {
|
||||
@@ -550,11 +577,11 @@ func TestSendSlackAllColors(t *testing.T) {
|
||||
priority string
|
||||
want string
|
||||
}{
|
||||
{"error", colorError},
|
||||
{"warning", colorWarning},
|
||||
{"success", colorSuccess},
|
||||
{"info", colorInfo},
|
||||
{"unknown", colorDefault},
|
||||
{prioError, colorError},
|
||||
{prioWarning, colorWarning},
|
||||
{prioSuccess, colorSuccess},
|
||||
{prioInfo, colorInfo},
|
||||
{prioUnknown, colorDefault},
|
||||
}
|
||||
|
||||
for _, tc := range colors {
|
||||
@@ -606,53 +633,19 @@ func TestSendSlackAllColors(t *testing.T) {
|
||||
func TestSendSlackClientError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
srv := httptest.NewServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}),
|
||||
assertSendStatusError(
|
||||
t, http.StatusBadRequest,
|
||||
notify.ErrSlackFailed, sendSlackInfo,
|
||||
)
|
||||
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) {
|
||||
t.Parallel()
|
||||
|
||||
srv := httptest.NewServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
}),
|
||||
assertSendStatusError(
|
||||
t, http.StatusBadGateway,
|
||||
notify.ErrSlackFailed, sendSlackInfo,
|
||||
)
|
||||
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) {
|
||||
@@ -977,74 +970,62 @@ func TestSendNotificationMattermostOnly(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendNotificationNtfyError(t *testing.T) {
|
||||
t.Parallel()
|
||||
// assertSendNotificationTolerates verifies SendNotification
|
||||
// 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(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.WriteHeader(status)
|
||||
}),
|
||||
)
|
||||
defer srv.Close()
|
||||
|
||||
ntfyURL, _ := url.Parse(srv.URL)
|
||||
target, _ := url.Parse(srv.URL)
|
||||
|
||||
svc := notify.NewTestService(http.DefaultTransport)
|
||||
svc.SetNtfyURL(ntfyURL)
|
||||
setURL(svc, target)
|
||||
|
||||
// Should not panic or block.
|
||||
svc.SendNotification(
|
||||
context.Background(), "t", "m", "error",
|
||||
context.Background(), "t", "m", priority,
|
||||
)
|
||||
|
||||
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) {
|
||||
t.Parallel()
|
||||
|
||||
srv := httptest.NewServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
}),
|
||||
assertSendNotificationTolerates(
|
||||
t, http.StatusForbidden, prioError,
|
||||
(*notify.Service).SetSlackWebhookURL,
|
||||
)
|
||||
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) {
|
||||
t.Parallel()
|
||||
|
||||
srv := httptest.NewServer(
|
||||
http.HandlerFunc(
|
||||
func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
}),
|
||||
assertSendNotificationTolerates(
|
||||
t, http.StatusBadGateway, prioWarning,
|
||||
(*notify.Service).SetMattermostWebhookURL,
|
||||
)
|
||||
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 ──────────────────────────
|
||||
|
||||
@@ -29,14 +29,14 @@ func TestAlertHistoryAddAndRecent(t *testing.T) {
|
||||
Timestamp: now.Add(-2 * time.Minute),
|
||||
Title: "first",
|
||||
Message: "msg1",
|
||||
Priority: "info",
|
||||
Priority: prioInfo,
|
||||
})
|
||||
|
||||
h.Add(notify.AlertEntry{
|
||||
Timestamp: now.Add(-1 * time.Minute),
|
||||
Title: "second",
|
||||
Message: "msg2",
|
||||
Priority: "warning",
|
||||
Priority: prioWarning,
|
||||
})
|
||||
|
||||
entries := h.Recent()
|
||||
|
||||
@@ -69,7 +69,7 @@ func (rc RetryConfig) backoff(attempt int) time.Duration {
|
||||
lo := 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)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,16 @@ import (
|
||||
|
||||
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.
|
||||
func populateState(t *testing.T, s *state.State) {
|
||||
t.Helper()
|
||||
@@ -20,7 +30,7 @@ func populateState(t *testing.T, s *state.State) {
|
||||
now := time.Now().UTC().Truncate(time.Second)
|
||||
|
||||
s.SetDomainState("example.com", &state.DomainState{
|
||||
Nameservers: []string{"ns1.example.com.", "ns2.example.com."},
|
||||
Nameservers: []string{testNS1, testNS2},
|
||||
LastChecked: now,
|
||||
})
|
||||
|
||||
@@ -31,17 +41,17 @@ func populateState(t *testing.T, s *state.State) {
|
||||
|
||||
s.SetHostnameState(testHostname, &state.HostnameState{
|
||||
RecordsByNameserver: map[string]*state.NameserverRecordState{
|
||||
"ns1.example.com.": {
|
||||
testNS1: {
|
||||
Records: map[string][]string{
|
||||
"A": {"93.184.216.34"},
|
||||
"A": {testIPv4},
|
||||
"AAAA": {"2606:2800:220:1:248:1893:25c8:1946"},
|
||||
},
|
||||
Status: "ok",
|
||||
LastChecked: now,
|
||||
},
|
||||
"ns2.example.com.": {
|
||||
testNS2: {
|
||||
Records: map[string][]string{
|
||||
"A": {"93.184.216.34"},
|
||||
"A": {testIPv4},
|
||||
},
|
||||
Status: "ok",
|
||||
LastChecked: now,
|
||||
@@ -152,13 +162,13 @@ func TestSaveLoadRoundTrip_Hostnames(t *testing.T) {
|
||||
func verifyNS1Records(t *testing.T, hn *state.HostnameState) {
|
||||
t.Helper()
|
||||
|
||||
ns1, ok := hn.RecordsByNameserver["ns1.example.com."]
|
||||
ns1, ok := hn.RecordsByNameserver[testNS1]
|
||||
if !ok {
|
||||
t.Fatal("missing nameserver ns1.example.com.")
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -653,7 +664,7 @@ func TestDomainState_GetSet(t *testing.T) {
|
||||
|
||||
now := time.Now().UTC().Truncate(time.Second)
|
||||
ds := &state.DomainState{
|
||||
Nameservers: []string{"ns1.test.com."},
|
||||
Nameservers: []string{testAltNS1},
|
||||
LastChecked: now,
|
||||
}
|
||||
|
||||
@@ -664,7 +675,7 @@ func TestDomainState_GetSet(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -674,7 +685,7 @@ func TestDomainState_GetSet(t *testing.T) {
|
||||
|
||||
// Overwrite.
|
||||
ds2 := &state.DomainState{
|
||||
Nameservers: []string{"ns1.test.com.", "ns2.test.com."},
|
||||
Nameservers: []string{testAltNS1, "ns2.test.com."},
|
||||
LastChecked: now.Add(time.Hour),
|
||||
}
|
||||
|
||||
@@ -704,8 +715,8 @@ func TestHostnameState_GetSet(t *testing.T) {
|
||||
now := time.Now().UTC().Truncate(time.Second)
|
||||
hs := &state.HostnameState{
|
||||
RecordsByNameserver: map[string]*state.NameserverRecordState{
|
||||
"ns1.example.com.": {
|
||||
Records: map[string][]string{"A": {"1.2.3.4"}},
|
||||
testNS1: {
|
||||
Records: map[string][]string{"A": {testIP}},
|
||||
Status: "ok",
|
||||
LastChecked: now,
|
||||
},
|
||||
@@ -720,7 +731,7 @@ func TestHostnameState_GetSet(t *testing.T) {
|
||||
t.Fatal("expected true for existing hostname")
|
||||
}
|
||||
|
||||
nsState, ok := got.RecordsByNameserver["ns1.example.com."]
|
||||
nsState, ok := got.RecordsByNameserver[testNS1]
|
||||
if !ok {
|
||||
t.Fatal("missing nameserver entry")
|
||||
}
|
||||
@@ -730,7 +741,7 @@ func TestHostnameState_GetSet(t *testing.T) {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -869,7 +880,7 @@ func TestCertificateState_ErrorField(t *testing.T) {
|
||||
|
||||
now := time.Now().UTC().Truncate(time.Second)
|
||||
cs := &state.CertificateState{
|
||||
Status: "error",
|
||||
Status: statusError,
|
||||
Error: "connection refused",
|
||||
LastChecked: now,
|
||||
}
|
||||
@@ -893,8 +904,8 @@ func TestCertificateState_ErrorField(t *testing.T) {
|
||||
t.Fatal("missing certificate after load")
|
||||
}
|
||||
|
||||
if got.Status != "error" {
|
||||
t.Errorf("status: got %q, want %q", got.Status, "error")
|
||||
if got.Status != statusError {
|
||||
t.Errorf("status: got %q, want %q", got.Status, statusError)
|
||||
}
|
||||
|
||||
if got.Error != "connection refused" {
|
||||
@@ -912,9 +923,9 @@ func TestHostnameState_ErrorField(t *testing.T) {
|
||||
now := time.Now().UTC().Truncate(time.Second)
|
||||
hs := &state.HostnameState{
|
||||
RecordsByNameserver: map[string]*state.NameserverRecordState{
|
||||
"ns1.example.com.": {
|
||||
testNS1: {
|
||||
Records: nil,
|
||||
Status: "error",
|
||||
Status: statusError,
|
||||
Error: "SERVFAIL",
|
||||
LastChecked: now,
|
||||
},
|
||||
@@ -941,9 +952,9 @@ func TestHostnameState_ErrorField(t *testing.T) {
|
||||
t.Fatal("missing hostname after load")
|
||||
}
|
||||
|
||||
nsState := got.RecordsByNameserver["ns1.example.com."]
|
||||
if nsState.Status != "error" {
|
||||
t.Errorf("status: got %q, want %q", nsState.Status, "error")
|
||||
nsState := got.RecordsByNameserver[testNS1]
|
||||
if nsState.Status != statusError {
|
||||
t.Errorf("status: got %q, want %q", nsState.Status, statusError)
|
||||
}
|
||||
|
||||
if nsState.Error != "SERVFAIL" {
|
||||
@@ -1062,7 +1073,8 @@ func TestConcurrentGetSet(t *testing.T) {
|
||||
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) {
|
||||
const iterations = 50
|
||||
|
||||
@@ -1085,7 +1097,7 @@ func runConcurrentOps(s *state.State, key string, now time.Time) {
|
||||
s.SetHostnameState(key+".example.com", &state.HostnameState{
|
||||
RecordsByNameserver: map[string]*state.NameserverRecordState{
|
||||
"ns1.test.": {
|
||||
Records: map[string][]string{"A": {"1.2.3.4"}},
|
||||
Records: map[string][]string{"A": {testIP}},
|
||||
Status: "ok",
|
||||
LastChecked: now,
|
||||
},
|
||||
|
||||
@@ -26,6 +26,12 @@ const tlsPort = 443
|
||||
// hoursPerDay converts days to hours for duration calculations.
|
||||
const hoursPerDay = 24
|
||||
|
||||
// Status values recorded for nameserver and certificate checks.
|
||||
const (
|
||||
statusOK = "ok"
|
||||
statusError = "error"
|
||||
)
|
||||
|
||||
// Params contains dependencies for Watcher.
|
||||
type Params struct {
|
||||
fx.In
|
||||
@@ -344,7 +350,7 @@ func buildHostnameState(
|
||||
for ns, recs := range records {
|
||||
hs.RecordsByNameserver[ns] = &state.NameserverRecordState{
|
||||
Records: recs,
|
||||
Status: "ok",
|
||||
Status: statusOK,
|
||||
LastChecked: now,
|
||||
}
|
||||
}
|
||||
@@ -402,7 +408,7 @@ func (w *Watcher) detectNSDisappearances(
|
||||
current map[string]map[string][]string,
|
||||
) {
|
||||
for ns, prevNS := range prev.RecordsByNameserver {
|
||||
if _, ok := current[ns]; ok || prevNS.Status != "ok" {
|
||||
if _, ok := current[ns]; ok || prevNS.Status != statusOK {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -421,7 +427,7 @@ func (w *Watcher) detectNSDisappearances(
|
||||
|
||||
for ns := range current {
|
||||
prevNS, ok := prev.RecordsByNameserver[ns]
|
||||
if !ok || prevNS.Status != "error" {
|
||||
if !ok || prevNS.Status != statusError {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -705,7 +711,7 @@ func (w *Watcher) handleTLSError(
|
||||
now time.Time,
|
||||
err error,
|
||||
) {
|
||||
if hasPrev && !w.firstRun && prev.Status == "ok" {
|
||||
if hasPrev && !w.firstRun && prev.Status == statusOK {
|
||||
msg := fmt.Sprintf(
|
||||
"Host: %s\nIP: %s\nError: %s",
|
||||
hostname, ip, err,
|
||||
@@ -721,7 +727,7 @@ func (w *Watcher) handleTLSError(
|
||||
|
||||
w.state.SetCertificateState(
|
||||
certKey, &state.CertificateState{
|
||||
Status: "error",
|
||||
Status: statusError,
|
||||
Error: err.Error(),
|
||||
LastChecked: now,
|
||||
},
|
||||
@@ -748,7 +754,7 @@ func (w *Watcher) handleTLSSuccess(
|
||||
Issuer: cert.Issuer,
|
||||
NotAfter: cert.NotAfter,
|
||||
SubjectAlternativeNames: cert.SubjectAlternativeNames,
|
||||
Status: "ok",
|
||||
Status: statusOK,
|
||||
LastChecked: now,
|
||||
},
|
||||
)
|
||||
@@ -760,7 +766,7 @@ func (w *Watcher) detectTLSChanges(
|
||||
prev *state.CertificateState,
|
||||
cert *tlscheck.CertificateInfo,
|
||||
) {
|
||||
if prev.Status == "error" {
|
||||
if prev.Status == statusError {
|
||||
msg := fmt.Sprintf(
|
||||
"Host: %s\nIP: %s\nTLS recovered",
|
||||
hostname, ip,
|
||||
|
||||
@@ -18,6 +18,17 @@ import (
|
||||
// errNotFound is returned when mock data is missing.
|
||||
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 ---
|
||||
|
||||
type mockResolver struct {
|
||||
@@ -256,8 +267,8 @@ func TestFirstRunBaseline(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Domains = []string{"example.com"}
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Domains = []string{testDomain}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
setupBaselineMocks(deps)
|
||||
@@ -269,37 +280,37 @@ func TestFirstRunBaseline(t *testing.T) {
|
||||
}
|
||||
|
||||
func setupBaselineMocks(deps *testDeps) {
|
||||
deps.resolver.nsRecords["example.com"] = []string{
|
||||
"ns1.example.com.",
|
||||
"ns2.example.com.",
|
||||
deps.resolver.nsRecords[testDomain] = []string{
|
||||
testNS1,
|
||||
testNS2,
|
||||
}
|
||||
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"93.184.216.34"}},
|
||||
"ns2.example.com.": {"A": {"93.184.216.34"}},
|
||||
deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIPv4}},
|
||||
testNS2: {"A": {testIPv4}},
|
||||
}
|
||||
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"93.184.216.34"}},
|
||||
"ns2.example.com.": {"A": {"93.184.216.34"}},
|
||||
deps.resolver.allRecords[testHost] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIPv4}},
|
||||
testNS2: {"A": {testIPv4}},
|
||||
}
|
||||
deps.resolver.ipAddresses["www.example.com"] = []string{
|
||||
"93.184.216.34",
|
||||
deps.resolver.ipAddresses[testHost] = []string{
|
||||
testIPv4,
|
||||
}
|
||||
deps.portChecker.results["93.184.216.34:80"] = true
|
||||
deps.portChecker.results["93.184.216.34:443"] = true
|
||||
deps.tlsChecker.certs["93.184.216.34:www.example.com"] = &tlscheck.CertificateInfo{
|
||||
CommonName: "www.example.com",
|
||||
Issuer: "DigiCert",
|
||||
CommonName: testHost,
|
||||
Issuer: testIssuer,
|
||||
NotAfter: time.Now().Add(90 * 24 * time.Hour),
|
||||
SubjectAlternativeNames: []string{
|
||||
"www.example.com",
|
||||
testHost,
|
||||
},
|
||||
}
|
||||
deps.tlsChecker.certs["93.184.216.34:example.com"] = &tlscheck.CertificateInfo{
|
||||
CommonName: "example.com",
|
||||
Issuer: "DigiCert",
|
||||
CommonName: testDomain,
|
||||
Issuer: testIssuer,
|
||||
NotAfter: time.Now().Add(90 * 24 * time.Hour),
|
||||
SubjectAlternativeNames: []string{
|
||||
"example.com",
|
||||
testDomain,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -348,24 +359,24 @@ func TestDomainPortAndTLSChecks(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Domains = []string{"example.com"}
|
||||
cfg.Domains = []string{testDomain}
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
deps.resolver.nsRecords["example.com"] = []string{
|
||||
"ns1.example.com.",
|
||||
deps.resolver.nsRecords[testDomain] = []string{
|
||||
testNS1,
|
||||
}
|
||||
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"93.184.216.34"}},
|
||||
deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIPv4}},
|
||||
}
|
||||
deps.portChecker.results["93.184.216.34:80"] = true
|
||||
deps.portChecker.results["93.184.216.34:443"] = true
|
||||
deps.tlsChecker.certs["93.184.216.34:example.com"] = &tlscheck.CertificateInfo{
|
||||
CommonName: "example.com",
|
||||
Issuer: "DigiCert",
|
||||
CommonName: testDomain,
|
||||
Issuer: testIssuer,
|
||||
NotAfter: time.Now().Add(90 * 24 * time.Hour),
|
||||
SubjectAlternativeNames: []string{
|
||||
"example.com",
|
||||
testDomain,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -406,17 +417,17 @@ func TestNSChangeDetection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Domains = []string{"example.com"}
|
||||
cfg.Domains = []string{testDomain}
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
deps.resolver.nsRecords["example.com"] = []string{
|
||||
"ns1.example.com.",
|
||||
"ns2.example.com.",
|
||||
deps.resolver.nsRecords[testDomain] = []string{
|
||||
testNS1,
|
||||
testNS2,
|
||||
}
|
||||
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"1.2.3.4"}},
|
||||
"ns2.example.com.": {"A": {"1.2.3.4"}},
|
||||
deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIP}},
|
||||
testNS2: {"A": {testIP}},
|
||||
}
|
||||
deps.portChecker.results["1.2.3.4:80"] = false
|
||||
deps.portChecker.results["1.2.3.4:443"] = false
|
||||
@@ -425,13 +436,13 @@ func TestNSChangeDetection(t *testing.T) {
|
||||
w.RunOnce(ctx)
|
||||
|
||||
deps.resolver.mu.Lock()
|
||||
deps.resolver.nsRecords["example.com"] = []string{
|
||||
"ns1.example.com.",
|
||||
deps.resolver.nsRecords[testDomain] = []string{
|
||||
testNS1,
|
||||
"ns3.example.com.",
|
||||
}
|
||||
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"1.2.3.4"}},
|
||||
"ns3.example.com.": {"A": {"1.2.3.4"}},
|
||||
deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIP}},
|
||||
"ns3.example.com.": {"A": {testIP}},
|
||||
}
|
||||
deps.resolver.mu.Unlock()
|
||||
|
||||
@@ -459,15 +470,15 @@ func TestRecordChangeDetection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"93.184.216.34"}},
|
||||
deps.resolver.allRecords[testHost] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIPv4}},
|
||||
}
|
||||
deps.resolver.ipAddresses["www.example.com"] = []string{
|
||||
"93.184.216.34",
|
||||
deps.resolver.ipAddresses[testHost] = []string{
|
||||
testIPv4,
|
||||
}
|
||||
deps.portChecker.results["93.184.216.34:80"] = false
|
||||
deps.portChecker.results["93.184.216.34:443"] = false
|
||||
@@ -476,10 +487,10 @@ func TestRecordChangeDetection(t *testing.T) {
|
||||
w.RunOnce(ctx)
|
||||
|
||||
deps.resolver.mu.Lock()
|
||||
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"93.184.216.35"}},
|
||||
deps.resolver.allRecords[testHost] = map[string]map[string][]string{
|
||||
testNS1: {"A": {"93.184.216.35"}},
|
||||
}
|
||||
deps.resolver.ipAddresses["www.example.com"] = []string{
|
||||
deps.resolver.ipAddresses[testHost] = []string{
|
||||
"93.184.216.35",
|
||||
}
|
||||
deps.resolver.mu.Unlock()
|
||||
@@ -501,24 +512,24 @@ func TestPortStateChange(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"1.2.3.4"}},
|
||||
deps.resolver.allRecords[testHost] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIP}},
|
||||
}
|
||||
deps.resolver.ipAddresses["www.example.com"] = []string{
|
||||
"1.2.3.4",
|
||||
deps.resolver.ipAddresses[testHost] = []string{
|
||||
testIP,
|
||||
}
|
||||
deps.portChecker.results["1.2.3.4:80"] = true
|
||||
deps.portChecker.results["1.2.3.4:443"] = true
|
||||
deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{
|
||||
CommonName: "www.example.com",
|
||||
Issuer: "DigiCert",
|
||||
CommonName: testHost,
|
||||
Issuer: testIssuer,
|
||||
NotAfter: time.Now().Add(90 * 24 * time.Hour),
|
||||
SubjectAlternativeNames: []string{
|
||||
"www.example.com",
|
||||
testHost,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -541,24 +552,24 @@ func TestTLSExpiryWarning(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"1.2.3.4"}},
|
||||
deps.resolver.allRecords[testHost] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIP}},
|
||||
}
|
||||
deps.resolver.ipAddresses["www.example.com"] = []string{
|
||||
"1.2.3.4",
|
||||
deps.resolver.ipAddresses[testHost] = []string{
|
||||
testIP,
|
||||
}
|
||||
deps.portChecker.results["1.2.3.4:80"] = true
|
||||
deps.portChecker.results["1.2.3.4:443"] = true
|
||||
deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{
|
||||
CommonName: "www.example.com",
|
||||
Issuer: "DigiCert",
|
||||
CommonName: testHost,
|
||||
Issuer: testIssuer,
|
||||
NotAfter: time.Now().Add(3 * 24 * time.Hour),
|
||||
SubjectAlternativeNames: []string{
|
||||
"www.example.com",
|
||||
testHost,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -592,25 +603,25 @@ func TestTLSExpiryWarningDedup(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
cfg.TLSInterval = 24 * time.Hour
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"1.2.3.4"}},
|
||||
deps.resolver.allRecords[testHost] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIP}},
|
||||
}
|
||||
deps.resolver.ipAddresses["www.example.com"] = []string{
|
||||
"1.2.3.4",
|
||||
deps.resolver.ipAddresses[testHost] = []string{
|
||||
testIP,
|
||||
}
|
||||
deps.portChecker.results["1.2.3.4:80"] = true
|
||||
deps.portChecker.results["1.2.3.4:443"] = true
|
||||
deps.tlsChecker.certs["1.2.3.4:www.example.com"] = &tlscheck.CertificateInfo{
|
||||
CommonName: "www.example.com",
|
||||
Issuer: "DigiCert",
|
||||
CommonName: testHost,
|
||||
Issuer: testIssuer,
|
||||
NotAfter: time.Now().Add(3 * 24 * time.Hour),
|
||||
SubjectAlternativeNames: []string{
|
||||
"www.example.com",
|
||||
testHost,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -647,17 +658,17 @@ func TestGracefulShutdown(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Domains = []string{"example.com"}
|
||||
cfg.Domains = []string{testDomain}
|
||||
cfg.DNSInterval = 100 * time.Millisecond
|
||||
cfg.TLSInterval = 100 * time.Millisecond
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
deps.resolver.nsRecords["example.com"] = []string{
|
||||
"ns1.example.com.",
|
||||
deps.resolver.nsRecords[testDomain] = []string{
|
||||
testNS1,
|
||||
}
|
||||
deps.resolver.allRecords["example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"1.2.3.4"}},
|
||||
deps.resolver.allRecords[testDomain] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIP}},
|
||||
}
|
||||
deps.portChecker.results["1.2.3.4:80"] = false
|
||||
deps.portChecker.results["1.2.3.4:443"] = false
|
||||
@@ -687,13 +698,13 @@ func setupHostnameIP(
|
||||
hostname, ip 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+":443"] = true
|
||||
deps.tlsChecker.certs[ip+":"+hostname] = &tlscheck.CertificateInfo{
|
||||
CommonName: hostname,
|
||||
Issuer: "DigiCert",
|
||||
Issuer: testIssuer,
|
||||
NotAfter: time.Now().Add(90 * 24 * time.Hour),
|
||||
SubjectAlternativeNames: []string{hostname},
|
||||
}
|
||||
@@ -702,7 +713,7 @@ func setupHostnameIP(
|
||||
func updateHostnameIP(deps *testDeps, hostname, ip string) {
|
||||
deps.resolver.mu.Lock()
|
||||
deps.resolver.allRecords[hostname] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {ip}},
|
||||
testNS1: {"A": {ip}},
|
||||
}
|
||||
deps.resolver.mu.Unlock()
|
||||
|
||||
@@ -714,7 +725,7 @@ func updateHostnameIP(deps *testDeps, hostname, ip string) {
|
||||
deps.tlsChecker.mu.Lock()
|
||||
deps.tlsChecker.certs[ip+":"+hostname] = &tlscheck.CertificateInfo{
|
||||
CommonName: hostname,
|
||||
Issuer: "DigiCert",
|
||||
Issuer: testIssuer,
|
||||
NotAfter: time.Now().Add(90 * 24 * time.Hour),
|
||||
SubjectAlternativeNames: []string{hostname},
|
||||
}
|
||||
@@ -725,11 +736,11 @@ func TestDNSRunsBeforePortAndTLSChecks(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
setupHostnameIP(deps, "www.example.com", "10.0.0.1")
|
||||
setupHostnameIP(deps, testHost, "10.0.0.1")
|
||||
|
||||
ctx := t.Context()
|
||||
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.
|
||||
updateHostnameIP(deps, "www.example.com", "10.0.0.2")
|
||||
updateHostnameIP(deps, testHost, "10.0.0.2")
|
||||
|
||||
w.RunOnce(ctx)
|
||||
|
||||
@@ -760,8 +771,8 @@ func TestSendTestNotification_Enabled(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Domains = []string{"example.com"}
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Domains = []string{testDomain}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
cfg.SendTestNotification = true
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
@@ -786,8 +797,8 @@ func TestSendTestNotification_ViaRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Domains = []string{"example.com"}
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Domains = []string{testDomain}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
cfg.SendTestNotification = true
|
||||
cfg.DNSInterval = 24 * time.Hour
|
||||
cfg.TLSInterval = 24 * time.Hour
|
||||
@@ -833,8 +844,8 @@ func TestSendTestNotification_Disabled(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Domains = []string{"example.com"}
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Domains = []string{testDomain}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
cfg.SendTestNotification = false
|
||||
cfg.DNSInterval = 24 * time.Hour
|
||||
cfg.TLSInterval = 24 * time.Hour
|
||||
@@ -871,16 +882,16 @@ func TestNSFailureAndRecovery(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := defaultTestConfig(t)
|
||||
cfg.Hostnames = []string{"www.example.com"}
|
||||
cfg.Hostnames = []string{testHost}
|
||||
|
||||
w, deps := newTestWatcher(t, cfg)
|
||||
|
||||
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"1.2.3.4"}},
|
||||
"ns2.example.com.": {"A": {"1.2.3.4"}},
|
||||
deps.resolver.allRecords[testHost] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIP}},
|
||||
testNS2: {"A": {testIP}},
|
||||
}
|
||||
deps.resolver.ipAddresses["www.example.com"] = []string{
|
||||
"1.2.3.4",
|
||||
deps.resolver.ipAddresses[testHost] = []string{
|
||||
testIP,
|
||||
}
|
||||
deps.portChecker.results["1.2.3.4:80"] = false
|
||||
deps.portChecker.results["1.2.3.4:443"] = false
|
||||
@@ -890,8 +901,8 @@ func TestNSFailureAndRecovery(t *testing.T) {
|
||||
w.RunOnce(ctx)
|
||||
|
||||
deps.resolver.mu.Lock()
|
||||
deps.resolver.allRecords["www.example.com"] = map[string]map[string][]string{
|
||||
"ns1.example.com.": {"A": {"1.2.3.4"}},
|
||||
deps.resolver.allRecords[testHost] = map[string]map[string][]string{
|
||||
testNS1: {"A": {testIP}},
|
||||
}
|
||||
deps.resolver.mu.Unlock()
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ set -eu
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
|
||||
# Pinned versions, 2026-07-07 (same pins as the Dockerfile)
|
||||
# golangci-lint v2.10.1
|
||||
GOLANGCI_LINT_REF="github.com/golangci/golangci-lint/v2/cmd/golangci-lint@5d1e709b7be35cb2025444e19de266b056b7b7ee"
|
||||
# Pinned versions, 2026-08-07 (same pins as the Dockerfile)
|
||||
# golangci-lint v2.12.2
|
||||
GOLANGCI_LINT_REF="github.com/golangci/golangci-lint/v2/cmd/golangci-lint@c0d3ddc9cf3faa61a4e378e879ece580256d76e5"
|
||||
# goimports v0.42.0
|
||||
GOIMPORTS_REF="golang.org/x/tools/cmd/goimports@009367f5c17a8d4c45a961a3a509277190a9a6f0"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user