144 lines
5.1 KiB
Go
144 lines
5.1 KiB
Go
package asks
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestConditionSubject(t *testing.T) { // 1202/AC1
|
|
s, err := ConditionSubject("mesh-delivery-teller")
|
|
if err != nil || s != "mesh.seat.operator-channel.accept.condition.mesh-delivery-teller" {
|
|
t.Fatalf("subject = %q, %v", s, err)
|
|
}
|
|
// The router splits an accept subject in six parts and reads the verb at 4 and the caller at 5.
|
|
parts := strings.Split(s, ".")
|
|
if len(parts) != 6 || parts[4] != "condition" || parts[5] != "mesh-delivery-teller" {
|
|
t.Errorf("subject %q does not keep the router's shape: %v", s, parts)
|
|
}
|
|
for _, bad := range []string{"", "a.b", "a*", "a>", "a b", "a\tb", "a\nb"} {
|
|
if _, err := ConditionSubject(bad); err == nil {
|
|
t.Errorf("publisher %q accepted", bad)
|
|
}
|
|
}
|
|
}
|
|
|
|
func raisedCondition() Condition {
|
|
return Condition{
|
|
Key: "delivery.stuck.mesh-mail", Severity: "warning",
|
|
Subject: Scope{Scope: "module", ID: "mesh-mail", Machine: "ace"}, State: "raised",
|
|
Summary: "plan 12 stopped", Headline: "Delivery of mesh-mail is stuck",
|
|
Needs: "approve the merge.", Explanation: "Needs you: approve the merge. The plan waits.",
|
|
Resolved: "The delivery of mesh-mail moved on.",
|
|
Actions: []Action{{Label: "Approve", Verb: "mesh-controller.assign", Machine: "ace",
|
|
Arguments: map[string]string{"why": ""}, Level: Approve}},
|
|
}
|
|
}
|
|
|
|
func clearedCondition() Condition {
|
|
return Condition{Key: "delivery.stuck.mesh-mail", Subject: Scope{Scope: "module", ID: "mesh-mail"}, State: "cleared"}
|
|
}
|
|
|
|
func TestConditionRoundTrip(t *testing.T) { // 1202/AC2
|
|
for _, c := range []Condition{raisedCondition(), clearedCondition()} {
|
|
data, err := EncodeCondition(c)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", c.State, err)
|
|
}
|
|
var probe map[string]any
|
|
if err := json.Unmarshal(data, &probe); err != nil || probe["v"] != float64(1) {
|
|
t.Fatalf("%s: %s does not carry v:1", c.State, data)
|
|
}
|
|
c.V = ConditionVersion
|
|
got, err := DecodeCondition(data)
|
|
if err != nil || !SameCondition(got, c) {
|
|
t.Errorf("%s round trip: %+v %v", c.State, got, err)
|
|
}
|
|
}
|
|
data, _ := EncodeCondition(raisedCondition())
|
|
var probe map[string]any
|
|
_ = json.Unmarshal(data, &probe)
|
|
for _, name := range []string{"key", "severity", "subject", "summary", "headline", "needs", "explanation", "resolved", "actions", "state"} {
|
|
if _, ok := probe[name]; !ok {
|
|
t.Errorf("the JSON has no %q: %s", name, data)
|
|
}
|
|
}
|
|
subject := probe["subject"].(map[string]any)
|
|
for _, name := range []string{"scope", "id", "machine"} {
|
|
if _, ok := subject[name]; !ok {
|
|
t.Errorf("the subject has no %q: %s", name, data)
|
|
}
|
|
}
|
|
action := probe["actions"].([]any)[0].(map[string]any)
|
|
for _, name := range []string{"label", "verb", "machine", "arguments", "level"} {
|
|
if _, ok := action[name]; !ok {
|
|
t.Errorf("the action has no %q: %s", name, data)
|
|
}
|
|
}
|
|
for _, in := range []string{`{"key":"k"}`, `{"v":2,"key":"k"}`} {
|
|
if _, err := DecodeCondition([]byte(in)); !errors.Is(err, ErrUnknownConditionVersion) {
|
|
t.Errorf("decode of %s = %v, want ErrUnknownConditionVersion", in, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConditionVerdict(t *testing.T) { // 1202/AC3
|
|
c := raisedCondition()
|
|
c.Needs, c.Explanation = "", "The plan waits."
|
|
_, err := EncodeCondition(c)
|
|
if err == nil || !strings.Contains(err.Error(), "Nothing for you to do.") {
|
|
t.Errorf("empty needs without its verdict: %v", err)
|
|
}
|
|
c.Explanation = "Nothing for you to do. The plan waits."
|
|
if _, err := EncodeCondition(c); err != nil {
|
|
t.Errorf("empty needs with its verdict refused: %v", err)
|
|
}
|
|
c = raisedCondition()
|
|
c.Explanation = "Nothing for you to do. The plan waits."
|
|
_, err = EncodeCondition(c)
|
|
if err == nil || !strings.Contains(err.Error(), "Needs you: approve the merge.") {
|
|
t.Errorf("needs set with the wrong verdict: %v", err)
|
|
}
|
|
c.Explanation = "Needs you: something else. The plan waits."
|
|
if _, err = EncodeCondition(c); err == nil {
|
|
t.Error("needs set with other needs in the verdict accepted")
|
|
}
|
|
}
|
|
|
|
func TestConditionRefused(t *testing.T) { // 1202/AC4
|
|
mutate := func(f func(*Condition)) error {
|
|
c := raisedCondition()
|
|
f(&c)
|
|
_, err := EncodeCondition(c)
|
|
return err
|
|
}
|
|
for name, f := range map[string]func(*Condition){
|
|
"severity": func(c *Condition) { c.Severity = "critical" },
|
|
"state": func(c *Condition) { c.State = "open" },
|
|
"key": func(c *Condition) { c.Key = "" },
|
|
"headline": func(c *Condition) { c.Headline = "" },
|
|
"long headline": func(c *Condition) { c.Headline = strings.Repeat("h", HeadlineLength+1) },
|
|
} {
|
|
if err := mutate(f); err == nil {
|
|
t.Errorf("a condition with a bad %s accepted", name)
|
|
}
|
|
}
|
|
if err := mutate(func(c *Condition) { c.Headline = strings.Repeat("h", HeadlineLength) }); err != nil {
|
|
t.Errorf("a headline of the greatest length refused: %v", err)
|
|
}
|
|
if _, err := EncodeCondition(clearedCondition()); err != nil {
|
|
t.Errorf("a cleared condition with only key, subject and state refused: %v", err)
|
|
}
|
|
c := clearedCondition()
|
|
c.Key = ""
|
|
if _, err := EncodeCondition(c); err == nil {
|
|
t.Error("a cleared condition without its key accepted")
|
|
}
|
|
c = clearedCondition()
|
|
c.State = "gone"
|
|
if _, err := EncodeCondition(c); err == nil {
|
|
t.Error("a condition with an unknown state accepted")
|
|
}
|
|
}
|