Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion pkg/errgrpc/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,17 @@ func ToNative(err error) error {
code = s.Code()
} else {
desc = err.Error()
code = codes.Unknown
// No gRPC status: default to Unknown, but map native context
// sentinels to their code so the switch below restores them
// instead of reclassifying as errdefs.ErrUnknown.
switch {
case errors.Is(err, context.DeadlineExceeded):
code = codes.DeadlineExceeded
case errors.Is(err, context.Canceled):
code = codes.Canceled
default:
code = codes.Unknown
}
}

var cls error // divide these into error classes, becomes the cause
Expand Down
69 changes: 69 additions & 0 deletions pkg/errgrpc/grpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,72 @@ func TestGRPCNestedError(t *testing.T) {

checkError(ToNative(ToGRPC(werr)))
}


// TestToNativeContextSentinels verifies that ToNative preserves the identity
// of native context sentinels (context.DeadlineExceeded and context.Canceled)
// when they are passed directly, without first being mapped to a gRPC status
// error via ToGRPC. This is the path taken when a ttrpc/gRPC client returns
// ctx.Err() on a per-call deadline and the caller runs it through ToNative.
//
// Unlike TestGRPCRoundTrip, these cases do NOT go through ToGRPC first, so
// status.FromError reports codes.Unknown. Without preserving the sentinel,
// the result wraps errdefs.ErrUnknown and errdefs.IsDeadlineExceeded /
// errdefs.IsCanceled stop recognizing it.
func TestToNativeContextSentinels(t *testing.T) {
for _, testcase := range []struct {
name string
input error
cause error
is func(error) bool
str string
}{
{
name: "bare deadline exceeded",
input: context.DeadlineExceeded,
cause: context.DeadlineExceeded,
is: errdefs.IsDeadlineExceeded,
str: "context deadline exceeded",
},
{
name: "wrapped deadline exceeded",
input: fmt.Errorf("get state for abc: %w", context.DeadlineExceeded),
cause: context.DeadlineExceeded,
is: errdefs.IsDeadlineExceeded,
str: "get state for abc: context deadline exceeded",
},
{
name: "bare canceled",
input: context.Canceled,
cause: context.Canceled,
is: errdefs.IsCanceled,
str: "context canceled",
},
{
name: "wrapped canceled",
input: fmt.Errorf("operation aborted: %w", context.Canceled),
cause: context.Canceled,
is: errdefs.IsCanceled,
str: "operation aborted: context canceled",
},
} {
t.Run(testcase.name, func(t *testing.T) {
nerr := ToNative(testcase.input)
t.Logf("input: %v, recovered: %v", testcase.input, nerr)

if !errors.Is(nerr, testcase.cause) {
t.Fatalf("unexpected cause: !errors.Is(%v, %v)", nerr, testcase.cause)
}
if !testcase.is(nerr) {
t.Fatalf("errdefs Is helper did not match recovered error: %v", nerr)
}
// The sentinel must not be reclassified as an unknown error.
if errdefs.IsUnknown(nerr) {
t.Fatalf("recovered error misclassified as unknown: %v", nerr)
}
if nerr.Error() != testcase.str {
t.Fatalf("unexpected string: %q != %q", nerr.Error(), testcase.str)
}
})
}
}
4 changes: 2 additions & 2 deletions pkg/go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/typeurl/v2 v2.3.0 h1:HZHPhRWo5XMy3QGQoPrUzbW/2ckwjfweHmOwlkIrPAQ=
github.com/containerd/typeurl/v2 v2.3.0/go.mod h1:Qk+PAdUYArVj41TnGi6rJ+48RF0PkcTc4i/taoBcK0w=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
Expand Down
Loading