github.com/grpc-ecosystem/grpc-gateway/v2@v2.19.1/runtime/context_test.go (about) 1 package runtime_test 2 3 import ( 4 "context" 5 "encoding/base64" 6 "net/http" 7 "reflect" 8 "testing" 9 "time" 10 11 "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 12 "google.golang.org/grpc/metadata" 13 ) 14 15 const ( 16 emptyForwardMetaCount = 1 17 ) 18 19 func TestAnnotateContext_WorksWithEmpty(t *testing.T) { 20 ctx := context.Background() 21 expectedRPCName := "/example.Example/Example" 22 expectedHTTPPathPattern := "/v1" 23 request, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com/v1", nil) 24 if err != nil { 25 t.Fatalf("http.NewRequestWithContext(ctx, %q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) 26 } 27 request.Header.Add("Some-Irrelevant-Header", "some value") 28 annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) 29 if err != nil { 30 t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) 31 return 32 } 33 md, ok := metadata.FromOutgoingContext(annotated) 34 if !ok || len(md) != emptyForwardMetaCount { 35 t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount, md) 36 } 37 } 38 39 func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) { 40 ctx := context.Background() 41 expectedRPCName := "/example.Example/Example" 42 expectedHTTPPathPattern := "/v1" 43 request, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com/v1", nil) 44 if err != nil { 45 t.Fatalf("http.NewRequestWithContext(ctx, %q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) 46 } 47 request.Header.Add("Some-Irrelevant-Header", "some value") 48 request.Header.Add("Grpc-Metadata-FooBar", "Value1") 49 request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2") 50 request.Header.Add("Grpc-Metadata-foo-bAz", "Value3") 51 request.Header.Add("Authorization", "Token 1234567890") 52 annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) 53 if err != nil { 54 t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) 55 return 56 } 57 md, ok := metadata.FromOutgoingContext(annotated) 58 if got, want := len(md), emptyForwardMetaCount+4; !ok || got != want { 59 t.Errorf("metadata items in context = %d want %d: %v", got, want, md) 60 } 61 if got, want := md["foobar"], []string{"Value1"}; !reflect.DeepEqual(got, want) { 62 t.Errorf(`md["grpcgateway-foobar"] = %q; want %q`, got, want) 63 } 64 if got, want := md["foo-baz"], []string{"Value2", "Value3"}; !reflect.DeepEqual(got, want) { 65 t.Errorf(`md["grpcgateway-foo-baz"] = %q want %q`, got, want) 66 } 67 if got, want := md["grpcgateway-authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) { 68 t.Errorf(`md["grpcgateway-authorization"] = %q want %q`, got, want) 69 } 70 if got, want := md["authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) { 71 t.Errorf(`md["authorization"] = %q want %q`, got, want) 72 } 73 if m, ok := runtime.RPCMethod(annotated); !ok { 74 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 75 } else if m != expectedRPCName { 76 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 77 } 78 79 if m, ok := runtime.HTTPPathPattern(annotated); !ok { 80 t.Errorf("runtime.HTTPPathPattern(annotated) failed with no value; want %s", expectedHTTPPathPattern) 81 } else if m != expectedHTTPPathPattern { 82 t.Errorf("runtime.HTTPPathPattern(annotated) failed with %s; want %s", m, expectedHTTPPathPattern) 83 } 84 } 85 86 func TestAnnotateContext_ForwardGrpcBinaryMetadata(t *testing.T) { 87 ctx := context.Background() 88 expectedRPCName := "/example.Example/Example" 89 request, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com", nil) 90 if err != nil { 91 t.Fatalf("http.NewRequestWithContext(ctx, %q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) 92 } 93 94 binData := []byte("\x00test-binary-data") 95 request.Header.Add("Grpc-Metadata-Test-Bin", base64.StdEncoding.EncodeToString(binData)) 96 97 annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 98 if err != nil { 99 t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) 100 return 101 } 102 md, ok := metadata.FromOutgoingContext(annotated) 103 if !ok || len(md) != emptyForwardMetaCount+1 { 104 t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount+1, md) 105 } 106 if got, want := md["test-bin"], []string{string(binData)}; !reflect.DeepEqual(got, want) { 107 t.Errorf(`md["test-bin"] = %q want %q`, got, want) 108 } 109 if m, ok := runtime.RPCMethod(annotated); !ok { 110 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 111 } else if m != expectedRPCName { 112 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 113 } 114 } 115 116 func TestAnnotateContext_XForwardedFor(t *testing.T) { 117 ctx := context.Background() 118 expectedRPCName := "/example.Example/Example" 119 request, err := http.NewRequestWithContext(ctx, "GET", "http://bar.foo.example.com", nil) 120 if err != nil { 121 t.Fatalf("http.NewRequestWithContext(ctx, %q, %q, nil) failed with %v; want success", "GET", "http://bar.foo.example.com", err) 122 } 123 request.Header.Add("X-Forwarded-For", "192.0.2.100") // client 124 request.RemoteAddr = "192.0.2.200:12345" // proxy 125 126 annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 127 if err != nil { 128 t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) 129 return 130 } 131 md, ok := metadata.FromOutgoingContext(annotated) 132 if !ok || len(md) != emptyForwardMetaCount+1 { 133 t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount+1, md) 134 } 135 if got, want := md["x-forwarded-host"], []string{"bar.foo.example.com"}; !reflect.DeepEqual(got, want) { 136 t.Errorf(`md["host"] = %v; want %v`, got, want) 137 } 138 // Note: it must be in order client, proxy1, proxy2 139 if got, want := md["x-forwarded-for"], []string{"192.0.2.100, 192.0.2.200"}; !reflect.DeepEqual(got, want) { 140 t.Errorf(`md["x-forwarded-for"] = %v want %v`, got, want) 141 } 142 if m, ok := runtime.RPCMethod(annotated); !ok { 143 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 144 } else if m != expectedRPCName { 145 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 146 } 147 } 148 149 func TestAnnotateContext_SupportsTimeouts(t *testing.T) { 150 ctx := context.Background() 151 expectedRPCName := "/example.Example/Example" 152 request, err := http.NewRequestWithContext(ctx, "GET", "http://example.com", nil) 153 if err != nil { 154 t.Fatalf(`http.NewRequestWithContext(ctx, "GET", "http://example.com", nil) failed with %v; want success`, err) 155 } 156 annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 157 if err != nil { 158 t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) 159 return 160 } 161 if _, ok := annotated.Deadline(); ok { 162 // no deadline by default 163 t.Errorf("annotated.Deadline() = _, true; want _, false") 164 } 165 166 const acceptableError = 50 * time.Millisecond 167 runtime.DefaultContextTimeout = 10 * time.Second 168 annotated, err = runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 169 if err != nil { 170 t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) 171 return 172 } 173 deadline, ok := annotated.Deadline() 174 if !ok { 175 t.Errorf("annotated.Deadline() = _, false; want _, true") 176 } 177 if got, want := time.Until(deadline), runtime.DefaultContextTimeout; got-want > acceptableError || got-want < -acceptableError { 178 t.Errorf("time.Until(deadline) = %v; want %v; with error %v", got, want, acceptableError) 179 } 180 181 for _, spec := range []struct { 182 timeout string 183 want time.Duration 184 }{ 185 { 186 timeout: "17H", 187 want: 17 * time.Hour, 188 }, 189 { 190 timeout: "19M", 191 want: 19 * time.Minute, 192 }, 193 { 194 timeout: "23S", 195 want: 23 * time.Second, 196 }, 197 { 198 timeout: "1009m", 199 want: 1009 * time.Millisecond, 200 }, 201 { 202 timeout: "1000003u", 203 want: 1000003 * time.Microsecond, 204 }, 205 { 206 timeout: "100000007n", 207 want: 100000007 * time.Nanosecond, 208 }, 209 } { 210 request.Header.Set("Grpc-Timeout", spec.timeout) 211 annotated, err = runtime.AnnotateContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 212 if err != nil { 213 t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) 214 return 215 } 216 deadline, ok := annotated.Deadline() 217 if !ok { 218 t.Errorf("annotated.Deadline() = _, false; want _, true; timeout = %q", spec.timeout) 219 } 220 if got, want := time.Until(deadline), spec.want; got-want > acceptableError || got-want < -acceptableError { 221 t.Errorf("time.Until(deadline) = %v; want %v; with error %v; timeout= %q", got, want, acceptableError, spec.timeout) 222 } 223 if m, ok := runtime.RPCMethod(annotated); !ok { 224 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 225 } else if m != expectedRPCName { 226 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 227 } 228 } 229 } 230 func TestAnnotateContext_SupportsCustomAnnotators(t *testing.T) { 231 ctx := context.Background() 232 md1 := func(context.Context, *http.Request) metadata.MD { return metadata.New(map[string]string{"foo": "bar"}) } 233 md2 := func(context.Context, *http.Request) metadata.MD { return metadata.New(map[string]string{"baz": "qux"}) } 234 expected := metadata.New(map[string]string{"foo": "bar", "baz": "qux"}) 235 expectedRPCName := "/example.Example/Example" 236 request, err := http.NewRequestWithContext(ctx, "GET", "http://example.com", nil) 237 if err != nil { 238 t.Fatalf(`http.NewRequestWithContext(ctx, "GET", "http://example.com", nil) failed with %v; want success`, err) 239 } 240 annotated, err := runtime.AnnotateContext(ctx, runtime.NewServeMux(runtime.WithMetadata(md1), runtime.WithMetadata(md2)), request, expectedRPCName) 241 if err != nil { 242 t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err) 243 return 244 } 245 actual, _ := metadata.FromOutgoingContext(annotated) 246 for key, e := range expected { 247 if a, ok := actual[key]; !ok || !reflect.DeepEqual(e, a) { 248 t.Errorf("metadata.MD[%s] = %v; want %v", key, a, e) 249 } 250 } 251 if m, ok := runtime.RPCMethod(annotated); !ok { 252 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 253 } else if m != expectedRPCName { 254 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 255 } 256 } 257 258 func TestAnnotateIncomingContext_WorksWithEmpty(t *testing.T) { 259 ctx := context.Background() 260 expectedRPCName := "/example.Example/Example" 261 expectedHTTPPathPattern := "/v1" 262 request, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com/v1", nil) 263 if err != nil { 264 t.Fatalf("http.NewRequestWithContext(ctx, %q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) 265 } 266 request.Header.Add("Some-Irrelevant-Header", "some value") 267 annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) 268 if err != nil { 269 t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) 270 return 271 } 272 md, ok := metadata.FromIncomingContext(annotated) 273 if !ok || len(md) != emptyForwardMetaCount { 274 t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount, md) 275 } 276 if m, ok := runtime.RPCMethod(annotated); !ok { 277 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 278 } else if m != expectedRPCName { 279 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 280 } 281 } 282 283 func TestAnnotateIncomingContext_ForwardsGrpcMetadata(t *testing.T) { 284 ctx := context.Background() 285 expectedRPCName := "/example.Example/Example" 286 expectedHTTPPathPattern := "/v1" 287 request, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com/v1", nil) 288 if err != nil { 289 t.Fatalf("http.NewRequestWithContext(ctx, %q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) 290 } 291 request.Header.Add("Some-Irrelevant-Header", "some value") 292 request.Header.Add("Grpc-Metadata-FooBar", "Value1") 293 request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2") 294 request.Header.Add("Grpc-Metadata-foo-bAz", "Value3") 295 request.Header.Add("Authorization", "Token 1234567890") 296 annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName, runtime.WithHTTPPathPattern(expectedHTTPPathPattern)) 297 if err != nil { 298 t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) 299 return 300 } 301 md, ok := metadata.FromIncomingContext(annotated) 302 if got, want := len(md), emptyForwardMetaCount+4; !ok || got != want { 303 t.Errorf("metadata items in context = %d want %d: %v", got, want, md) 304 } 305 if got, want := md["foobar"], []string{"Value1"}; !reflect.DeepEqual(got, want) { 306 t.Errorf(`md["grpcgateway-foobar"] = %q; want %q`, got, want) 307 } 308 if got, want := md["foo-baz"], []string{"Value2", "Value3"}; !reflect.DeepEqual(got, want) { 309 t.Errorf(`md["grpcgateway-foo-baz"] = %q want %q`, got, want) 310 } 311 if got, want := md["grpcgateway-authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) { 312 t.Errorf(`md["grpcgateway-authorization"] = %q want %q`, got, want) 313 } 314 if got, want := md["authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) { 315 t.Errorf(`md["authorization"] = %q want %q`, got, want) 316 } 317 if m, ok := runtime.RPCMethod(annotated); !ok { 318 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 319 } else if m != expectedRPCName { 320 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 321 } 322 if m, ok := runtime.HTTPPathPattern(annotated); !ok { 323 t.Errorf("runtime.HTTPPathPattern(annotated) failed with no value; want %s", expectedHTTPPathPattern) 324 } else if m != expectedHTTPPathPattern { 325 t.Errorf("runtime.HTTPPathPattern(annotated) failed with %s; want %s", m, expectedHTTPPathPattern) 326 } 327 } 328 329 func TestAnnotateIncomingContext_ForwardGrpcBinaryMetadata(t *testing.T) { 330 ctx := context.Background() 331 expectedRPCName := "/example.Example/Example" 332 request, err := http.NewRequestWithContext(ctx, "GET", "http://www.example.com", nil) 333 if err != nil { 334 t.Fatalf("http.NewRequestWithContext(ctx, %q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err) 335 } 336 337 binData := []byte("\x00test-binary-data") 338 request.Header.Add("Grpc-Metadata-Test-Bin", base64.StdEncoding.EncodeToString(binData)) 339 340 annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 341 if err != nil { 342 t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) 343 return 344 } 345 md, ok := metadata.FromIncomingContext(annotated) 346 if !ok || len(md) != emptyForwardMetaCount+1 { 347 t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount+1, md) 348 } 349 if got, want := md["test-bin"], []string{string(binData)}; !reflect.DeepEqual(got, want) { 350 t.Errorf(`md["test-bin"] = %q want %q`, got, want) 351 } 352 if m, ok := runtime.RPCMethod(annotated); !ok { 353 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 354 } else if m != expectedRPCName { 355 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 356 } 357 } 358 359 func TestAnnotateIncomingContext_XForwardedFor(t *testing.T) { 360 ctx := context.Background() 361 expectedRPCName := "/example.Example/Example" 362 request, err := http.NewRequestWithContext(ctx, "GET", "http://bar.foo.example.com", nil) 363 if err != nil { 364 t.Fatalf("http.NewRequestWithContext(ctx, %q, %q, nil) failed with %v; want success", "GET", "http://bar.foo.example.com", err) 365 } 366 request.Header.Add("X-Forwarded-For", "192.0.2.100") // client 367 request.RemoteAddr = "192.0.2.200:12345" // proxy 368 369 annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 370 if err != nil { 371 t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) 372 return 373 } 374 md, ok := metadata.FromIncomingContext(annotated) 375 if !ok || len(md) != emptyForwardMetaCount+1 { 376 t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount+1, md) 377 } 378 if got, want := md["x-forwarded-host"], []string{"bar.foo.example.com"}; !reflect.DeepEqual(got, want) { 379 t.Errorf(`md["host"] = %v; want %v`, got, want) 380 } 381 // Note: it must be in order client, proxy1, proxy2 382 if got, want := md["x-forwarded-for"], []string{"192.0.2.100, 192.0.2.200"}; !reflect.DeepEqual(got, want) { 383 t.Errorf(`md["x-forwarded-for"] = %v want %v`, got, want) 384 } 385 if m, ok := runtime.RPCMethod(annotated); !ok { 386 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 387 } else if m != expectedRPCName { 388 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 389 } 390 } 391 392 func TestAnnotateIncomingContext_SupportsTimeouts(t *testing.T) { 393 // While run all test, TestAnnotateContext_SupportsTimeouts() will change the DefaultContextTimeout, so reset it to zero. 394 runtime.DefaultContextTimeout = 0 * time.Second 395 expectedRPCName := "/example.Example/Example" 396 ctx := context.Background() 397 request, err := http.NewRequestWithContext(ctx, "GET", "http://example.com", nil) 398 if err != nil { 399 t.Fatalf(`http.NewRequestWithContext(ctx, "GET", "http://example.com", nil) failed with %v; want success`, err) 400 } 401 annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 402 if err != nil { 403 t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) 404 return 405 } 406 if _, ok := annotated.Deadline(); ok { 407 // no deadline by default 408 t.Errorf("annotated.Deadline() = _, true; want _, false") 409 } 410 411 const acceptableError = 50 * time.Millisecond 412 runtime.DefaultContextTimeout = 10 * time.Second 413 annotated, err = runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 414 if err != nil { 415 t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) 416 return 417 } 418 deadline, ok := annotated.Deadline() 419 if !ok { 420 t.Errorf("annotated.Deadline() = _, false; want _, true") 421 } 422 if got, want := time.Until(deadline), runtime.DefaultContextTimeout; got-want > acceptableError || got-want < -acceptableError { 423 t.Errorf("time.Until(deadline) = %v; want %v; with error %v", got, want, acceptableError) 424 } 425 426 for _, spec := range []struct { 427 timeout string 428 want time.Duration 429 }{ 430 { 431 timeout: "17H", 432 want: 17 * time.Hour, 433 }, 434 { 435 timeout: "19M", 436 want: 19 * time.Minute, 437 }, 438 { 439 timeout: "23S", 440 want: 23 * time.Second, 441 }, 442 { 443 timeout: "1009m", 444 want: 1009 * time.Millisecond, 445 }, 446 { 447 timeout: "1000003u", 448 want: 1000003 * time.Microsecond, 449 }, 450 { 451 timeout: "100000007n", 452 want: 100000007 * time.Nanosecond, 453 }, 454 } { 455 request.Header.Set("Grpc-Timeout", spec.timeout) 456 annotated, err = runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(), request, expectedRPCName) 457 if err != nil { 458 t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) 459 return 460 } 461 deadline, ok := annotated.Deadline() 462 if !ok { 463 t.Errorf("annotated.Deadline() = _, false; want _, true; timeout = %q", spec.timeout) 464 } 465 if got, want := time.Until(deadline), spec.want; got-want > acceptableError || got-want < -acceptableError { 466 t.Errorf("time.Until(deadline) = %v; want %v; with error %v; timeout= %q", got, want, acceptableError, spec.timeout) 467 } 468 if m, ok := runtime.RPCMethod(annotated); !ok { 469 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 470 } else if m != expectedRPCName { 471 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 472 } 473 } 474 } 475 func TestAnnotateIncomingContext_SupportsCustomAnnotators(t *testing.T) { 476 ctx := context.Background() 477 md1 := func(context.Context, *http.Request) metadata.MD { return metadata.New(map[string]string{"foo": "bar"}) } 478 md2 := func(context.Context, *http.Request) metadata.MD { return metadata.New(map[string]string{"baz": "qux"}) } 479 expected := metadata.New(map[string]string{"foo": "bar", "baz": "qux"}) 480 expectedRPCName := "/example.Example/Example" 481 request, err := http.NewRequestWithContext(ctx, "GET", "http://example.com", nil) 482 if err != nil { 483 t.Fatalf(`http.NewRequestWithContext(ctx, "GET", "http://example.com", nil) failed with %v; want success`, err) 484 } 485 annotated, err := runtime.AnnotateIncomingContext(ctx, runtime.NewServeMux(runtime.WithMetadata(md1), runtime.WithMetadata(md2)), request, expectedRPCName) 486 if err != nil { 487 t.Errorf("runtime.AnnotateIncomingContext(ctx, %#v) failed with %v; want success", request, err) 488 return 489 } 490 actual, _ := metadata.FromIncomingContext(annotated) 491 for key, e := range expected { 492 if a, ok := actual[key]; !ok || !reflect.DeepEqual(e, a) { 493 t.Errorf("metadata.MD[%s] = %v; want %v", key, a, e) 494 } 495 } 496 if m, ok := runtime.RPCMethod(annotated); !ok { 497 t.Errorf("runtime.RPCMethod(annotated) failed with no value; want %s", expectedRPCName) 498 } else if m != expectedRPCName { 499 t.Errorf("runtime.RPCMethod(annotated) failed with %s; want %s", m, expectedRPCName) 500 } 501 }