113 lines
2.8 KiB
Go
113 lines
2.8 KiB
Go
// This file is part of the happyDomain (R) project.
|
|
// Copyright (c) 2020-2026 happyDomain
|
|
// Authors: Pierre-Olivier Mercier, et al.
|
|
|
|
package checker
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
)
|
|
|
|
// fakeObs is an in-memory ObservationGetter backed by a single HTTPData
|
|
// payload stored under ObservationKeyHTTP. A nil payload makes Get return
|
|
// an error, which lets tests cover the loadHTTPData failure branch.
|
|
type fakeObs struct {
|
|
data *HTTPData
|
|
failGet bool
|
|
}
|
|
|
|
func (f *fakeObs) Get(_ context.Context, key sdk.ObservationKey, dest any) error {
|
|
if f.failGet {
|
|
return errString("forced get failure")
|
|
}
|
|
if key != ObservationKeyHTTP {
|
|
return errString("unexpected key: " + key)
|
|
}
|
|
if f.data == nil {
|
|
return errString("no data")
|
|
}
|
|
raw, err := json.Marshal(f.data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return json.Unmarshal(raw, dest)
|
|
}
|
|
|
|
func (f *fakeObs) GetRelated(_ context.Context, _ sdk.ObservationKey) ([]sdk.RelatedObservation, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
type errString string
|
|
|
|
func (e errString) Error() string { return string(e) }
|
|
|
|
// runRule is a small wrapper that builds a fakeObs around the supplied
|
|
// HTTPData and evaluates the rule with the given options. It returns the
|
|
// states verbatim; assertion is left to the caller.
|
|
func runRule(t *testing.T, r sdk.CheckRule, data *HTTPData, opts sdk.CheckerOptions) []sdk.CheckState {
|
|
t.Helper()
|
|
if opts == nil {
|
|
opts = sdk.CheckerOptions{}
|
|
}
|
|
states := r.Evaluate(context.Background(), &fakeObs{data: data}, opts)
|
|
if len(states) == 0 {
|
|
t.Fatalf("rule %q returned no states (must always return at least one)", r.Name())
|
|
}
|
|
return states
|
|
}
|
|
|
|
func httpsProbe(addr string) HTTPProbe {
|
|
return HTTPProbe{
|
|
Scheme: "https",
|
|
Host: "example.test",
|
|
IP: "203.0.113.1",
|
|
Port: 443,
|
|
Address: addr,
|
|
TCPConnected: true,
|
|
StatusCode: 200,
|
|
Headers: map[string]string{},
|
|
}
|
|
}
|
|
|
|
func httpProbe(addr string) HTTPProbe {
|
|
p := httpsProbe(addr)
|
|
p.Scheme = "http"
|
|
p.Port = 80
|
|
return p
|
|
}
|
|
|
|
func mustStatus(t *testing.T, states []sdk.CheckState, want sdk.Status) {
|
|
t.Helper()
|
|
for _, s := range states {
|
|
if s.Status != want {
|
|
t.Fatalf("status: got %s (%q), want %s; full states: %+v", s.Status, s.Code, want, states)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ruleByName looks a rule up in the global registry by Name(). It exists
|
|
// so tests can drive rules wired declaratively (HeaderRule and friends)
|
|
// without depending on a concrete type.
|
|
func ruleByName(t *testing.T, name string) sdk.CheckRule {
|
|
t.Helper()
|
|
for _, r := range Rules() {
|
|
if r.Name() == name {
|
|
return r
|
|
}
|
|
}
|
|
t.Fatalf("rule %q not found in registry", name)
|
|
return nil
|
|
}
|
|
|
|
func hasCode(states []sdk.CheckState, code string) bool {
|
|
for _, s := range states {
|
|
if s.Code == code {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|