go.uber.org/yarpc@v1.72.1/transport/grpc/stream_integration_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 grpc_test
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"testing"
    28  
    29  	"github.com/gogo/protobuf/types"
    30  	"github.com/stretchr/testify/require"
    31  	"go.uber.org/yarpc/api/peer"
    32  	"go.uber.org/yarpc/encoding/protobuf"
    33  	"go.uber.org/yarpc/peer/direct"
    34  	"go.uber.org/yarpc/transport/grpc"
    35  	. "go.uber.org/yarpc/x/yarpctest"
    36  	"go.uber.org/yarpc/yarpcerrors"
    37  )
    38  
    39  func TestStreaming(t *testing.T) {
    40  	newDirectChooser := func(id peer.Identifier, transport peer.Transport) (peer.Chooser, error) {
    41  		trans, ok := transport.(*grpc.Transport)
    42  		if !ok {
    43  			return nil, fmt.Errorf("transport was not a grpc.Transport")
    44  		}
    45  		return direct.New(direct.Configuration{}, trans.NewDialer())
    46  	}
    47  	protoerr := protobuf.NewError(yarpcerrors.CodeAborted, "test error",
    48  		protobuf.WithErrorDetails(&types.StringValue{Value: "val"}))
    49  	p := NewPortProvider(t)
    50  	tests := []struct {
    51  		name     string
    52  		services Lifecycle
    53  		requests Action
    54  	}{
    55  		{
    56  			name: "stream requests",
    57  			services: Lifecycles(
    58  				GRPCService(
    59  					Name("myservice"),
    60  					p.NamedPort("1"),
    61  					Proc(
    62  						Name("proc"),
    63  						EchoStreamHandler(),
    64  					),
    65  				),
    66  			),
    67  			requests: ConcurrentAction(
    68  				RepeatAction(
    69  					GRPCStreamRequest(
    70  						p.NamedPort("1"),
    71  						Service("myservice"),
    72  						Procedure("proc"),
    73  						ClientStreamActions(
    74  							SendStreamMsg("test"),
    75  							RecvStreamMsg("test"),
    76  							SendStreamMsg("test2"),
    77  							RecvStreamMsg("test2"),
    78  							CloseStream(),
    79  						),
    80  					),
    81  					10,
    82  				),
    83  				3,
    84  			),
    85  		},
    86  		{
    87  			name: "stream close from client",
    88  			services: Lifecycles(
    89  				GRPCService(
    90  					Name("myservice"),
    91  					p.NamedPort("2"),
    92  					Proc(
    93  						Name("proc"),
    94  						OrderedStreamHandler(
    95  							RecvStreamMsg("test"),
    96  							SendStreamMsg("test1"),
    97  							RecvStreamMsg("test2"),
    98  							SendStreamMsg("test3"),
    99  							RecvStreamErr(io.EOF.Error()),
   100  							SendStreamMsg("test4"),
   101  							StreamHandlerError(io.EOF),
   102  						),
   103  					),
   104  				),
   105  			),
   106  			requests: Actions(
   107  				GRPCStreamRequest(
   108  					p.NamedPort("2"),
   109  					Service("myservice"),
   110  					Procedure("proc"),
   111  					ClientStreamActions(
   112  						SendStreamMsg("test"),
   113  						RecvStreamMsg("test1"),
   114  						SendStreamMsg("test2"),
   115  						RecvStreamMsg("test3"),
   116  						CloseStream(),
   117  						RecvStreamMsg("test4"),
   118  					),
   119  				),
   120  			),
   121  		},
   122  		{
   123  			name: "stream close from server",
   124  			services: Lifecycles(
   125  				GRPCService(
   126  					Name("myservice"),
   127  					p.NamedPort("3"),
   128  					Proc(
   129  						Name("proc"),
   130  						OrderedStreamHandler(
   131  							RecvStreamMsg("test"),
   132  							SendStreamMsg("test1"),
   133  							RecvStreamMsg("test2"),
   134  							SendStreamMsg("test3"),
   135  						), // End of Stream
   136  					),
   137  				),
   138  			),
   139  			requests: Actions(
   140  				GRPCStreamRequest(
   141  					p.NamedPort("3"),
   142  					Service("myservice"),
   143  					Procedure("proc"),
   144  					ClientStreamActions(
   145  						SendStreamMsg("test"),
   146  						RecvStreamMsg("test1"),
   147  						SendStreamMsg("test2"),
   148  						RecvStreamMsg("test3"),
   149  						RecvStreamErr(io.EOF.Error()),
   150  					),
   151  				),
   152  			),
   153  		},
   154  		{
   155  			name: "stream close from server with error",
   156  			services: Lifecycles(
   157  				GRPCService(
   158  					Name("myservice"),
   159  					p.NamedPort("4"),
   160  					Proc(
   161  						Name("proc"),
   162  						OrderedStreamHandler(
   163  							RecvStreamMsg("test"),
   164  							SendStreamMsg("test1"),
   165  							RecvStreamMsg("test2"),
   166  							SendStreamMsg("test3"),
   167  							StreamHandlerError(yarpcerrors.InternalErrorf("myerroooooor")),
   168  						),
   169  					),
   170  				),
   171  			),
   172  			requests: Actions(
   173  				GRPCStreamRequest(
   174  					p.NamedPort("4"),
   175  					Service("myservice"),
   176  					Procedure("proc"),
   177  					ClientStreamActions(
   178  						SendStreamMsg("test"),
   179  						RecvStreamMsg("test1"),
   180  						SendStreamMsg("test2"),
   181  						RecvStreamMsg("test3"),
   182  						RecvStreamErr(yarpcerrors.InternalErrorf("myerroooooor").Error()),
   183  					),
   184  				),
   185  			),
   186  		},
   187  		{
   188  			name: "stream recv after close",
   189  			services: Lifecycles(
   190  				GRPCService(
   191  					Name("myservice"),
   192  					p.NamedPort("5"),
   193  					Proc(
   194  						Name("proc"),
   195  						OrderedStreamHandler(
   196  							RecvStreamMsg("test"),
   197  							RecvStreamErr(io.EOF.Error()),
   198  							SendStreamMsg("test1"),
   199  							SendStreamMsg("test2"),
   200  							SendStreamMsg("test3"),
   201  							StreamHandlerError(yarpcerrors.InternalErrorf("test")),
   202  						),
   203  					),
   204  				),
   205  			),
   206  			requests: Actions(
   207  				GRPCStreamRequest(
   208  					p.NamedPort("5"),
   209  					Service("myservice"),
   210  					Procedure("proc"),
   211  					ClientStreamActions(
   212  						SendStreamMsg("test"),
   213  						CloseStream(),
   214  						SendStreamMsgAndExpectError("lala", io.EOF.Error()),
   215  						RecvStreamMsg("test1"),
   216  						RecvStreamMsg("test2"),
   217  						RecvStreamMsg("test3"),
   218  						RecvStreamErr(yarpcerrors.InternalErrorf("test").Error()),
   219  					),
   220  				),
   221  			),
   222  		},
   223  		{
   224  			name: "stream header test",
   225  			services: Lifecycles(
   226  				GRPCService(
   227  					Name("myservice"),
   228  					p.NamedPort("6"),
   229  					Proc(
   230  						Name("proc"),
   231  						OrderedStreamHandler(
   232  							StreamSendHeaders(map[string]string{"key": "value"}),
   233  							WantHeader("req_key", "req_val"),
   234  							WantHeader("req_key2", "req_val2"),
   235  							RecvStreamMsg("test"),
   236  						), // End of Stream
   237  					),
   238  				),
   239  			),
   240  			requests: Actions(
   241  				GRPCStreamRequest(
   242  					p.NamedPort("6"),
   243  					Service("myservice"),
   244  					Procedure("proc"),
   245  					WithHeader("req_key", "req_val"),
   246  					WithHeader("req_key2", "req_val2"),
   247  					ClientStreamActions(
   248  						WantHeaders(map[string]string{"key": "value"}),
   249  						SendStreamMsg("test"),
   250  						RecvStreamErr(io.EOF.Error()),
   251  					),
   252  				),
   253  			),
   254  		},
   255  		{
   256  			name: "stream invalid request",
   257  			services: Lifecycles(
   258  				GRPCService(
   259  					Name("myservice"),
   260  					p.NamedPort("7"),
   261  				),
   262  			),
   263  			requests: Actions(
   264  				GRPCStreamRequest(
   265  					p.NamedPort("7"),
   266  					Service("myservice"),
   267  					Procedure("proc"),
   268  					ClientStreamActions(
   269  						RecvStreamErr(yarpcerrors.UnimplementedErrorf("unrecognized procedure \"proc\" for service \"myservice\"").Error()),
   270  					),
   271  				),
   272  			),
   273  		},
   274  		{
   275  			name: "stream invalid client decode",
   276  			services: Lifecycles(
   277  				GRPCService(
   278  					Name("myservice"),
   279  					p.NamedPort("8"),
   280  				),
   281  			),
   282  			requests: Actions(
   283  				GRPCStreamRequest(
   284  					p.NamedPort("8"),
   285  					Service("myservice"),
   286  					Procedure("proc"),
   287  					ClientStreamActions(
   288  						SendStreamDecodeErrorAndExpectError(errors.New("nooooo"), "nooooo", "unknown"),
   289  					),
   290  				),
   291  			),
   292  		},
   293  		{
   294  			name: "stream invalid client decode yarpcerr",
   295  			services: Lifecycles(
   296  				GRPCService(
   297  					Name("myservice"),
   298  					p.NamedPort("9"),
   299  				),
   300  			),
   301  			requests: Actions(
   302  				GRPCStreamRequest(
   303  					p.NamedPort("9"),
   304  					Service("myservice"),
   305  					Procedure("proc"),
   306  					ClientStreamActions(
   307  						SendStreamDecodeErrorAndExpectError(yarpcerrors.InternalErrorf("test"), yarpcerrors.InternalErrorf("test").Error()),
   308  					),
   309  				),
   310  			),
   311  		},
   312  		{
   313  			// The direct chooser is rather unique in that it releases the peer in
   314  			// the onFinish function. Other choosers reuse the peer across calls and
   315  			// only release it as part of chooser.Stop(). This case ensures we don't
   316  			// call onFinish prematurely.
   317  			name: "single use chooser",
   318  			services: Lifecycles(
   319  				GRPCService(
   320  					Name("myservice"),
   321  					p.NamedPort("10"),
   322  					Proc(
   323  						Name("proc"),
   324  						EchoStreamHandler(),
   325  					),
   326  				),
   327  			),
   328  			requests: ConcurrentAction(
   329  				RepeatAction(
   330  					GRPCStreamRequest(
   331  						p.NamedPort("10"),
   332  						Service("myservice"),
   333  						Procedure("proc"),
   334  						ShardKey(fmt.Sprintf("127.0.0.1:%d", p.NamedPort("10").Port)),
   335  						Chooser(newDirectChooser),
   336  						ClientStreamActions(
   337  							SendStreamMsg("test"),
   338  							RecvStreamMsg("test"),
   339  							SendStreamMsg("test2"),
   340  							RecvStreamMsg("test2"),
   341  							CloseStream(),
   342  						),
   343  					),
   344  					10,
   345  				),
   346  				3,
   347  			),
   348  		},
   349  		{
   350  			name: "server invalid send read",
   351  			services: Lifecycles(
   352  				GRPCService(
   353  					Name("myservice"),
   354  					p.NamedPort("12"),
   355  					Proc(
   356  						Name("proc"),
   357  						OrderedStreamHandler(
   358  							SendStreamDecodeErrorAndExpectError(yarpcerrors.InternalErrorf("test"), yarpcerrors.InternalErrorf("test").Error()),
   359  						),
   360  					),
   361  				),
   362  			),
   363  			requests: Actions(
   364  				GRPCStreamRequest(
   365  					p.NamedPort("12"),
   366  					Service("myservice"),
   367  					Procedure("proc"),
   368  					ClientStreamActions(
   369  						RecvStreamErr(io.EOF.Error()),
   370  					),
   371  				),
   372  			),
   373  		},
   374  
   375  		{
   376  			name: "stream with error details",
   377  			services: Lifecycles(
   378  				GRPCService(
   379  					Name("myservice"),
   380  					p.NamedPort("13"),
   381  					Proc(
   382  						Name("proc"),
   383  						OrderedStreamHandler(
   384  							SendStreamMsg("test1"),
   385  							StreamHandlerError(protoerr),
   386  						),
   387  					),
   388  				),
   389  			),
   390  			requests: Actions(
   391  				GRPCStreamRequest(
   392  					p.NamedPort("13"),
   393  					Service("myservice"),
   394  					Procedure("proc"),
   395  					ClientStreamActions(
   396  						RecvStreamMsg("test1"),
   397  						RecvStreamErrInstance(yarpcerrors.FromError(protoerr)),
   398  					),
   399  				),
   400  			),
   401  		},
   402  	}
   403  
   404  	for _, tt := range tests {
   405  		t.Run(tt.name, func(t *testing.T) {
   406  			require.NoError(t, tt.services.Start(t))
   407  			tt.requests.Run(t)
   408  			require.NoError(t, tt.services.Stop(t))
   409  		})
   410  	}
   411  }