//go:build integration package main import ( "bytes" "context" "strings" "testing" "git.novox.be/novox/mesh-sdk/go/compose" ) func TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer(t *testing.T) { open := aMesh(t) ctx := t.Context() twoRivalsAndANote(t, open) // Straight into the store, as a node that came to this before the act. for _, m := range []string{"rival-one", "rival-two", "notes"} { if _, err := open.inventory.Assign(ctx, "laptop", m); err != nil { t.Fatal(err) } } said := answered(t, func() error { return assignCommand(ctx, "unassign", []string{"laptop", "notes"}) }) if _, _, err := resolveNode(ctx, open, "laptop"); err == nil || !unresolvable(err) { t.Fatalf("laptop resolves with two claimants of one seat: %v", err) } if n := strings.Count(said, "laptop does not resolve now"); n != 1 { t.Errorf("the answer says laptop does not resolve %d times, want once:\n%s", n, said) } if strings.Contains(said, "is left out of the rest of the mesh") { t.Errorf("the answer carries a line from a read that is not its resolution:\n%s", said) } } func TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt(t *testing.T) { open := aMesh(t) ctx := t.Context() aProviderAndItsConsumer(t, open) if _, err := assign(ctx, open, "laptop", "db", "app"); err != nil { t.Fatal(err) } said, err := unassign(ctx, open, "laptop", "app") if err != nil { t.Fatal(err) } if _, _, err := resolveNode(ctx, open, "laptop"); err != nil { t.Fatal(err) } if strings.Contains(said, "does not resolve") || strings.Contains(said, "could not be read") { t.Errorf("a node that resolves is said not to:\n%s", said) } } func TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal(t *testing.T) { open := aMesh(t) ctx := t.Context() twoRivalsAndANote(t, open) if _, err := assign(ctx, open, "laptop", "rival-one"); err != nil { t.Fatal(err) } // Kept and not resolvable: a second claimant of the seat, which assignment keeps. said, err := assign(ctx, open, "laptop", "rival-two") if err == nil { t.Fatalf("two claimants of one node seat resolved:\n%s", said) } _, _, planErr := resolveNode(ctx, open, "laptop") if planErr == nil || planErr.Error() != err.Error() { t.Errorf("the act's refusal is not the plan's right after:\nact: %v\nplan: %v", err, planErr) } if strings.Contains(said, "now has") { t.Errorf("the answer says a seat is now held on a node that does not resolve:\n%s", said) } } // The other readers of the whole mesh still say a machine they leave out, on standard error (novox/hq // issue 188); an act sends it elsewhere. The line is mesh-sdk's (compose.Declared.Said); where it goes is the context's. func TestAMachineLeftOutIsSaidWhereTheContextSays(t *testing.T) { line := "laptop is left out of the rest of the mesh: it does not resolve: why" var buf bytes.Buffer sayFound(leftOutSaidBy(context.Background(), &buf), compose.Declared{Said: []string{line}}) if buf.String() != line+"\n" { t.Errorf("said %q", buf.String()) } got := answered(t, func() error { sayFound(context.Background(), compose.Declared{Said: []string{line}}) return nil }) if !strings.Contains(got, "laptop is left out") { t.Errorf("without an act's writer the line did not reach standard error: %q", got) } }