package main import ( "encoding/json" "strings" "testing" ) // **One machine's failure must never take the answer away from a reader asking about the others.** // // A blocked machine is not on the private network, and a mesh whose hub is that machine has no hub // — which came back through the reading as a refusal, so `status` printed nothing at all and // `status --json` emitted multi-line prose on stderr and not one byte of JSON. A machine-readable // interface that stops being machine-readable exactly when something is wrong is one nobody can // build an alarm on. func TestOneBlockedMachineDoesNotDestroyTheWholeDocument(t *testing.T) { open := aMesh(t) ctx := t.Context() // Break the hub, using nothing but the command a person has. one, two := rivals() register(t, open, one) register(t, open, two) for _, m := range []string{"rival-one", "rival-two"} { if _, err := assign(ctx, open, "anchor", m); err != nil && m == "rival-one" { t.Fatal(err) } } asked, err := theThreeQuestions(ctx, open) if err != nil { t.Fatalf("one blocked machine made the whole mesh unreadable: %v", err) } body, err := statusAsJSON(asked) if err != nil { t.Fatal(err) } var parsed map[string]any if err := json.Unmarshal(body, &parsed); err != nil { t.Fatalf("what a script would read is not JSON: %v\n%s", err, body) } // The failure is in the document, as data, on the machine it belongs to. unresolved, _ := parsed["unresolved"].([]any) if len(unresolved) == 0 { t.Fatalf("a machine that cannot be worked out is absent from the document:\n%s", body) } var found bool for _, row := range unresolved { entry, _ := row.(map[string]any) if entry["node"] != "anchor" { continue } found = true problem, _ := entry["problem"].(string) if !strings.Contains(problem, "the-seat") { t.Errorf("the machine's problem is not its own words: %q", problem) } } if !found { t.Fatalf("the blocked machine is not the one named:\n%s", body) } // And the mesh is still counted, so a reader can tell "none blocked" from "none at all". if parsed["machines"] != float64(2) { t.Errorf("the rest of the document did not survive: %v", parsed["machines"]) } } // A well mesh carries the field as an empty list, not as nothing: a reader distinguishing "none // blocked" from "this field is missing" would have to handle both, and null is the one that gets // forgotten. func TestAWellMeshCarriesAnEmptyUnresolvedList(t *testing.T) { open := aMesh(t) asked, err := theThreeQuestions(t.Context(), open) if err != nil { t.Fatal(err) } body, err := statusAsJSON(asked) if err != nil { t.Fatal(err) } var parsed map[string]any if err := json.Unmarshal(body, &parsed); err != nil { t.Fatal(err) } list, ok := parsed["unresolved"].([]any) if !ok { t.Fatalf("\"unresolved\" is %T, not a list:\n%s", parsed["unresolved"], body) } if len(list) != 0 { t.Fatalf("a well mesh reports blocked machines: %v", list) } if _, said := parsed["network"]; said { t.Errorf("a well mesh says the network could not be computed: %v", parsed["network"]) } } // And the page says it too, from the same reading. A board that renders "all well" over a mesh // where nothing can be sent anywhere is worse than a board that is down. func TestThePageSaysWhichMachinesCannotBeWorkedOut(t *testing.T) { open := aMesh(t) ctx := t.Context() one, two := rivals() register(t, open, one) register(t, open, two) for _, m := range []string{"rival-one", "rival-two"} { if _, err := assign(ctx, open, "anchor", m); err != nil && m == "rival-one" { t.Fatal(err) } } asked, err := theThreeQuestions(ctx, open) if err != nil { t.Fatal(err) } rendered := render(t, viewOf(asked)) for _, want := range []string{"Can everything be worked out?", "anchor", "the-seat"} { if !strings.Contains(rendered, want) { t.Fatalf("the page does not say %q:\n%s", want, rendered) } } }