Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added simple wrapper for grpc errors for getting nodeID and address #1391

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
* Added nodeID and address to operation and transport errors
* Prevented create decoder instance until start read a message from topics

## v3.99.4
Expand Down
8 changes: 8 additions & 0 deletions internal/xerrors/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ func (e *operationError) Code() int32 {
return int32(e.code)
}

func (e *operationError) NodeID() uint32 {
return e.nodeID
}

func (e *operationError) Address() string {
return e.address
}

func (e *operationError) Name() string {
return "operation/" + e.code.String()
}
Expand Down
33 changes: 30 additions & 3 deletions internal/xerrors/operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,30 @@ import (
"github.com/stretchr/testify/require"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Issue"

"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
)

func TestIsOperationError(t *testing.T) {
for _, tt := range []struct {
name string
err error
codes []Ydb.StatusIds_StatusCode
match bool
}{
// check only operation error with any ydb status code
{
name: xtest.CurrentFileLine(),
err: &operationError{code: Ydb.StatusIds_BAD_REQUEST},
match: true,
},
{
name: xtest.CurrentFileLine(),
err: fmt.Errorf("wrapped: %w", &operationError{code: Ydb.StatusIds_BAD_REQUEST}),
match: true,
},
{
name: xtest.CurrentFileLine(),
err: Join(
fmt.Errorf("test"),
&operationError{code: Ydb.StatusIds_BAD_REQUEST},
Expand All @@ -34,16 +40,19 @@ func TestIsOperationError(t *testing.T) {
},
// match ydb status code
{
name: xtest.CurrentFileLine(),
err: &operationError{code: Ydb.StatusIds_BAD_REQUEST},
codes: []Ydb.StatusIds_StatusCode{Ydb.StatusIds_BAD_REQUEST},
match: true,
},
{
name: xtest.CurrentFileLine(),
err: fmt.Errorf("wrapped: %w", &operationError{code: Ydb.StatusIds_BAD_REQUEST}),
codes: []Ydb.StatusIds_StatusCode{Ydb.StatusIds_BAD_REQUEST},
match: true,
},
{
name: xtest.CurrentFileLine(),
err: Join(
fmt.Errorf("test"),
&operationError{code: Ydb.StatusIds_BAD_REQUEST},
Expand All @@ -54,16 +63,19 @@ func TestIsOperationError(t *testing.T) {
},
// no match ydb status code
{
name: xtest.CurrentFileLine(),
err: &operationError{code: Ydb.StatusIds_BAD_REQUEST},
codes: []Ydb.StatusIds_StatusCode{Ydb.StatusIds_ABORTED},
match: false,
},
{
name: xtest.CurrentFileLine(),
err: fmt.Errorf("wrapped: %w", &operationError{code: Ydb.StatusIds_BAD_REQUEST}),
codes: []Ydb.StatusIds_StatusCode{Ydb.StatusIds_ABORTED},
match: false,
},
{
name: xtest.CurrentFileLine(),
err: Join(
fmt.Errorf("test"),
&operationError{code: Ydb.StatusIds_BAD_REQUEST},
Expand All @@ -73,18 +85,20 @@ func TestIsOperationError(t *testing.T) {
match: false,
},
} {
t.Run("", func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.match, IsOperationError(tt.err, tt.codes...))
})
}
}

func TestIsOperationErrorTransactionLocksInvalidated(t *testing.T) {
for _, tt := range [...]struct {
name string
err error
isTLI bool
}{
{
name: xtest.CurrentFileLine(),
err: Operation(
WithStatusCode(Ydb.StatusIds_ABORTED),
WithIssues([]*Ydb_Issue.IssueMessage{{
Expand All @@ -94,6 +108,7 @@ func TestIsOperationErrorTransactionLocksInvalidated(t *testing.T) {
isTLI: true,
},
{
name: xtest.CurrentFileLine(),
err: Operation(
WithStatusCode(Ydb.StatusIds_OVERLOADED),
WithIssues([]*Ydb_Issue.IssueMessage{{
Expand All @@ -103,12 +118,14 @@ func TestIsOperationErrorTransactionLocksInvalidated(t *testing.T) {
isTLI: false,
},
{
name: xtest.CurrentFileLine(),
err: Operation(
WithStatusCode(Ydb.StatusIds_ABORTED),
),
isTLI: false,
},
{
name: xtest.CurrentFileLine(),
err: Operation(
WithStatusCode(Ydb.StatusIds_ABORTED),
WithIssues([]*Ydb_Issue.IssueMessage{{
Expand All @@ -120,30 +137,40 @@ func TestIsOperationErrorTransactionLocksInvalidated(t *testing.T) {
isTLI: true,
},
} {
t.Run("", func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.isTLI, IsOperationErrorTransactionLocksInvalidated(tt.err))
})
}
}

func Test_operationError_Error(t *testing.T) {
for _, tt := range []struct {
name string
err error
text string
}{
{
name: xtest.CurrentFileLine(),
err: Operation(WithStatusCode(Ydb.StatusIds_BAD_REQUEST), WithAddress("localhost")),
text: "operation/BAD_REQUEST (code = 400010, address = localhost)",
},
{
name: xtest.CurrentFileLine(),
err: Operation(WithStatusCode(Ydb.StatusIds_BAD_REQUEST), WithNodeID(100500)),
text: "operation/BAD_REQUEST (code = 400010, nodeID = 100500)",
},
{
name: xtest.CurrentFileLine(),
err: Operation(WithStatusCode(Ydb.StatusIds_BAD_REQUEST)),
text: "operation/BAD_REQUEST (code = 400010)",
},
{
name: xtest.CurrentFileLine(),
err: Operation(WithStatusCode(Ydb.StatusIds_BAD_SESSION)),
text: "operation/BAD_SESSION (code = 400100)",
},
{
name: xtest.CurrentFileLine(),
err: Operation(WithStatusCode(Ydb.StatusIds_PRECONDITION_FAILED), WithIssues([]*Ydb_Issue.IssueMessage{
{
Message: "issue one",
Expand Down Expand Up @@ -177,7 +204,7 @@ func Test_operationError_Error(t *testing.T) {
text: "operation/PRECONDITION_FAILED (code = 400120, issues = [{15:3 => #1 'issue one'},{#2 'issue two' [{test.yql:16:4 => #3 'issue three'},{#4 'issue four'}]}])", //nolint:lll
},
} {
t.Run("", func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.text, tt.err.Error())
})
}
Expand Down
12 changes: 10 additions & 2 deletions internal/xerrors/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ func (e *transportError) GRPCStatus() *grpcStatus.Status {

func (e *transportError) isYdbError() {}

func (e *transportError) NodeID() uint32 {
return e.nodeID
}

func (e *transportError) Address() string {
return e.address
}

func (e *transportError) Code() int32 {
return int32(e.status.Code())
}
Expand Down Expand Up @@ -134,8 +142,8 @@ func IsTransportError(err error, codes ...grpcCodes.Code) bool {
var status *grpcStatus.Status
if t := (*transportError)(nil); errors.As(err, &t) {
status = t.status
} else if t, has := grpcStatus.FromError(err); has {
status = t
} else if s, has := grpcStatus.FromError(err); has {
status = s
}
if status != nil {
if len(codes) == 0 {
Expand Down
12 changes: 10 additions & 2 deletions internal/xerrors/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,27 @@ func TestGrpcError(t *testing.T) {

func TestTransportErrorString(t *testing.T) {
for _, tt := range []struct {
name string
err error
text string
}{
{
name: xtest.CurrentFileLine(),
err: Transport(grpcStatus.Error(grpcCodes.FailedPrecondition, "")),
text: "transport/FailedPrecondition (code = 9, source error = \"rpc error: code = FailedPrecondition desc = \")",
},
{
name: xtest.CurrentFileLine(),
err: Transport(grpcStatus.Error(grpcCodes.Unavailable, ""), WithAddress("localhost:2135")),
text: "transport/Unavailable (code = 14, source error = \"rpc error: code = Unavailable desc = \", address: \"localhost:2135\")", //nolint:lll
},
{
name: xtest.CurrentFileLine(),
err: Transport(grpcStatus.Error(grpcCodes.Unavailable, ""), WithNodeID(100500)),
text: "transport/Unavailable (code = 14, source error = \"rpc error: code = Unavailable desc = \", nodeID = 100500)", //nolint:lll
},
} {
t.Run("", func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.text, tt.err.Error())
})
}
Expand Down Expand Up @@ -189,7 +197,7 @@ func TestTransportErrorName(t *testing.T) {
name: "transport/Aborted",
},
} {
t.Run("", func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
if tt.err == nil {
require.Nil(t, TransportError(tt.err)) //nolint:testifylint
} else {
Expand Down
Loading