go.uber.org/yarpc@v1.72.1/x/yarpctest/roundtrip_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 yarpctest
    22  
    23  import (
    24  	"context"
    25  	"errors"
    26  	"testing"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  	"go.uber.org/yarpc/api/middleware"
    31  	"go.uber.org/yarpc/api/transport"
    32  	"go.uber.org/yarpc/internal/testtime"
    33  	"go.uber.org/yarpc/yarpcerrors"
    34  )
    35  
    36  func TestServiceRouting(t *testing.T) {
    37  	p := NewPortProvider(t)
    38  	tests := []struct {
    39  		name     string
    40  		services Lifecycle
    41  		requests Action
    42  	}{
    43  		{
    44  			name: "http to http request",
    45  			services: Lifecycles(
    46  				HTTPService(
    47  					Name("myservice"),
    48  					p.NamedPort("1"),
    49  					Proc(Name("echo"), EchoHandler()),
    50  				),
    51  			),
    52  			requests: ConcurrentAction(
    53  				RepeatAction(
    54  					HTTPRequest(
    55  						p.NamedPort("1"),
    56  						GiveTimeout(testtime.Second),
    57  						Body("test body"),
    58  						Service("myservice"),
    59  						Procedure("echo"),
    60  						WantRespBody("test body"),
    61  					),
    62  					10,
    63  				),
    64  				3,
    65  			),
    66  		},
    67  		{
    68  			name: "tchannel to tchannel request",
    69  			services: Lifecycles(
    70  				TChannelService(
    71  					Name("myservice"),
    72  					p.NamedPort("2"),
    73  					Proc(Name("echo"), EchoHandler()),
    74  				),
    75  			),
    76  			requests: ConcurrentAction(
    77  				RepeatAction(
    78  					TChannelRequest(
    79  						p.NamedPort("2"),
    80  						GiveTimeout(testtime.Second),
    81  						Body("test body"),
    82  						Service("myservice"),
    83  						Procedure("echo"),
    84  						WantRespBody("test body"),
    85  					),
    86  					10,
    87  				),
    88  				3,
    89  			),
    90  		},
    91  		{
    92  			name: "grpc to grpc request",
    93  			services: Lifecycles(
    94  				GRPCService(
    95  					Name("myservice"),
    96  					p.NamedPort("3"),
    97  					Proc(Name("echo"), EchoHandler()),
    98  				),
    99  			),
   100  			requests: ConcurrentAction(
   101  				RepeatAction(
   102  					GRPCRequest(
   103  						p.NamedPort("3"),
   104  						GiveTimeout(testtime.Second),
   105  						Body("test body"),
   106  						Service("myservice"),
   107  						Procedure("echo"),
   108  						WantRespBody("test body"),
   109  					),
   110  					10,
   111  				),
   112  				3,
   113  			),
   114  		},
   115  		{
   116  			name: "response errors",
   117  			services: Lifecycles(
   118  				HTTPService(
   119  					Name("myservice"),
   120  					p.NamedPort("4-http"),
   121  					Proc(
   122  						Name("error"),
   123  						ErrorHandler(
   124  							errors.New("error from myservice"),
   125  						),
   126  					),
   127  				),
   128  				TChannelService(
   129  					Name("myotherservice"),
   130  					p.NamedPort("4-tch"),
   131  					Proc(Name("error"), ErrorHandler(errors.New("error from myotherservice"))),
   132  				),
   133  				GRPCService(
   134  					Name("myotherservice2"),
   135  					p.NamedPort("4-grpc"),
   136  					Proc(Name("error"), ErrorHandler(errors.New("error from myotherservice2"))),
   137  				),
   138  			),
   139  			requests: Actions(
   140  				HTTPRequest(
   141  					p.NamedPort("4-http"),
   142  					Service("myservice"),
   143  					Procedure("error"),
   144  					WantError("error from myservice"),
   145  				),
   146  				TChannelRequest(
   147  					p.NamedPort("4-tch"),
   148  					Service("myotherservice"),
   149  					Procedure("error"),
   150  					WantError("error from myotherservice"),
   151  				),
   152  				GRPCRequest(
   153  					p.NamedPort("4-grpc"),
   154  					Service("myotherservice2"),
   155  					Procedure("error"),
   156  					WantError("error from myotherservice2"),
   157  				),
   158  			),
   159  		},
   160  		{
   161  			name: "ordered requests",
   162  			services: Lifecycles(
   163  				HTTPService(
   164  					Name("myservice"),
   165  					p.NamedPort("5"),
   166  					Proc(
   167  						Name("proc"),
   168  						OrderedRequestHandler(
   169  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   170  							StaticHandler("success"),
   171  							EchoHandlerWithPrefix("echo: "),
   172  							EchoHandler(),
   173  						),
   174  					),
   175  				),
   176  			),
   177  			requests: Actions(
   178  				HTTPRequest(
   179  					p.NamedPort("5"),
   180  					Service("myservice"),
   181  					Procedure("proc"),
   182  					ShardKey("ignoreme"),
   183  					WantError(yarpcerrors.InternalErrorf("internal error").Error()),
   184  				),
   185  				HTTPRequest(
   186  					p.NamedPort("5"),
   187  					Service("myservice"),
   188  					Procedure("proc"),
   189  					WantRespBody("success"),
   190  				),
   191  				HTTPRequest(
   192  					p.NamedPort("5"),
   193  					Service("myservice"),
   194  					Procedure("proc"),
   195  					Body("hello"),
   196  					WantRespBody("echo: hello"),
   197  				),
   198  				HTTPRequest(
   199  					p.NamedPort("5"),
   200  					Service("myservice"),
   201  					Procedure("proc"),
   202  					GiveAndWantLargeBodyIsEchoed(1<<17),
   203  				),
   204  			),
   205  		},
   206  		{
   207  			name: "ordered request headers",
   208  			services: Lifecycles(
   209  				HTTPService(
   210  					Name("myservice"),
   211  					p.NamedPort("6"),
   212  					Proc(
   213  						Name("proc"),
   214  						OrderedRequestHandler(
   215  							ErrorHandler(
   216  								yarpcerrors.InternalErrorf("internal error"),
   217  								WantHeader("key1", "val1"),
   218  								WantHeader("key2", "val2"),
   219  								WithHeader("resp_key1", "resp_val1"),
   220  								WithHeader("resp_key2", "resp_val2"),
   221  							),
   222  							StaticHandler(
   223  								"success",
   224  								WantHeader("successKey", "successValue"),
   225  								WithHeader("responseKey", "responseValue"),
   226  							),
   227  						),
   228  					),
   229  				),
   230  			),
   231  			requests: Actions(
   232  				HTTPRequest(
   233  					p.NamedPort("6"),
   234  					Service("myservice"),
   235  					Procedure("proc"),
   236  					ShardKey("ignoreme"),
   237  					WithHeader("key1", "val1"),
   238  					WithHeader("key2", "val2"),
   239  					WantError(yarpcerrors.InternalErrorf("internal error").Error()),
   240  				),
   241  				HTTPRequest(
   242  					p.NamedPort("6"),
   243  					Service("myservice"),
   244  					Procedure("proc"),
   245  					WithHeader("successKey", "successValue"),
   246  					WantRespBody("success"),
   247  					WantHeader("responseKey", "responseValue"),
   248  				),
   249  			),
   250  		},
   251  		{
   252  			name: "hardcoded peer",
   253  			services: Lifecycles(
   254  				TChannelService(
   255  					Name("myservice"),
   256  					Port(54321),
   257  					Proc(Name("echo"), EchoHandler()),
   258  				),
   259  			),
   260  			requests: ConcurrentAction(
   261  				RepeatAction(
   262  					TChannelRequest(
   263  						Port(54321),
   264  						Body("test body"),
   265  						Service("myservice"),
   266  						Procedure("echo"),
   267  						WantRespBody("test body"),
   268  					),
   269  					10,
   270  				),
   271  				3,
   272  			),
   273  		},
   274  		{
   275  			name: "hardcoded peer (same as above, testing reuse)",
   276  			services: Lifecycles(
   277  				TChannelService(
   278  					Name("myservice"),
   279  					Port(54321),
   280  					Proc(Name("echo"), EchoHandler()),
   281  				),
   282  			),
   283  			requests: ConcurrentAction(
   284  				RepeatAction(
   285  					TChannelRequest(
   286  						Port(54321),
   287  						Body("test body"),
   288  						Service("myservice"),
   289  						Procedure("echo"),
   290  						WantRespBody("test body"),
   291  					),
   292  					10,
   293  				),
   294  				3,
   295  			),
   296  		},
   297  		{
   298  			name: "HTTP request retry error",
   299  			services: Lifecycles(
   300  				HTTPService(
   301  					Name("myservice"),
   302  					p.NamedPort("7"),
   303  					Proc(
   304  						Name("proc"),
   305  						OrderedRequestHandler(
   306  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   307  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   308  							StaticHandler("success"),
   309  						),
   310  					),
   311  				),
   312  			),
   313  			requests: Actions(
   314  				HTTPRequest(
   315  					p.NamedPort("7"),
   316  					Service("myservice"),
   317  					Procedure("proc"),
   318  					WantError(yarpcerrors.InternalErrorf("internal error").Error()),
   319  					Retry(1, 10*testtime.Millisecond),
   320  				),
   321  			),
   322  		},
   323  		{
   324  			name: "HTTP request retry success",
   325  			services: Lifecycles(
   326  				HTTPService(
   327  					Name("myservice"),
   328  					p.NamedPort("8"),
   329  					Proc(
   330  						Name("proc"),
   331  						OrderedRequestHandler(
   332  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   333  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   334  							StaticHandler("success"),
   335  						),
   336  					),
   337  				),
   338  			),
   339  			requests: Actions(
   340  				HTTPRequest(
   341  					p.NamedPort("8"),
   342  					Service("myservice"),
   343  					Procedure("proc"),
   344  					WantRespBody("success"),
   345  					Retry(2, 10*testtime.Millisecond),
   346  				),
   347  			),
   348  		},
   349  		{
   350  			name: "TChannel request retry error",
   351  			services: Lifecycles(
   352  				TChannelService(
   353  					Name("myservice"),
   354  					p.NamedPort("9"),
   355  					Proc(
   356  						Name("proc"),
   357  						OrderedRequestHandler(
   358  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   359  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   360  							StaticHandler("success"),
   361  						),
   362  					),
   363  				),
   364  			),
   365  			requests: Actions(
   366  				TChannelRequest(
   367  					p.NamedPort("9"),
   368  					Service("myservice"),
   369  					Procedure("proc"),
   370  					WantError(yarpcerrors.InternalErrorf("internal error").Error()),
   371  					Retry(1, 10*testtime.Millisecond),
   372  				),
   373  			),
   374  		},
   375  		{
   376  			name: "TChannel request retry success",
   377  			services: Lifecycles(
   378  				TChannelService(
   379  					Name("myservice"),
   380  					p.NamedPort("10"),
   381  					Proc(
   382  						Name("proc"),
   383  						OrderedRequestHandler(
   384  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   385  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   386  							StaticHandler("success"),
   387  						),
   388  					),
   389  				),
   390  			),
   391  			requests: Actions(
   392  				TChannelRequest(
   393  					p.NamedPort("10"),
   394  					Service("myservice"),
   395  					Procedure("proc"),
   396  					WantRespBody("success"),
   397  					Retry(2, 10*testtime.Millisecond),
   398  				),
   399  			),
   400  		},
   401  		{
   402  			name: "GRPC request retry error",
   403  			services: Lifecycles(
   404  				GRPCService(
   405  					Name("myservice"),
   406  					p.NamedPort("11"),
   407  					Proc(
   408  						Name("proc"),
   409  						OrderedRequestHandler(
   410  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   411  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   412  							StaticHandler("success"),
   413  						),
   414  					),
   415  				),
   416  			),
   417  			requests: Actions(
   418  				GRPCRequest(
   419  					p.NamedPort("11"),
   420  					Service("myservice"),
   421  					Procedure("proc"),
   422  					WantError(yarpcerrors.InternalErrorf("internal error").Error()),
   423  					Retry(1, 10*testtime.Millisecond),
   424  				),
   425  			),
   426  		},
   427  		{
   428  			name: "GRPC request retry success",
   429  			services: Lifecycles(
   430  				GRPCService(
   431  					Name("myservice"),
   432  					p.NamedPort("12"),
   433  					Proc(
   434  						Name("proc"),
   435  						OrderedRequestHandler(
   436  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   437  							ErrorHandler(yarpcerrors.InternalErrorf("internal error")),
   438  							StaticHandler("success"),
   439  						),
   440  					),
   441  				),
   442  			),
   443  			requests: Actions(
   444  				GRPCRequest(
   445  					p.NamedPort("12"),
   446  					Service("myservice"),
   447  					Procedure("proc"),
   448  					WantRespBody("success"),
   449  					Retry(2, 10*testtime.Millisecond),
   450  				),
   451  			),
   452  		},
   453  	}
   454  
   455  	for _, tt := range tests {
   456  		t.Run(tt.name, func(t *testing.T) {
   457  			require.NoError(t, tt.services.Start(t))
   458  			defer func() { require.NoError(t, tt.services.Stop(t)) }()
   459  			tt.requests.Run(t)
   460  		})
   461  	}
   462  }
   463  
   464  func TestUnaryOutboundMiddleware(t *testing.T) {
   465  	p := NewPortProvider(t)
   466  
   467  	const (
   468  		service            = "service"
   469  		correctProcedure   = "correct-procedure"
   470  		incorrectProcedure = "inccorect"
   471  	)
   472  
   473  	mw := middleware.UnaryOutboundFunc(
   474  		func(ctx context.Context, req *transport.Request, next transport.UnaryOutbound) (*transport.Response, error) {
   475  			// fix procedure name
   476  			req.Procedure = correctProcedure
   477  			return next.Call(ctx, req)
   478  		})
   479  
   480  	tests := []struct {
   481  		name    string
   482  		service Lifecycle
   483  		request Action
   484  	}{
   485  		{
   486  			name: "HTTP",
   487  			service: HTTPService(
   488  				Name(service),
   489  				Proc(Name(correctProcedure), EchoHandler()),
   490  				p.NamedPort("http"),
   491  			),
   492  			request: HTTPRequest(
   493  				Service(service),
   494  				Procedure(incorrectProcedure),
   495  				UnaryOutboundMiddleware(mw),
   496  				p.NamedPort("http"),
   497  			),
   498  		},
   499  		{
   500  			name: "TChannel",
   501  			service: TChannelService(
   502  				Name(service),
   503  				Proc(Name(correctProcedure), EchoHandler()),
   504  				p.NamedPort("TChannel"),
   505  			),
   506  			request: TChannelRequest(
   507  				Service(service),
   508  				Procedure(incorrectProcedure),
   509  				UnaryOutboundMiddleware(mw),
   510  				p.NamedPort("TChannel"),
   511  			),
   512  		},
   513  		{
   514  			name: "gRPC",
   515  			service: GRPCService(
   516  				Name(service),
   517  				Proc(Name(correctProcedure), EchoHandler()),
   518  				p.NamedPort("grpc"),
   519  			),
   520  			request: GRPCRequest(
   521  				Service(service),
   522  				Procedure(incorrectProcedure),
   523  				UnaryOutboundMiddleware(mw),
   524  				p.NamedPort("grpc"),
   525  			),
   526  		},
   527  	}
   528  
   529  	for _, tt := range tests {
   530  		t.Run(tt.name, func(t *testing.T) {
   531  			require.NoError(t, tt.service.Start(t))
   532  			defer func() { assert.NoError(t, tt.service.Stop(t)) }()
   533  			tt.request.Run(t)
   534  		})
   535  	}
   536  }