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
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.
151 lines
5.5 KiB
Go
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)
|
|
}
|
|
}
|