A hold answered keep on the phone could not be changed: its ask ended with the answer, nothing listed it, and a kept hold is never lifted by itself. The view lists every hold with its node, cause and answer (mesh-delivery-cli holds) and answers the standing hold ask with hold-release or hold-keep through its one write; the teller takes a later view answer that changes a hold's option into the answer of that asking, never an older one.
92 lines
3.6 KiB
Go
92 lines
3.6 KiB
Go
package view
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// heldE is the assigner's hold of module at fp, as it writes it in its wants.
|
|
func heldE(t *testing.T, module, fp, node, words string) Entry {
|
|
t.Helper()
|
|
key, err := delivery.HeldKey(module, fp)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
v, err := delivery.EncodeHeld(delivery.Held{Node: node, Words: words})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return Entry{Bucket: delivery.AssignerWantsBucket, Key: key, Value: v, At: t0}
|
|
}
|
|
|
|
func answered(t *testing.T, key, id, option string) Entry {
|
|
t.Helper()
|
|
v, err := delivery.EncodeAnswer(delivery.Answer{Option: option, Warrant: id + "@2026-10-25T04:00:00Z", Words: "the operator, via telegram, chose " + option})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return Entry{Bucket: delivery.AnswersBucket, Key: key, Value: v, At: t0}
|
|
}
|
|
|
|
// 1906/N23-AC1: given holds in the assigner's wants, the view lists each with its node, its cause in words, its hold ask and
|
|
// the answer that stands for that asking; a hold without an ask says so, and a held key is never taken for a want.
|
|
func TestTheViewListsEveryHoldWithItsNodeCauseAndAnswer(t *testing.T) {
|
|
m := New()
|
|
e, a := holdAsk(t)
|
|
fill(m, e, heldE(t, "plex", fpNew, "ace", "health failed, phase running: connection refused"), answered(t, e.Key, a.ID, "keep"),
|
|
heldE(t, "web", fpNew, "g14", "health failed"))
|
|
got := m.Holds()
|
|
if len(got) != 2 {
|
|
t.Fatalf("holds = %+v", got)
|
|
}
|
|
p := got[0]
|
|
if p.Module != "plex" || p.FP != fpNew || p.Node != "ace" || !strings.Contains(p.Words, "connection refused") || p.AskKey != e.Key || p.Asking != a.ID || p.Answer != "keep" {
|
|
t.Errorf("plex = %+v", p)
|
|
}
|
|
if w := got[1]; w.Module != "web" || w.Node != "g14" || w.AskKey != "" || w.Answer != "" {
|
|
t.Errorf("web = %+v", w)
|
|
}
|
|
if len(m.Snapshot().Wants) != 0 {
|
|
t.Errorf("a hold was taken for a want: %+v", m.Snapshot().Wants)
|
|
}
|
|
}
|
|
|
|
// 1906/N23-AC2: given a hold ask answered "keep" (the ask ended with it), when the operator releases the hold, then the view
|
|
// writes its answer "release" to that asking under the ask's view key, though the ask was answered; the fingerprint may be the
|
|
// start of its hex. The same answer again, an unknown hold and another option are refused, and write nothing.
|
|
func TestAKeptHoldCanBeReleased(t *testing.T) {
|
|
m, w := New(), &memWriter{}
|
|
m.SetWriter(w)
|
|
e, a := holdAsk(t)
|
|
fill(m, e, heldE(t, "plex", fpNew, "ace", "health failed"), answered(t, e.Key, a.ID, "keep"))
|
|
short := strings.TrimPrefix(fpNew, delivery.SourcePrefix2)[:8]
|
|
if _, err := m.AnswerHold("plex", short, HoldRelease, "it was a flake"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
va, err := delivery.DecodeViewAnswer(w.puts[e.Key+".view"])
|
|
if err != nil || va.Asking != a.ID || va.Option != HoldRelease || va.Words != "it was a flake" {
|
|
t.Fatalf("the view's answer = %+v, %v", va, err)
|
|
}
|
|
w.puts = nil
|
|
fill(m, answered(t, e.Key, a.ID, HoldRelease))
|
|
for name, try := range map[string]func() error{
|
|
"again": func() error { _, err := m.AnswerHold("plex", fpNew, HoldRelease, ""); return err },
|
|
"unknown": func() error { _, err := m.AnswerHold("plex", "ffff", HoldKeep, ""); return err },
|
|
"option": func() error { _, err := m.AnswerHold("plex", fpNew, "restore", ""); return err },
|
|
"module": func() error { _, err := m.AnswerHold("web", fpNew, HoldKeep, ""); return err },
|
|
} {
|
|
if err := try(); err == nil {
|
|
t.Errorf("%s: not refused", name)
|
|
}
|
|
}
|
|
if len(w.puts) != 0 {
|
|
t.Errorf("a refused answer wrote %v", w.puts)
|
|
}
|
|
// And kept again: the operator may change their mind both ways.
|
|
if _, err := m.AnswerHold("plex", fpNew, HoldKeep, ""); err != nil {
|
|
t.Errorf("keep after release: %v", err)
|
|
}
|
|
}
|