Files
mesh-catalog/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/operator_test.go
T

114 lines
3.0 KiB
Go

package main
import (
"fmt"
"sync"
"time"
"git.novox.be/novox/mesh-sdk/go/asks"
sdk "git.novox.be/novox/mesh-sdk/go/delivery"
)
// fakeOperator is the gate's bucket asks and the teller behind it: it keeps the asks written, and answers as the test says
// (the teller's answer under the ask's key). In auto mode it approves every ask the moment it is read (the tests of other
// behaviour, which are not about the Approve). An ask is known here by its key (mesh-sdk go/delivery MergeAskKey), as the
// delivery keeps it.
type fakeOperator struct {
mu sync.Mutex
now func() time.Time
auto bool
asked []asks.Ask
byKey map[string]sdk.Ask
order []string
seen map[string]bool
cancelled []string
state map[string]string
answers map[string]*sdk.Answer
refuse error
}
func newFakeOperator(now func() time.Time) *fakeOperator {
return &fakeOperator{now: now, byKey: map[string]sdk.Ask{}, seen: map[string]bool{}, state: map[string]string{}, answers: map[string]*sdk.Answer{}}
}
func (o *fakeOperator) Ask(key string, a sdk.Ask) error {
o.mu.Lock()
defer o.mu.Unlock()
if o.refuse != nil {
return o.refuse
}
if err := a.Ask.Check(o.now()); err != nil {
return err
}
if _, err := sdk.EncodeAsk(a); err != nil {
return err
}
if o.state[key] == "open" && sdk.SameAsk(o.byKey[key], a) {
return nil // the same ask is there, as kvOperator leaves it
}
o.asked = append(o.asked, a.Ask)
o.byKey[key] = a
if _, known := o.seen[key]; !known {
o.order = append(o.order, key)
o.seen[key] = true
}
o.state[key] = "open"
delete(o.answers, key)
return nil
}
func (o *fakeOperator) Cancel(key string) error {
o.mu.Lock()
defer o.mu.Unlock()
o.cancelled = append(o.cancelled, key)
o.state[key] = "cancelled"
return nil
}
func (o *fakeOperator) Where(key string) (*sdk.Answer, error) {
o.mu.Lock()
defer o.mu.Unlock()
if o.auto && o.state[key] == "open" {
o.answerLocked(key, OptionApprove)
}
return o.answers[key], nil
}
// ask is the router's ask at a key, as the gate composed it.
func (o *fakeOperator) ask(key string) asks.Ask {
if a, ok := o.byKey[key]; ok {
return a.Ask
}
panic("no ask " + key)
}
func (o *fakeOperator) answerLocked(key, option string) {
a := o.ask(key)
opt, _ := a.Option(option)
o.state[key] = "answered"
o.answers[key] = &sdk.Answer{Option: option, Warrant: fmt.Sprintf("%s@%s", a.ID, o.now().UTC().Format(time.RFC3339)),
Words: "the operator, via telegram, chose " + opt.Label}
}
// answer is the operator's choice, proven to the teller by the router and written by it.
func (o *fakeOperator) answer(key, option string) {
o.mu.Lock()
defer o.mu.Unlock()
o.answerLocked(key, option)
}
// open is the keys of the asks waiting for an answer, in the order asked.
func (o *fakeOperator) open() []string {
o.mu.Lock()
defer o.mu.Unlock()
var out []string
for _, k := range o.order {
if o.state[k] == "open" {
out = append(out, k)
}
}
return out
}
func (o *fakeOperator) count() int { o.mu.Lock(); defer o.mu.Unlock(); return len(o.asked) }