Say what rotate printed when the served rotation test fails (issue 1945)
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -434,13 +435,24 @@ func TestServedADoneKeyIsComposedAndGranted(t *testing.T) {
|
||||
func TestServedARotationRewritesOnlyTheCompositionsThatUseIt(t *testing.T) {
|
||||
m := aServedMesh(t)
|
||||
before := map[string]map[string]uint64{"anchor": m.revisions(t, "anchor"), "laptop": m.revisions(t, "laptop")}
|
||||
if err := rotateCommand(t.Context(), []string{"postgres-database"}); err != nil {
|
||||
t.Fatalf("rotate: %v", err)
|
||||
holders, _ := m.open.inventory.HoldersOf(t.Context(), "postgres-database", "")
|
||||
said, err := capturedOutput(func() error { return rotateCommand(t.Context(), []string{"postgres-database"}) })
|
||||
if err != nil {
|
||||
t.Fatalf("rotate: %v\n%s", err, said)
|
||||
}
|
||||
t.Logf("rotate said (holders before: %+v):\n%s", holders, said)
|
||||
defer func() {
|
||||
if t.Failed() {
|
||||
t.Logf("rotate said:\n%s", said)
|
||||
}
|
||||
}()
|
||||
boardKey, _ := sdkdelivery.ComposedKey("laptop", "board", fpOf('b'))
|
||||
storeKey, _ := sdkdelivery.ComposedKey("anchor", "store", fpOf('a'))
|
||||
// The board's sealed credential file is new: its composition moves with the rotation.
|
||||
m.waitFor(t, nil, "laptop", boardKey, before["laptop"][boardKey])
|
||||
if rev := m.waitForOrSay(t, "laptop", boardKey, before["laptop"][boardKey]); rev == 0 {
|
||||
t.Fatalf("the board's composition did not move within a minute after the rotation; rotate said (holders before: %+v):\n%s\n%s",
|
||||
holders, said, m.whatIsThere(t, "laptop"))
|
||||
}
|
||||
moved := map[string]bool{}
|
||||
for node, was := range before {
|
||||
for k, rev := range m.revisions(t, node) {
|
||||
@@ -461,3 +473,46 @@ func TestServedARotationRewritesOnlyTheCompositionsThatUseIt(t *testing.T) {
|
||||
t.Errorf("%d declarations were sent", n)
|
||||
}
|
||||
}
|
||||
|
||||
// waitForOrSay is waitFor that answers 0 instead of failing, for a caller that says more.
|
||||
func (m *servedMesh) waitForOrSay(t *testing.T, node, key string, after uint64) uint64 {
|
||||
t.Helper()
|
||||
bucket, _ := sdkdelivery.ComposedBucketFor(node)
|
||||
deadline := time.Now().Add(time.Minute)
|
||||
for time.Now().Before(deadline) {
|
||||
if kv, err := m.controller.KeyValue(t.Context(), bucket); err == nil {
|
||||
if e, err := kv.Get(t.Context(), key); err == nil && e.Revision() > after {
|
||||
return e.Revision()
|
||||
}
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// capturedOutput runs act with this process's standard output captured, and answers what it printed.
|
||||
func capturedOutput(act func() error) (string, error) {
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
return "", act()
|
||||
}
|
||||
was := os.Stdout
|
||||
os.Stdout = w
|
||||
done := make(chan string)
|
||||
go func() {
|
||||
var b strings.Builder
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
n, err := r.Read(buf)
|
||||
b.Write(buf[:n])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
done <- b.String()
|
||||
}()
|
||||
actErr := act()
|
||||
os.Stdout = was
|
||||
w.Close()
|
||||
return <-done, actErr
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user