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
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
957
958
959
960 func TestABEPatch(t *testing.T) {
961 if testing.Short() {
962 t.Skip()
963 return
964 }
965
966 port := 8088
967
968
969 uuid := postABE(t, port, &examplepb.ABitOfEverything{StringValue: "strprefix/bar", Int32Value: 32})
970
971
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
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
1003
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
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
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 = ""
1127 if diff := cmp.Diff(got, want, protocmp.Transform()); diff != "" {
1128 t.Errorf(diff)
1129 }
1130 })
1131 }
1132 }
1133
1134
1135
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
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
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
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
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
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
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 }
2615
View as plain text