140 lines
4.3 KiB
Go
140 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// 1262/AC2: mail-store answers accounts a and b; status answers that it serves, and is granted a and b.
|
|
func TestStatusAnswersItServesAndTheGrantedAccounts(t *testing.T) {
|
|
b := &Bundle{Accounts: func(context.Context) (json.RawMessage, error) {
|
|
return json.Marshal(map[string]any{"accounts": []map[string]any{
|
|
{"account": "a", "kind": "imap"}, {"account": "b", "kind": "imap"},
|
|
}})
|
|
}}
|
|
out, err := b.statusTool(nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := out.(map[string]any)
|
|
if m["serves"] != true {
|
|
t.Fatalf("serves: %v", m["serves"])
|
|
}
|
|
got, _ := m["accounts"].([]string)
|
|
if len(got) != 2 || got[0] != "a" || got[1] != "b" {
|
|
t.Fatalf("accounts: %v", m["accounts"])
|
|
}
|
|
}
|
|
|
|
// 1262/AC3: mail-store does not answer (or refuses); status answers that it does not serve, and why, and does
|
|
// not panic.
|
|
func TestStatusAnswersItDoesNotServeWhenMailStoreRefuses(t *testing.T) {
|
|
b := &Bundle{Accounts: func(context.Context) (json.RawMessage, error) {
|
|
return nil, errors.New("refused: mesh-mail-web is not granted any account")
|
|
}}
|
|
out, err := b.statusTool(nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := out.(map[string]any)
|
|
if m["serves"] != false {
|
|
t.Fatalf("serves: %v", m["serves"])
|
|
}
|
|
why, _ := m["why"].(string)
|
|
if why == "" {
|
|
t.Fatalf("no reason given: %v", m)
|
|
}
|
|
}
|
|
|
|
// Same AC3, the other half: mail-store answers something this module cannot read.
|
|
func TestStatusAnswersItDoesNotServeWhenMailStoresAnswerCannotBeRead(t *testing.T) {
|
|
b := &Bundle{Accounts: func(context.Context) (json.RawMessage, error) {
|
|
return json.RawMessage(`{"accounts": "not a list"}`), nil
|
|
}}
|
|
out, err := b.statusTool(nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
m := out.(map[string]any)
|
|
if m["serves"] != false || m["why"] == "" {
|
|
t.Fatalf("%v", m)
|
|
}
|
|
}
|
|
|
|
// review round 1 finding 4: mail-webclient.status and mail_web_health both say the HTTP endpoint's own state
|
|
// (main.go's serveHTTP) rather than going on claiming to serve and to be healthy regardless — one test per
|
|
// state (setting up sign-in, listening, ended).
|
|
func TestStatusAndHealthSayTheHTTPEndpointsState(t *testing.T) {
|
|
accountsOK := func(context.Context) (json.RawMessage, error) {
|
|
return json.Marshal(map[string]any{"accounts": []any{}})
|
|
}
|
|
operatorsOK := operatorsFile(t, "alice")
|
|
|
|
cases := []struct {
|
|
name string
|
|
phase string
|
|
err error
|
|
}{
|
|
{"setting up sign-in", HTTPSettingUpSignIn, errors.New("the issuer could not be reached")},
|
|
{"ended", HTTPEnded, errors.New("listen tcp :8080: bind: address already in use")},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
h := NewHTTPStatus()
|
|
h.set(c.phase, c.err)
|
|
b := &Bundle{HTTP: h, Accounts: accountsOK, Env: Env{Operators: operatorsOK}}
|
|
|
|
statusOut, err := b.statusTool(nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sm := statusOut.(map[string]any)
|
|
if sm["serves"] != false {
|
|
t.Fatalf("status serves: %v, want false while %s", sm["serves"], c.phase)
|
|
}
|
|
if why, _ := sm["why"].(string); !strings.Contains(why, c.phase) {
|
|
t.Fatalf("status why %q does not name the phase %q", why, c.phase)
|
|
}
|
|
|
|
healthOut, err := b.healthTool(nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
hm := healthOut.(map[string]any)
|
|
if hm["healthy"] != false {
|
|
t.Fatalf("health healthy: %v, want false while %s", hm["healthy"], c.phase)
|
|
}
|
|
if why, _ := hm["why"].(string); !strings.Contains(why, c.phase) {
|
|
t.Fatalf("health why %q does not name the phase %q", why, c.phase)
|
|
}
|
|
})
|
|
}
|
|
|
|
// HTTPListening: status and health go back to their own, ordinary checks (mail-store's own accounts
|
|
// answer, the operators setting), neither blocked by the HTTP endpoint's own state any more.
|
|
t.Run("listening", func(t *testing.T) {
|
|
h := NewHTTPStatus()
|
|
h.set(HTTPListening, nil)
|
|
b := &Bundle{HTTP: h, Accounts: accountsOK, Env: Env{Operators: operatorsOK}}
|
|
|
|
statusOut, err := b.statusTool(nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if sm := statusOut.(map[string]any); sm["serves"] != true {
|
|
t.Fatalf("status serves: %v, want true once listening", sm["serves"])
|
|
}
|
|
|
|
healthOut, err := b.healthTool(nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if hm := healthOut.(map[string]any); hm["healthy"] != true {
|
|
t.Fatalf("health healthy: %v, want true once listening: %v", hm["healthy"], hm)
|
|
}
|
|
})
|
|
}
|