| index 73a886c99..7d43c29a8 100644 |
| --- a/internal/hostfiles/relay_test.go |
| +++ b/internal/hostfiles/relay_test.go |
| @@ -1,13 +1,43 @@ |
| package hostfiles |
| |
| import ( |
| + "bytes" |
| "context" |
| "errors" |
| + "log" |
| + "strings" |
| "sync" |
| "testing" |
| "time" |
| ) |
| |
| +// relayLog captures the package's log lines for one test. |
| +type relayLog struct { |
| + mu sync.Mutex |
| + buf bytes.Buffer |
| +} |
| + |
| +func (l *relayLog) Write(p []byte) (int, error) { |
| + l.mu.Lock() |
| + defer l.mu.Unlock() |
| + return l.buf.Write(p) |
| +} |
| + |
| +func (l *relayLog) count(substr string) int { |
| + l.mu.Lock() |
| + defer l.mu.Unlock() |
| + return strings.Count(l.buf.String(), substr) |
| +} |
| + |
| +func captureRelayLog(t *testing.T) *relayLog { |
| + t.Helper() |
| + l := &relayLog{} |
| + prev := log.Writer() |
| + log.SetOutput(l) |
| + t.Cleanup(func() { log.SetOutput(prev) }) |
| + return l |
| +} |
| + |
| type flakyStager struct { |
| mu sync.Mutex |
| fail int |
| @@ -39,8 +69,11 @@ func (f *flakyStager) last() []byte { |
| } |
| |
| // Ruling 22: Publish never waits on the store; Run stages the latest body, |
| -// retrying a failed stage, and stages nothing again once it has. |
| +// retrying a failed stage, and stages nothing again once it has. Two |
| +// failed stages log one "failing" line and the stage that follows one |
| +// "recovered" line: transitions, as run.go logs a scan, not every retry. |
| func TestPlatformRelayStagesTheLatestBodyWithoutBlockingItsCaller(t *testing.T) { |
| + logs := captureRelayLog(t) |
| st := &flakyStager{fail: 2, block: make(chan struct{})} |
| r := &PlatformRelay{Name: "instance-key-adoption.json", Stage: st, Retry: 10 * time.Millisecond} |
| ctx, cancel := context.WithCancel(context.Background()) |
| @@ -69,6 +102,9 @@ func TestPlatformRelayStagesTheLatestBodyWithoutBlockingItsCaller(t *testing.T) |
| if n != 1 { |
| t.Fatalf("staged %d times, want once", n) |
| } |
| + if failing, recovered := logs.count(r.Name+": stage failing"), logs.count(r.Name+": stage recovered"); failing != 1 || recovered != 1 { |
| + t.Fatalf("logged %d failing and %d recovered lines across two failed stages, want one of each", failing, recovered) |
| + } |
| cancel() |
| if err := <-done; !errors.Is(err, context.Canceled) { |
| t.Fatalf("Run = %v", err) |