node public-domain: asking what it is no longer takes it away
`node public-domain <name>` cleared the domain. It reads like a question — it is exactly what anybody types to find out what the answer is — and it silently took every routed name the node had. There is no output that makes up for that: by the time it prints, the fact is gone, and the mesh cannot tell a person what a domain used to be. The bare form reports now. Clearing is still a real thing to want — a machine that stops facing the outside composes no names, and lab-versus-production is this one setting (novox/hq ADR 0056) — so it keeps a way to be said, by name: `--clear`. A domain and `--clear` together are refused rather than one of them silently winning. The other `node` subcommands were checked. `add`, `list` and `show` write nothing they were not asked to, so there is nothing to make consistent with. `overlay place <node>` with no flags has the same shape — it clears the endpoint, the site and the hub flag — and is deliberately left alone here. It is a verb rather than a question and every caller passes flags, so the fix is a different judgement and belongs in its own change. The usage text gains the three forms, and `module forget`'s new flag, neither of which it named before. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// **A read-shaped invocation is never a destructive write.**
|
||||
//
|
||||
// `node public-domain anchor` used to clear the domain. It reads like a question — it is what
|
||||
// anybody types to find out what the answer is — and it silently took every routed name the node
|
||||
// had. There is no output that makes up for that: by the time it prints, the fact is gone.
|
||||
func TestAskingForANodesPublicDomainDoesNotTakeItAway(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
if err := open.inventory.SetPublicDomain(ctx, "anchor", "example.test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := publicDomain(ctx, open.inventory, []string{"anchor"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
domain, err := open.inventory.PublicDomainOf(ctx, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if domain != "example.test" {
|
||||
t.Fatalf("asking what the domain is took it away: %q", domain)
|
||||
}
|
||||
}
|
||||
|
||||
// Clearing is a real thing to want — a machine that stops facing the outside composes no names —
|
||||
// so it keeps a way to be said. What it stops being is what happens when nothing was said.
|
||||
func TestClearingANodesPublicDomainIsAskedForByName(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
if err := open.inventory.SetPublicDomain(ctx, "anchor", "example.test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := publicDomain(ctx, open.inventory, []string{"anchor", "--clear"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
domain, err := open.inventory.PublicDomainOf(ctx, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if domain != "" {
|
||||
t.Fatalf("--clear did not clear it: %q", domain)
|
||||
}
|
||||
}
|
||||
|
||||
// A domain sets it, as it always did.
|
||||
func TestGivingANodeAPublicDomainSetsIt(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
if err := publicDomain(ctx, open.inventory, []string{"anchor", "example.test"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
domain, err := open.inventory.PublicDomainOf(ctx, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if domain != "example.test" {
|
||||
t.Fatalf("got %q", domain)
|
||||
}
|
||||
}
|
||||
|
||||
// A domain and --clear say opposite things. Refused rather than one of them silently winning.
|
||||
func TestADomainAndClearTogetherIsRefused(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
if err := open.inventory.SetPublicDomain(ctx, "anchor", "example.test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := publicDomain(ctx, open.inventory, []string{"anchor", "other.test", "--clear"})
|
||||
if err == nil {
|
||||
t.Fatal("a domain and --clear together were accepted")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "not both") {
|
||||
t.Fatalf("the refusal does not say why: %v", err)
|
||||
}
|
||||
// And neither half happened.
|
||||
domain, err := open.inventory.PublicDomainOf(ctx, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if domain != "example.test" {
|
||||
t.Fatalf("a refused command changed something: %q", domain)
|
||||
}
|
||||
}
|
||||
|
||||
// Asking about a name the mesh has never heard of is a refusal, not "it has no public domain" —
|
||||
// which is true of that name and says nothing.
|
||||
func TestAskingAboutAMachineTheMeshHasNeverHeardOfIsRefused(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
if err := publicDomain(t.Context(), open.inventory, []string{"nowhere"}); err == nil {
|
||||
t.Fatal("a name the mesh does not know was answered as if it were a machine")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user