mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
test+refactor: real sidecar test, deterministic test sleeps, slog step line (#22)
* test(sidecar): replace assertTrue(true) placeholder with real server test
MainTest.mainExists() always passed and inflated the green-check count.
DriverServiceTest covers RPCs, but SidecarServer start/stop had no
coverage. Drop the placeholder and add SidecarServerTest that binds to
port 0, asserts a real ephemeral port, and stops cleanly.
* test(agent): drop 50ms sleep before cancel in TestServer_AcceptCancelsOnContext
Accept's closeListenerOnCancel watcher closes the listener as soon as
ctx fires, regardless of whether the outer Accept has reached
listener.Accept() yet. The sleep was a CI-flake surface (50ms is not
enough on a slow runner), and dropping it still exercises the same
outcome — Accept returns with ctx.Err() after cancellation.
Stable across 50x -count runs.
* test(agent): replace 2s sleep with done-chan in TestConn_SnapshotTimesOutIfSDKSilent
The silent-SDK fake held the connection open via time.Sleep(2s), which
coupled the test's wall clock to the server's 200ms snapshot-timeout
assertion. Swap for a done channel closed by t.Cleanup — the goroutine
exits when the test ends, independent of timing.
* test(maestro): make WaitForHealth_PollsUntilReady deterministic
Replace the 50ms wall-clock sleep that flipped healthReady with a
healthReadyAfterCall counter in the fake server. The handler returns
ready=true once healthCalls reaches the threshold, so the test's
"at least 2 polls before ready" assertion is satisfied by call
count rather than a race between the flip goroutine and the 25ms
poll loop.
* refactor(runner): route per-step progress through slog instead of fmt.Printf
The runner already carries a *slog.Logger for warnings (logger.Warn on
decode failures, predicate errors). The per-step status line was the
outlier — a bare fmt.Printf that wrote to os.Stdout unconditionally,
bypassing both the injected logger and any caller-configured writer.
Switch it to logger.Info("step", "index", ..., "screen", ..., "nodes", ...).
The caller (cmd/uatu) is responsible for wiring a logger whose handler
renders to the right stream; the next commit adds that wiring.
* feat(cli): render runner progress via a thin slog handler on stdout
progressHandler writes Info records as "msg key=value ..." and prefixes
warnings/errors with their level, matching the prose style of the
surrounding CLI status prints. Wired into the runner via
runner.Options.Logger so the per-step status line still lands on stdout
without slog's default time= / level= framing.
This commit is contained in:
7 files changed
+88
-26
No files matched your search
@@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// newProgressLogger wires a slog.Logger that prints user-facing progress
|
||||
// lines to the CLI's stdout stream. Info messages render as
|
||||
// "msg key=value ..." to match the prose style of other CLI prints;
|
||||
// warnings and errors get a "warn:" / "error:" prefix so they stand
|
||||
// out in the same stream.
|
||||
func newProgressLogger(writer io.Writer) *slog.Logger {
|
||||
return slog.New(&progressHandler{writer: writer, level: slog.LevelInfo})
|
||||
}
|
||||
|
||||
type progressHandler struct {
|
||||
writer io.Writer
|
||||
level slog.Level
|
||||
}
|
||||
|
||||
func (h *progressHandler) Enabled(_ context.Context, level slog.Level) bool {
|
||||
return level >= h.level
|
||||
}
|
||||
|
||||
func (h *progressHandler) Handle(_ context.Context, record slog.Record) error {
|
||||
var builder strings.Builder
|
||||
if record.Level >= slog.LevelWarn {
|
||||
fmt.Fprintf(&builder, "%s: ", strings.ToLower(record.Level.String()))
|
||||
}
|
||||
builder.WriteString(record.Message)
|
||||
record.Attrs(func(attr slog.Attr) bool {
|
||||
fmt.Fprintf(&builder, " %s=%s", attr.Key, formatAttrValue(attr.Value))
|
||||
return true
|
||||
})
|
||||
builder.WriteByte('\n')
|
||||
_, err := io.WriteString(h.writer, builder.String())
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *progressHandler) WithAttrs(_ []slog.Attr) slog.Handler { return h }
|
||||
func (h *progressHandler) WithGroup(_ string) slog.Handler { return h }
|
||||
|
||||
func formatAttrValue(value slog.Value) string {
|
||||
if value.Kind() == slog.KindString {
|
||||
return fmt.Sprintf("%q", value.String())
|
||||
}
|
||||
return value.String()
|
||||
}
|
||||
@@ -181,6 +181,7 @@ func runTestPipeline(ctx context.Context, options testOptions, stdout io.Writer)
|
||||
Driver: driverClient,
|
||||
Verifier: verifierInstance,
|
||||
TraceWriter: traceWriter,
|
||||
Logger: newProgressLogger(stdout),
|
||||
})
|
||||
|
||||
terminateCtx, terminateCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
|
||||
Reference in new issue
Block a user