github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/status/status_test.go (about)

     1  /*
     2   *
     3   * Copyright 2017 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package status
    20  
    21  import (
    22  	"context"
    23  	"errors"
    24  	"fmt"
    25  	"testing"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"github.com/golang/protobuf/ptypes"
    29  	apb "github.com/golang/protobuf/ptypes/any"
    30  	dpb "github.com/golang/protobuf/ptypes/duration"
    31  	"github.com/google/go-cmp/cmp"
    32  	"github.com/hxx258456/ccgo/grpc/codes"
    33  	"github.com/hxx258456/ccgo/grpc/internal/grpctest"
    34  	"github.com/hxx258456/ccgo/grpc/internal/status"
    35  	cpb "google.golang.org/genproto/googleapis/rpc/code"
    36  	epb "google.golang.org/genproto/googleapis/rpc/errdetails"
    37  	spb "google.golang.org/genproto/googleapis/rpc/status"
    38  )
    39  
    40  type s struct {
    41  	grpctest.Tester
    42  }
    43  
    44  func Test(t *testing.T) {
    45  	grpctest.RunSubTests(t, s{})
    46  }
    47  
    48  // errEqual is essentially a copy of testutils.StatusErrEqual(), to avoid a
    49  // cyclic dependency.
    50  func errEqual(err1, err2 error) bool {
    51  	status1, ok := FromError(err1)
    52  	if !ok {
    53  		return false
    54  	}
    55  	status2, ok := FromError(err2)
    56  	if !ok {
    57  		return false
    58  	}
    59  	return proto.Equal(status1.Proto(), status2.Proto())
    60  }
    61  
    62  func (s) TestErrorsWithSameParameters(t *testing.T) {
    63  	const description = "some description"
    64  	e1 := Errorf(codes.AlreadyExists, description)
    65  	e2 := Errorf(codes.AlreadyExists, description)
    66  	if e1 == e2 || !errEqual(e1, e2) {
    67  		t.Fatalf("Errors should be equivalent but unique - e1: %v, %v  e2: %p, %v", e1.(*status.Error), e1, e2.(*status.Error), e2)
    68  	}
    69  }
    70  
    71  func (s) TestFromToProto(t *testing.T) {
    72  	s := &spb.Status{
    73  		Code:    int32(codes.Internal),
    74  		Message: "test test test",
    75  		Details: []*apb.Any{{TypeUrl: "foo", Value: []byte{3, 2, 1}}},
    76  	}
    77  
    78  	err := FromProto(s)
    79  	if got := err.Proto(); !proto.Equal(s, got) {
    80  		t.Fatalf("Expected errors to be identical - s: %v  got: %v", s, got)
    81  	}
    82  }
    83  
    84  func (s) TestFromNilProto(t *testing.T) {
    85  	tests := []*Status{nil, FromProto(nil)}
    86  	for _, s := range tests {
    87  		if c := s.Code(); c != codes.OK {
    88  			t.Errorf("s: %v - Expected s.Code() = OK; got %v", s, c)
    89  		}
    90  		if m := s.Message(); m != "" {
    91  			t.Errorf("s: %v - Expected s.Message() = \"\"; got %q", s, m)
    92  		}
    93  		if p := s.Proto(); p != nil {
    94  			t.Errorf("s: %v - Expected s.Proto() = nil; got %q", s, p)
    95  		}
    96  		if e := s.Err(); e != nil {
    97  			t.Errorf("s: %v - Expected s.Err() = nil; got %v", s, e)
    98  		}
    99  	}
   100  }
   101  
   102  func (s) TestError(t *testing.T) {
   103  	err := Error(codes.Internal, "test description")
   104  	if got, want := err.Error(), "rpc error: code = Internal desc = test description"; got != want {
   105  		t.Fatalf("err.Error() = %q; want %q", got, want)
   106  	}
   107  	s, _ := FromError(err)
   108  	if got, want := s.Code(), codes.Internal; got != want {
   109  		t.Fatalf("err.Code() = %s; want %s", got, want)
   110  	}
   111  	if got, want := s.Message(), "test description"; got != want {
   112  		t.Fatalf("err.Message() = %s; want %s", got, want)
   113  	}
   114  }
   115  
   116  func (s) TestErrorOK(t *testing.T) {
   117  	err := Error(codes.OK, "foo")
   118  	if err != nil {
   119  		t.Fatalf("Error(codes.OK, _) = %p; want nil", err.(*status.Error))
   120  	}
   121  }
   122  
   123  func (s) TestErrorProtoOK(t *testing.T) {
   124  	s := &spb.Status{Code: int32(codes.OK)}
   125  	if got := ErrorProto(s); got != nil {
   126  		t.Fatalf("ErrorProto(%v) = %v; want nil", s, got)
   127  	}
   128  }
   129  
   130  func (s) TestFromError(t *testing.T) {
   131  	code, message := codes.Internal, "test description"
   132  	err := Error(code, message)
   133  	s, ok := FromError(err)
   134  	if !ok || s.Code() != code || s.Message() != message || s.Err() == nil {
   135  		t.Fatalf("FromError(%v) = %v, %v; want <Code()=%s, Message()=%q, Err()!=nil>, true", err, s, ok, code, message)
   136  	}
   137  }
   138  
   139  func (s) TestFromErrorOK(t *testing.T) {
   140  	code, message := codes.OK, ""
   141  	s, ok := FromError(nil)
   142  	if !ok || s.Code() != code || s.Message() != message || s.Err() != nil {
   143  		t.Fatalf("FromError(nil) = %v, %v; want <Code()=%s, Message()=%q, Err=nil>, true", s, ok, code, message)
   144  	}
   145  }
   146  
   147  type customError struct {
   148  	Code    codes.Code
   149  	Message string
   150  	Details []*apb.Any
   151  }
   152  
   153  func (c customError) Error() string {
   154  	return fmt.Sprintf("rpc error: code = %s desc = %s", c.Code, c.Message)
   155  }
   156  
   157  func (c customError) GRPCStatus() *Status {
   158  	return status.FromProto(&spb.Status{
   159  		Code:    int32(c.Code),
   160  		Message: c.Message,
   161  		Details: c.Details,
   162  	})
   163  }
   164  
   165  func (s) TestFromErrorImplementsInterface(t *testing.T) {
   166  	code, message := codes.Internal, "test description"
   167  	details := []*apb.Any{{
   168  		TypeUrl: "testUrl",
   169  		Value:   []byte("testValue"),
   170  	}}
   171  	err := customError{
   172  		Code:    code,
   173  		Message: message,
   174  		Details: details,
   175  	}
   176  	s, ok := FromError(err)
   177  	if !ok || s.Code() != code || s.Message() != message || s.Err() == nil {
   178  		t.Fatalf("FromError(%v) = %v, %v; want <Code()=%s, Message()=%q, Err()!=nil>, true", err, s, ok, code, message)
   179  	}
   180  	pd := s.Proto().GetDetails()
   181  	if len(pd) != 1 || !proto.Equal(pd[0], details[0]) {
   182  		t.Fatalf("s.Proto.GetDetails() = %v; want <Details()=%s>", pd, details)
   183  	}
   184  }
   185  
   186  func (s) TestFromErrorUnknownError(t *testing.T) {
   187  	code, message := codes.Unknown, "unknown error"
   188  	err := errors.New("unknown error")
   189  	s, ok := FromError(err)
   190  	if ok || s.Code() != code || s.Message() != message {
   191  		t.Fatalf("FromError(%v) = %v, %v; want <Code()=%s, Message()=%q>, false", err, s, ok, code, message)
   192  	}
   193  }
   194  
   195  func (s) TestConvertKnownError(t *testing.T) {
   196  	code, message := codes.Internal, "test description"
   197  	err := Error(code, message)
   198  	s := Convert(err)
   199  	if s.Code() != code || s.Message() != message {
   200  		t.Fatalf("Convert(%v) = %v; want <Code()=%s, Message()=%q>", err, s, code, message)
   201  	}
   202  }
   203  
   204  func (s) TestConvertUnknownError(t *testing.T) {
   205  	code, message := codes.Unknown, "unknown error"
   206  	err := errors.New("unknown error")
   207  	s := Convert(err)
   208  	if s.Code() != code || s.Message() != message {
   209  		t.Fatalf("Convert(%v) = %v; want <Code()=%s, Message()=%q>", err, s, code, message)
   210  	}
   211  }
   212  
   213  func (s) TestStatus_ErrorDetails(t *testing.T) {
   214  	tests := []struct {
   215  		code    codes.Code
   216  		details []proto.Message
   217  	}{
   218  		{
   219  			code:    codes.NotFound,
   220  			details: nil,
   221  		},
   222  		{
   223  			code: codes.NotFound,
   224  			details: []proto.Message{
   225  				&epb.ResourceInfo{
   226  					ResourceType: "book",
   227  					ResourceName: "projects/1234/books/5678",
   228  					Owner:        "User",
   229  				},
   230  			},
   231  		},
   232  		{
   233  			code: codes.Internal,
   234  			details: []proto.Message{
   235  				&epb.DebugInfo{
   236  					StackEntries: []string{
   237  						"first stack",
   238  						"second stack",
   239  					},
   240  				},
   241  			},
   242  		},
   243  		{
   244  			code: codes.Unavailable,
   245  			details: []proto.Message{
   246  				&epb.RetryInfo{
   247  					RetryDelay: &dpb.Duration{Seconds: 60},
   248  				},
   249  				&epb.ResourceInfo{
   250  					ResourceType: "book",
   251  					ResourceName: "projects/1234/books/5678",
   252  					Owner:        "User",
   253  				},
   254  			},
   255  		},
   256  	}
   257  
   258  	for _, tc := range tests {
   259  		s, err := New(tc.code, "").WithDetails(tc.details...)
   260  		if err != nil {
   261  			t.Fatalf("(%v).WithDetails(%+v) failed: %v", str(s), tc.details, err)
   262  		}
   263  		details := s.Details()
   264  		for i := range details {
   265  			if !proto.Equal(details[i].(proto.Message), tc.details[i]) {
   266  				t.Fatalf("(%v).Details()[%d] = %+v, want %+v", str(s), i, details[i], tc.details[i])
   267  			}
   268  		}
   269  	}
   270  }
   271  
   272  func (s) TestStatus_WithDetails_Fail(t *testing.T) {
   273  	tests := []*Status{
   274  		nil,
   275  		FromProto(nil),
   276  		New(codes.OK, ""),
   277  	}
   278  	for _, s := range tests {
   279  		if s, err := s.WithDetails(); err == nil || s != nil {
   280  			t.Fatalf("(%v).WithDetails(%+v) = %v, %v; want nil, non-nil", str(s), []proto.Message{}, s, err)
   281  		}
   282  	}
   283  }
   284  
   285  func (s) TestStatus_ErrorDetails_Fail(t *testing.T) {
   286  	tests := []struct {
   287  		s *Status
   288  		i []interface{}
   289  	}{
   290  		{
   291  			nil,
   292  			nil,
   293  		},
   294  		{
   295  			FromProto(nil),
   296  			nil,
   297  		},
   298  		{
   299  			New(codes.OK, ""),
   300  			[]interface{}{},
   301  		},
   302  		{
   303  			FromProto(&spb.Status{
   304  				Code: int32(cpb.Code_CANCELLED),
   305  				Details: []*apb.Any{
   306  					{
   307  						TypeUrl: "",
   308  						Value:   []byte{},
   309  					},
   310  					mustMarshalAny(&epb.ResourceInfo{
   311  						ResourceType: "book",
   312  						ResourceName: "projects/1234/books/5678",
   313  						Owner:        "User",
   314  					}),
   315  				},
   316  			}),
   317  			[]interface{}{
   318  				errors.New(`message type url "" is invalid`),
   319  				&epb.ResourceInfo{
   320  					ResourceType: "book",
   321  					ResourceName: "projects/1234/books/5678",
   322  					Owner:        "User",
   323  				},
   324  			},
   325  		},
   326  	}
   327  	for _, tc := range tests {
   328  		got := tc.s.Details()
   329  		if !cmp.Equal(got, tc.i, cmp.Comparer(proto.Equal), cmp.Comparer(equalError)) {
   330  			t.Errorf("(%v).Details() = %+v, want %+v", str(tc.s), got, tc.i)
   331  		}
   332  	}
   333  }
   334  
   335  func equalError(x, y error) bool {
   336  	return x == y || (x != nil && y != nil && x.Error() == y.Error())
   337  }
   338  
   339  func str(s *Status) string {
   340  	if s == nil {
   341  		return "nil"
   342  	}
   343  	if s.Proto() == nil {
   344  		return "<Code=OK>"
   345  	}
   346  	return fmt.Sprintf("<Code=%v, Message=%q, Details=%+v>", s.Code(), s.Message(), s.Details())
   347  }
   348  
   349  // mustMarshalAny converts a protobuf message to an any.
   350  func mustMarshalAny(msg proto.Message) *apb.Any {
   351  	any, err := ptypes.MarshalAny(msg)
   352  	if err != nil {
   353  		panic(fmt.Sprintf("ptypes.MarshalAny(%+v) failed: %v", msg, err))
   354  	}
   355  	return any
   356  }
   357  
   358  func (s) TestFromContextError(t *testing.T) {
   359  	testCases := []struct {
   360  		in   error
   361  		want *Status
   362  	}{
   363  		{in: nil, want: New(codes.OK, "")},
   364  		{in: context.DeadlineExceeded, want: New(codes.DeadlineExceeded, context.DeadlineExceeded.Error())},
   365  		{in: context.Canceled, want: New(codes.Canceled, context.Canceled.Error())},
   366  		{in: errors.New("other"), want: New(codes.Unknown, "other")},
   367  		{in: fmt.Errorf("wrapped: %w", context.DeadlineExceeded), want: New(codes.DeadlineExceeded, "wrapped: "+context.DeadlineExceeded.Error())},
   368  		{in: fmt.Errorf("wrapped: %w", context.Canceled), want: New(codes.Canceled, "wrapped: "+context.Canceled.Error())},
   369  	}
   370  	for _, tc := range testCases {
   371  		got := FromContextError(tc.in)
   372  		if got.Code() != tc.want.Code() || got.Message() != tc.want.Message() {
   373  			t.Errorf("FromContextError(%v) = %v; want %v", tc.in, got, tc.want)
   374  		}
   375  	}
   376  }