github.com/letsencrypt/boulder@v0.20251208.0/grpc/errors_test.go (about)

     1  package grpc
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net"
     8  	"testing"
     9  	"time"
    10  
    11  	"google.golang.org/grpc"
    12  	"google.golang.org/grpc/credentials/insecure"
    13  
    14  	"github.com/jmhodges/clock"
    15  
    16  	berrors "github.com/letsencrypt/boulder/errors"
    17  	"github.com/letsencrypt/boulder/grpc/test_proto"
    18  	"github.com/letsencrypt/boulder/identifier"
    19  	"github.com/letsencrypt/boulder/metrics"
    20  	"github.com/letsencrypt/boulder/test"
    21  )
    22  
    23  type errorServer struct {
    24  	test_proto.UnimplementedChillerServer
    25  	err error
    26  }
    27  
    28  func (s *errorServer) Chill(_ context.Context, _ *test_proto.Time) (*test_proto.Time, error) {
    29  	return nil, s.err
    30  }
    31  
    32  func TestErrorWrapping(t *testing.T) {
    33  	serverMetrics, err := newServerMetrics(metrics.NoopRegisterer)
    34  	test.AssertNotError(t, err, "creating server metrics")
    35  	smi := newServerMetadataInterceptor(serverMetrics, clock.NewFake())
    36  	clientMetrics, err := newClientMetrics(metrics.NoopRegisterer)
    37  	test.AssertNotError(t, err, "creating client metrics")
    38  	cmi := clientMetadataInterceptor{time.Second, clientMetrics, clock.NewFake(), true}
    39  	srv := grpc.NewServer(grpc.UnaryInterceptor(smi.Unary))
    40  	es := &errorServer{}
    41  	test_proto.RegisterChillerServer(srv, es)
    42  	lis, err := net.Listen("tcp", "127.0.0.1:")
    43  	test.AssertNotError(t, err, "Failed to create listener")
    44  	go func() { _ = srv.Serve(lis) }()
    45  	defer srv.Stop()
    46  
    47  	conn, err := grpc.Dial(
    48  		lis.Addr().String(),
    49  		grpc.WithTransportCredentials(insecure.NewCredentials()),
    50  		grpc.WithUnaryInterceptor(cmi.Unary),
    51  	)
    52  	test.AssertNotError(t, err, "Failed to dial grpc test server")
    53  	client := test_proto.NewChillerClient(conn)
    54  
    55  	// RateLimitError with a RetryAfter of 500ms.
    56  	expectRetryAfter := time.Millisecond * 500
    57  	es.err = berrors.RateLimitError(expectRetryAfter, "yup")
    58  	_, err = client.Chill(context.Background(), &test_proto.Time{})
    59  	test.Assert(t, err != nil, fmt.Sprintf("nil error returned, expected: %s", err))
    60  	test.AssertDeepEquals(t, err, es.err)
    61  	var bErr *berrors.BoulderError
    62  	ok := errors.As(err, &bErr)
    63  	test.Assert(t, ok, "asserting error as boulder error")
    64  	// Ensure we got a RateLimitError
    65  	test.AssertErrorIs(t, bErr, berrors.RateLimit)
    66  	// Ensure our RetryAfter is still 500ms.
    67  	test.AssertEquals(t, bErr.RetryAfter, expectRetryAfter)
    68  
    69  	test.AssertNil(t, wrapError(context.Background(), nil), "Wrapping nil should still be nil")
    70  	test.AssertNil(t, unwrapError(nil, nil), "Unwrapping nil should still be nil")
    71  }
    72  
    73  // TestSubErrorWrapping tests that a boulder error with suberrors can be
    74  // correctly wrapped and unwrapped across the RPC layer.
    75  func TestSubErrorWrapping(t *testing.T) {
    76  	serverMetrics, err := newServerMetrics(metrics.NoopRegisterer)
    77  	test.AssertNotError(t, err, "creating server metrics")
    78  	smi := newServerMetadataInterceptor(serverMetrics, clock.NewFake())
    79  	clientMetrics, err := newClientMetrics(metrics.NoopRegisterer)
    80  	test.AssertNotError(t, err, "creating client metrics")
    81  	cmi := clientMetadataInterceptor{time.Second, clientMetrics, clock.NewFake(), true}
    82  	srv := grpc.NewServer(grpc.UnaryInterceptor(smi.Unary))
    83  	es := &errorServer{}
    84  	test_proto.RegisterChillerServer(srv, es)
    85  	lis, err := net.Listen("tcp", "127.0.0.1:")
    86  	test.AssertNotError(t, err, "Failed to create listener")
    87  	go func() { _ = srv.Serve(lis) }()
    88  	defer srv.Stop()
    89  
    90  	conn, err := grpc.Dial(
    91  		lis.Addr().String(),
    92  		grpc.WithTransportCredentials(insecure.NewCredentials()),
    93  		grpc.WithUnaryInterceptor(cmi.Unary),
    94  	)
    95  	test.AssertNotError(t, err, "Failed to dial grpc test server")
    96  	client := test_proto.NewChillerClient(conn)
    97  
    98  	subErrors := []berrors.SubBoulderError{
    99  		{
   100  			Identifier: identifier.NewDNS("chillserver.com"),
   101  			BoulderError: &berrors.BoulderError{
   102  				Type:   berrors.RejectedIdentifier,
   103  				Detail: "2 ill 2 chill",
   104  			},
   105  		},
   106  	}
   107  
   108  	es.err = (&berrors.BoulderError{
   109  		Type:   berrors.Malformed,
   110  		Detail: "malformed chill req",
   111  	}).WithSubErrors(subErrors)
   112  
   113  	_, err = client.Chill(context.Background(), &test_proto.Time{})
   114  	test.Assert(t, err != nil, fmt.Sprintf("nil error returned, expected: %s", err))
   115  	test.AssertDeepEquals(t, err, es.err)
   116  }