mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
fix(runner,sample-app): surface silent errors and demo a failing property (#15)
* fix(runner): surface non-deadline WaitForIdle errors Previously the WaitForIdle return value was discarded entirely, hiding real driver failures (gRPC transport errors, sidecar crashes) behind the expected deadline-exceeded case. Log non-deadline errors so they are visible without changing control flow. * chore(sample-app): drop unused uptime_millis extractor Registered in SampleApplication but never consumed by spec.ts. * fix(sample-app): drop trivial appIsRunning property app_state was hardcoded to 'running' so the property was a tautology that could never fail. Removing both the extractor and the property is the simplest fix; demo-grade properties that can fail land next. * feat(sample-app): add Reset button that zeroes clickCount Pairs with the next commit's tap-reset action so the fuzzer can violate clickCountNeverDecreases and demonstrate uatu actually finding a property violation. * feat(sample-app): add tap-reset action to exercise Reset button Weighted at 10/122, fuzzer reaches it within a short run. Pairs with the Reset button to demonstrate uatu detecting the clickCountNeverDecreases violation. * fix(runner): filter WaitForIdle errors via context state, not errors.Is errors.Is(err, context.DeadlineExceeded) misses gRPC's wrapped status.DeadlineExceeded, so every step under the maestro driver logged a spurious warning. Check idleCtx.Err() instead — captures both deadline-fired and parent-canceled cases regardless of how the driver wraps them. * chore(sample-app): tune action weights so demo violates in ~30s Prior weights left tap-reset rare enough that short demo runs missed the violation by chance. Bumped to 30/107, with typeUsername reduced since username noise doesn't help exercise clickCount. * refactor(runner): route warnings through slog Adds Options.Logger (defaults to slog.Default()) and converts the three warning sites that were using fmt.Printf. Progress line stays on Printf since it's user-facing UI, not a log. Makes the warnings testable via a capturing handler. * test(runner): assert WaitForIdle driver errors are logged Captures slog output via TextHandler into a buffer and asserts the warning message + injected error text appear when the mock driver returns a non-context error from WaitForIdle. Guards against a regression of the silent-error swallow.
This commit is contained in:
5 files changed
+67
-13
No files matched your search
@@ -1,9 +1,11 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -267,6 +269,41 @@ func TestScreenFromSnapshot(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestRunner_LogsWaitForIdleDriverErrors(t *testing.T) {
|
||||
snapshots := []map[string]json.RawMessage{
|
||||
{"balance": json.RawMessage(`100`)},
|
||||
}
|
||||
state := newHarness(t, snapshots)
|
||||
state.startSDK(t)
|
||||
state.acceptConnection(t)
|
||||
state.mock.Failures[mockdriver.ActionWaitForIdle] = errors.New("sidecar lost gRPC stream")
|
||||
|
||||
var logBuf bytes.Buffer
|
||||
logger := slog.New(slog.NewTextHandler(&logBuf, &slog.HandlerOptions{Level: slog.LevelWarn}))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
if _, err := Run(ctx, Options{
|
||||
Duration: 100 * time.Millisecond,
|
||||
SnapshotTimeout: 2 * time.Second,
|
||||
IdleTimeout: 50 * time.Millisecond,
|
||||
Connection: state.conn,
|
||||
Driver: state.mock,
|
||||
Verifier: state.verifier,
|
||||
TraceWriter: state.writer,
|
||||
Logger: logger,
|
||||
}); err != nil {
|
||||
t.Fatalf("Run: %v", err)
|
||||
}
|
||||
output := logBuf.String()
|
||||
if !strings.Contains(output, "wait_for_idle failed") {
|
||||
t.Errorf("expected wait_for_idle warning, got: %q", output)
|
||||
}
|
||||
if !strings.Contains(output, "sidecar lost gRPC stream") {
|
||||
t.Errorf("expected driver error message in warning, got: %q", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyAction_InputTextSurfacesFocusTapError(t *testing.T) {
|
||||
t.Run("selector focus tap fails", func(t *testing.T) {
|
||||
driverMock := mockdriver.New()
|
||||
|
||||
Reference in new issue
Block a user