github.com/grpc-ecosystem/grpc-gateway/v2@v2.19.1/examples/internal/integration/integration_test.go (about) 1 package integration_test 2 3 import ( 4 "bufio" 5 "bytes" 6 "context" 7 "encoding/base64" 8 "encoding/json" 9 "fmt" 10 "io" 11 "net/http" 12 "net/url" 13 "reflect" 14 "strconv" 15 "strings" 16 "sync" 17 "testing" 18 "time" 19 20 "github.com/google/go-cmp/cmp" 21 "github.com/grpc-ecosystem/grpc-gateway/v2/examples/internal/proto/examplepb" 22 "github.com/grpc-ecosystem/grpc-gateway/v2/examples/internal/proto/pathenum" 23 "github.com/grpc-ecosystem/grpc-gateway/v2/examples/internal/proto/sub" 24 "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 25 statuspb "google.golang.org/genproto/googleapis/rpc/status" 26 "google.golang.org/grpc/codes" 27 "google.golang.org/protobuf/encoding/protojson" 28 "google.golang.org/protobuf/proto" 29 "google.golang.org/protobuf/testing/protocmp" 30 "google.golang.org/protobuf/types/known/emptypb" 31 fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" 32 "google.golang.org/protobuf/types/known/structpb" 33 ) 34 35 var marshaler = &runtime.JSONPb{} 36 37 func TestEcho(t *testing.T) { 38 if testing.Short() { 39 t.Skip() 40 return 41 } 42 43 for _, apiPrefix := range []string{"v1", "v2"} { 44 t.Run(apiPrefix, func(t *testing.T) { 45 testEcho(t, 8088, apiPrefix, "application/json") 46 testEchoOneof(t, 8088, apiPrefix, "application/json") 47 testEchoOneof1(t, 8088, apiPrefix, "application/json") 48 testEchoOneof2(t, 8088, apiPrefix, "application/json") 49 testEchoPathParamOverwrite(t, 8088) 50 testEchoNested(t, 8088) 51 testEchoNestedOverride(t, 8088) 52 testEchoBody(t, 8088, apiPrefix, true) 53 testEchoBody(t, 8088, apiPrefix, false) 54 // Use SendHeader/SetTrailer without gRPC server https://github.com/grpc-ecosystem/grpc-gateway/issues/517#issuecomment-684625645 55 testEchoBody(t, 8089, apiPrefix, true) 56 testEchoBody(t, 8089, apiPrefix, false) 57 testEchoWithNonASCIIHeaderValues(t, 8088, apiPrefix) 58 testEchoWithInvalidHeaderKey(t, 8088, apiPrefix) 59 }) 60 } 61 } 62 63 func TestEchoUnauthorized(t *testing.T) { 64 if testing.Short() { 65 t.Skip() 66 return 67 } 68 apiURL := "http://localhost:8088/v1/example/echo_unauthorized" 69 resp, err := http.Get(apiURL) 70 if err != nil { 71 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 72 return 73 } 74 defer resp.Body.Close() 75 buf, err := io.ReadAll(resp.Body) 76 if err != nil { 77 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 78 return 79 } 80 msg := new(statuspb.Status) 81 if err := marshaler.Unmarshal(buf, msg); err != nil { 82 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 83 return 84 } 85 86 if got, want := resp.StatusCode, http.StatusUnauthorized; got != want { 87 t.Errorf("resp.StatusCode = %d; want %d", got, want) 88 } 89 90 if value := resp.Header.Get("WWW-Authenticate"); value == "" { 91 t.Errorf("WWW-Authenticate header should not be empty") 92 } 93 } 94 95 func TestEchoPatch(t *testing.T) { 96 if testing.Short() { 97 t.Skip() 98 return 99 } 100 101 sent := examplepb.DynamicMessage{ 102 StructField: &structpb.Struct{Fields: map[string]*structpb.Value{ 103 "struct_key": {Kind: &structpb.Value_StructValue{ 104 StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ 105 "layered_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "struct_val"}}, 106 }}, 107 }}, 108 }}, 109 ValueField: &structpb.Value{Kind: &structpb.Value_StructValue{ 110 StructValue: &structpb.Struct{Fields: map[string]*structpb.Value{ 111 "value_struct_key": {Kind: &structpb.Value_StringValue{StringValue: "value_struct_val"}}, 112 }}, 113 }}, 114 } 115 payload, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(&sent) 116 if err != nil { 117 t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) 118 } 119 120 apiURL := "http://localhost:8088/v1/example/echo_patch" 121 req, err := http.NewRequest("PATCH", apiURL, bytes.NewReader(payload)) 122 if err != nil { 123 t.Errorf("http.NewRequest(PATCH, %q) failed with %v; want success", apiURL, err) 124 return 125 } 126 resp, err := http.DefaultClient.Do(req) 127 if err != nil { 128 t.Errorf("http.Post(%#v) failed with %v; want success", req, err) 129 return 130 } 131 defer resp.Body.Close() 132 buf, err := io.ReadAll(resp.Body) 133 if err != nil { 134 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 135 return 136 } 137 138 if got, want := resp.StatusCode, http.StatusOK; got != want { 139 t.Errorf("resp.StatusCode = %d; want %d", got, want) 140 t.Logf("%s", buf) 141 } 142 143 var received examplepb.DynamicMessageUpdate 144 if err := marshaler.Unmarshal(buf, &received); err != nil { 145 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 146 return 147 } 148 if diff := cmp.Diff(received.Body, sent, protocmp.Transform()); diff != "" { 149 t.Errorf(diff) 150 } 151 if diff := cmp.Diff(received.UpdateMask, fieldmaskpb.FieldMask{Paths: []string{ 152 "struct_field.struct_key.layered_struct_key", "value_field.value_struct_key", 153 }}, protocmp.Transform(), protocmp.SortRepeatedFields(received.UpdateMask, "paths")); diff != "" { 154 t.Errorf(diff) 155 } 156 } 157 158 func TestForwardResponseOption(t *testing.T) { 159 if testing.Short() { 160 t.Skip() 161 return 162 } 163 164 ctx := context.Background() 165 ctx, cancel := context.WithCancel(ctx) 166 defer cancel() 167 168 port := 7079 169 go func() { 170 if err := runGateway( 171 ctx, 172 fmt.Sprintf(":%d", port), 173 runtime.WithForwardResponseOption( 174 func(_ context.Context, w http.ResponseWriter, _ proto.Message) error { 175 w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.1+json") 176 return nil 177 }, 178 ), 179 ); err != nil { 180 t.Errorf("runGateway() failed with %v; want success", err) 181 return 182 } 183 }() 184 if err := waitForGateway(ctx, uint16(port)); err != nil { 185 t.Errorf("waitForGateway(ctx, %d) failed with %v; want success", port, err) 186 } 187 testEcho(t, port, "v1", "application/vnd.docker.plugins.v1.1+json") 188 } 189 190 func TestForwardResponseOptionHTTPPathPattern(t *testing.T) { 191 if testing.Short() { 192 t.Skip() 193 return 194 } 195 196 ctx := context.Background() 197 ctx, cancel := context.WithCancel(ctx) 198 defer cancel() 199 200 port := 7080 201 go func() { 202 if err := runGateway( 203 ctx, 204 fmt.Sprintf(":%d", port), 205 runtime.WithForwardResponseOption( 206 func(ctx context.Context, w http.ResponseWriter, _ proto.Message) error { 207 path, _ := runtime.HTTPPathPattern(ctx) 208 w.Header().Set("Content-Type", path) 209 return nil 210 }, 211 ), 212 ); err != nil { 213 t.Errorf("runGateway() failed with %v; want success", err) 214 return 215 } 216 }() 217 if err := waitForGateway(ctx, uint16(port)); err != nil { 218 t.Errorf("waitForGateway(ctx, %d) failed with %v; want success", port, err) 219 } 220 testEcho(t, port, "v1", "/v1/example/echo/{id}") 221 } 222 223 func testEcho(t *testing.T, port int, apiPrefix string, contentType string) { 224 apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid", port, apiPrefix) 225 resp, err := http.Post(apiURL, "application/json", strings.NewReader("{}")) 226 if err != nil { 227 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 228 return 229 } 230 defer resp.Body.Close() 231 buf, err := io.ReadAll(resp.Body) 232 if err != nil { 233 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 234 return 235 } 236 237 if got, want := resp.StatusCode, http.StatusOK; got != want { 238 t.Errorf("resp.StatusCode = %d; want %d", got, want) 239 t.Logf("%s", buf) 240 } 241 242 msg := new(examplepb.UnannotatedSimpleMessage) 243 if err := marshaler.Unmarshal(buf, msg); err != nil { 244 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 245 return 246 } 247 if got, want := msg.Id, "myid"; got != want { 248 t.Errorf("msg.Id = %q; want %q", got, want) 249 } 250 251 if value := resp.Header.Get("Content-Type"); value != contentType { 252 t.Errorf("Content-Type was %s, wanted %s", value, contentType) 253 } 254 } 255 256 func testEchoOneof(t *testing.T, port int, apiPrefix string, contentType string) { 257 apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid/10/golang", port, apiPrefix) 258 resp, err := http.Get(apiURL) 259 if err != nil { 260 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 261 return 262 } 263 defer resp.Body.Close() 264 buf, err := io.ReadAll(resp.Body) 265 if err != nil { 266 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 267 return 268 } 269 270 if got, want := resp.StatusCode, http.StatusOK; got != want { 271 t.Errorf("resp.StatusCode = %d; want %d", got, want) 272 t.Logf("%s", buf) 273 } 274 275 msg := new(examplepb.UnannotatedSimpleMessage) 276 if err := marshaler.Unmarshal(buf, msg); err != nil { 277 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 278 return 279 } 280 if got, want := msg.GetLang(), "golang"; got != want { 281 t.Errorf("msg.GetLang() = %q; want %q", got, want) 282 } 283 284 if value := resp.Header.Get("Content-Type"); value != contentType { 285 t.Errorf("Content-Type was %s, wanted %s", value, contentType) 286 } 287 } 288 289 func testEchoOneof1(t *testing.T, port int, apiPrefix string, contentType string) { 290 apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo1/myid/10/golang", port, apiPrefix) 291 resp, err := http.Get(apiURL) 292 if err != nil { 293 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 294 return 295 } 296 defer resp.Body.Close() 297 buf, err := io.ReadAll(resp.Body) 298 if err != nil { 299 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 300 return 301 } 302 303 if got, want := resp.StatusCode, http.StatusOK; got != want { 304 t.Errorf("resp.StatusCode = %d; want %d", got, want) 305 t.Logf("%s", buf) 306 } 307 308 msg := new(examplepb.UnannotatedSimpleMessage) 309 if err := marshaler.Unmarshal(buf, msg); err != nil { 310 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 311 return 312 } 313 if got, want := msg.GetStatus().GetNote(), "golang"; got != want { 314 t.Errorf("msg.GetStatus().GetNote() = %q; want %q", got, want) 315 } 316 317 if value := resp.Header.Get("Content-Type"); value != contentType { 318 t.Errorf("Content-Type was %s, wanted %s", value, contentType) 319 } 320 } 321 322 func testEchoOneof2(t *testing.T, port int, apiPrefix string, contentType string) { 323 apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo2/golang", port, apiPrefix) 324 resp, err := http.Get(apiURL) 325 if err != nil { 326 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 327 return 328 } 329 defer resp.Body.Close() 330 buf, err := io.ReadAll(resp.Body) 331 if err != nil { 332 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 333 return 334 } 335 336 if got, want := resp.StatusCode, http.StatusOK; got != want { 337 t.Errorf("resp.StatusCode = %d; want %d", got, want) 338 t.Logf("%s", buf) 339 } 340 341 msg := new(examplepb.UnannotatedSimpleMessage) 342 if err := marshaler.Unmarshal(buf, msg); err != nil { 343 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 344 return 345 } 346 if got, want := msg.GetNo().GetNote(), "golang"; got != want { 347 t.Errorf("msg.GetNo().GetNote() = %q; want %q", got, want) 348 } 349 350 if value := resp.Header.Get("Content-Type"); value != contentType { 351 t.Errorf("Content-Type was %s, wanted %s", value, contentType) 352 } 353 } 354 355 func testEchoPathParamOverwrite(t *testing.T, port int) { 356 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/echo/resource/my_resource_id?resourceId=bad_resource_id", port) 357 resp, err := http.Get(apiURL) 358 if err != nil { 359 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 360 return 361 } 362 defer resp.Body.Close() 363 buf, err := io.ReadAll(resp.Body) 364 if err != nil { 365 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 366 return 367 } 368 369 if got, want := resp.StatusCode, http.StatusOK; got != want { 370 t.Errorf("resp.StatusCode = %d; want %d", got, want) 371 t.Logf("%s", buf) 372 } 373 374 msg := new(examplepb.UnannotatedSimpleMessage) 375 if err := marshaler.Unmarshal(buf, msg); err != nil { 376 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 377 return 378 } 379 if got, want := msg.GetResourceId(), "my_resource_id"; got != want { 380 t.Errorf("msg.GetResourceId() = %q; want %q", got, want) 381 } 382 } 383 384 func testEchoNested(t *testing.T, port int) { 385 resp, err := http.Get(fmt.Sprintf("http://localhost:%d/v1/example/echo/nested/my_nested_id?n_id.val=foo", port)) 386 if err != nil { 387 t.Errorf("http.Get() failed with %v; want success", err) 388 return 389 } 390 defer resp.Body.Close() 391 buf, err := io.ReadAll(resp.Body) 392 if err != nil { 393 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 394 return 395 } 396 397 if got, want := resp.StatusCode, http.StatusOK; got != want { 398 t.Errorf("resp.StatusCode = %d; want %d", got, want) 399 t.Logf("%s", buf) 400 } 401 402 msg := new(examplepb.UnannotatedSimpleMessage) 403 if err := marshaler.Unmarshal(buf, msg); err != nil { 404 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 405 return 406 } 407 if got, want := msg.NId.Val, "foo"; got != want { 408 t.Errorf("msg.NId.Val = %q; want %q", got, want) 409 } 410 } 411 412 func testEchoNestedOverride(t *testing.T, port int) { 413 resp, err := http.Get(fmt.Sprintf("http://localhost:%d/v1/example/echo/nested/my_nested_id?nId.nId=bad_id", port)) 414 if err != nil { 415 t.Errorf("http.Get() failed with %v; want success", err) 416 return 417 } 418 defer resp.Body.Close() 419 buf, err := io.ReadAll(resp.Body) 420 if err != nil { 421 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 422 return 423 } 424 425 if got, want := resp.StatusCode, http.StatusOK; got != want { 426 t.Errorf("resp.StatusCode = %d; want %d", got, want) 427 t.Logf("%s", buf) 428 } 429 430 msg := new(examplepb.UnannotatedSimpleMessage) 431 if err := marshaler.Unmarshal(buf, msg); err != nil { 432 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 433 return 434 } 435 if got, want := msg.NId.NId, "my_nested_id"; got != want { 436 t.Errorf("msg.NId.NId = %q; want %q", got, want) 437 } 438 } 439 440 func testEchoBody(t *testing.T, port int, apiPrefix string, useTrailers bool) { 441 sent := examplepb.UnannotatedSimpleMessage{Id: "example"} 442 payload, err := marshaler.Marshal(&sent) 443 if err != nil { 444 t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", payload, err) 445 } 446 447 apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo_body", port, apiPrefix) 448 449 req, err := http.NewRequest("POST", apiURL, bytes.NewReader(payload)) 450 if err != nil { 451 t.Errorf("http.NewRequest() failed with %v; want success", err) 452 return 453 } 454 if useTrailers { 455 req.Header.Set("TE", "trailers") 456 } 457 458 resp, err := http.DefaultClient.Do(req) 459 if err != nil { 460 t.Errorf("client.Do(%v) failed with %v; want success", req, err) 461 return 462 } 463 defer resp.Body.Close() 464 buf, err := io.ReadAll(resp.Body) 465 if err != nil { 466 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 467 return 468 } 469 470 if got, want := resp.StatusCode, http.StatusOK; got != want { 471 t.Errorf("resp.StatusCode = %d; want %d", got, want) 472 t.Logf("%s", buf) 473 } 474 475 var received examplepb.UnannotatedSimpleMessage 476 if err := marshaler.Unmarshal(buf, &received); err != nil { 477 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 478 return 479 } 480 if diff := cmp.Diff(&received, &sent, protocmp.Transform()); diff != "" { 481 t.Errorf(diff) 482 } 483 484 if got, want := resp.Header.Get("Grpc-Metadata-Foo"), "foo1"; got != want { 485 t.Errorf("Grpc-Metadata-Foo was %q, wanted %q", got, want) 486 } 487 if got, want := resp.Header.Get("Grpc-Metadata-Bar"), "bar1"; got != want { 488 t.Errorf("Grpc-Metadata-Bar was %q, wanted %q", got, want) 489 } 490 491 wantedTrailers := map[bool]map[string]string{ 492 true: { 493 "Grpc-Trailer-Foo": "foo2", 494 "Grpc-Trailer-Bar": "bar2", 495 }, 496 false: {}, 497 } 498 499 for trailer, want := range wantedTrailers[useTrailers] { 500 if got := resp.Trailer.Get(trailer); got != want { 501 t.Errorf("%s was %q, wanted %q", trailer, got, want) 502 } 503 } 504 } 505 506 func TestABE(t *testing.T) { 507 if testing.Short() { 508 t.Skip() 509 return 510 } 511 512 testABECreate(t, 8088) 513 testABECreateBody(t, 8088) 514 testABEBulkCreate(t, 8088, true) 515 testABEBulkCreate(t, 8088, false) 516 testABEBulkCreateWithError(t, 8088) 517 testABELookup(t, 8088) 518 testABELookupNotFound(t, 8088, true) 519 testABELookupNotFound(t, 8088, false) 520 testABEList(t, 8088) 521 testABEDownload(t, 8088) 522 testABEBulkEcho(t, 8088) 523 testABEBulkEchoZeroLength(t, 8088) 524 testAdditionalBindings(t, 8088) 525 testABERepeated(t, 8088) 526 testABEExists(t, 8088) 527 testABEExistsNotFound(t, 8088) 528 testABEOptions(t, 8088) 529 testABETrace(t, 8088) 530 } 531 532 func testABECreate(t *testing.T, port int) { 533 want := &examplepb.ABitOfEverything{ 534 FloatValue: 1.5, 535 DoubleValue: 2.5, 536 Int64Value: 4294967296, 537 Uint64Value: 9223372036854775807, 538 Int32Value: -2147483648, 539 Fixed64Value: 9223372036854775807, 540 Fixed32Value: 4294967295, 541 BoolValue: true, 542 StringValue: "strprefix/foo", 543 Uint32Value: 4294967295, 544 Sfixed32Value: 2147483647, 545 Sfixed64Value: -4611686018427387904, 546 Sint32Value: 2147483647, 547 Sint64Value: 4611686018427387903, 548 NonConventionalNameValue: "camelCase", 549 EnumValue: examplepb.NumericEnum_ZERO, 550 PathEnumValue: pathenum.PathEnum_DEF, 551 NestedPathEnumValue: pathenum.MessagePathEnum_JKL, 552 EnumValueAnnotation: examplepb.NumericEnum_ONE, 553 } 554 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/%f/%f/%d/separator/%d/%d/%d/%d/%v/%s/%d/%d/%d/%d/%d/%s/%s/%s/%s/%s", port, want.FloatValue, want.DoubleValue, want.Int64Value, want.Uint64Value, want.Int32Value, want.Fixed64Value, want.Fixed32Value, want.BoolValue, want.StringValue, want.Uint32Value, want.Sfixed32Value, want.Sfixed64Value, want.Sint32Value, want.Sint64Value, want.NonConventionalNameValue, want.EnumValue, want.PathEnumValue, want.NestedPathEnumValue, want.EnumValueAnnotation) 555 556 resp, err := http.Post(apiURL, "application/json", strings.NewReader("{}")) 557 if err != nil { 558 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 559 return 560 } 561 defer resp.Body.Close() 562 buf, err := io.ReadAll(resp.Body) 563 if err != nil { 564 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 565 return 566 } 567 568 if got, want := resp.StatusCode, http.StatusOK; got != want { 569 t.Errorf("resp.StatusCode = %d; want %d", got, want) 570 t.Logf("%s", buf) 571 } 572 573 msg := new(examplepb.ABitOfEverything) 574 if err := marshaler.Unmarshal(buf, msg); err != nil { 575 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 576 return 577 } 578 if msg.Uuid == "" { 579 t.Error("msg.Uuid is empty; want not empty") 580 } 581 msg.Uuid = "" 582 if diff := cmp.Diff(msg, want, protocmp.Transform()); diff != "" { 583 t.Errorf(diff) 584 } 585 } 586 587 func testABECreateBody(t *testing.T, port int) { 588 optionalStrVal := "optional-str" 589 want := &examplepb.ABitOfEverything{ 590 FloatValue: 1.5, 591 DoubleValue: 2.5, 592 Int64Value: 4294967296, 593 Uint64Value: 9223372036854775807, 594 Int32Value: -2147483648, 595 Fixed64Value: 9223372036854775807, 596 Fixed32Value: 4294967295, 597 BoolValue: true, 598 StringValue: "strprefix/foo", 599 Uint32Value: 4294967295, 600 Sfixed32Value: 2147483647, 601 Sfixed64Value: -4611686018427387904, 602 Sint32Value: 2147483647, 603 Sint64Value: 4611686018427387903, 604 NonConventionalNameValue: "camelCase", 605 EnumValue: examplepb.NumericEnum_ONE, 606 PathEnumValue: pathenum.PathEnum_ABC, 607 NestedPathEnumValue: pathenum.MessagePathEnum_GHI, 608 609 Nested: []*examplepb.ABitOfEverything_Nested{ 610 { 611 Name: "bar", 612 Amount: 10, 613 }, 614 { 615 Name: "baz", 616 Amount: 20, 617 }, 618 }, 619 RepeatedStringValue: []string{"a", "b", "c"}, 620 OneofValue: &examplepb.ABitOfEverything_OneofString{ 621 OneofString: "x", 622 }, 623 MapValue: map[string]examplepb.NumericEnum{ 624 "a": examplepb.NumericEnum_ONE, 625 "b": examplepb.NumericEnum_ZERO, 626 }, 627 MappedStringValue: map[string]string{ 628 "a": "x", 629 "b": "y", 630 }, 631 MappedNestedValue: map[string]*examplepb.ABitOfEverything_Nested{ 632 "a": {Name: "x", Amount: 1}, 633 "b": {Name: "y", Amount: 2}, 634 }, 635 RepeatedEnumAnnotation: []examplepb.NumericEnum{ 636 examplepb.NumericEnum_ONE, 637 examplepb.NumericEnum_ZERO, 638 }, 639 EnumValueAnnotation: examplepb.NumericEnum_ONE, 640 RepeatedStringAnnotation: []string{ 641 "a", 642 "b", 643 }, 644 RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{ 645 { 646 Name: "hoge", 647 Amount: 10, 648 }, 649 { 650 Name: "fuga", 651 Amount: 20, 652 }, 653 }, 654 NestedAnnotation: &examplepb.ABitOfEverything_Nested{ 655 Name: "hoge", 656 Amount: 10, 657 }, 658 OptionalStringValue: &optionalStrVal, 659 } 660 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) 661 payload, err := marshaler.Marshal(want) 662 if err != nil { 663 t.Fatalf("marshaler.Marshal(%#v) failed with %v; want success", want, err) 664 } 665 666 resp, err := http.Post(apiURL, "application/json", bytes.NewReader(payload)) 667 if err != nil { 668 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 669 return 670 } 671 defer resp.Body.Close() 672 buf, err := io.ReadAll(resp.Body) 673 if err != nil { 674 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 675 return 676 } 677 678 if got, want := resp.StatusCode, http.StatusOK; got != want { 679 t.Errorf("resp.StatusCode = %d; want %d", got, want) 680 t.Logf("%s", buf) 681 } 682 683 msg := new(examplepb.ABitOfEverything) 684 if err := marshaler.Unmarshal(buf, msg); err != nil { 685 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 686 return 687 } 688 if msg.Uuid == "" { 689 t.Error("msg.Uuid is empty; want not empty") 690 } 691 msg.Uuid = "" 692 if diff := cmp.Diff(msg, want, protocmp.Transform()); diff != "" { 693 t.Errorf(diff) 694 } 695 } 696 697 func testABEBulkCreate(t *testing.T, port int, useTrailers bool) { 698 count := 0 699 r, w := io.Pipe() 700 go func(w io.WriteCloser) { 701 defer func() { 702 if cerr := w.Close(); cerr != nil { 703 t.Errorf("w.Close() failed with %v; want success", cerr) 704 } 705 }() 706 for _, val := range []string{ 707 "foo", "bar", "baz", "qux", "quux", 708 } { 709 strVal := fmt.Sprintf("strprefix/%s", val) 710 want := &examplepb.ABitOfEverything{ 711 FloatValue: 1.5, 712 DoubleValue: 2.5, 713 Int64Value: 4294967296, 714 Uint64Value: 9223372036854775807, 715 Int32Value: -2147483648, 716 Fixed64Value: 9223372036854775807, 717 Fixed32Value: 4294967295, 718 BoolValue: true, 719 StringValue: strVal, 720 Uint32Value: 4294967295, 721 Sfixed32Value: 2147483647, 722 Sfixed64Value: -4611686018427387904, 723 Sint32Value: 2147483647, 724 Sint64Value: 4611686018427387903, 725 NonConventionalNameValue: "camelCase", 726 EnumValue: examplepb.NumericEnum_ONE, 727 PathEnumValue: pathenum.PathEnum_ABC, 728 NestedPathEnumValue: pathenum.MessagePathEnum_GHI, 729 730 Nested: []*examplepb.ABitOfEverything_Nested{ 731 { 732 Name: "hoge", 733 Amount: 10, 734 }, 735 { 736 Name: "fuga", 737 Amount: 20, 738 }, 739 }, 740 RepeatedEnumAnnotation: []examplepb.NumericEnum{ 741 examplepb.NumericEnum_ONE, 742 examplepb.NumericEnum_ZERO, 743 }, 744 EnumValueAnnotation: examplepb.NumericEnum_ONE, 745 RepeatedStringAnnotation: []string{ 746 "a", 747 "b", 748 }, 749 RepeatedNestedAnnotation: []*examplepb.ABitOfEverything_Nested{ 750 { 751 Name: "hoge", 752 Amount: 10, 753 }, 754 { 755 Name: "fuga", 756 Amount: 20, 757 }, 758 }, 759 NestedAnnotation: &examplepb.ABitOfEverything_Nested{ 760 Name: "hoge", 761 Amount: 10, 762 }, 763 OptionalStringValue: &strVal, 764 } 765 out, err := marshaler.Marshal(want) 766 if err != nil { 767 t.Errorf("marshaler.Marshal(%#v, w) failed with %v; want success", want, err) 768 return 769 } 770 if _, err := w.Write(out); err != nil { 771 t.Errorf("w.Write() failed with %v; want success", err) 772 return 773 } 774 if _, err := io.WriteString(w, "\n"); err != nil { 775 t.Errorf("w.Write(%q) failed with %v; want success", "\n", err) 776 return 777 } 778 count++ 779 } 780 }(w) 781 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/bulk", port) 782 783 req, err := http.NewRequest("POST", apiURL, r) 784 if err != nil { 785 t.Errorf("http.NewRequest() failed with %v; want success", err) 786 return 787 } 788 req.Header.Set("Content-Type", "application/json") 789 790 if useTrailers { 791 req.Header.Set("TE", "trailers") 792 } 793 794 resp, err := http.DefaultClient.Do(req) 795 if err != nil { 796 t.Errorf("client.Do(%v) failed with %v; want success", req, err) 797 return 798 } 799 800 defer resp.Body.Close() 801 buf, err := io.ReadAll(resp.Body) 802 if err != nil { 803 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 804 return 805 } 806 807 if got, want := resp.StatusCode, http.StatusOK; got != want { 808 t.Errorf("resp.StatusCode = %d; want %d", got, want) 809 t.Logf("%s", buf) 810 } 811 812 msg := new(emptypb.Empty) 813 if err := marshaler.Unmarshal(buf, msg); err != nil { 814 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 815 return 816 } 817 818 if got, want := resp.Header.Get("Grpc-Metadata-Count"), fmt.Sprintf("%d", count); got != want { 819 t.Errorf("Grpc-Metadata-Count was %q, wanted %q", got, want) 820 } 821 822 wantedTrailers := map[bool]map[string]string{ 823 true: { 824 "Grpc-Trailer-Foo": "foo2", 825 "Grpc-Trailer-Bar": "bar2", 826 }, 827 false: {}, 828 } 829 830 for trailer, want := range wantedTrailers[useTrailers] { 831 if got := resp.Trailer.Get(trailer); got != want { 832 t.Errorf("%s was %q, wanted %q", trailer, got, want) 833 } 834 } 835 } 836 837 func testABEBulkCreateWithError(t *testing.T, port int) { 838 count := 0 839 r, w := io.Pipe() 840 go func(w io.WriteCloser) { 841 defer func() { 842 if cerr := w.Close(); cerr != nil { 843 t.Errorf("w.Close() failed with %v; want success", cerr) 844 } 845 }() 846 for _, val := range []string{ 847 "foo", "bar", "baz", "qux", "quux", 848 } { 849 time.Sleep(1 * time.Millisecond) 850 851 want := &examplepb.ABitOfEverything{ 852 StringValue: fmt.Sprintf("strprefix/%s", val), 853 } 854 out, err := marshaler.Marshal(want) 855 if err != nil { 856 t.Errorf("marshaler.Marshal(%#v, w) failed with %v; want success", want, err) 857 return 858 } 859 if _, err := w.Write(out); err != nil { 860 t.Errorf("w.Write() failed with %v; want success", err) 861 return 862 } 863 if _, err := io.WriteString(w, "\n"); err != nil { 864 t.Errorf("w.Write(%q) failed with %v; want success", "\n", err) 865 return 866 } 867 count++ 868 } 869 }(w) 870 871 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/bulk", port) 872 request, err := http.NewRequest("POST", apiURL, r) 873 if err != nil { 874 t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "POST", apiURL, err) 875 } 876 request.Header.Add("Grpc-Metadata-error", "some error") 877 878 resp, err := http.DefaultClient.Do(request) 879 if err != nil { 880 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 881 return 882 } 883 defer resp.Body.Close() 884 buf, err := io.ReadAll(resp.Body) 885 if err != nil { 886 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 887 return 888 } 889 890 if got, want := resp.StatusCode, http.StatusBadRequest; got != want { 891 t.Errorf("resp.StatusCode = %d; want %d", got, want) 892 t.Logf("%s", buf) 893 } 894 895 msg := new(statuspb.Status) 896 if err := marshaler.Unmarshal(buf, msg); err != nil { 897 t.Fatalf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 898 } 899 } 900 901 func testABELookup(t *testing.T, port int) { 902 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) 903 cresp, err := http.Post(apiURL, "application/json", strings.NewReader(` 904 {"bool_value": true, "string_value": "strprefix/example"} 905 `)) 906 if err != nil { 907 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 908 return 909 } 910 defer cresp.Body.Close() 911 buf, err := io.ReadAll(cresp.Body) 912 if err != nil { 913 t.Errorf("io.ReadAll(cresp.Body) failed with %v; want success", err) 914 return 915 } 916 if got, want := cresp.StatusCode, http.StatusOK; got != want { 917 t.Errorf("resp.StatusCode = %d; want %d", got, want) 918 t.Logf("%s", buf) 919 return 920 } 921 922 want := new(examplepb.ABitOfEverything) 923 if err := marshaler.Unmarshal(buf, want); err != nil { 924 t.Errorf("marshaler.Unmarshal(%s, want) failed with %v; want success", buf, err) 925 return 926 } 927 928 apiURL = fmt.Sprintf("%s/%s", apiURL, want.Uuid) 929 resp, err := http.Get(apiURL) 930 if err != nil { 931 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 932 return 933 } 934 defer resp.Body.Close() 935 936 buf, err = io.ReadAll(resp.Body) 937 if err != nil { 938 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 939 return 940 } 941 942 msg := new(examplepb.ABitOfEverything) 943 if err := marshaler.Unmarshal(buf, msg); err != nil { 944 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 945 return 946 } 947 if diff := cmp.Diff(msg, want, protocmp.Transform()); diff != "" { 948 t.Errorf(diff) 949 } 950 951 if got, want := resp.Header.Get("Grpc-Metadata-Uuid"), want.Uuid; got != want { 952 t.Errorf("Grpc-Metadata-Uuid was %s, wanted %s", got, want) 953 } 954 } 955 956 // TestABEPatch demonstrates partially updating a resource. 957 // First, we'll create an ABE resource with known values for string_value and int32_value 958 // Then, issue a PATCH request updating only the string_value 959 // Then, GET the resource and verify that string_value is changed, but int32_value isn't 960 func TestABEPatch(t *testing.T) { 961 if testing.Short() { 962 t.Skip() 963 return 964 } 965 966 port := 8088 967 968 // create a record with a known string_value and int32_value 969 uuid := postABE(t, port, &examplepb.ABitOfEverything{StringValue: "strprefix/bar", Int32Value: 32}) 970 971 // issue PATCH request, only updating string_value 972 req, err := http.NewRequest( 973 http.MethodPatch, 974 fmt.Sprintf("http://localhost:%d/v2/example/a_bit_of_everything/%s", port, uuid), 975 strings.NewReader(`{"string_value": "strprefix/foo"}`), 976 ) 977 if err != nil { 978 t.Fatalf("http.NewRequest(PATCH) failed with %v; want success", err) 979 } 980 patchResp, err := http.DefaultClient.Do(req) 981 if err != nil { 982 t.Fatalf("failed to issue PATCH request: %v", err) 983 } 984 if got, want := patchResp.StatusCode, http.StatusOK; got != want { 985 if body, err := io.ReadAll(patchResp.Body); err != nil { 986 t.Errorf("patchResp body couldn't be read: %v", err) 987 } else { 988 t.Errorf("patchResp.StatusCode= %d; want %d resp: %v", got, want, string(body)) 989 } 990 } 991 992 // issue GET request, verifying that string_value is changed and int32_value is not 993 getRestatuspbody := getABE(t, port, uuid) 994 if got, want := getRestatuspbody.StringValue, "strprefix/foo"; got != want { 995 t.Errorf("string_value= %q; want %q", got, want) 996 } 997 if got, want := getRestatuspbody.Int32Value, int32(32); got != want { 998 t.Errorf("int_32_value= %d; want %d", got, want) 999 } 1000 } 1001 1002 // TestABEPatchBody demonstrates the ability to specify an update mask within the request body. 1003 // This binding does not use an automatically generated update_mask. 1004 func TestABEPatchBody(t *testing.T) { 1005 if testing.Short() { 1006 t.Skip() 1007 return 1008 } 1009 1010 port := 8088 1011 1012 for _, tc := range []struct { 1013 name string 1014 originalValue *examplepb.ABitOfEverything 1015 input *examplepb.UpdateV2Request 1016 want *examplepb.ABitOfEverything 1017 }{ 1018 { 1019 name: "with fieldmask provided", 1020 originalValue: &examplepb.ABitOfEverything{ 1021 Int32Value: 42, 1022 StringValue: "rabbit", 1023 SingleNested: &examplepb.ABitOfEverything_Nested{ 1024 Name: "some value that will get overwritten", 1025 Amount: 345, 1026 }, 1027 }, 1028 input: &examplepb.UpdateV2Request{ 1029 Abe: &examplepb.ABitOfEverything{ 1030 StringValue: "some value that won't get updated because it's not in the field mask", 1031 SingleNested: &examplepb.ABitOfEverything_Nested{ 1032 Amount: 456, 1033 }, 1034 }, 1035 UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"single_nested"}}, 1036 }, 1037 want: &examplepb.ABitOfEverything{ 1038 Int32Value: 42, 1039 StringValue: "rabbit", 1040 SingleNested: &examplepb.ABitOfEverything_Nested{ 1041 Amount: 456, 1042 }, 1043 }, 1044 }, 1045 { 1046 // N.B. This case passes the empty field mask to the UpdateV2 method so falls back to PUT semantics as per the implementation. 1047 name: "with empty fieldmask", 1048 originalValue: &examplepb.ABitOfEverything{ 1049 Int32Value: 42, 1050 StringValue: "some value that will get overwritten", 1051 SingleNested: &examplepb.ABitOfEverything_Nested{ 1052 Name: "value that will get empty", 1053 Amount: 345, 1054 }, 1055 }, 1056 input: &examplepb.UpdateV2Request{ 1057 Abe: &examplepb.ABitOfEverything{ 1058 StringValue: "some updated value because the fieldMask is nil", 1059 SingleNested: &examplepb.ABitOfEverything_Nested{ 1060 Amount: 456, 1061 }, 1062 }, 1063 UpdateMask: &fieldmaskpb.FieldMask{}, 1064 }, 1065 want: &examplepb.ABitOfEverything{ 1066 StringValue: "some updated value because the fieldMask is nil", 1067 SingleNested: &examplepb.ABitOfEverything_Nested{ 1068 Amount: 456, 1069 }, 1070 }, 1071 }, 1072 { 1073 // N.B. This case passes the nil field mask to the UpdateV2 method so falls back to PUT semantics as per the implementation. 1074 name: "with nil fieldmask", 1075 originalValue: &examplepb.ABitOfEverything{ 1076 Int32Value: 42, 1077 StringValue: "some value that will get overwritten", 1078 SingleNested: &examplepb.ABitOfEverything_Nested{ 1079 Name: "value that will get empty", 1080 Amount: 123, 1081 }, 1082 }, 1083 input: &examplepb.UpdateV2Request{ 1084 Abe: &examplepb.ABitOfEverything{ 1085 StringValue: "some updated value because the fieldMask is nil", 1086 SingleNested: &examplepb.ABitOfEverything_Nested{ 1087 Amount: 657, 1088 }, 1089 }, 1090 UpdateMask: nil, 1091 }, 1092 want: &examplepb.ABitOfEverything{ 1093 StringValue: "some updated value because the fieldMask is nil", 1094 SingleNested: &examplepb.ABitOfEverything_Nested{ 1095 Amount: 657, 1096 }, 1097 }, 1098 }, 1099 } { 1100 t.Run(tc.name, func(t *testing.T) { 1101 originalABE := tc.originalValue 1102 uuid := postABE(t, port, originalABE) 1103 1104 patchBody := tc.input 1105 patchReq, err := http.NewRequest( 1106 http.MethodPatch, 1107 fmt.Sprintf("http://localhost:%d/v2a/example/a_bit_of_everything/%s", port, uuid), 1108 strings.NewReader(mustMarshal(t, patchBody)), 1109 ) 1110 if err != nil { 1111 t.Fatalf("http.NewRequest(PATCH) failed with %v; want success", err) 1112 } 1113 patchResp, err := http.DefaultClient.Do(patchReq) 1114 if err != nil { 1115 t.Fatalf("failed to issue PATCH request: %v", err) 1116 } 1117 if got, want := patchResp.StatusCode, http.StatusOK; got != want { 1118 if body, err := io.ReadAll(patchResp.Body); err != nil { 1119 t.Errorf("patchResp body couldn't be read: %v", err) 1120 } else { 1121 t.Errorf("patchResp.StatusCode= %d; want %d resp: %v", got, want, string(body)) 1122 } 1123 } 1124 1125 want, got := tc.want, getABE(t, port, uuid) 1126 got.Uuid = "" // empty out uuid so we don't need to worry about it in comparisons 1127 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 1128 t.Errorf(diff) 1129 } 1130 }) 1131 } 1132 } 1133 1134 // mustMarshal marshals the given object into a json string, calling t.Fatal if an error occurs. Useful in testing to 1135 // inline marshalling whenever you don't expect the marshalling to return an error 1136 func mustMarshal(t *testing.T, i interface{}) string { 1137 b, err := marshaler.Marshal(i) 1138 if err != nil { 1139 t.Fatalf("failed to marshal %#v: %v", i, err) 1140 } 1141 1142 return string(b) 1143 } 1144 1145 // postABE conveniently creates a new ABE record for ease in testing 1146 func postABE(t *testing.T, port int, abe *examplepb.ABitOfEverything) (uuid string) { 1147 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) 1148 postResp, err := http.Post(apiURL, "application/json", strings.NewReader(mustMarshal(t, abe))) 1149 if err != nil { 1150 t.Fatalf("http.Post(%q) failed with %v; want success", apiURL, err) 1151 return 1152 } 1153 body, err := io.ReadAll(postResp.Body) 1154 if err != nil { 1155 t.Fatalf("postResp body couldn't be read: %v", err) 1156 } 1157 var f struct { 1158 UUID string `json:"uuid"` 1159 } 1160 if err := marshaler.Unmarshal(body, &f); err != nil { 1161 t.Fatalf("postResp body couldn't be unmarshalled: %v. body: %s", err, string(body)) 1162 } 1163 if f.UUID == "" { 1164 t.Fatalf("want uuid from postResp, but got none. body: %s", string(body)) 1165 } 1166 return f.UUID 1167 } 1168 1169 // getABE conveniently fetches an ABE record for ease in testing 1170 func getABE(t *testing.T, port int, uuid string) *examplepb.ABitOfEverything { 1171 gURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/%s", port, uuid) 1172 getResp, err := http.Get(gURL) 1173 if err != nil { 1174 t.Fatalf("http.Get(%s) failed with %v; want success", gURL, err) 1175 } 1176 defer getResp.Body.Close() 1177 1178 if got, want := getResp.StatusCode, http.StatusOK; got != want { 1179 t.Fatalf("getResp.StatusCode= %d, want %d. resp: %v", got, want, getResp) 1180 } 1181 var getRestatuspbody examplepb.ABitOfEverything 1182 body, err := io.ReadAll(getResp.Body) 1183 if err != nil { 1184 t.Fatalf("getResp body couldn't be read: %v", err) 1185 } 1186 if err := marshaler.Unmarshal(body, &getRestatuspbody); err != nil { 1187 t.Fatalf("getResp body couldn't be unmarshalled: %v body: %s", err, string(body)) 1188 } 1189 1190 return &getRestatuspbody 1191 } 1192 1193 func testABELookupNotFound(t *testing.T, port int, useTrailers bool) { 1194 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) 1195 uuid := "not_exist" 1196 apiURL = fmt.Sprintf("%s/%s", apiURL, uuid) 1197 1198 req, err := http.NewRequest("GET", apiURL, nil) 1199 if err != nil { 1200 t.Errorf("http.NewRequest() failed with %v; want success", err) 1201 return 1202 } 1203 1204 if useTrailers { 1205 req.Header.Set("TE", "trailers") 1206 } 1207 1208 resp, err := http.DefaultClient.Do(req) 1209 if err != nil { 1210 t.Errorf("client.Do(%v) failed with %v; want success", req, err) 1211 return 1212 } 1213 defer resp.Body.Close() 1214 1215 buf, err := io.ReadAll(resp.Body) 1216 if err != nil { 1217 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 1218 return 1219 } 1220 1221 if got, want := resp.StatusCode, http.StatusNotFound; got != want { 1222 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1223 t.Logf("%s", buf) 1224 return 1225 } 1226 1227 msg := new(statuspb.Status) 1228 if err := marshaler.Unmarshal(buf, msg); err != nil { 1229 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 1230 return 1231 } 1232 1233 if got, want := msg.Code, int32(codes.NotFound); got != want { 1234 t.Errorf("msg.Code = %d; want %d", got, want) 1235 return 1236 } 1237 1238 if got, want := msg.Message, "not found"; got != want { 1239 t.Errorf("msg.Message = %s; want %s", got, want) 1240 return 1241 } 1242 1243 if got, want := resp.Header.Get("Grpc-Metadata-Uuid"), uuid; got != want { 1244 t.Errorf("Grpc-Metadata-Uuid was %s, wanted %s", got, want) 1245 } 1246 1247 trailers := map[bool]map[string]string{ 1248 true: { 1249 "Grpc-Trailer-Foo": "foo2", 1250 "Grpc-Trailer-Bar": "bar2", 1251 }, 1252 false: { 1253 "Grpc-Trailer-Foo": "", 1254 "Grpc-Trailer-Bar": "", 1255 }, 1256 } 1257 1258 for trailer, want := range trailers[useTrailers] { 1259 if got := resp.Trailer.Get(trailer); got != want { 1260 t.Errorf("%s was %q, wanted %q", trailer, got, want) 1261 } 1262 } 1263 } 1264 1265 func testABEList(t *testing.T, port int) { 1266 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) 1267 resp, err := http.Get(apiURL) 1268 if err != nil { 1269 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 1270 return 1271 } 1272 defer resp.Body.Close() 1273 1274 dec := marshaler.NewDecoder(resp.Body) 1275 var i int 1276 for i = 0; ; i++ { 1277 var item struct { 1278 Result json.RawMessage `json:"result"` 1279 Error map[string]interface{} `json:"error"` 1280 } 1281 err := dec.Decode(&item) 1282 if err == io.EOF { 1283 break 1284 } 1285 if err != nil { 1286 t.Errorf("dec.Decode(&item) failed with %v; want success; i = %d", err, i) 1287 } 1288 if len(item.Error) != 0 { 1289 t.Errorf("item.Error = %#v; want empty; i = %d", item.Error, i) 1290 continue 1291 } 1292 msg := new(examplepb.ABitOfEverything) 1293 if err := marshaler.Unmarshal(item.Result, msg); err != nil { 1294 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", item.Result, err) 1295 } 1296 } 1297 if i <= 0 { 1298 t.Errorf("i == %d; want > 0", i) 1299 } 1300 1301 value := resp.Header.Get("Grpc-Metadata-Count") 1302 if value == "" { 1303 t.Errorf("Grpc-Metadata-Count should not be empty") 1304 } 1305 1306 count, err := strconv.Atoi(value) 1307 if err != nil { 1308 t.Errorf("failed to Atoi %q: %v", value, err) 1309 } 1310 1311 if count <= 0 { 1312 t.Errorf("count == %d; want > 0", count) 1313 } 1314 } 1315 1316 func testABEDownload(t *testing.T, port int) { 1317 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/download", port) 1318 resp, err := http.Get(apiURL) 1319 if err != nil { 1320 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 1321 return 1322 } 1323 defer resp.Body.Close() 1324 1325 wantHeader := "text/html" 1326 if value := resp.Header.Get("Content-Type"); value != wantHeader { 1327 t.Fatalf("testABEDownload() Content-Type failed: got %s, want %s", value, wantHeader) 1328 } 1329 1330 body, err := readAll(resp.Body) 1331 if err != nil { 1332 t.Fatalf("readAll(resp.Body) failed with %v; want success", err) 1333 } 1334 1335 want := []string{"Hello 1", "Hello 2"} 1336 if !reflect.DeepEqual(body, want) { 1337 t.Errorf("testABEDownload() failed: got %v, want %v", body, want) 1338 } 1339 } 1340 1341 func testABEBulkEcho(t *testing.T, port int) { 1342 reqr, reqw := io.Pipe() 1343 var wg sync.WaitGroup 1344 var want []*sub.StringMessage 1345 wg.Add(1) 1346 go func() { 1347 defer wg.Done() 1348 defer reqw.Close() 1349 for i := 0; i < 10; i++ { 1350 s := fmt.Sprintf("message %d", i) 1351 msg := &sub.StringMessage{Value: &s} 1352 buf, err := marshaler.Marshal(msg) 1353 if err != nil { 1354 t.Errorf("marshaler.Marshal(%v) failed with %v; want success", msg, err) 1355 return 1356 } 1357 if _, err = reqw.Write(buf); err != nil { 1358 t.Errorf("reqw.Write(%q) failed with %v; want success", string(buf), err) 1359 return 1360 } 1361 want = append(want, msg) 1362 } 1363 }() 1364 1365 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/echo", port) 1366 req, err := http.NewRequest("POST", apiURL, reqr) 1367 if err != nil { 1368 t.Errorf("http.NewRequest(%q, %q, reqr) failed with %v; want success", "POST", apiURL, err) 1369 return 1370 } 1371 req.Header.Set("Content-Type", "application/json") 1372 req.Header.Set("Transfer-Encoding", "chunked") 1373 resp, err := http.DefaultClient.Do(req) 1374 if err != nil { 1375 t.Errorf("http.Post(%q, %q, req) failed with %v; want success", apiURL, "application/json", err) 1376 return 1377 } 1378 defer resp.Body.Close() 1379 if got, want := resp.StatusCode, http.StatusOK; got != want { 1380 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1381 } 1382 1383 var got []*sub.StringMessage 1384 wg.Add(1) 1385 go func() { 1386 defer wg.Done() 1387 1388 dec := marshaler.NewDecoder(resp.Body) 1389 for i := 0; ; i++ { 1390 var item struct { 1391 Result json.RawMessage `json:"result"` 1392 Error map[string]interface{} `json:"error"` 1393 } 1394 err := dec.Decode(&item) 1395 if err == io.EOF { 1396 break 1397 } 1398 if err != nil { 1399 t.Errorf("dec.Decode(&item) failed with %v; want success; i = %d", err, i) 1400 } 1401 if len(item.Error) != 0 { 1402 t.Errorf("item.Error = %#v; want empty; i = %d", item.Error, i) 1403 continue 1404 } 1405 msg := new(sub.StringMessage) 1406 if err := marshaler.Unmarshal(item.Result, msg); err != nil { 1407 t.Errorf("marshaler.Unmarshal(%q, msg) failed with %v; want success", item.Result, err) 1408 } 1409 got = append(got, msg) 1410 } 1411 }() 1412 1413 wg.Wait() 1414 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 1415 t.Errorf(diff) 1416 } 1417 } 1418 1419 func testABEBulkEchoZeroLength(t *testing.T, port int) { 1420 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/echo", port) 1421 req, err := http.NewRequest("POST", apiURL, bytes.NewReader(nil)) 1422 if err != nil { 1423 t.Errorf("http.NewRequest(%q, %q, bytes.NewReader(nil)) failed with %v; want success", "POST", apiURL, err) 1424 return 1425 } 1426 req.Header.Set("Content-Type", "application/json") 1427 req.Header.Set("Transfer-Encoding", "chunked") 1428 resp, err := http.DefaultClient.Do(req) 1429 if err != nil { 1430 t.Errorf("http.Post(%q, %q, req) failed with %v; want success", apiURL, "application/json", err) 1431 return 1432 } 1433 defer resp.Body.Close() 1434 if got, want := resp.StatusCode, http.StatusOK; got != want { 1435 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1436 } 1437 1438 dec := marshaler.NewDecoder(resp.Body) 1439 var item struct { 1440 Result json.RawMessage `json:"result"` 1441 Error map[string]interface{} `json:"error"` 1442 } 1443 if err := dec.Decode(&item); err == nil { 1444 t.Errorf("dec.Decode(&item) succeeded; want io.EOF; item = %#v", item) 1445 } else if err != io.EOF { 1446 t.Errorf("dec.Decode(&item) failed with %v; want success", err) 1447 return 1448 } 1449 } 1450 1451 func testAdditionalBindings(t *testing.T, port int) { 1452 for i, f := range []func() *http.Response{ 1453 func() *http.Response { 1454 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/echo/hello", port) 1455 resp, err := http.Get(apiURL) 1456 if err != nil { 1457 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 1458 return nil 1459 } 1460 return resp 1461 }, 1462 func() *http.Response { 1463 apiURL := fmt.Sprintf("http://localhost:%d/v2/example/echo", port) 1464 resp, err := http.Post(apiURL, "application/json", strings.NewReader(`"hello"`)) 1465 if err != nil { 1466 t.Errorf("http.Post(%q, %q, %q) failed with %v; want success", apiURL, "application/json", `"hello"`, err) 1467 return nil 1468 } 1469 return resp 1470 }, 1471 func() *http.Response { 1472 r, w := io.Pipe() 1473 go func() { 1474 defer w.Close() 1475 w.Write([]byte(`"hello"`)) 1476 }() 1477 apiURL := fmt.Sprintf("http://localhost:%d/v2/example/echo", port) 1478 resp, err := http.Post(apiURL, "application/json", r) 1479 if err != nil { 1480 t.Errorf("http.Post(%q, %q, %q) failed with %v; want success", apiURL, "application/json", `"hello"`, err) 1481 return nil 1482 } 1483 return resp 1484 }, 1485 func() *http.Response { 1486 apiURL := fmt.Sprintf("http://localhost:%d/v2/example/echo?value=hello", port) 1487 resp, err := http.Get(apiURL) 1488 if err != nil { 1489 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 1490 return nil 1491 } 1492 return resp 1493 }, 1494 } { 1495 resp := f() 1496 if resp == nil { 1497 continue 1498 } 1499 1500 defer resp.Body.Close() 1501 buf, err := io.ReadAll(resp.Body) 1502 if err != nil { 1503 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success; i=%d", err, i) 1504 return 1505 } 1506 if got, want := resp.StatusCode, http.StatusOK; got != want { 1507 t.Errorf("resp.StatusCode = %d; want %d; i=%d", got, want, i) 1508 t.Logf("%s", buf) 1509 } 1510 1511 msg := new(sub.StringMessage) 1512 if err := marshaler.Unmarshal(buf, msg); err != nil { 1513 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success; %d", buf, err, i) 1514 return 1515 } 1516 if got, want := msg.GetValue(), "hello"; got != want { 1517 t.Errorf("msg.GetValue() = %q; want %q", got, want) 1518 } 1519 } 1520 } 1521 1522 func testABERepeated(t *testing.T, port int) { 1523 f := func(v reflect.Value) string { 1524 var f func(v reflect.Value, idx int) string 1525 s := make([]string, v.Len()) 1526 switch v.Index(0).Kind() { 1527 case reflect.Slice: 1528 f = func(v reflect.Value, idx int) string { 1529 t := v.Index(idx).Type().Elem().Kind() 1530 if t == reflect.Uint8 { 1531 return base64.URLEncoding.EncodeToString(v.Index(idx).Interface().([]byte)) 1532 } 1533 // Could handle more elegantly 1534 panic("unknown slice of type: " + t.String()) 1535 } 1536 default: 1537 f = func(v reflect.Value, idx int) string { 1538 return fmt.Sprintf("%v", v.Index(idx).Interface()) 1539 } 1540 } 1541 for i := 0; i < v.Len(); i++ { 1542 s[i] = f(v, i) 1543 } 1544 return strings.Join(s, ",") 1545 } 1546 want := &examplepb.ABitOfEverythingRepeated{ 1547 PathRepeatedFloatValue: []float32{ 1548 1.5, 1549 -1.5, 1550 }, 1551 PathRepeatedDoubleValue: []float64{ 1552 2.5, 1553 -2.5, 1554 }, 1555 PathRepeatedInt64Value: []int64{ 1556 4294967296, 1557 -4294967296, 1558 }, 1559 PathRepeatedUint64Value: []uint64{ 1560 0, 1561 9223372036854775807, 1562 }, 1563 PathRepeatedInt32Value: []int32{ 1564 2147483647, 1565 -2147483648, 1566 }, 1567 PathRepeatedFixed64Value: []uint64{ 1568 0, 1569 9223372036854775807, 1570 }, 1571 PathRepeatedFixed32Value: []uint32{ 1572 0, 1573 4294967295, 1574 }, 1575 PathRepeatedBoolValue: []bool{ 1576 true, 1577 false, 1578 }, 1579 PathRepeatedStringValue: []string{ 1580 "foo", 1581 "bar", 1582 }, 1583 PathRepeatedBytesValue: [][]byte{ 1584 {0x00}, 1585 {0xFF}, 1586 }, 1587 PathRepeatedUint32Value: []uint32{ 1588 0, 1589 4294967295, 1590 }, 1591 PathRepeatedEnumValue: []examplepb.NumericEnum{ 1592 examplepb.NumericEnum_ZERO, 1593 examplepb.NumericEnum_ONE, 1594 }, 1595 PathRepeatedSfixed32Value: []int32{ 1596 2147483647, 1597 -2147483648, 1598 }, 1599 PathRepeatedSfixed64Value: []int64{ 1600 4294967296, 1601 -4294967296, 1602 }, 1603 PathRepeatedSint32Value: []int32{ 1604 2147483647, 1605 -2147483648, 1606 }, 1607 PathRepeatedSint64Value: []int64{ 1608 4611686018427387903, 1609 -4611686018427387904, 1610 }, 1611 } 1612 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything_repeated/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s", port, f(reflect.ValueOf(want.PathRepeatedFloatValue)), f(reflect.ValueOf(want.PathRepeatedDoubleValue)), f(reflect.ValueOf(want.PathRepeatedInt64Value)), f(reflect.ValueOf(want.PathRepeatedUint64Value)), f(reflect.ValueOf(want.PathRepeatedInt32Value)), f(reflect.ValueOf(want.PathRepeatedFixed64Value)), f(reflect.ValueOf(want.PathRepeatedFixed32Value)), f(reflect.ValueOf(want.PathRepeatedBoolValue)), f(reflect.ValueOf(want.PathRepeatedStringValue)), f(reflect.ValueOf(want.PathRepeatedBytesValue)), f(reflect.ValueOf(want.PathRepeatedUint32Value)), f(reflect.ValueOf(want.PathRepeatedEnumValue)), f(reflect.ValueOf(want.PathRepeatedSfixed32Value)), f(reflect.ValueOf(want.PathRepeatedSfixed64Value)), f(reflect.ValueOf(want.PathRepeatedSint32Value)), f(reflect.ValueOf(want.PathRepeatedSint64Value))) 1613 1614 resp, err := http.Get(apiURL) 1615 if err != nil { 1616 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 1617 return 1618 } 1619 defer resp.Body.Close() 1620 buf, err := io.ReadAll(resp.Body) 1621 if err != nil { 1622 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 1623 return 1624 } 1625 1626 if got, want := resp.StatusCode, http.StatusOK; got != want { 1627 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1628 t.Logf("%s", buf) 1629 } 1630 1631 msg := new(examplepb.ABitOfEverythingRepeated) 1632 if err := marshaler.Unmarshal(buf, msg); err != nil { 1633 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 1634 return 1635 } 1636 if diff := cmp.Diff(msg, want, protocmp.Transform()); diff != "" { 1637 t.Errorf(diff) 1638 } 1639 } 1640 1641 func TestTimeout(t *testing.T) { 1642 if testing.Short() { 1643 t.Skip() 1644 return 1645 } 1646 1647 apiURL := "http://localhost:8088/v2/example/timeout" 1648 req, err := http.NewRequest("GET", apiURL, nil) 1649 if err != nil { 1650 t.Errorf(`http.NewRequest("GET", %q, nil) failed with %v; want success`, apiURL, err) 1651 return 1652 } 1653 req.Header.Set("Grpc-Timeout", "10m") 1654 resp, err := http.DefaultClient.Do(req) 1655 if err != nil { 1656 t.Errorf("http.DefaultClient.Do(%#v) failed with %v; want success", req, err) 1657 return 1658 } 1659 defer resp.Body.Close() 1660 1661 if got, want := resp.StatusCode, http.StatusGatewayTimeout; got != want { 1662 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1663 } 1664 } 1665 1666 func TestInvalidTimeout(t *testing.T) { 1667 if testing.Short() { 1668 t.Skip() 1669 return 1670 } 1671 1672 apiURL := "http://localhost:8088/v2/example/timeout" 1673 req, err := http.NewRequest("GET", apiURL, nil) 1674 if err != nil { 1675 t.Errorf(`http.NewRequest("GET", %q, nil) failed with %v; want success`, apiURL, err) 1676 return 1677 } 1678 req.Header.Set("Grpc-Timeout", "INVALID") 1679 resp, err := http.DefaultClient.Do(req) 1680 if err != nil { 1681 t.Errorf("http.DefaultClient.Do(%#v) failed with %v; want success", req, err) 1682 return 1683 } 1684 defer resp.Body.Close() 1685 1686 if got, want := resp.StatusCode, http.StatusBadRequest; got != want { 1687 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1688 } 1689 } 1690 1691 func TestPostWithEmptyBody(t *testing.T) { 1692 if testing.Short() { 1693 t.Skip() 1694 return 1695 } 1696 1697 apiURL := "http://localhost:8088/v2/example/postwithemptybody/name" 1698 rep, err := http.Post(apiURL, "application/json", nil) 1699 if err != nil { 1700 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 1701 return 1702 } 1703 1704 if rep.StatusCode != http.StatusOK { 1705 t.Errorf("http.Post(%q) response code is %d; want %d", apiURL, 1706 rep.StatusCode, http.StatusOK) 1707 return 1708 } 1709 } 1710 1711 func TestUnknownPath(t *testing.T) { 1712 if testing.Short() { 1713 t.Skip() 1714 return 1715 } 1716 1717 apiURL := "http://localhost:8088" 1718 resp, err := http.Post(apiURL, "application/json", strings.NewReader("{}")) 1719 if err != nil { 1720 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 1721 return 1722 } 1723 defer resp.Body.Close() 1724 buf, err := io.ReadAll(resp.Body) 1725 if err != nil { 1726 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 1727 return 1728 } 1729 1730 if got, want := resp.StatusCode, http.StatusNotFound; got != want { 1731 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1732 t.Logf("%s", buf) 1733 } 1734 } 1735 1736 func TestNotImplemented(t *testing.T) { 1737 if testing.Short() { 1738 t.Skip() 1739 return 1740 } 1741 1742 apiURL := "http://localhost:8088/v1/example/echo/myid" 1743 resp, err := http.Get(apiURL) 1744 if err != nil { 1745 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 1746 return 1747 } 1748 defer resp.Body.Close() 1749 buf, err := io.ReadAll(resp.Body) 1750 if err != nil { 1751 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 1752 return 1753 } 1754 if got, want := resp.StatusCode, http.StatusNotImplemented; got != want { 1755 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1756 t.Logf("%s", buf) 1757 } 1758 } 1759 1760 func TestInvalidArgument(t *testing.T) { 1761 if testing.Short() { 1762 t.Skip() 1763 return 1764 } 1765 1766 apiURL := "http://localhost:8088/v1/example/echo/myid/not_int64" 1767 resp, err := http.Get(apiURL) 1768 if err != nil { 1769 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 1770 return 1771 } 1772 defer resp.Body.Close() 1773 buf, err := io.ReadAll(resp.Body) 1774 if err != nil { 1775 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 1776 return 1777 } 1778 1779 if got, want := resp.StatusCode, http.StatusBadRequest; got != want { 1780 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1781 t.Logf("%s", buf) 1782 } 1783 } 1784 1785 func TestResponseBody(t *testing.T) { 1786 if testing.Short() { 1787 t.Skip() 1788 return 1789 } 1790 1791 testResponseBody(t, 8088) 1792 testResponseBodies(t, 8088) 1793 testResponseStrings(t, 8088) 1794 } 1795 1796 func testResponseBody(t *testing.T, port int) { 1797 apiURL := fmt.Sprintf("http://localhost:%d/responsebody/foo", port) 1798 resp, err := http.Get(apiURL) 1799 if err != nil { 1800 t.Fatalf("http.Get(%q) failed with %v; want success", apiURL, err) 1801 } 1802 1803 defer resp.Body.Close() 1804 buf, err := io.ReadAll(resp.Body) 1805 if err != nil { 1806 t.Fatalf("io.ReadAll(resp.Body) failed with %v; want success", err) 1807 } 1808 1809 if got, want := resp.StatusCode, http.StatusOK; got != want { 1810 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1811 t.Logf("%s", buf) 1812 } 1813 1814 if diff := cmp.Diff(string(buf), `{"data":"foo"}`); diff != "" { 1815 t.Errorf(diff) 1816 } 1817 } 1818 1819 func TestResponseBodyStream(t *testing.T) { 1820 apiURL := "http://localhost:8088/responsebody/stream/foo" 1821 resp, err := http.Get(apiURL) 1822 if err != nil { 1823 t.Fatalf("http.Get(%q) failed with %v; want success", apiURL, err) 1824 } 1825 1826 defer resp.Body.Close() 1827 body, err := readAll(resp.Body) 1828 if err != nil { 1829 t.Fatalf("readAll(resp.Body) failed with %v; want success", err) 1830 } 1831 1832 if got, want := resp.StatusCode, http.StatusOK; got != want { 1833 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1834 } 1835 1836 if diff := cmp.Diff(body, []string{`{"result":{"data":"first foo"}}`, `{"result":{"data":"second foo"}}`}); diff != "" { 1837 t.Errorf(diff) 1838 } 1839 } 1840 1841 func TestResponseBodyStreamHttpBody(t *testing.T) { 1842 apiURL := "http://localhost:8088/v1/example/download" 1843 resp, err := http.Get(apiURL) 1844 if err != nil { 1845 t.Fatalf("http.Get(%q) failed with %v; want success", apiURL, err) 1846 } 1847 1848 defer resp.Body.Close() 1849 body, err := readAll(resp.Body) 1850 if err != nil { 1851 t.Fatalf("readAll(resp.Body) failed with %v; want success", err) 1852 } 1853 1854 if got, want := resp.StatusCode, http.StatusOK; got != want { 1855 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1856 } 1857 1858 if diff := cmp.Diff(body, []string{"Hello 1", "Hello 2"}); diff != "" { 1859 t.Errorf(diff) 1860 } 1861 } 1862 1863 func TestResponseBodyStreamHttpBodyError(t *testing.T) { 1864 apiURL := "http://localhost:8088/v1/example/download?error=true" 1865 resp, err := http.Get(apiURL) 1866 if err != nil { 1867 t.Fatalf("http.Get(%q) failed with %v; want success", apiURL, err) 1868 } 1869 1870 defer resp.Body.Close() 1871 body, err := readAll(resp.Body) 1872 if err != nil { 1873 t.Fatalf("readAll(resp.Body) failed with %v; want success", err) 1874 } 1875 1876 if got, want := resp.StatusCode, http.StatusOK; got != want { 1877 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1878 } 1879 1880 if diff := cmp.Diff(body, []string{"Hello 1", "Hello 2", `{"error":{"code":3,"message":"error","details":[]}}`}); diff != "" { 1881 t.Errorf(diff) 1882 } 1883 } 1884 1885 func readAll(body io.ReadCloser) ([]string, error) { 1886 var b []string 1887 reader := bufio.NewReader(body) 1888 for { 1889 l, err := reader.ReadBytes('\n') 1890 switch { 1891 case err == io.EOF: 1892 return b, nil 1893 case err != nil: 1894 return nil, err 1895 } 1896 1897 b = append(b, string(bytes.TrimSpace(l))) 1898 } 1899 } 1900 1901 func testResponseBodies(t *testing.T, port int) { 1902 apiURL := fmt.Sprintf("http://localhost:%d/responsebodies/foo", port) 1903 resp, err := http.Get(apiURL) 1904 if err != nil { 1905 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 1906 return 1907 } 1908 defer resp.Body.Close() 1909 buf, err := io.ReadAll(resp.Body) 1910 if err != nil { 1911 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 1912 return 1913 } 1914 1915 if got, want := resp.StatusCode, http.StatusOK; got != want { 1916 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1917 t.Logf("%s", buf) 1918 } 1919 1920 var got []*examplepb.RepeatedResponseBodyOut_Response 1921 err = marshaler.Unmarshal(buf, &got) 1922 if err != nil { 1923 t.Errorf("marshaler.Unmarshal failed with %v; want success", err) 1924 return 1925 } 1926 want := []*examplepb.RepeatedResponseBodyOut_Response{ 1927 { 1928 Data: "foo", 1929 Type: examplepb.RepeatedResponseBodyOut_Response_UNKNOWN, 1930 }, 1931 } 1932 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 1933 t.Errorf(diff) 1934 } 1935 } 1936 1937 func testResponseStrings(t *testing.T, port int) { 1938 ctx, cancel := context.WithCancel(context.Background()) 1939 defer cancel() 1940 1941 port = 8087 1942 // Run Secondary server with different marshalling 1943 ch := make(chan error) 1944 go func() { 1945 err := runGateway( 1946 ctx, 1947 fmt.Sprintf(":%d", port), 1948 ) 1949 if err != nil { 1950 ch <- fmt.Errorf("cannot run gateway service: %v", err) 1951 } 1952 }() 1953 1954 if err := waitForGateway(ctx, uint16(port)); err != nil { 1955 t.Fatalf("waitForGateway(ctx, %d) failed with %v; want success", port, err) 1956 } 1957 1958 t.Run("Response strings", func(t *testing.T) { 1959 apiURL := fmt.Sprintf("http://localhost:%d/responsestrings/foo", port) 1960 resp, err := http.Get(apiURL) 1961 if err != nil { 1962 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 1963 return 1964 } 1965 defer resp.Body.Close() 1966 buf, err := io.ReadAll(resp.Body) 1967 if err != nil { 1968 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 1969 return 1970 } 1971 1972 if got, want := resp.StatusCode, http.StatusOK; got != want { 1973 t.Errorf("resp.StatusCode = %d; want %d", got, want) 1974 t.Logf("%s", buf) 1975 } 1976 1977 var got []string 1978 err = marshaler.Unmarshal(buf, &got) 1979 if err != nil { 1980 t.Errorf("marshaler.Unmarshal failed with %v; want success", err) 1981 return 1982 } 1983 want := []string{"hello", "foo"} 1984 if diff := cmp.Diff(got, want); diff != "" { 1985 t.Errorf(diff) 1986 } 1987 }) 1988 1989 t.Run("Empty response strings", func(t *testing.T) { 1990 apiURL := fmt.Sprintf("http://localhost:%d/responsestrings/empty", port) 1991 resp, err := http.Get(apiURL) 1992 if err != nil { 1993 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 1994 return 1995 } 1996 defer resp.Body.Close() 1997 buf, err := io.ReadAll(resp.Body) 1998 if err != nil { 1999 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 2000 return 2001 } 2002 2003 if got, want := resp.StatusCode, http.StatusOK; got != want { 2004 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2005 t.Logf("%s", buf) 2006 } 2007 2008 var got []string 2009 err = marshaler.Unmarshal(buf, &got) 2010 if err != nil { 2011 t.Errorf("marshaler.Unmarshal failed with %v; want success", err) 2012 return 2013 } 2014 want := []string{} 2015 if diff := cmp.Diff(got, want); diff != "" { 2016 t.Errorf(diff) 2017 } 2018 }) 2019 2020 t.Run("Response bodies", func(t *testing.T) { 2021 apiURL := fmt.Sprintf("http://localhost:%d/responsebodies/foo", port) 2022 resp, err := http.Get(apiURL) 2023 if err != nil { 2024 t.Errorf("http.Get(%q) failed with %v; want success", apiURL, err) 2025 return 2026 } 2027 defer resp.Body.Close() 2028 buf, err := io.ReadAll(resp.Body) 2029 if err != nil { 2030 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 2031 return 2032 } 2033 2034 if got, want := resp.StatusCode, http.StatusOK; got != want { 2035 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2036 t.Logf("%s", buf) 2037 } 2038 2039 var got []*examplepb.RepeatedResponseBodyOut_Response 2040 err = marshaler.Unmarshal(buf, &got) 2041 if err != nil { 2042 t.Errorf("marshaler.Unmarshal failed with %v; want success", err) 2043 return 2044 } 2045 want := []*examplepb.RepeatedResponseBodyOut_Response{ 2046 { 2047 Data: "foo", 2048 Type: examplepb.RepeatedResponseBodyOut_Response_UNKNOWN, 2049 }, 2050 } 2051 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 2052 t.Errorf(diff) 2053 } 2054 }) 2055 } 2056 2057 func TestRequestQueryParams(t *testing.T) { 2058 testRequestQueryParams(t, 8088) 2059 } 2060 2061 func TestRequestQueryParamsInProcessGateway(t *testing.T) { 2062 testRequestQueryParams(t, 8089) 2063 } 2064 2065 func testRequestQueryParams(t *testing.T, port int) { 2066 if testing.Short() { 2067 t.Skip() 2068 return 2069 } 2070 2071 formValues := url.Values{} 2072 formValues.Set("string_value", "hello-world") 2073 formValues.Add("repeated_string_value", "demo1") 2074 formValues.Add("repeated_string_value", "demo2") 2075 formValues.Add("optional_string_value", "optional-val") 2076 mappedStringValueStr := fmt.Sprintf("mapped_string_value[%v]=%v", "map_key", "map_value") 2077 2078 testCases := []struct { 2079 name string 2080 httpMethod string 2081 contentType string 2082 apiURL string 2083 wantContent *examplepb.ABitOfEverything 2084 requestContent io.Reader 2085 }{ 2086 { 2087 name: "get url query values", 2088 httpMethod: "GET", 2089 contentType: "application/json", 2090 apiURL: fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/params/get/foo?double_value=%v&bool_value=%v&%v", port, 1234.56, true, mappedStringValueStr), 2091 wantContent: &examplepb.ABitOfEverything{ 2092 SingleNested: &examplepb.ABitOfEverything_Nested{ 2093 Name: "foo", 2094 }, 2095 DoubleValue: 1234.56, 2096 BoolValue: true, 2097 MappedStringValue: map[string]string{ 2098 "map_key": "map_value", 2099 }, 2100 }, 2101 }, 2102 { 2103 name: "get nested enum url parameter", 2104 httpMethod: "GET", 2105 contentType: "application/json", 2106 // If nested_enum.OK were FALSE, the content of single_nested would be {} due to how 0 values are serialized 2107 apiURL: fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/params/get/nested_enum/TRUE", port), 2108 wantContent: &examplepb.ABitOfEverything{ 2109 SingleNested: &examplepb.ABitOfEverything_Nested{ 2110 Ok: examplepb.ABitOfEverything_Nested_TRUE, 2111 }, 2112 }, 2113 }, 2114 { 2115 name: "post url query values", 2116 httpMethod: "POST", 2117 contentType: "application/json", 2118 apiURL: fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/params/post/hello-world?double_value=%v&bool_value=%v", port, 1234.56, true), 2119 wantContent: &examplepb.ABitOfEverything{ 2120 SingleNested: &examplepb.ABitOfEverything_Nested{ 2121 Name: "foo", 2122 Amount: 100, 2123 }, 2124 DoubleValue: 1234.56, 2125 BoolValue: true, 2126 StringValue: "hello-world", 2127 }, 2128 requestContent: strings.NewReader(`{"name":"foo","amount":100}`), 2129 }, 2130 { 2131 name: "post form and url query values", 2132 httpMethod: "POST", 2133 contentType: "application/x-www-form-urlencoded", 2134 apiURL: fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/params/get/foo?double_value=%v&bool_value=%v", port, 1234.56, true), 2135 wantContent: &examplepb.ABitOfEverything{ 2136 SingleNested: &examplepb.ABitOfEverything_Nested{ 2137 Name: "foo", 2138 }, 2139 DoubleValue: 1234.56, 2140 BoolValue: true, 2141 StringValue: "hello-world", 2142 RepeatedStringValue: []string{"demo1", "demo2"}, 2143 OptionalStringValue: func() *string { 2144 val := formValues.Get("optional_string_value") 2145 return &val 2146 }(), 2147 }, 2148 requestContent: strings.NewReader(formValues.Encode()), 2149 }, 2150 } 2151 2152 for _, tc := range testCases { 2153 t.Run(tc.name, func(t *testing.T) { 2154 req, err := http.NewRequest(tc.httpMethod, tc.apiURL, tc.requestContent) 2155 if err != nil { 2156 t.Errorf("http.method (%q) http.url (%q) failed with %v; want success", tc.httpMethod, tc.apiURL, err) 2157 return 2158 } 2159 2160 req.Header.Add("Content-Type", tc.contentType) 2161 2162 resp, err := http.DefaultClient.Do(req) 2163 if err != nil { 2164 t.Errorf("http.method (%q) http.url (%q) failed with %v; want success", tc.httpMethod, tc.apiURL, err) 2165 return 2166 } 2167 defer resp.Body.Close() 2168 2169 buf, err := io.ReadAll(resp.Body) 2170 if err != nil { 2171 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 2172 return 2173 } 2174 2175 if gotCode, wantCode := resp.StatusCode, http.StatusOK; gotCode != wantCode { 2176 t.Errorf("resp.StatusCode = %d; want %d", gotCode, wantCode) 2177 t.Logf("%s", buf) 2178 } 2179 2180 got := new(examplepb.ABitOfEverything) 2181 err = marshaler.Unmarshal(buf, &got) 2182 if err != nil { 2183 t.Errorf("marshaler.Unmarshal(buf, got) failed with %v; want success", err) 2184 return 2185 } 2186 if diff := cmp.Diff(got, tc.wantContent, protocmp.Transform()); diff != "" { 2187 t.Errorf("http.method (%q) http.url (%q)\n%s", tc.httpMethod, tc.apiURL, diff) 2188 } 2189 }) 2190 } 2191 } 2192 2193 func TestNonStandardNames(t *testing.T) { 2194 if testing.Short() { 2195 t.Skip() 2196 return 2197 } 2198 2199 ctx := context.Background() 2200 ctx, cancel := context.WithCancel(ctx) 2201 defer cancel() 2202 2203 go func() { 2204 marshaler := &runtime.JSONPb{ 2205 MarshalOptions: protojson.MarshalOptions{ 2206 UseEnumNumbers: false, 2207 EmitUnpopulated: true, 2208 UseProtoNames: true, 2209 }, 2210 } 2211 err := runGateway( 2212 ctx, 2213 ":8081", 2214 runtime.WithMarshalerOption(runtime.MIMEWildcard, marshaler), 2215 ) 2216 if err != nil { 2217 t.Errorf("runGateway() failed with %v; want success", err) 2218 return 2219 } 2220 }() 2221 go func() { 2222 err := runGateway( 2223 ctx, 2224 ":8082", 2225 ) 2226 if err != nil { 2227 t.Errorf("runGateway() failed with %v; want success", err) 2228 return 2229 } 2230 }() 2231 2232 if err := waitForGateway(ctx, 8081); err != nil { 2233 t.Errorf("waitForGateway(ctx, 8081) failed with %v; want success", err) 2234 } 2235 if err := waitForGateway(ctx, 8082); err != nil { 2236 t.Errorf("waitForGateway(ctx, 8082) failed with %v; want success", err) 2237 } 2238 2239 for _, tc := range []struct { 2240 name string 2241 port int 2242 method string 2243 jsonBody string 2244 want proto.Message 2245 }{ 2246 { 2247 "Test standard update method", 2248 8081, 2249 "update", 2250 `{ 2251 "id": "foo", 2252 "Num": "1", 2253 "line_num": "42", 2254 "langIdent": "English", 2255 "STATUS": "good", 2256 "en_GB": "1", 2257 "no": "yes", 2258 "thing": { 2259 "subThing": { 2260 "sub_value": "hi" 2261 } 2262 } 2263 }`, 2264 &examplepb.NonStandardMessage{ 2265 Id: "foo", 2266 Num: 1, 2267 LineNum: 42, 2268 LangIdent: "English", 2269 STATUS: "good", 2270 En_GB: 1, 2271 No: "yes", 2272 Thing: &examplepb.NonStandardMessage_Thing{ 2273 SubThing: &examplepb.NonStandardMessage_Thing_SubThing{ 2274 SubValue: "hi", 2275 }, 2276 }, 2277 }, 2278 }, 2279 { 2280 "Test update method using json_names in message", 2281 8081, 2282 "update_with_json_names", 2283 // N.B. json_names have no effect if not using UseProtoNames: false 2284 `{ 2285 "id": "foo", 2286 "Num": "1", 2287 "line_num": "42", 2288 "langIdent": "English", 2289 "STATUS": "good", 2290 "en_GB": "1", 2291 "no": "yes", 2292 "thing": { 2293 "subThing": { 2294 "sub_value": "hi" 2295 } 2296 } 2297 }`, 2298 &examplepb.NonStandardMessageWithJSONNames{ 2299 Id: "foo", 2300 Num: 1, 2301 LineNum: 42, 2302 LangIdent: "English", 2303 STATUS: "good", 2304 En_GB: 1, 2305 No: "yes", 2306 Thing: &examplepb.NonStandardMessageWithJSONNames_Thing{ 2307 SubThing: &examplepb.NonStandardMessageWithJSONNames_Thing_SubThing{ 2308 SubValue: "hi", 2309 }, 2310 }, 2311 }, 2312 }, 2313 { 2314 "Test standard update method with UseProtoNames: false marshaller option", 2315 8082, 2316 "update", 2317 `{ 2318 "id": "foo", 2319 "Num": "1", 2320 "lineNum": "42", 2321 "langIdent": "English", 2322 "STATUS": "good", 2323 "enGB": "1", 2324 "no": "yes", 2325 "thing": { 2326 "subThing": { 2327 "subValue": "hi" 2328 } 2329 } 2330 }`, 2331 &examplepb.NonStandardMessage{ 2332 Id: "foo", 2333 Num: 1, 2334 LineNum: 42, 2335 LangIdent: "English", 2336 STATUS: "good", 2337 En_GB: 1, 2338 No: "yes", 2339 Thing: &examplepb.NonStandardMessage_Thing{ 2340 SubThing: &examplepb.NonStandardMessage_Thing_SubThing{ 2341 SubValue: "hi", 2342 }, 2343 }, 2344 }, 2345 }, 2346 { 2347 "Test update method using json_names in message with UseProtoNames: false marshaller option", 2348 8082, 2349 "update_with_json_names", 2350 `{ 2351 "ID": "foo", 2352 "Num": "1", 2353 "LineNum": "42", 2354 "langIdent": "English", 2355 "status": "good", 2356 "En_GB": "1", 2357 "yes": "yes", 2358 "Thingy": { 2359 "SubThing": { 2360 "sub_Value": "hi" 2361 } 2362 } 2363 }`, 2364 &examplepb.NonStandardMessageWithJSONNames{ 2365 Id: "foo", 2366 Num: 1, 2367 LineNum: 42, 2368 LangIdent: "English", 2369 STATUS: "good", 2370 En_GB: 1, 2371 No: "yes", 2372 Thing: &examplepb.NonStandardMessageWithJSONNames_Thing{ 2373 SubThing: &examplepb.NonStandardMessageWithJSONNames_Thing_SubThing{ 2374 SubValue: "hi", 2375 }, 2376 }, 2377 }, 2378 }, 2379 } { 2380 t.Run(tc.name, func(t *testing.T) { 2381 testNonStandardNames(t, tc.port, tc.method, tc.jsonBody, tc.want) 2382 }) 2383 } 2384 } 2385 2386 func testNonStandardNames(t *testing.T, port int, method string, jsonBody string, want proto.Message) { 2387 req, err := http.NewRequest( 2388 http.MethodPatch, 2389 fmt.Sprintf("http://localhost:%d/v1/example/non_standard/%s", port, method), 2390 strings.NewReader(jsonBody), 2391 ) 2392 if err != nil { 2393 t.Fatalf("http.NewRequest(PATCH) failed with %v; want success", err) 2394 } 2395 patchResp, err := http.DefaultClient.Do(req) 2396 if err != nil { 2397 t.Fatalf("failed to issue PATCH request: %v", err) 2398 } 2399 2400 body, err := io.ReadAll(patchResp.Body) 2401 if err != nil { 2402 t.Errorf("patchResp body couldn't be read: %v", err) 2403 } 2404 2405 t.Log(string(body)) 2406 2407 if got, want := patchResp.StatusCode, http.StatusOK; got != want { 2408 t.Errorf("patchResp.StatusCode= %d; want %d resp: %v", got, want, string(body)) 2409 } 2410 2411 got := want.ProtoReflect().New().Interface() 2412 err = marshaler.Unmarshal(body, got) 2413 if err != nil { 2414 t.Fatalf("marshaler.Unmarshal failed: %v", err) 2415 } 2416 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" { 2417 t.Errorf(diff) 2418 } 2419 } 2420 2421 func testABEExists(t *testing.T, port int) { 2422 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) 2423 cresp, err := http.Post(apiURL, "application/json", strings.NewReader(` 2424 {"bool_value": true, "string_value": "strprefix/example"} 2425 `)) 2426 if err != nil { 2427 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 2428 return 2429 } 2430 defer cresp.Body.Close() 2431 buf, err := io.ReadAll(cresp.Body) 2432 if err != nil { 2433 t.Errorf("io.ReadAll(cresp.Body) failed with %v; want success", err) 2434 return 2435 } 2436 if got, want := cresp.StatusCode, http.StatusOK; got != want { 2437 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2438 t.Logf("%s", buf) 2439 return 2440 } 2441 2442 want := new(examplepb.ABitOfEverything) 2443 if err := marshaler.Unmarshal(buf, want); err != nil { 2444 t.Errorf("marshaler.Unmarshal(%s, want) failed with %v; want success", buf, err) 2445 return 2446 } 2447 2448 apiURL = fmt.Sprintf("%s/%s", apiURL, want.Uuid) 2449 resp, err := http.Head(apiURL) 2450 if err != nil { 2451 t.Errorf("http.Head(%q) failed with %v; want success", apiURL, err) 2452 return 2453 } 2454 defer resp.Body.Close() 2455 2456 if got, want := resp.StatusCode, http.StatusOK; got != want { 2457 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2458 t.Logf("%s", buf) 2459 } 2460 } 2461 2462 func testABEExistsNotFound(t *testing.T, port int) { 2463 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) 2464 apiURL = fmt.Sprintf("%s/%s", apiURL, "not_exist") 2465 resp, err := http.Head(apiURL) 2466 if err != nil { 2467 t.Errorf("http.Head(%q) failed with %v; want success", apiURL, err) 2468 return 2469 } 2470 defer resp.Body.Close() 2471 2472 if got, want := resp.StatusCode, http.StatusNotFound; got != want { 2473 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2474 return 2475 } 2476 } 2477 2478 func testABEOptions(t *testing.T, port int) { 2479 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/test", port) 2480 req, err := http.NewRequest(http.MethodOptions, apiURL, strings.NewReader(` 2481 {"bool_value": true, "string_value": "strprefix/example"} 2482 `)) 2483 req.Header.Set("Content-Type", "application/json") 2484 if err != nil { 2485 t.Errorf("http.NewRequest(http.MethodTrace, %q, ...) failed with %v; want success", apiURL, err) 2486 return 2487 } 2488 client := &http.Client{} 2489 resp, err := client.Do(req) 2490 if err != nil { 2491 t.Fatal(err) 2492 } 2493 defer resp.Body.Close() 2494 if got, want := resp.StatusCode, http.StatusOK; got != want { 2495 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2496 return 2497 } 2498 2499 value := resp.Header.Get("Grpc-Metadata-Allow") 2500 if value != "OPTIONS, GET, HEAD, POST, PUT, TRACE" { 2501 t.Errorf("Grpc-Metadata-Allow does not have the expected HTTP methods") 2502 t.Logf("%s", value) 2503 } 2504 } 2505 2506 func testABETrace(t *testing.T, port int) { 2507 apiURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/test", port) 2508 req, err := http.NewRequest(http.MethodTrace, apiURL, strings.NewReader(` 2509 {"bool_value": true, "string_value": "strprefix/example"} 2510 `)) 2511 req.Header.Set("Content-Type", "application/json") 2512 if err != nil { 2513 t.Errorf("http.NewRequest(http.MethodTrace, %q, ...) failed with %v; want success", apiURL, err) 2514 return 2515 } 2516 client := &http.Client{} 2517 resp, err := client.Do(req) 2518 if err != nil { 2519 t.Fatal(err) 2520 } 2521 defer resp.Body.Close() 2522 buf, err := io.ReadAll(resp.Body) 2523 if err != nil { 2524 t.Errorf("io.ReadAll(cresp.Body) failed with %v; want success", err) 2525 return 2526 } 2527 if got, want := resp.StatusCode, http.StatusOK; got != want { 2528 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2529 t.Logf("%s", buf) 2530 return 2531 } 2532 2533 want := new(examplepb.ABitOfEverything) 2534 if err := marshaler.Unmarshal(buf, want); err != nil { 2535 t.Errorf("marshaler.Unmarshal(%s, want) failed with %v; want success", buf, err) 2536 return 2537 } 2538 } 2539 2540 func testEchoWithNonASCIIHeaderValues(t *testing.T, port int, apiPrefix string) { 2541 apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid", port, apiPrefix) 2542 2543 req, err := http.NewRequest("POST", apiURL, strings.NewReader("{}")) 2544 if err != nil { 2545 t.Errorf("http.NewRequest() = err: %v", err) 2546 return 2547 } 2548 req.Header.Add("Content-Type", "application/json") 2549 req.Header.Add("Grpc-Metadata-Location", "Gjøvik") 2550 resp, err := http.DefaultClient.Do(req) 2551 if err != nil { 2552 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 2553 return 2554 } 2555 defer resp.Body.Close() 2556 2557 buf, err := io.ReadAll(resp.Body) 2558 if err != nil { 2559 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 2560 return 2561 } 2562 2563 if got, want := resp.StatusCode, http.StatusOK; got != want { 2564 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2565 t.Logf("%s", buf) 2566 } 2567 2568 msg := new(examplepb.UnannotatedSimpleMessage) 2569 if err := marshaler.Unmarshal(buf, msg); err != nil { 2570 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 2571 return 2572 } 2573 if got, want := msg.Id, "myid"; got != want { 2574 t.Errorf("msg.Id = %q; want %q", got, want) 2575 } 2576 } 2577 2578 func testEchoWithInvalidHeaderKey(t *testing.T, port int, apiPrefix string) { 2579 apiURL := fmt.Sprintf("http://localhost:%d/%s/example/echo/myid", port, apiPrefix) 2580 2581 req, err := http.NewRequest("POST", apiURL, strings.NewReader("{}")) 2582 if err != nil { 2583 t.Errorf("http.NewRequest() = err: %v", err) 2584 return 2585 } 2586 req.Header.Add("Content-Type", "application/json") 2587 req.Header.Add("Grpc-Metadata-Foo+Bar", "Hello") 2588 resp, err := http.DefaultClient.Do(req) 2589 if err != nil { 2590 t.Errorf("http.Post(%q) failed with %v; want success", apiURL, err) 2591 return 2592 } 2593 defer resp.Body.Close() 2594 2595 buf, err := io.ReadAll(resp.Body) 2596 if err != nil { 2597 t.Errorf("io.ReadAll(resp.Body) failed with %v; want success", err) 2598 return 2599 } 2600 2601 if got, want := resp.StatusCode, http.StatusOK; got != want { 2602 t.Errorf("resp.StatusCode = %d; want %d", got, want) 2603 t.Logf("%s", buf) 2604 } 2605 2606 msg := new(examplepb.UnannotatedSimpleMessage) 2607 if err := marshaler.Unmarshal(buf, msg); err != nil { 2608 t.Errorf("marshaler.Unmarshal(%s, msg) failed with %v; want success", buf, err) 2609 return 2610 } 2611 if got, want := msg.Id, "myid"; got != want { 2612 t.Errorf("msg.Id = %q; want %q", got, want) 2613 } 2614 }