go.uber.org/yarpc@v1.72.1/encoding/protobuf/testing/testing_test.go (about)

     1  // Copyright (c) 2022 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package testing
    22  
    23  import (
    24  	"context"
    25  	"io"
    26  	"testing"
    27  
    28  	"google.golang.org/grpc/codes"
    29  	"google.golang.org/grpc/status"
    30  
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  	"go.uber.org/yarpc"
    34  	"go.uber.org/yarpc/api/transport"
    35  	"go.uber.org/yarpc/encoding/protobuf"
    36  	"go.uber.org/yarpc/internal/grpcctx"
    37  	"go.uber.org/yarpc/internal/prototest/example"
    38  	"go.uber.org/yarpc/internal/prototest/examplepb"
    39  	"go.uber.org/yarpc/internal/prototest/exampleutil"
    40  	"go.uber.org/yarpc/internal/testtime"
    41  	"go.uber.org/yarpc/internal/testutils"
    42  	intyarpcerrors "go.uber.org/yarpc/internal/yarpcerrors"
    43  	"go.uber.org/yarpc/yarpcerrors"
    44  )
    45  
    46  func TestIntegration(t *testing.T) {
    47  	t.Parallel()
    48  	for _, transportType := range testutils.AllTransportTypes {
    49  		transportType := transportType
    50  		t.Run(transportType.String(), func(t *testing.T) { testIntegrationForTransportType(t, transportType) })
    51  	}
    52  }
    53  
    54  func testIntegrationForTransportType(t *testing.T, transportType testutils.TransportType) {
    55  	expectedStreamingHeaders := transport.NewHeaders().With("firstTestKey", "firstTestValue")
    56  	keyValueYARPCServer := example.NewKeyValueYARPCServer()
    57  	fooYARPCServer := example.NewFooYARPCServer(expectedStreamingHeaders)
    58  	assert.NoError(
    59  		t,
    60  		exampleutil.WithClients(
    61  			transportType,
    62  			keyValueYARPCServer,
    63  			fooYARPCServer,
    64  			nil,
    65  			func(clients *exampleutil.Clients) error {
    66  				testIntegration(t, transportType, clients, keyValueYARPCServer, expectedStreamingHeaders)
    67  				return nil
    68  			},
    69  		),
    70  	)
    71  }
    72  
    73  func testIntegration(
    74  	t *testing.T,
    75  	ttype testutils.TransportType,
    76  	clients *exampleutil.Clients,
    77  	keyValueYARPCServer *example.KeyValueYARPCServer,
    78  	expectedStreamingHeaders transport.Headers,
    79  ) {
    80  	keyValueYARPCServer.SetNextError(intyarpcerrors.NewWithNamef(yarpcerrors.CodeUnknown, "foo-bar", "baz"))
    81  	err := setValue(clients.KeyValueYARPCClient, "foo", "bar")
    82  	assert.Equal(t, intyarpcerrors.NewWithNamef(yarpcerrors.CodeUnknown, "foo-bar", "baz"), err)
    83  	keyValueYARPCServer.SetNextError(intyarpcerrors.NewWithNamef(yarpcerrors.CodeUnknown, "foo-bar", "baz"))
    84  	err = setValueGRPC(clients.KeyValueGRPCClient, clients.ContextWrapper, "foo", "bar")
    85  	assert.Equal(t, status.Error(codes.Unknown, "foo-bar: baz"), err)
    86  
    87  	t.Run("error_details", func(t *testing.T) {
    88  		if ttype == testutils.TransportTypeTChannel {
    89  			t.Skip("TChannel does not support error details")
    90  		}
    91  
    92  		if ttype == testutils.TransportTypeHTTP {
    93  			// @todo internal code: RPC-2065
    94  			t.Skip("Error details for HTTP is currently broken")
    95  		}
    96  
    97  		keyValueYARPCServer.SetNextError(protobuf.NewError(yarpcerrors.CodeInternal, "foo-bar", protobuf.WithErrorDetails(&examplepb.EchoBothRequest{})))
    98  		err = setValue(clients.KeyValueYARPCClient, "foo", "bar")
    99  		require.Len(t, protobuf.GetErrorDetails(err), 1)
   100  		assert.Equal(t, protobuf.GetErrorDetails(err)[0], &examplepb.EchoBothRequest{})
   101  		assert.Equal(t, yarpcerrors.FromError(err).Code(), yarpcerrors.CodeInternal)
   102  		assert.Equal(t, yarpcerrors.FromError(err).Message(), "foo-bar")
   103  
   104  		keyValueYARPCServer.SetNextError(protobuf.NewError(yarpcerrors.CodeInternal, "hello world"))
   105  		err = setValue(clients.KeyValueYARPCClient, "foo", "bar")
   106  		assert.Equal(t, yarpcerrors.CodeInternal, yarpcerrors.FromError(err).Code())
   107  		assert.Equal(t, "hello world", yarpcerrors.FromError(err).Message())
   108  	})
   109  
   110  	assert.NoError(t, setValue(clients.KeyValueYARPCClient, "foo", ""))
   111  
   112  	_, err = getValue(clients.KeyValueYARPCClient, "foo")
   113  	assert.Equal(t, yarpcerrors.Newf(yarpcerrors.CodeNotFound, "foo"), err)
   114  	_, err = getValueGRPC(clients.KeyValueGRPCClient, clients.ContextWrapper, "foo")
   115  	assert.Equal(t, status.Error(codes.NotFound, "foo"), err)
   116  	_, err = getValue(clients.KeyValueYARPCJSONClient, "foo")
   117  	assert.Equal(t, yarpcerrors.Newf(yarpcerrors.CodeNotFound, "foo"), err)
   118  
   119  	assert.NoError(t, setValue(clients.KeyValueYARPCClient, "foo", "bar"))
   120  	value, err := getValue(clients.KeyValueYARPCClient, "foo")
   121  	assert.NoError(t, err)
   122  	assert.Equal(t, "bar", value)
   123  
   124  	assert.NoError(t, setValue(clients.KeyValueYARPCJSONClient, "foo", "baz"))
   125  	value, err = getValue(clients.KeyValueYARPCJSONClient, "foo")
   126  	assert.NoError(t, err)
   127  	assert.Equal(t, "baz", value)
   128  
   129  	keyValueYARPCServer.SetNextError(yarpcerrors.Newf(yarpcerrors.CodeFailedPrecondition, "baz"))
   130  	value, err = getValue(clients.KeyValueYARPCClient, "foo")
   131  	assert.Equal(t, yarpcerrors.Newf(yarpcerrors.CodeFailedPrecondition, "baz"), err)
   132  	assert.Equal(t, "baz", value)
   133  
   134  	assert.NoError(t, setValueGRPC(clients.KeyValueGRPCClient, clients.ContextWrapper, "foo", "barGRPC"))
   135  	value, err = getValueGRPC(clients.KeyValueGRPCClient, clients.ContextWrapper, "foo")
   136  	assert.NoError(t, err)
   137  	assert.Equal(t, "barGRPC", value)
   138  
   139  	assert.NoError(t, setValue(clients.KeyValueYARPCClient, "foo", ""))
   140  	_, err = getValue(clients.KeyValueYARPCClient, "foo")
   141  	assert.Error(t, err)
   142  
   143  	assert.NoError(t, setValue(clients.KeyValueYARPCClient, "foo", "baz"))
   144  	assert.NoError(t, setValue(clients.KeyValueYARPCClient, "baz", "bat"))
   145  	value, err = getValue(clients.KeyValueYARPCClient, "foo")
   146  	assert.NoError(t, err)
   147  	assert.Equal(t, "baz", value)
   148  	value, err = getValue(clients.KeyValueYARPCClient, "baz")
   149  	assert.NoError(t, err)
   150  	assert.Equal(t, "bat", value)
   151  
   152  	contextWrapper := clients.ContextWrapper
   153  	streamOptions := make([]yarpc.CallOption, 0, expectedStreamingHeaders.Len())
   154  	for k, v := range expectedStreamingHeaders.Items() {
   155  		streamOptions = append(streamOptions, yarpc.WithHeader(k, v))
   156  		contextWrapper = contextWrapper.WithHeader(k, v)
   157  	}
   158  
   159  	messages := []string{"foo", "bar", "baz"}
   160  	gotMessages, err := echoOut(clients.FooYARPCClient, messages, streamOptions...)
   161  	assert.NoError(t, err)
   162  	assert.Equal(t, messages, gotMessages)
   163  
   164  	gotMessages, err = echoIn(clients.FooYARPCClient, "foo", 3, streamOptions...)
   165  	assert.NoError(t, err)
   166  	assert.Equal(t, []string{"foo", "foo", "foo"}, gotMessages)
   167  
   168  	gotMessages, err = echoBoth(clients.FooYARPCClient, "foo", 2, 2, streamOptions...)
   169  	assert.NoError(t, err)
   170  	assert.Equal(t, []string{"foo", "foo", "foo", "foo"}, gotMessages)
   171  
   172  	gotMessages, err = echoOutGRPC(clients.FooGRPCClient, contextWrapper, messages)
   173  	assert.NoError(t, err)
   174  	assert.Equal(t, messages, gotMessages)
   175  
   176  	gotMessages, err = echoInGRPC(clients.FooGRPCClient, contextWrapper, "foo", 3)
   177  	assert.NoError(t, err)
   178  	assert.Equal(t, []string{"foo", "foo", "foo"}, gotMessages)
   179  
   180  	gotMessages, err = echoBothGRPC(clients.FooGRPCClient, contextWrapper, "foo", 2, 2)
   181  	assert.NoError(t, err)
   182  	assert.Equal(t, []string{"foo", "foo", "foo", "foo"}, gotMessages)
   183  }
   184  
   185  func getValue(keyValueYARPCClient examplepb.KeyValueYARPCClient, key string, options ...yarpc.CallOption) (string, error) {
   186  	ctx, cancel := context.WithTimeout(context.Background(), testtime.Second)
   187  	defer cancel()
   188  	response, err := keyValueYARPCClient.GetValue(ctx, &examplepb.GetValueRequest{Key: key}, options...)
   189  	if response != nil {
   190  		return response.Value, err
   191  	}
   192  	return "", err
   193  }
   194  
   195  func setValue(keyValueYARPCClient examplepb.KeyValueYARPCClient, key string, value string, options ...yarpc.CallOption) error {
   196  	ctx, cancel := context.WithTimeout(context.Background(), testtime.Second)
   197  	defer cancel()
   198  	_, err := keyValueYARPCClient.SetValue(ctx, &examplepb.SetValueRequest{Key: key, Value: value}, options...)
   199  	return err
   200  }
   201  
   202  func getValueGRPC(keyValueGRPCClient examplepb.KeyValueClient, contextWrapper *grpcctx.ContextWrapper, key string) (string, error) {
   203  	ctx, cancel := context.WithTimeout(context.Background(), testtime.Second)
   204  	defer cancel()
   205  	response, err := keyValueGRPCClient.GetValue(contextWrapper.Wrap(ctx), &examplepb.GetValueRequest{Key: key})
   206  	if response != nil {
   207  		return response.Value, err
   208  	}
   209  	return "", err
   210  }
   211  
   212  func setValueGRPC(keyValueGRPCClient examplepb.KeyValueClient, contextWrapper *grpcctx.ContextWrapper, key string, value string) error {
   213  	ctx, cancel := context.WithTimeout(context.Background(), testtime.Second)
   214  	defer cancel()
   215  	_, err := keyValueGRPCClient.SetValue(contextWrapper.Wrap(ctx), &examplepb.SetValueRequest{Key: key, Value: value})
   216  	return err
   217  }
   218  
   219  func echoOut(fooYARPCClient examplepb.FooYARPCClient, messages []string, options ...yarpc.CallOption) ([]string, error) {
   220  	ctx, cancel := context.WithTimeout(context.Background(), testtime.Second)
   221  	defer cancel()
   222  	client, err := fooYARPCClient.EchoOut(ctx, options...)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	for _, message := range messages {
   227  		if err := client.Send(&examplepb.EchoOutRequest{Message: message}); err != nil {
   228  			return nil, err
   229  		}
   230  	}
   231  	response, err := client.CloseAndRecv()
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	return response.AllMessages, nil
   236  }
   237  
   238  func echoIn(fooYARPCClient examplepb.FooYARPCClient, message string, numResponses int, options ...yarpc.CallOption) ([]string, error) {
   239  	ctx, cancel := context.WithTimeout(context.Background(), testtime.Second)
   240  	defer cancel()
   241  	client, err := fooYARPCClient.EchoIn(ctx, &examplepb.EchoInRequest{Message: message, NumResponses: int64(numResponses)}, options...)
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  	var messages []string
   246  	for response, err := client.Recv(); err != io.EOF; response, err = client.Recv() {
   247  		if err != nil {
   248  			return nil, err
   249  		}
   250  		messages = append(messages, response.Message)
   251  	}
   252  	return messages, nil
   253  }
   254  
   255  func echoBoth(fooYARPCClient examplepb.FooYARPCClient, message string, numResponses int, count int, options ...yarpc.CallOption) ([]string, error) {
   256  	ctx, cancel := context.WithTimeout(context.Background(), testtime.Second)
   257  	defer cancel()
   258  	client, err := fooYARPCClient.EchoBoth(ctx, options...)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	var messages []string
   264  	var recvErr error
   265  	done := make(chan struct{})
   266  	go func() {
   267  		for response, err := client.Recv(); err != io.EOF; response, err = client.Recv() {
   268  			if err != nil {
   269  				recvErr = err
   270  				break
   271  			}
   272  			messages = append(messages, response.Message)
   273  		}
   274  		close(done)
   275  	}()
   276  
   277  	for i := 0; i < count; i++ {
   278  		if err := client.Send(&examplepb.EchoBothRequest{Message: message, NumResponses: int64(numResponses)}); err != nil {
   279  			return nil, err
   280  		}
   281  	}
   282  	if err := client.CloseSend(); err != nil {
   283  		return nil, err
   284  	}
   285  
   286  	<-done
   287  	return messages, recvErr
   288  }
   289  
   290  func echoOutGRPC(fooClient examplepb.FooClient, contextWrapper *grpcctx.ContextWrapper, messages []string) ([]string, error) {
   291  	client, err := fooClient.EchoOut(contextWrapper.Wrap(context.Background()))
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  	for _, message := range messages {
   296  		if err := client.Send(&examplepb.EchoOutRequest{Message: message}); err != nil {
   297  			return nil, err
   298  		}
   299  	}
   300  	response, err := client.CloseAndRecv()
   301  	if err != nil {
   302  		return nil, err
   303  	}
   304  	return response.AllMessages, nil
   305  }
   306  
   307  func echoInGRPC(fooClient examplepb.FooClient, contextWrapper *grpcctx.ContextWrapper, message string, numResponses int) ([]string, error) {
   308  	client, err := fooClient.EchoIn(contextWrapper.Wrap(context.Background()), &examplepb.EchoInRequest{Message: message, NumResponses: int64(numResponses)})
   309  	if err != nil {
   310  		return nil, err
   311  	}
   312  	var messages []string
   313  	for response, err := client.Recv(); err != io.EOF; response, err = client.Recv() {
   314  		if err != nil {
   315  			return nil, err
   316  		}
   317  		messages = append(messages, response.Message)
   318  	}
   319  	return messages, nil
   320  }
   321  
   322  func echoBothGRPC(fooClient examplepb.FooClient, contextWrapper *grpcctx.ContextWrapper, message string, numResponses int, count int) ([]string, error) {
   323  	client, err := fooClient.EchoBoth(contextWrapper.Wrap(context.Background()))
   324  	if err != nil {
   325  		return nil, err
   326  	}
   327  
   328  	var messages []string
   329  	var recvErr error
   330  	done := make(chan struct{})
   331  	go func() {
   332  		for response, err := client.Recv(); err != io.EOF; response, err = client.Recv() {
   333  			if err != nil {
   334  				recvErr = err
   335  				break
   336  			}
   337  			messages = append(messages, response.Message)
   338  		}
   339  		close(done)
   340  	}()
   341  
   342  	for i := 0; i < count; i++ {
   343  		if err := client.Send(&examplepb.EchoBothRequest{Message: message, NumResponses: int64(numResponses)}); err != nil {
   344  			return nil, err
   345  		}
   346  	}
   347  	if err := client.CloseSend(); err != nil {
   348  		return nil, err
   349  	}
   350  
   351  	<-done
   352  	return messages, recvErr
   353  }