github.com/aavshr/aws-sdk-go@v1.41.3/private/model/api/codegentest/service/rpcservice/eventstream_test.go (about) 1 // Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. 2 3 //go:build go1.16 4 // +build go1.16 5 6 package rpcservice 7 8 import ( 9 "bytes" 10 "context" 11 "io/ioutil" 12 "net/http" 13 "reflect" 14 "strings" 15 "sync" 16 "testing" 17 "time" 18 19 "github.com/aavshr/aws-sdk-go/aws" 20 "github.com/aavshr/aws-sdk-go/aws/awserr" 21 "github.com/aavshr/aws-sdk-go/aws/corehandlers" 22 "github.com/aavshr/aws-sdk-go/aws/request" 23 "github.com/aavshr/aws-sdk-go/awstesting/unit" 24 "github.com/aavshr/aws-sdk-go/private/protocol" 25 "github.com/aavshr/aws-sdk-go/private/protocol/eventstream" 26 "github.com/aavshr/aws-sdk-go/private/protocol/eventstream/eventstreamapi" 27 "github.com/aavshr/aws-sdk-go/private/protocol/eventstream/eventstreamtest" 28 "github.com/aavshr/aws-sdk-go/private/protocol/jsonrpc" 29 ) 30 31 var _ time.Time 32 var _ awserr.Error 33 var _ context.Context 34 var _ sync.WaitGroup 35 var _ strings.Reader 36 37 func TestEmptyStream_Read(t *testing.T) { 38 expectEvents, eventMsgs := mockEmptyStreamReadEvents() 39 sess, cleanupFn, err := eventstreamtest.SetupEventStreamSession(t, 40 eventstreamtest.ServeEventStream{ 41 T: t, 42 Events: eventMsgs, 43 }, 44 true, 45 ) 46 if err != nil { 47 t.Fatalf("expect no error, %v", err) 48 } 49 defer cleanupFn() 50 51 svc := New(sess) 52 resp, err := svc.EmptyStream(nil) 53 if err != nil { 54 t.Fatalf("expect no error got, %v", err) 55 } 56 defer resp.GetStream().Close() 57 // Trim off response output type pseudo event so only event messages remain. 58 expectEvents = expectEvents[1:] 59 60 var i int 61 for event := range resp.GetStream().Events() { 62 if event == nil { 63 t.Errorf("%d, expect event, got nil", i) 64 } 65 if e, a := expectEvents[i], event; !reflect.DeepEqual(e, a) { 66 t.Errorf("%d, expect %T %v, got %T %v", i, e, e, a, a) 67 } 68 i++ 69 } 70 71 if err := resp.GetStream().Err(); err != nil { 72 t.Errorf("expect no error, %v", err) 73 } 74 } 75 76 func TestEmptyStream_ReadClose(t *testing.T) { 77 _, eventMsgs := mockEmptyStreamReadEvents() 78 sess, cleanupFn, err := eventstreamtest.SetupEventStreamSession(t, 79 eventstreamtest.ServeEventStream{ 80 T: t, 81 Events: eventMsgs, 82 }, 83 true, 84 ) 85 if err != nil { 86 t.Fatalf("expect no error, %v", err) 87 } 88 defer cleanupFn() 89 90 svc := New(sess) 91 resp, err := svc.EmptyStream(nil) 92 if err != nil { 93 t.Fatalf("expect no error got, %v", err) 94 } 95 96 resp.GetStream().Close() 97 <-resp.GetStream().Events() 98 99 if err := resp.GetStream().Err(); err != nil { 100 t.Errorf("expect no error, %v", err) 101 } 102 } 103 104 func TestEmptyStream_ReadUnknownEvent(t *testing.T) { 105 expectEvents, eventMsgs := mockEmptyStreamReadEvents() 106 eventOffset := 1 107 108 unknownEvent := eventstream.Message{ 109 Headers: eventstream.Headers{ 110 eventstreamtest.EventMessageTypeHeader, 111 { 112 Name: eventstreamapi.EventTypeHeader, 113 Value: eventstream.StringValue("UnknownEventName"), 114 }, 115 }, 116 Payload: []byte("some unknown event"), 117 } 118 119 eventMsgs = append(eventMsgs[:eventOffset], 120 append([]eventstream.Message{unknownEvent}, eventMsgs[eventOffset:]...)...) 121 122 expectEvents = append(expectEvents[:eventOffset], 123 append([]EmptyEventStreamEvent{ 124 &EmptyEventStreamUnknownEvent{ 125 Type: "UnknownEventName", 126 Message: unknownEvent, 127 }, 128 }, 129 expectEvents[eventOffset:]...)...) 130 131 sess, cleanupFn, err := eventstreamtest.SetupEventStreamSession(t, 132 eventstreamtest.ServeEventStream{ 133 T: t, 134 Events: eventMsgs, 135 }, 136 true, 137 ) 138 if err != nil { 139 t.Fatalf("expect no error, %v", err) 140 } 141 defer cleanupFn() 142 143 svc := New(sess) 144 resp, err := svc.EmptyStream(nil) 145 if err != nil { 146 t.Fatalf("expect no error got, %v", err) 147 } 148 defer resp.GetStream().Close() 149 // Trim off response output type pseudo event so only event messages remain. 150 expectEvents = expectEvents[1:] 151 152 var i int 153 for event := range resp.GetStream().Events() { 154 if event == nil { 155 t.Errorf("%d, expect event, got nil", i) 156 } 157 if e, a := expectEvents[i], event; !reflect.DeepEqual(e, a) { 158 t.Errorf("%d, expect %T %v, got %T %v", i, e, e, a, a) 159 } 160 i++ 161 } 162 163 if err := resp.GetStream().Err(); err != nil { 164 t.Errorf("expect no error, %v", err) 165 } 166 } 167 168 func BenchmarkEmptyStream_Read(b *testing.B) { 169 _, eventMsgs := mockEmptyStreamReadEvents() 170 var buf bytes.Buffer 171 encoder := eventstream.NewEncoder(&buf) 172 for _, msg := range eventMsgs { 173 if err := encoder.Encode(msg); err != nil { 174 b.Fatalf("failed to encode message, %v", err) 175 } 176 } 177 stream := &loopReader{source: bytes.NewReader(buf.Bytes())} 178 179 sess := unit.Session 180 svc := New(sess, &aws.Config{ 181 Endpoint: aws.String("https://example.com"), 182 DisableParamValidation: aws.Bool(true), 183 }) 184 svc.Handlers.Send.Swap(corehandlers.SendHandler.Name, 185 request.NamedHandler{Name: "mockSend", 186 Fn: func(r *request.Request) { 187 r.HTTPResponse = &http.Response{ 188 Status: "200 OK", 189 StatusCode: 200, 190 Header: http.Header{}, 191 Body: ioutil.NopCloser(stream), 192 } 193 }, 194 }, 195 ) 196 197 resp, err := svc.EmptyStream(nil) 198 if err != nil { 199 b.Fatalf("failed to create request, %v", err) 200 } 201 defer resp.GetStream().Close() 202 b.ResetTimer() 203 204 for i := 0; i < b.N; i++ { 205 if err = resp.GetStream().Err(); err != nil { 206 b.Fatalf("expect no error, got %v", err) 207 } 208 event := <-resp.GetStream().Events() 209 if event == nil { 210 b.Fatalf("expect event, got nil, %v, %d", resp.GetStream().Err(), i) 211 } 212 } 213 } 214 215 func mockEmptyStreamReadEvents() ( 216 []EmptyEventStreamEvent, 217 []eventstream.Message, 218 ) { 219 expectEvents := []EmptyEventStreamEvent{ 220 &EmptyStreamOutput{}, 221 } 222 223 var marshalers request.HandlerList 224 marshalers.PushBackNamed(jsonrpc.BuildHandler) 225 payloadMarshaler := protocol.HandlerPayloadMarshal{ 226 Marshalers: marshalers, 227 } 228 _ = payloadMarshaler 229 230 eventMsgs := []eventstream.Message{ 231 { 232 Headers: eventstream.Headers{ 233 eventstreamtest.EventMessageTypeHeader, 234 { 235 Name: eventstreamapi.EventTypeHeader, 236 Value: eventstream.StringValue("initial-response"), 237 }, 238 }, 239 Payload: eventstreamtest.MarshalEventPayload(payloadMarshaler, expectEvents[0]), 240 }, 241 } 242 243 return expectEvents, eventMsgs 244 } 245 246 func TestGetEventStream_Read(t *testing.T) { 247 expectEvents, eventMsgs := mockGetEventStreamReadEvents() 248 sess, cleanupFn, err := eventstreamtest.SetupEventStreamSession(t, 249 eventstreamtest.ServeEventStream{ 250 T: t, 251 Events: eventMsgs, 252 }, 253 true, 254 ) 255 if err != nil { 256 t.Fatalf("expect no error, %v", err) 257 } 258 defer cleanupFn() 259 260 svc := New(sess) 261 resp, err := svc.GetEventStream(nil) 262 if err != nil { 263 t.Fatalf("expect no error got, %v", err) 264 } 265 defer resp.GetStream().Close() 266 expectResp := expectEvents[0].(*GetEventStreamOutput) 267 if e, a := expectResp.IntVal, resp.IntVal; !reflect.DeepEqual(e, a) { 268 t.Errorf("expect %v, got %v", e, a) 269 } 270 if e, a := expectResp.StrVal, resp.StrVal; !reflect.DeepEqual(e, a) { 271 t.Errorf("expect %v, got %v", e, a) 272 } 273 // Trim off response output type pseudo event so only event messages remain. 274 expectEvents = expectEvents[1:] 275 276 var i int 277 for event := range resp.GetStream().Events() { 278 if event == nil { 279 t.Errorf("%d, expect event, got nil", i) 280 } 281 if e, a := expectEvents[i], event; !reflect.DeepEqual(e, a) { 282 t.Errorf("%d, expect %T %v, got %T %v", i, e, e, a, a) 283 } 284 i++ 285 } 286 287 if err := resp.GetStream().Err(); err != nil { 288 t.Errorf("expect no error, %v", err) 289 } 290 } 291 292 func TestGetEventStream_ReadClose(t *testing.T) { 293 _, eventMsgs := mockGetEventStreamReadEvents() 294 sess, cleanupFn, err := eventstreamtest.SetupEventStreamSession(t, 295 eventstreamtest.ServeEventStream{ 296 T: t, 297 Events: eventMsgs, 298 }, 299 true, 300 ) 301 if err != nil { 302 t.Fatalf("expect no error, %v", err) 303 } 304 defer cleanupFn() 305 306 svc := New(sess) 307 resp, err := svc.GetEventStream(nil) 308 if err != nil { 309 t.Fatalf("expect no error got, %v", err) 310 } 311 312 // Assert calling Err before close does not close the stream. 313 resp.GetStream().Err() 314 select { 315 case _, ok := <-resp.GetStream().Events(): 316 if !ok { 317 t.Fatalf("expect stream not to be closed, but was") 318 } 319 default: 320 } 321 322 resp.GetStream().Close() 323 <-resp.GetStream().Events() 324 325 if err := resp.GetStream().Err(); err != nil { 326 t.Errorf("expect no error, %v", err) 327 } 328 } 329 330 func TestGetEventStream_ReadUnknownEvent(t *testing.T) { 331 expectEvents, eventMsgs := mockGetEventStreamReadEvents() 332 eventOffset := 1 333 334 unknownEvent := eventstream.Message{ 335 Headers: eventstream.Headers{ 336 eventstreamtest.EventMessageTypeHeader, 337 { 338 Name: eventstreamapi.EventTypeHeader, 339 Value: eventstream.StringValue("UnknownEventName"), 340 }, 341 }, 342 Payload: []byte("some unknown event"), 343 } 344 345 eventMsgs = append(eventMsgs[:eventOffset], 346 append([]eventstream.Message{unknownEvent}, eventMsgs[eventOffset:]...)...) 347 348 expectEvents = append(expectEvents[:eventOffset], 349 append([]EventStreamEvent{ 350 &EventStreamUnknownEvent{ 351 Type: "UnknownEventName", 352 Message: unknownEvent, 353 }, 354 }, 355 expectEvents[eventOffset:]...)...) 356 357 sess, cleanupFn, err := eventstreamtest.SetupEventStreamSession(t, 358 eventstreamtest.ServeEventStream{ 359 T: t, 360 Events: eventMsgs, 361 }, 362 true, 363 ) 364 if err != nil { 365 t.Fatalf("expect no error, %v", err) 366 } 367 defer cleanupFn() 368 369 svc := New(sess) 370 resp, err := svc.GetEventStream(nil) 371 if err != nil { 372 t.Fatalf("expect no error got, %v", err) 373 } 374 defer resp.GetStream().Close() 375 // Trim off response output type pseudo event so only event messages remain. 376 expectEvents = expectEvents[1:] 377 378 var i int 379 for event := range resp.GetStream().Events() { 380 if event == nil { 381 t.Errorf("%d, expect event, got nil", i) 382 } 383 if e, a := expectEvents[i], event; !reflect.DeepEqual(e, a) { 384 t.Errorf("%d, expect %T %v, got %T %v", i, e, e, a, a) 385 } 386 i++ 387 } 388 389 if err := resp.GetStream().Err(); err != nil { 390 t.Errorf("expect no error, %v", err) 391 } 392 } 393 394 func BenchmarkGetEventStream_Read(b *testing.B) { 395 _, eventMsgs := mockGetEventStreamReadEvents() 396 var buf bytes.Buffer 397 encoder := eventstream.NewEncoder(&buf) 398 for _, msg := range eventMsgs { 399 if err := encoder.Encode(msg); err != nil { 400 b.Fatalf("failed to encode message, %v", err) 401 } 402 } 403 stream := &loopReader{source: bytes.NewReader(buf.Bytes())} 404 405 sess := unit.Session 406 svc := New(sess, &aws.Config{ 407 Endpoint: aws.String("https://example.com"), 408 DisableParamValidation: aws.Bool(true), 409 }) 410 svc.Handlers.Send.Swap(corehandlers.SendHandler.Name, 411 request.NamedHandler{Name: "mockSend", 412 Fn: func(r *request.Request) { 413 r.HTTPResponse = &http.Response{ 414 Status: "200 OK", 415 StatusCode: 200, 416 Header: http.Header{}, 417 Body: ioutil.NopCloser(stream), 418 } 419 }, 420 }, 421 ) 422 423 resp, err := svc.GetEventStream(nil) 424 if err != nil { 425 b.Fatalf("failed to create request, %v", err) 426 } 427 defer resp.GetStream().Close() 428 b.ResetTimer() 429 430 for i := 0; i < b.N; i++ { 431 if err = resp.GetStream().Err(); err != nil { 432 b.Fatalf("expect no error, got %v", err) 433 } 434 event := <-resp.GetStream().Events() 435 if event == nil { 436 b.Fatalf("expect event, got nil, %v, %d", resp.GetStream().Err(), i) 437 } 438 } 439 } 440 441 func mockGetEventStreamReadEvents() ( 442 []EventStreamEvent, 443 []eventstream.Message, 444 ) { 445 expectEvents := []EventStreamEvent{ 446 &GetEventStreamOutput{ 447 IntVal: aws.Int64(123), 448 StrVal: aws.String("string value goes here"), 449 }, 450 &EmptyEvent{}, 451 &ExplicitPayloadEvent{ 452 LongVal: aws.Int64(1234), 453 NestedVal: &NestedShape{ 454 IntVal: aws.Int64(123), 455 StrVal: aws.String("string value goes here"), 456 }, 457 StringVal: aws.String("string value goes here"), 458 }, 459 &HeaderOnlyEvent{ 460 BlobVal: []byte("blob value goes here"), 461 BoolVal: aws.Bool(true), 462 ByteVal: aws.Int64(1), 463 IntegerVal: aws.Int64(123), 464 LongVal: aws.Int64(1234), 465 ShortVal: aws.Int64(12), 466 StringVal: aws.String("string value goes here"), 467 TimeVal: aws.Time(time.Unix(1396594860, 0).UTC()), 468 }, 469 &ImplicitPayloadEvent{ 470 ByteVal: aws.Int64(1), 471 IntegerVal: aws.Int64(123), 472 ShortVal: aws.Int64(12), 473 }, 474 &PayloadOnlyEvent{ 475 NestedVal: &NestedShape{ 476 IntVal: aws.Int64(123), 477 StrVal: aws.String("string value goes here"), 478 }, 479 }, 480 &PayloadOnlyBlobEvent{ 481 BlobPayload: []byte("blob value goes here"), 482 }, 483 &PayloadOnlyStringEvent{ 484 StringPayload: aws.String("string value goes here"), 485 }, 486 } 487 488 var marshalers request.HandlerList 489 marshalers.PushBackNamed(jsonrpc.BuildHandler) 490 payloadMarshaler := protocol.HandlerPayloadMarshal{ 491 Marshalers: marshalers, 492 } 493 _ = payloadMarshaler 494 495 eventMsgs := []eventstream.Message{ 496 { 497 Headers: eventstream.Headers{ 498 eventstreamtest.EventMessageTypeHeader, 499 { 500 Name: eventstreamapi.EventTypeHeader, 501 Value: eventstream.StringValue("initial-response"), 502 }, 503 }, 504 Payload: eventstreamtest.MarshalEventPayload(payloadMarshaler, expectEvents[0]), 505 }, 506 { 507 Headers: eventstream.Headers{ 508 eventstreamtest.EventMessageTypeHeader, 509 { 510 Name: eventstreamapi.EventTypeHeader, 511 Value: eventstream.StringValue("Empty"), 512 }, 513 }, 514 }, 515 { 516 Headers: eventstream.Headers{ 517 eventstreamtest.EventMessageTypeHeader, 518 { 519 Name: eventstreamapi.EventTypeHeader, 520 Value: eventstream.StringValue("ExplicitPayload"), 521 }, 522 { 523 Name: "LongVal", 524 Value: eventstream.Int64Value(*expectEvents[2].(*ExplicitPayloadEvent).LongVal), 525 }, 526 { 527 Name: "StringVal", 528 Value: eventstream.StringValue(*expectEvents[2].(*ExplicitPayloadEvent).StringVal), 529 }, 530 }, 531 Payload: eventstreamtest.MarshalEventPayload(payloadMarshaler, expectEvents[2]), 532 }, 533 { 534 Headers: eventstream.Headers{ 535 eventstreamtest.EventMessageTypeHeader, 536 { 537 Name: eventstreamapi.EventTypeHeader, 538 Value: eventstream.StringValue("Headers"), 539 }, 540 { 541 Name: "BlobVal", 542 Value: eventstream.BytesValue(expectEvents[3].(*HeaderOnlyEvent).BlobVal), 543 }, 544 { 545 Name: "BoolVal", 546 Value: eventstream.BoolValue(*expectEvents[3].(*HeaderOnlyEvent).BoolVal), 547 }, 548 { 549 Name: "ByteVal", 550 Value: eventstream.Int8Value(int8(*expectEvents[3].(*HeaderOnlyEvent).ByteVal)), 551 }, 552 { 553 Name: "IntegerVal", 554 Value: eventstream.Int32Value(int32(*expectEvents[3].(*HeaderOnlyEvent).IntegerVal)), 555 }, 556 { 557 Name: "LongVal", 558 Value: eventstream.Int64Value(*expectEvents[3].(*HeaderOnlyEvent).LongVal), 559 }, 560 { 561 Name: "ShortVal", 562 Value: eventstream.Int16Value(int16(*expectEvents[3].(*HeaderOnlyEvent).ShortVal)), 563 }, 564 { 565 Name: "StringVal", 566 Value: eventstream.StringValue(*expectEvents[3].(*HeaderOnlyEvent).StringVal), 567 }, 568 { 569 Name: "TimeVal", 570 Value: eventstream.TimestampValue(*expectEvents[3].(*HeaderOnlyEvent).TimeVal), 571 }, 572 }, 573 }, 574 { 575 Headers: eventstream.Headers{ 576 eventstreamtest.EventMessageTypeHeader, 577 { 578 Name: eventstreamapi.EventTypeHeader, 579 Value: eventstream.StringValue("ImplicitPayload"), 580 }, 581 { 582 Name: "ByteVal", 583 Value: eventstream.Int8Value(int8(*expectEvents[4].(*ImplicitPayloadEvent).ByteVal)), 584 }, 585 }, 586 Payload: eventstreamtest.MarshalEventPayload(payloadMarshaler, expectEvents[4]), 587 }, 588 { 589 Headers: eventstream.Headers{ 590 eventstreamtest.EventMessageTypeHeader, 591 { 592 Name: eventstreamapi.EventTypeHeader, 593 Value: eventstream.StringValue("PayloadOnly"), 594 }, 595 }, 596 Payload: eventstreamtest.MarshalEventPayload(payloadMarshaler, expectEvents[5]), 597 }, 598 { 599 Headers: eventstream.Headers{ 600 eventstreamtest.EventMessageTypeHeader, 601 { 602 Name: eventstreamapi.EventTypeHeader, 603 Value: eventstream.StringValue("PayloadOnlyBlob"), 604 }, 605 }, 606 Payload: expectEvents[6].(*PayloadOnlyBlobEvent).BlobPayload, 607 }, 608 { 609 Headers: eventstream.Headers{ 610 eventstreamtest.EventMessageTypeHeader, 611 { 612 Name: eventstreamapi.EventTypeHeader, 613 Value: eventstream.StringValue("PayloadOnlyString"), 614 }, 615 }, 616 Payload: []byte(*expectEvents[7].(*PayloadOnlyStringEvent).StringPayload), 617 }, 618 } 619 620 return expectEvents, eventMsgs 621 } 622 func TestGetEventStream_ReadException(t *testing.T) { 623 expectEvents := []EventStreamEvent{ 624 &GetEventStreamOutput{ 625 IntVal: aws.Int64(123), 626 StrVal: aws.String("string value goes here"), 627 }, 628 &ExceptionEvent{ 629 RespMetadata: protocol.ResponseMetadata{ 630 StatusCode: 200, 631 }, 632 IntVal: aws.Int64(123), 633 Message_: aws.String("string value goes here"), 634 }, 635 } 636 637 var marshalers request.HandlerList 638 marshalers.PushBackNamed(jsonrpc.BuildHandler) 639 payloadMarshaler := protocol.HandlerPayloadMarshal{ 640 Marshalers: marshalers, 641 } 642 643 eventMsgs := []eventstream.Message{ 644 { 645 Headers: eventstream.Headers{ 646 eventstreamtest.EventMessageTypeHeader, 647 { 648 Name: eventstreamapi.EventTypeHeader, 649 Value: eventstream.StringValue("initial-response"), 650 }, 651 }, 652 Payload: eventstreamtest.MarshalEventPayload(payloadMarshaler, expectEvents[0]), 653 }, 654 { 655 Headers: eventstream.Headers{ 656 eventstreamtest.EventExceptionTypeHeader, 657 { 658 Name: eventstreamapi.ExceptionTypeHeader, 659 Value: eventstream.StringValue("Exception"), 660 }, 661 }, 662 Payload: eventstreamtest.MarshalEventPayload(payloadMarshaler, expectEvents[1]), 663 }, 664 } 665 666 sess, cleanupFn, err := eventstreamtest.SetupEventStreamSession(t, 667 eventstreamtest.ServeEventStream{ 668 T: t, 669 Events: eventMsgs, 670 }, 671 true, 672 ) 673 if err != nil { 674 t.Fatalf("expect no error, %v", err) 675 } 676 defer cleanupFn() 677 678 svc := New(sess) 679 resp, err := svc.GetEventStream(nil) 680 if err != nil { 681 t.Fatalf("expect no error got, %v", err) 682 } 683 684 defer resp.GetStream().Close() 685 686 <-resp.GetStream().Events() 687 688 err = resp.GetStream().Err() 689 if err == nil { 690 t.Fatalf("expect err, got none") 691 } 692 693 expectErr := &ExceptionEvent{ 694 RespMetadata: protocol.ResponseMetadata{ 695 StatusCode: 200, 696 }, 697 IntVal: aws.Int64(123), 698 Message_: aws.String("string value goes here"), 699 } 700 aerr, ok := err.(awserr.Error) 701 if !ok { 702 t.Errorf("expect exception, got %T, %#v", err, err) 703 } 704 if e, a := expectErr.Code(), aerr.Code(); e != a { 705 t.Errorf("expect %v, got %v", e, a) 706 } 707 if e, a := expectErr.Message(), aerr.Message(); e != a { 708 t.Errorf("expect %v, got %v", e, a) 709 } 710 711 if e, a := expectErr, aerr; !reflect.DeepEqual(e, a) { 712 t.Errorf("expect error %+#v, got %+#v", e, a) 713 } 714 } 715 716 var _ awserr.Error = (*ExceptionEvent)(nil) 717 var _ awserr.Error = (*ExceptionEvent2)(nil) 718 719 type loopReader struct { 720 source *bytes.Reader 721 } 722 723 func (c *loopReader) Read(p []byte) (int, error) { 724 if c.source.Len() == 0 { 725 c.source.Seek(0, 0) 726 } 727 728 return c.source.Read(p) 729 }