A push outlasted the console's 30s wait and, when it sent the bus its changed user list, the broker's reload forgot the reply it may send: the push happened and its caller was told it did not answer. Calls now answer in full or as running with an id, a push answers before it sends, refused answers are recorded on their call, and 'calls' reads them back.
82 lines
3.0 KiB
Go
82 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
"github.com/novox/mesh-controller/internal/link"
|
|
)
|
|
|
|
// consoleWaits is how long the console waits for an answer (mesh-tools node-tools/internal/bus
|
|
// RequestTimeout) — the shortest wait of a caller the mesh ships.
|
|
const consoleWaits = 30 * time.Second
|
|
|
|
// **A call's one answer is never later than its caller or the bus allow** (novox/hq issue 265): a
|
|
// holder answers within AnswerWithin, which must be inside both the console's wait and the window the
|
|
// bus gives an answer. Before, the console waited 30s, the bus 60s, and a push ran as long as it ran.
|
|
func TestAVerbAnswersInsideEveryWaitOnIt(t *testing.T) {
|
|
if link.AnswerWithin >= consoleWaits/2 {
|
|
t.Errorf("a call answers within %s: not well inside the console's %s", link.AnswerWithin, consoleWaits)
|
|
}
|
|
if link.AnswerWithin >= broker.ResponseTTL {
|
|
t.Errorf("a call answers within %s, after the bus stops permitting an answer at %s", link.AnswerWithin, broker.ResponseTTL)
|
|
}
|
|
}
|
|
|
|
// A push — named or through command — answers before it runs: it sends the machine holding the bus
|
|
// first, and the broker reloading its user list forgets the answer it was about to permit.
|
|
func TestAPushAnswersBeforeItSends(t *testing.T) {
|
|
for _, c := range []struct {
|
|
verb string
|
|
args map[string]any
|
|
want bool
|
|
}{
|
|
{"push", map[string]any{"node": "anchor"}, true},
|
|
{"push", map[string]any{}, true},
|
|
{"command", map[string]any{"command": "push anchor"}, true},
|
|
{"command", map[string]any{"command": "push --behind"}, true},
|
|
{"command", map[string]any{"command": "builds"}, false},
|
|
{"status", map[string]any{}, false},
|
|
{"assign", map[string]any{"node": "anchor", "module": "m"}, false},
|
|
} {
|
|
argv, err := argvFor(c.verb, c.args)
|
|
if err != nil {
|
|
t.Fatalf("%s %v: %v", c.verb, c.args, err)
|
|
}
|
|
if got := answersFirst(argv); got != c.want {
|
|
t.Errorf("%s %v answers first: %v, want %v", c.verb, c.args, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// `calls` is served, takes a call's id and nothing else, and says plainly when it holds no such call.
|
|
func TestCallsIsServedAndSaysWhatItKeeps(t *testing.T) {
|
|
handlers, behind, err := seatToolHandlers()
|
|
if err != nil || len(behind) != 0 {
|
|
t.Fatalf("%v %v", behind, err)
|
|
}
|
|
calls, ok := handlers["calls"]
|
|
if !ok {
|
|
t.Fatal("calls is not served")
|
|
}
|
|
if _, err := calls(context.Background(), json.RawMessage(`{"node":"anchor"}`)); err == nil ||
|
|
!strings.Contains(err.Error(), `"node"`) {
|
|
t.Errorf("calls took an argument it does not declare: %v", err)
|
|
}
|
|
if _, err := calls(context.Background(), json.RawMessage(`{"call":"call-0-0"}`)); err == nil ||
|
|
!strings.Contains(err.Error(), "not across a restart") {
|
|
t.Errorf("an unknown call was not said plainly: %v", err)
|
|
}
|
|
got, err := calls(context.Background(), json.RawMessage(`{}`))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, listed := got.(map[string]any)["calls"]; !listed {
|
|
t.Errorf("calls answered %v", got)
|
|
}
|
|
}
|