From 6f69816ca5473b0cca58a4fd86bfbb108904a916 Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 6 Jun 2026 12:47:21 +0530 Subject: [PATCH] test(sidecar): assert gRPC error status surfaces from action RPC --- internal/driver/sidecar/client_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/internal/driver/sidecar/client_test.go b/internal/driver/sidecar/client_test.go index 58beba6..9afeddf 100644 --- a/internal/driver/sidecar/client_test.go +++ b/internal/driver/sidecar/client_test.go @@ -46,6 +46,7 @@ type fakeServer struct { metrics *driverpb.MetricsResponse healthError error + tapError error } func (s *fakeServer) Health(_ context.Context, _ *driverpb.Empty) (*driverpb.HealthStatus, error) { @@ -80,6 +81,9 @@ func (s *fakeServer) Terminate(_ context.Context, _ *driverpb.Empty) (*driverpb. func (s *fakeServer) Tap(_ context.Context, point *driverpb.Point) (*driverpb.Empty, error) { s.mutex.Lock() defer s.mutex.Unlock() + if s.tapError != nil { + return nil, s.tapError + } s.taps = append(s.taps, point.GetX(), point.GetY()) return &driverpb.Empty{}, nil } @@ -381,6 +385,27 @@ func TestClient_WaitForIdleForwardsMillis(t *testing.T) { } } +// TestClient_RPCErrorSurfaces is the representative check that a gRPC error +// status from the sidecar propagates out of an action RPC instead of being +// swallowed into a nil error. Per-method coverage of the sidecar-side status +// mapping lives in the sidecar server tests. +func TestClient_RPCErrorSurfaces(t *testing.T) { + state := newHarness(t) + state.fake.mutex.Lock() + state.fake.tapError = status.Error(codes.Internal, "device offline") + state.fake.mutex.Unlock() + client, _ := Dial(state.address) + defer client.Close() + + err := client.Tap(context.Background(), 1, 2) + if err == nil { + t.Fatal("expected Tap to surface the gRPC error, got nil") + } + if status.Code(err) != codes.Internal { + t.Errorf("expected INTERNAL code, got %v", status.Code(err)) + } +} + // TestClient_DoubleTapSelectorFiresTwice confirms the selector fallback // composes exactly two taps; a broken composition would single-tap and the // double-tap gesture would silently degrade.