Hold that a joining machine is a peer of the hub only while its token lives
mesh/delivery delivered
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery-group group feat/a-machine-joins-through-the-tunnel delivered: every member is delivered
mesh/delivery delivered
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery-group group feat/a-machine-joins-through-the-tunnel delivered: every member is delivered
The rows of novox/hq ADR 0169's table the controller answers for: the hub's composed tunnel carries a machine whose live token was issued for its key, drops it when the token expires unused, and nothing is recorded for something that is not a tunnel key.
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
)
|
||||
|
||||
// aMachineJoining is a machine with a live token issued for a tunnel key, given its address — what
|
||||
// `token issue --overlay-key` records before it pushes the hub (novox/hq ADR 0169).
|
||||
func aMachineJoining(t *testing.T, ctx context.Context, inv *inventory.Inventory, name string,
|
||||
validFor time.Duration) string {
|
||||
t.Helper()
|
||||
record, err := inv.AddNode(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := inv.IssueToken(ctx, name, validFor); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
key := aPublicKey(t)
|
||||
if err := inv.RecordOverlayKey(ctx, record.ID, key); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := inv.BindTokenToKey(ctx, record.ID, key); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cidr, err := overlayRange(ctx, inv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := inv.AssignAddress(ctx, record.ID, cidr); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
// hubPeers are the keys the hub's composed tunnel carries.
|
||||
func hubPeers(t *testing.T, ctx context.Context, inv *inventory.Inventory) map[string]bool {
|
||||
t.Helper()
|
||||
g, err := network(ctx, inv, map[string]bool{"anchor": true, "laptop": true}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out := map[string]bool{}
|
||||
for _, p := range g.Graph()["anchor"] {
|
||||
out[p.Key] = true
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// **A machine joining is a peer of the hub while its token can be used, and not after** (novox/hq
|
||||
// ADR 0169): the hub's composed tunnel carries a machine whose token was issued for its key, so the
|
||||
// tunnel answers the first time it knocks; a token that expired unused takes the peer with it at the
|
||||
// hub's next composition.
|
||||
func TestAMachineJoiningIsAPeerOfTheHubUntilItsTokenExpires(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
inv := open.inventory
|
||||
|
||||
joining := aMachineJoining(t, ctx, inv, "joiner", time.Hour)
|
||||
expired := aMachineJoining(t, ctx, inv, "late", 2*time.Second)
|
||||
time.Sleep(2100 * time.Millisecond)
|
||||
|
||||
peers := hubPeers(t, ctx, inv)
|
||||
if !peers[joining] {
|
||||
t.Fatalf("the hub does not carry the machine its live token was issued for: %v", peers)
|
||||
}
|
||||
if peers[expired] {
|
||||
t.Fatalf("the hub still carries a machine whose token expired unused: %v", peers)
|
||||
}
|
||||
|
||||
// A token issued without a key gives the hub nothing to carry: there is no key to carry.
|
||||
if _, err := inv.AddNode(ctx, "keyless"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := inv.IssueToken(ctx, "keyless", time.Hour); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if after := hubPeers(t, ctx, inv); len(after) != len(peers) {
|
||||
t.Fatalf("a token issued without a key changed the hub's peers: %v, was %v", after, peers)
|
||||
}
|
||||
}
|
||||
|
||||
// **A tunnel key that is not one is refused before anything is recorded** (novox/hq ADR 0169): a
|
||||
// token issued for it would be a tunnel the hub could never answer.
|
||||
func TestATokenIsNotIssuedForSomethingThatIsNotATunnelKey(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
record, err := open.inventory.AddNode(ctx, "joiner")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := throughTheTunnel(ctx, open, record, "not-a-key", "10.77.0.1:4222"); err == nil {
|
||||
t.Fatal("a token was issued for something that is not a tunnel key")
|
||||
}
|
||||
if held := placementOf(t, ctx, open.inventory, "joiner"); held.Key != "" || held.Address != "" {
|
||||
t.Fatalf("a refused key left a record behind: %+v", held)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user