Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Mazurskiy <mmazurskiy@gitlab.com>2023-05-17 13:51:18 +0300
committerMikhail Mazurskiy <mmazurskiy@gitlab.com>2023-05-18 03:25:13 +0300
commit64dbd379058e89264802d03a9621ec98b987b58a (patch)
treeb24a1f76ce2e37f43800c50fa84883ae369424db /internal/testhelper/testserver/structerr_interceptors_test.go
parent624fc0095e283c990a627b702b6eaf5a99c2da7b (diff)
Decouple production code from test proto
WithInterceptedMetadata() uses testproto.ErrorMetadata, which is in a test-only package. This function is only used in tests so move it to testhelper and interceptors into testserver
Diffstat (limited to 'internal/testhelper/testserver/structerr_interceptors_test.go')
-rw-r--r--internal/testhelper/testserver/structerr_interceptors_test.go184
1 files changed, 184 insertions, 0 deletions
diff --git a/internal/testhelper/testserver/structerr_interceptors_test.go b/internal/testhelper/testserver/structerr_interceptors_test.go
new file mode 100644
index 000000000..330c823b5
--- /dev/null
+++ b/internal/testhelper/testserver/structerr_interceptors_test.go
@@ -0,0 +1,184 @@
+package testserver
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "testing"
+
+ grpcmwlogrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
+ "github.com/sirupsen/logrus"
+ "github.com/sirupsen/logrus/hooks/test"
+ "github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/log"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/structerr"
+ "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper"
+ "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb/testproto"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/credentials/insecure"
+ "google.golang.org/grpc/interop/grpc_testing"
+ "google.golang.org/grpc/status"
+)
+
+func TestInterceptedError(t *testing.T) {
+ t.Parallel()
+
+ for _, tc := range []struct {
+ desc string
+ err error
+ expectedErr error
+ }{
+ {
+ desc: "normal error",
+ err: fmt.Errorf("test"),
+ expectedErr: fmt.Errorf("test"),
+ },
+ {
+ desc: "structured error",
+ err: structerr.NewNotFound("not found"),
+ expectedErr: structerr.NewNotFound("not found"),
+ },
+ {
+ desc: "wrapped structured error",
+ err: fmt.Errorf("wrapped: %w", structerr.NewNotFound("not found")),
+ expectedErr: fmt.Errorf("wrapped: %w", structerr.NewNotFound("not found")),
+ },
+ {
+ desc: "metadata",
+ err: structerr.NewNotFound("not found").WithMetadata("key", "value"),
+ expectedErr: structerr.NewNotFound("not found").WithDetail(
+ &testproto.ErrorMetadata{
+ Key: []byte("key"),
+ Value: []byte("value"),
+ },
+ ),
+ },
+ {
+ desc: "wrapped error with metadata",
+ err: fmt.Errorf("wrapped: %w", structerr.NewNotFound("not found").WithMetadata("key", "value")),
+ expectedErr: structerr.NewNotFound("wrapped: not found").WithDetail(
+ &testproto.ErrorMetadata{
+ Key: []byte("key"),
+ Value: []byte("value"),
+ },
+ ),
+ },
+ } {
+ t.Run(tc.desc, func(t *testing.T) {
+ err := interceptedError(tc.err)
+ testhelper.RequireGrpcError(t, tc.expectedErr, err)
+ })
+ }
+}
+
+type mockService struct {
+ grpc_testing.UnimplementedTestServiceServer
+ err error
+}
+
+func (m *mockService) UnaryCall(
+ context.Context, *grpc_testing.SimpleRequest,
+) (*grpc_testing.SimpleResponse, error) {
+ return &grpc_testing.SimpleResponse{}, m.err
+}
+
+func TestFieldsProducer(t *testing.T) {
+ t.Parallel()
+
+ ctx := testhelper.Context(t)
+ logger, loggerHook := test.NewNullLogger()
+ logger.SetLevel(logrus.ErrorLevel)
+
+ listener, err := net.Listen("tcp", "localhost:0")
+ require.NoError(t, err)
+
+ service := &mockService{}
+ server := grpc.NewServer(
+ grpc.ChainUnaryInterceptor(
+ grpcmwlogrus.UnaryServerInterceptor(
+ logrus.NewEntry(logger),
+ grpcmwlogrus.WithMessageProducer(
+ log.MessageProducer(
+ grpcmwlogrus.DefaultMessageProducer,
+ structerr.FieldsProducer,
+ ),
+ ),
+ ),
+ ),
+ )
+ grpc_testing.RegisterTestServiceServer(server, service)
+
+ go testhelper.MustServe(t, server, listener)
+ defer server.Stop()
+
+ conn, err := grpc.Dial(listener.Addr().String(),
+ grpc.WithTransportCredentials(insecure.NewCredentials()),
+ )
+ require.NoError(t, err)
+ defer testhelper.MustClose(t, conn)
+
+ client := grpc_testing.NewTestServiceClient(conn)
+
+ for _, tc := range []struct {
+ desc string
+ returnedErr error
+ expectedErr error
+ expectedMetadata []map[string]any
+ }{
+ {
+ desc: "no error",
+ returnedErr: nil,
+ },
+ {
+ desc: "plain error",
+ returnedErr: errors.New("message"),
+ expectedErr: status.Error(codes.Unknown, "message"),
+ },
+ {
+ desc: "structured error",
+ returnedErr: structerr.New("message"),
+ expectedErr: status.Error(codes.Unknown, "message"),
+ },
+ {
+ desc: "structured error with metadata",
+ returnedErr: structerr.New("message").WithMetadata("key", "value"),
+ expectedErr: status.Error(codes.Unknown, "message"),
+ expectedMetadata: []map[string]any{
+ {
+ "key": "value",
+ },
+ },
+ },
+ {
+ desc: "structured error with nested metadata",
+ returnedErr: structerr.New("message: %w", structerr.New("nested").WithMetadata("nested", "value")).WithMetadata("key", "value"),
+ expectedErr: status.Error(codes.Unknown, "message: nested"),
+ expectedMetadata: []map[string]any{
+ {
+ "key": "value",
+ "nested": "value",
+ },
+ },
+ },
+ } {
+ t.Run(tc.desc, func(t *testing.T) {
+ loggerHook.Reset()
+
+ service.err = tc.returnedErr
+
+ _, err := client.UnaryCall(ctx, &grpc_testing.SimpleRequest{})
+ testhelper.ProtoEqual(t, tc.expectedErr, err)
+
+ var metadata []map[string]any
+ for _, entry := range loggerHook.AllEntries() {
+ if untypedMetadata := entry.Data["error_metadata"]; untypedMetadata != nil {
+ require.IsType(t, untypedMetadata, map[string]any{})
+ metadata = append(metadata, untypedMetadata.(map[string]any))
+ }
+ }
+ require.Equal(t, tc.expectedMetadata, metadata)
+ })
+ }
+}