Take the assigner's ask in the SDK's layout and name the asking in the view's answer, so a stale answer never fills a later asking (issue 1297 B9 and B10)
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/asks"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
)
|
||||
|
||||
@@ -15,11 +12,6 @@ import (
|
||||
// which alone fills an ask's answer, takes it from there as it takes a warrant from the phone: under the ask's own key, once,
|
||||
// by compare-and-set. The merge's ask needs proof (ADR 0421 §1, issue 953) and is never answered from a view key.
|
||||
|
||||
// An ask of the assigner as the teller reads it: the router's ask under "ask". Its other fields are the assigner's.
|
||||
type assignerAsk struct {
|
||||
Ask asks.Ask `json:"ask"`
|
||||
}
|
||||
|
||||
// OnViewAnswer handles a key put in the view's bucket answers. A key that is no view answer key, or is the answer to an ask that
|
||||
// needs proof of who answered, is left and said.
|
||||
func (t *Teller) OnViewAnswer(key string) {
|
||||
@@ -76,13 +68,13 @@ func (t *Teller) fillFromView(askKey string) {
|
||||
t.logf("%s: the view's answer is not readable and fills nothing: %v", viewKey, err)
|
||||
return
|
||||
}
|
||||
var ask assignerAsk
|
||||
if err := json.Unmarshal(rawAsk, &ask); err != nil || ask.Ask.ID == "" {
|
||||
t.logf("%s: the assigner's ask is not readable and takes no answer (%v)", askKey, err)
|
||||
ask, err := delivery.DecodeAssignerAsk(askKey, rawAsk)
|
||||
if err != nil {
|
||||
t.logf("%s: the assigner's ask is not readable and takes no answer: %v", askKey, err)
|
||||
return
|
||||
}
|
||||
if !slices.ContainsFunc(ask.Ask.Options, func(o asks.Option) bool { return o.ID == va.Option }) {
|
||||
t.logf("%s: the view answered %q and the ask offers no option %q: nothing is written", askKey, va.Option, va.Option)
|
||||
if err := delivery.ViewAnswerFits(va, ask); err != nil {
|
||||
t.logf("%s: nothing is written: %v", askKey, err)
|
||||
return
|
||||
}
|
||||
akey := delivery.AnswerKey(askKey)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -22,16 +21,21 @@ func holdAsk(t *testing.T) (key string, value []byte, ask asks.Ask) {
|
||||
ask = asks.Ask{ID: delivery.AskID(key), Headline: "plex is held after a failed health check", Explanation: "ace failed the check.", Who: asks.Operator,
|
||||
Expires: now.Add(asks.ApproveLasts), OnExpiry: "the fingerprint stays held",
|
||||
Options: []asks.Option{{ID: "release", Label: "Release", Does: "lets the move go on", Level: asks.Approve}, {ID: "keep", Label: "Keep held", Does: "keeps it held", Level: asks.Approve}}}
|
||||
value, err = json.Marshal(map[string]any{"v": 1, "ask": ask})
|
||||
value, err = delivery.EncodeAssignerAsk(key, delivery.AssignerAsk{Ask: ask})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return key, value, ask
|
||||
}
|
||||
|
||||
func holdKey() string {
|
||||
k, _ := delivery.HoldAskKey("plex", fpHeld)
|
||||
return k
|
||||
}
|
||||
|
||||
func viewAnswer(t *testing.T, option, words string) []byte {
|
||||
t.Helper()
|
||||
v, err := delivery.EncodeViewAnswer(delivery.ViewAnswer{Option: option, Words: words})
|
||||
v, err := delivery.EncodeViewAnswer(delivery.ViewAnswer{Asking: delivery.AskID(holdKey()), Option: option, Words: words})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -108,7 +112,7 @@ func TestAViewAnswerOfAnOptionTheAskDoesNotOfferFillsNothing(t *testing.T) { //
|
||||
assigner[key] = value
|
||||
view[key+".view"] = viewAnswer(t, "delete", "")
|
||||
b.t.OnViewAnswer(key + ".view")
|
||||
if b.answers.writes != 0 || !strings.Contains(b.logs.String(), `offers no option "delete"`) {
|
||||
if b.answers.writes != 0 || !strings.Contains(b.logs.String(), `chose "delete"`) {
|
||||
t.Errorf("writes %d, log:\n%s", b.answers.writes, b.logs.String())
|
||||
}
|
||||
}
|
||||
@@ -153,3 +157,20 @@ func TestAnUnreadableViewAnswerOrAskFillsNothing(t *testing.T) { // 1297/B10
|
||||
t.Errorf("filled from something unreadable; log:\n%s", b.logs.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAStaleViewAnswerOfAnotherAskingFillsNothing(t *testing.T) { // 1297/B10 (stale answer)
|
||||
b := newBed(t)
|
||||
assigner, view := withView(b)
|
||||
key, value, _ := holdAsk(t)
|
||||
assigner[key] = value
|
||||
stale, err := delivery.EncodeViewAnswer(delivery.ViewAnswer{Asking: "an-earlier-asking", Option: "release"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
view[key+".view"] = stale
|
||||
b.t.OnViewAnswer(key + ".view")
|
||||
b.t.OnAssignerAsk(key)
|
||||
if b.answers.writes != 0 || !strings.Contains(b.logs.String(), "an-earlier-asking") {
|
||||
t.Errorf("writes %d; log:\n%s", b.answers.writes, b.logs.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ module mesh-delivery-teller
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023151240-d9384bcb239a
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023132058-f625d98713e4
|
||||
github.com/nats-io/nats-server/v2 v2.11.17
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user