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 }