Files
mesh-sdk/go/health/health_test.go
T
jochen 33917f91ac
mesh/merge-gate pass: builds mesh-sdk, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript), go/merge-check.sh (go)
mesh/delivery delivered
mesh/delivery-group group feat/386-a-wait-for-the-operator merged: every member is merged
Refuse every form of path or address in a wait's words, a contradicting healthy answer, and a malformed wait at Waiting
From the review of mesh-sdk#18: quoted and bracketed paths, home and relative
paths, IPv6, host and port, UNC and drive paths passed the check.
2026-10-10 21:10:01 +02:00

151 lines
5.5 KiB
Go

package health
import (
"encoding/json"
"strings"
"testing"
)
func roundTrip(t *testing.T, a Answer) Answer {
t.Helper()
b, err := json.Marshal(a)
if err != nil {
t.Fatal(err)
}
got, err := Read(b)
if err != nil {
t.Fatal(err)
}
return got
}
var password = Wait{Part: "the source games", Secret: "smb-password-games", What: "the password of the source games"}
func TestEachConstructorSaysItsStateAndKeepsHealthyForAnOlderReader(t *testing.T) {
for _, c := range []struct {
a Answer
state string
healthy bool
}{
{Healthy("all armed"), StateHealthy, true},
{Unhealthy("the share is unreachable"), StateUnhealthy, false},
{Waiting("the source games waits for its password", password), StateWaits, false},
} {
b, _ := json.Marshal(c.a)
var old struct {
Healthy bool `json:"healthy"`
Why string `json:"why"`
}
if err := json.Unmarshal(b, &old); err != nil || old.Healthy != c.healthy || old.Why == "" {
t.Fatalf("an older reader of %s reads %+v (%v)", b, old, err)
}
if got := roundTrip(t, c.a); got.State != c.state || got.Healthy != c.healthy {
t.Fatalf("%s read as %+v", b, got)
}
}
}
func TestAWaitIsReadWithWhatItNames(t *testing.T) {
got := roundTrip(t, Waiting("waits", password, Wait{Part: "the source games", Setting: "smb-users", What: "the username of the source games"}))
if got.State != StateWaits || len(got.Waits) != 2 || got.Waits[0].Secret != "smb-password-games" || got.Waits[1].Setting != "smb-users" {
t.Fatalf("read as %+v", got)
}
}
func TestAnAnswerWithoutStateIsReadFromHealthy(t *testing.T) {
for raw, want := range map[string]string{`{"healthy":true,"why":"ok"}`: StateHealthy, `{"healthy":false,"why":"down"}`: StateUnhealthy} {
got, err := Read([]byte(raw))
if err != nil || got.State != want {
t.Fatalf("%s read as %+v, %v", raw, got, err)
}
}
}
func TestAWaitThatCannotBeReadIsUnhealthyAndSaysWhy(t *testing.T) {
for name, c := range map[string]struct {
w []Wait
says string
}{
"no wait": {nil, "names nothing"},
"neither": {[]Wait{{Part: "p", What: "w"}}, "neither a secret nor a setting"},
"both": {[]Wait{{Part: "p", Secret: "a", Setting: "b", What: "w"}}, "both"},
"not a name": {[]Wait{{Part: "p", Secret: "Smb Password", What: "w"}}, "not a name"},
"no what": {[]Wait{{Part: "p", Secret: "a"}}, "does not say what"},
"no part": {[]Wait{{Secret: "a", What: "w"}}, "which part"},
"two lines": {[]Wait{{Part: "p", Secret: "a", What: "the password\nhunter2"}}, "more than one line"},
"an address": {[]Wait{{Part: "p", Secret: "a", What: "the password of 192.0.2.76"}}, "path or an address"},
"a url": {[]Wait{{Part: "p", Secret: "a", What: "the password of smb://host/share"}}, "path or an address"},
"a path": {[]Wait{{Part: "the source at /mnt/games", Secret: "a", What: "the password"}}, "path or an address"},
} {
b, _ := json.Marshal(Answer{State: StateWaits, Why: "it waits", Waits: c.w})
got, err := Read(b)
if err != nil {
t.Fatalf("%s: %v", name, err)
}
if got.State != StateUnhealthy || got.Healthy || !strings.Contains(got.Why, c.says) {
t.Fatalf("%s: read as %+v, want unhealthy saying %q", name, got, c.says)
}
}
}
func TestAnUnknownStateIsUnhealthy(t *testing.T) {
got, err := Read([]byte(`{"state":"fine","healthy":true}`))
if err != nil || got.State != StateUnhealthy || got.Healthy {
t.Fatalf("read as %+v, %v", got, err)
}
}
func TestWaitsBesideAFaultAreSaidAndExcuseNothing(t *testing.T) {
got := roundTrip(t, Unhealthy("the share is unreachable", password, Wait{Part: "p", What: "w"}))
if got.State != StateUnhealthy || len(got.Waits) != 1 {
t.Fatalf("read as %+v: the readable wait is kept, the other dropped, the state stays unhealthy", got)
}
if h := roundTrip(t, Answer{State: StateHealthy, Healthy: true, Why: "ok", Waits: []Wait{password}}); len(h.Waits) != 0 {
t.Fatalf("a healthy answer kept its waits: %+v", h)
}
}
func TestWaitingWithNothingIsUnhealthy(t *testing.T) {
if a := Waiting("it waits"); a.State != StateUnhealthy {
t.Fatalf("Waiting with no wait is %+v", a)
}
}
func TestNotAnAnswerIsAnError(t *testing.T) {
if _, err := Read([]byte(`"yes"`)); err == nil {
t.Fatal("a string read as an answer")
}
}
func TestEveryFormOfPathOrAddressIsRefused(t *testing.T) {
for _, words := range []string{
"the source (/mnt/games)", `the source "/mnt/games"`, "the folder ~/games", "the folder ./games",
"2001:db8::1", "fe80::1%eth0", "2001:0db8:0000:0000:0000:0000:0000:0001", "nas.lan:445", "192.0.2.7:445",
`\\nas\games`, `C:\Users\x`, "smb://nas/games", "198.51.100.4",
} {
w := Wait{Part: "the source games", Secret: "smb-password-games", What: "the password of " + words}
if err := w.Check(); err == nil {
t.Errorf("%q passed as words for the operator", words)
}
}
for _, words := range []string{"the password of the source games", "the username of the source games-2", "the API key, issued by the vendor"} {
w := Wait{Part: "the source games", Secret: "smb-password-games", What: words}
if err := w.Check(); err != nil {
t.Errorf("%q refused: %v", words, err)
}
}
}
func TestHealthyStateWithHealthyFalseIsUnhealthy(t *testing.T) {
got, err := Read([]byte(`{"state":"healthy","healthy":false,"why":"x"}`))
if err != nil || got.State != StateUnhealthy || !strings.Contains(got.Why, "contradict") {
t.Fatalf("read as %+v, %v", got, err)
}
}
func TestWaitingChecksItsWaits(t *testing.T) {
if a := Waiting("it waits", Wait{Part: "p", What: "w"}); a.State != StateUnhealthy || !strings.Contains(a.Why, "neither") {
t.Fatalf("Waiting with a malformed wait is %+v", a)
}
}