A VPN client rewrote the laptop's resolver file and every mesh name failed while each module read healthy: nothing asked the machine. The engine now looks every 30 s at the resolver file the uplink holder declared (naming the program that rewrote it), the names through each listed resolver (NXDOMAIN for a mesh name's IPv6 address is a finding, issue 262), the tunnel's handshake with the hub, the bus and the default route; a part is unhealthy on its second failing look, and the statement carries it.
55 lines
2.3 KiB
Go
55 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/novox/mesh-host/internal/declaration"
|
|
"github.com/novox/mesh-host/internal/liveness"
|
|
"github.com/novox/mesh-host/internal/network"
|
|
)
|
|
|
|
// The machine's networking in the engine's statement (novox/hq ADR 0241): the file judged is the one the
|
|
// uplink holder declares whole, the mesh name asked is the bus's, and the statement carries the parts.
|
|
|
|
func TestTheResolverFileJudgedIsTheOneAModuleDeclaresWhole(t *testing.T) {
|
|
d := &declaration.Declaration{Resources: []declaration.Resource{
|
|
&declaration.File{ID: "hosts.file", Type: "file", Path: "/etc/hosts", Content: "x"},
|
|
&declaration.File{ID: "networkmanager.resolv", Type: "file", Path: network.ResolvConf, Content: "nameserver 10.10.0.1\n"},
|
|
}}
|
|
content, owner, ok := declaredResolvConf(d)
|
|
if !ok || owner != "networkmanager" || content != "nameserver 10.10.0.1\n" {
|
|
t.Fatalf("got %q %q %v", content, owner, ok)
|
|
}
|
|
d.Resources[1].(*declaration.File).CreateOnce = true
|
|
if _, _, ok := declaredResolvConf(d); ok {
|
|
t.Fatal("a seed nobody holds the machine to was judged as the declared file")
|
|
}
|
|
if _, _, ok := declaredResolvConf(nil); ok {
|
|
t.Fatal("no declaration declared a file")
|
|
}
|
|
}
|
|
|
|
func TestTheMeshNameAskedIsTheBuses(t *testing.T) {
|
|
for broker, want := range map[string]string{"anchor.internal:4222": "anchor.internal", "192.0.2.10:5671": "",
|
|
"anchor.internal": "anchor.internal", "[2001:db8::1]:4222": ""} {
|
|
if got := hostOf(broker); got != want {
|
|
t.Errorf("%s: got %q, want %q", broker, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTheStatementCarriesTheNetwork(t *testing.T) {
|
|
at := time.Date(2026, 10, 7, 12, 0, 0, 0, time.UTC)
|
|
h := healthAsReported(liveness.Statement{At: at}, &network.Statement{State: network.Unhealthy, Since: at,
|
|
Parts: []network.Part{{Part: network.PartResolvConf, State: network.Unhealthy, Writer: "FortiClient",
|
|
Owner: "networkmanager", Reason: "the resolver file was rewritten by another program", Since: at}}})
|
|
if h.Network == nil || h.Network.State != network.Unhealthy || len(h.Network.Parts) != 1 ||
|
|
h.Network.Parts[0].Writer != "FortiClient" || h.Network.Parts[0].Owner != "networkmanager" {
|
|
t.Fatalf("the statement says %+v", h.Network)
|
|
}
|
|
if h := healthAsReported(liveness.Statement{At: at}, nil); h.Network != nil {
|
|
t.Fatal("an engine with no network judge said a network")
|
|
}
|
|
}
|