happyDomain/checkers/domain_expiry_test.go
Pierre-Olivier Mercier fa781a537d checkers: migrate to checker-sdk-go v1.2.0 []CheckState signature
Rules now return []CheckState, the engine stamps RuleName from the rule,
and the HTTP rule-result lookup matches on RuleName rather than Code.
domain_contact emits one state per role (Subject) instead of a
concatenated single-state message.
2026-04-28 13:06:23 +07:00

145 lines
4.5 KiB
Go

// This file is part of the happyDomain (R) project.
// Copyright (c) 2020-2026 happyDomain
// Authors: Pierre-Olivier Mercier, et al.
//
// This program is offered under a commercial and under the AGPL license.
// For commercial licensing, contact us at <contact@happydomain.org>.
//
// For AGPL licensing:
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package checkers
import (
"context"
"encoding/json"
"testing"
"time"
sdk "git.happydns.org/checker-sdk-go/checker"
"git.happydns.org/happyDomain/model"
)
func TestDomainExpiryRule_Evaluate(t *testing.T) {
rule := &domainExpiryRule{}
now := time.Now()
cases := []struct {
name string
expiresIn time.Duration
opts happydns.CheckerOptions
want happydns.Status
code string
}{
{"already expired", -5 * 24 * time.Hour, nil, happydns.StatusCrit, "expiry_critical"},
{"critical default", 3 * 24 * time.Hour, nil, happydns.StatusCrit, "expiry_critical"},
{"warning default", 15 * 24 * time.Hour, nil, happydns.StatusWarn, "expiry_warning"},
{"ok default", 90 * 24 * time.Hour, nil, happydns.StatusOK, "expiry_ok"},
{"ok with custom thresholds", 10 * 24 * time.Hour, happydns.CheckerOptions{
"warning_days": float64(5),
"critical_days": float64(2),
}, happydns.StatusOK, "expiry_ok"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
obs := newWhoisObs(&WHOISData{
ExpiryDate: now.Add(tc.expiresIn),
Registrar: "Test Registrar",
})
states := rule.Evaluate(context.Background(), obs, tc.opts)
if len(states) != 1 {
t.Fatalf("expected 1 state, got %d", len(states))
}
st := states[0]
if st.Status != tc.want {
t.Errorf("status = %v, want %v (msg=%q)", st.Status, tc.want, st.Message)
}
if st.Code != tc.code {
t.Errorf("code = %q, want %q", st.Code, tc.code)
}
})
}
}
func TestDomainExpiryRule_EvaluateObservationError(t *testing.T) {
rule := &domainExpiryRule{}
obs := &stubObservationGetter{key: ObservationKeyWhois, err: errString("boom")}
states := rule.Evaluate(context.Background(), obs, nil)
if len(states) != 1 {
t.Fatalf("expected 1 state, got %d", len(states))
}
st := states[0]
if st.Status != happydns.StatusError {
t.Fatalf("expected StatusError, got %v", st.Status)
}
if st.Code != "whois_error" {
t.Errorf("code = %q, want whois_error", st.Code)
}
}
func TestDomainExpiryRule_ValidateOptions(t *testing.T) {
rule := &domainExpiryRule{}
cases := []struct {
name string
opts happydns.CheckerOptions
wantErr bool
}{
{"defaults", nil, false},
{"valid custom", happydns.CheckerOptions{"warning_days": 30.0, "critical_days": 7.0}, false},
{"crit >= warn", happydns.CheckerOptions{"warning_days": 5.0, "critical_days": 5.0}, true},
{"warn wrong type", happydns.CheckerOptions{"warning_days": "thirty"}, true},
{"warn negative", happydns.CheckerOptions{"warning_days": -1.0}, true},
{"crit negative", happydns.CheckerOptions{"critical_days": -3.0}, true},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
err := rule.ValidateOptions(tc.opts)
if (err != nil) != tc.wantErr {
t.Errorf("ValidateOptions err=%v, wantErr=%v", err, tc.wantErr)
}
})
}
}
func TestWhoisProvider_ExtractMetrics(t *testing.T) {
p := &whoisProvider{}
collected := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
data := WHOISData{
ExpiryDate: collected.Add(10 * 24 * time.Hour),
Registrar: "Acme",
}
raw, err := json.Marshal(data)
if err != nil {
t.Fatal(err)
}
metrics, err := p.ExtractMetrics(sdk.StaticReportContext(raw), collected)
if err != nil {
t.Fatal(err)
}
if len(metrics) != 1 {
t.Fatalf("expected 1 metric, got %d", len(metrics))
}
m := metrics[0]
if m.Name != "domain_expiry_days_remaining" {
t.Errorf("name = %q", m.Name)
}
if m.Value < 9.99 || m.Value > 10.01 {
t.Errorf("value = %v, want ~10", m.Value)
}
if m.Labels["registrar"] != "Acme" {
t.Errorf("registrar label = %q", m.Labels["registrar"])
}
}