mesh/merge-gate head 19e3eac74658 merged into trunk 89cfa9431d8f — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
mesh/repo-check head 19e3eac74658 merged into trunk 89cfa9431d8f — pass: its merge-check.sh passed
mesh/delivery delivered
83 lines
2.5 KiB
Go
83 lines
2.5 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
sdkdelivery "git.novox.be/novox/mesh-sdk/go/delivery"
|
|
"github.com/nats-io/nats.go/jetstream"
|
|
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
"github.com/novox/mesh-controller/internal/inventory"
|
|
"github.com/novox/mesh-controller/internal/testbus"
|
|
)
|
|
|
|
// 1183/AC5: with the watchman's presence bucket holding a node online and no alive message ever sent, the node reads here
|
|
// in `nodes` four minutes later by the controller's clock, however old its last report; and an alive message still sent
|
|
// by a node-engine is published to the same bus without error and changes nothing.
|
|
func TestAnOnlineNodeReadsHereWithNoAliveMessage(t *testing.T) { // 1183/AC5
|
|
js, err := broker.Dial(testbus.URL(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(js.Close)
|
|
if _, err := broker.RaiseBuckets(js, []broker.Bucket{
|
|
{Module: sdkdelivery.WatchmanModule, Name: "presence", History: sdkdelivery.PresenceHistory},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
api, err := jetstream.New(js.Conn())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
kv, err := api.KeyValue(ctx, sdkdelivery.PresenceBucket)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
put := func(node string, online bool) {
|
|
t.Helper()
|
|
key, err := sdkdelivery.PresenceNodeKey(node)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body, err := sdkdelivery.EncodePresence(sdkdelivery.Presence{Online: online})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := kv.Put(ctx, key, body); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
put("ace", true)
|
|
put("laptop", false)
|
|
// A node-engine still sending its alive message: harmless.
|
|
if err := js.Conn().Publish("mesh.control.ace.alive", []byte(`{"node":"ace"}`)); err != nil {
|
|
t.Fatalf("an alive message could not be published: %v", err)
|
|
}
|
|
if err := js.Conn().Flush(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
later := time.Now().Add(4 * time.Minute)
|
|
nodes := []inventory.Node{{Name: "ace", LastSeen: time.Now().Add(-time.Hour)},
|
|
{Name: "laptop", LastSeen: time.Now().Add(-time.Hour)}}
|
|
read := func(ctx context.Context, names []string) (map[string]presenceEntry, error) {
|
|
return readPresence(ctx, js.Conn(), names)
|
|
}
|
|
heard, err := nodesHeard(ctx, nodes, read, later)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := heardFromAt(heard[0], later); got != "here" {
|
|
t.Fatalf("a node online by presence reads %q four minutes later", got)
|
|
}
|
|
if got := heardFromAt(heard[1], later); got == "here" {
|
|
t.Fatalf("a node offline by presence reads %q", got)
|
|
}
|
|
}
|