github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/http2/frame_test.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package http2 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "reflect" 12 "strings" 13 "testing" 14 "unsafe" 15 ) 16 17 func testFramer() (*Framer, *bytes.Buffer) { 18 buf := new(bytes.Buffer) 19 return NewFramer(buf, buf), buf 20 } 21 22 func TestFrameSizes(t *testing.T) { 23 // Catch people rearranging the FrameHeader fields. 24 if got, want := int(unsafe.Sizeof(FrameHeader{})), 12; got != want { 25 t.Errorf("FrameHeader size = %d; want %d", got, want) 26 } 27 } 28 29 func TestFrameTypeString(t *testing.T) { 30 tests := []struct { 31 ft FrameType 32 want string 33 }{ 34 {FrameData, "DATA"}, 35 {FramePing, "PING"}, 36 {FrameGoAway, "GOAWAY"}, 37 {0xf, "UNKNOWN_FRAME_TYPE_15"}, 38 } 39 40 for i, tt := range tests { 41 got := tt.ft.String() 42 if got != tt.want { 43 t.Errorf("%d. String(FrameType %d) = %q; want %q", i, int(tt.ft), got, tt.want) 44 } 45 } 46 } 47 48 func TestWriteRST(t *testing.T) { 49 fr, buf := testFramer() 50 var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4 51 var errCode uint32 = 7<<24 + 6<<16 + 5<<8 + 4 52 fr.WriteRSTStream(streamID, ErrCode(errCode)) 53 const wantEnc = "\x00\x00\x04\x03\x00\x01\x02\x03\x04\x07\x06\x05\x04" 54 if buf.String() != wantEnc { 55 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 56 } 57 f, err := fr.ReadFrame() 58 if err != nil { 59 t.Fatal(err) 60 } 61 want := &RSTStreamFrame{ 62 FrameHeader: FrameHeader{ 63 valid: true, 64 Type: 0x3, 65 Flags: 0x0, 66 Length: 0x4, 67 StreamID: 0x1020304, 68 }, 69 ErrCode: 0x7060504, 70 } 71 if !reflect.DeepEqual(f, want) { 72 t.Errorf("parsed back %#v; want %#v", f, want) 73 } 74 } 75 76 func TestWriteData(t *testing.T) { 77 fr, buf := testFramer() 78 var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4 79 data := []byte("ABC") 80 fr.WriteData(streamID, true, data) 81 const wantEnc = "\x00\x00\x03\x00\x01\x01\x02\x03\x04ABC" 82 if buf.String() != wantEnc { 83 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 84 } 85 f, err := fr.ReadFrame() 86 if err != nil { 87 t.Fatal(err) 88 } 89 df, ok := f.(*DataFrame) 90 if !ok { 91 t.Fatalf("got %T; want *DataFrame", f) 92 } 93 if !bytes.Equal(df.Data(), data) { 94 t.Errorf("got %q; want %q", df.Data(), data) 95 } 96 if f.Header().Flags&1 == 0 { 97 t.Errorf("didn't see END_STREAM flag") 98 } 99 } 100 101 func TestWriteHeaders(t *testing.T) { 102 tests := []struct { 103 name string 104 p HeadersFrameParam 105 wantEnc string 106 wantFrame *HeadersFrame 107 }{ 108 { 109 "basic", 110 HeadersFrameParam{ 111 StreamID: 42, 112 BlockFragment: []byte("abc"), 113 Priority: PriorityParam{}, 114 }, 115 "\x00\x00\x03\x01\x00\x00\x00\x00*abc", 116 &HeadersFrame{ 117 FrameHeader: FrameHeader{ 118 valid: true, 119 StreamID: 42, 120 Type: FrameHeaders, 121 Length: uint32(len("abc")), 122 }, 123 Priority: PriorityParam{}, 124 headerFragBuf: []byte("abc"), 125 }, 126 }, 127 { 128 "basic + end flags", 129 HeadersFrameParam{ 130 StreamID: 42, 131 BlockFragment: []byte("abc"), 132 EndStream: true, 133 EndHeaders: true, 134 Priority: PriorityParam{}, 135 }, 136 "\x00\x00\x03\x01\x05\x00\x00\x00*abc", 137 &HeadersFrame{ 138 FrameHeader: FrameHeader{ 139 valid: true, 140 StreamID: 42, 141 Type: FrameHeaders, 142 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders, 143 Length: uint32(len("abc")), 144 }, 145 Priority: PriorityParam{}, 146 headerFragBuf: []byte("abc"), 147 }, 148 }, 149 { 150 "with padding", 151 HeadersFrameParam{ 152 StreamID: 42, 153 BlockFragment: []byte("abc"), 154 EndStream: true, 155 EndHeaders: true, 156 PadLength: 5, 157 Priority: PriorityParam{}, 158 }, 159 "\x00\x00\t\x01\r\x00\x00\x00*\x05abc\x00\x00\x00\x00\x00", 160 &HeadersFrame{ 161 FrameHeader: FrameHeader{ 162 valid: true, 163 StreamID: 42, 164 Type: FrameHeaders, 165 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded, 166 Length: uint32(1 + len("abc") + 5), // pad length + contents + padding 167 }, 168 Priority: PriorityParam{}, 169 headerFragBuf: []byte("abc"), 170 }, 171 }, 172 { 173 "with priority", 174 HeadersFrameParam{ 175 StreamID: 42, 176 BlockFragment: []byte("abc"), 177 EndStream: true, 178 EndHeaders: true, 179 PadLength: 2, 180 Priority: PriorityParam{ 181 StreamDep: 15, 182 Exclusive: true, 183 Weight: 127, 184 }, 185 }, 186 "\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x0f\u007fabc\x00\x00", 187 &HeadersFrame{ 188 FrameHeader: FrameHeader{ 189 valid: true, 190 StreamID: 42, 191 Type: FrameHeaders, 192 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority, 193 Length: uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding 194 }, 195 Priority: PriorityParam{ 196 StreamDep: 15, 197 Exclusive: true, 198 Weight: 127, 199 }, 200 headerFragBuf: []byte("abc"), 201 }, 202 }, 203 } 204 for _, tt := range tests { 205 fr, buf := testFramer() 206 if err := fr.WriteHeaders(tt.p); err != nil { 207 t.Errorf("test %q: %v", tt.name, err) 208 continue 209 } 210 if buf.String() != tt.wantEnc { 211 t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc) 212 } 213 f, err := fr.ReadFrame() 214 if err != nil { 215 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) 216 continue 217 } 218 if !reflect.DeepEqual(f, tt.wantFrame) { 219 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) 220 } 221 } 222 } 223 224 func TestWriteContinuation(t *testing.T) { 225 const streamID = 42 226 tests := []struct { 227 name string 228 end bool 229 frag []byte 230 231 wantFrame *ContinuationFrame 232 }{ 233 { 234 "not end", 235 false, 236 []byte("abc"), 237 &ContinuationFrame{ 238 FrameHeader: FrameHeader{ 239 valid: true, 240 StreamID: streamID, 241 Type: FrameContinuation, 242 Length: uint32(len("abc")), 243 }, 244 headerFragBuf: []byte("abc"), 245 }, 246 }, 247 { 248 "end", 249 true, 250 []byte("def"), 251 &ContinuationFrame{ 252 FrameHeader: FrameHeader{ 253 valid: true, 254 StreamID: streamID, 255 Type: FrameContinuation, 256 Flags: FlagContinuationEndHeaders, 257 Length: uint32(len("def")), 258 }, 259 headerFragBuf: []byte("def"), 260 }, 261 }, 262 } 263 for _, tt := range tests { 264 fr, _ := testFramer() 265 if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil { 266 t.Errorf("test %q: %v", tt.name, err) 267 continue 268 } 269 fr.AllowIllegalReads = true 270 f, err := fr.ReadFrame() 271 if err != nil { 272 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) 273 continue 274 } 275 if !reflect.DeepEqual(f, tt.wantFrame) { 276 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) 277 } 278 } 279 } 280 281 func TestWritePriority(t *testing.T) { 282 const streamID = 42 283 tests := []struct { 284 name string 285 priority PriorityParam 286 wantFrame *PriorityFrame 287 }{ 288 { 289 "not exclusive", 290 PriorityParam{ 291 StreamDep: 2, 292 Exclusive: false, 293 Weight: 127, 294 }, 295 &PriorityFrame{ 296 FrameHeader{ 297 valid: true, 298 StreamID: streamID, 299 Type: FramePriority, 300 Length: 5, 301 }, 302 PriorityParam{ 303 StreamDep: 2, 304 Exclusive: false, 305 Weight: 127, 306 }, 307 }, 308 }, 309 310 { 311 "exclusive", 312 PriorityParam{ 313 StreamDep: 3, 314 Exclusive: true, 315 Weight: 77, 316 }, 317 &PriorityFrame{ 318 FrameHeader{ 319 valid: true, 320 StreamID: streamID, 321 Type: FramePriority, 322 Length: 5, 323 }, 324 PriorityParam{ 325 StreamDep: 3, 326 Exclusive: true, 327 Weight: 77, 328 }, 329 }, 330 }, 331 } 332 for _, tt := range tests { 333 fr, _ := testFramer() 334 if err := fr.WritePriority(streamID, tt.priority); err != nil { 335 t.Errorf("test %q: %v", tt.name, err) 336 continue 337 } 338 f, err := fr.ReadFrame() 339 if err != nil { 340 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) 341 continue 342 } 343 if !reflect.DeepEqual(f, tt.wantFrame) { 344 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) 345 } 346 } 347 } 348 349 func TestWriteSettings(t *testing.T) { 350 fr, buf := testFramer() 351 settings := []Setting{{1, 2}, {3, 4}} 352 fr.WriteSettings(settings...) 353 const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04" 354 if buf.String() != wantEnc { 355 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 356 } 357 f, err := fr.ReadFrame() 358 if err != nil { 359 t.Fatal(err) 360 } 361 sf, ok := f.(*SettingsFrame) 362 if !ok { 363 t.Fatalf("Got a %T; want a SettingsFrame", f) 364 } 365 var got []Setting 366 sf.ForeachSetting(func(s Setting) error { 367 got = append(got, s) 368 valBack, ok := sf.Value(s.ID) 369 if !ok || valBack != s.Val { 370 t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok, s.Val) 371 } 372 return nil 373 }) 374 if !reflect.DeepEqual(settings, got) { 375 t.Errorf("Read settings %+v != written settings %+v", got, settings) 376 } 377 } 378 379 func TestWriteSettingsAck(t *testing.T) { 380 fr, buf := testFramer() 381 fr.WriteSettingsAck() 382 const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00" 383 if buf.String() != wantEnc { 384 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 385 } 386 } 387 388 func TestWriteWindowUpdate(t *testing.T) { 389 fr, buf := testFramer() 390 const streamID = 1<<24 + 2<<16 + 3<<8 + 4 391 const incr = 7<<24 + 6<<16 + 5<<8 + 4 392 if err := fr.WriteWindowUpdate(streamID, incr); err != nil { 393 t.Fatal(err) 394 } 395 const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04" 396 if buf.String() != wantEnc { 397 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 398 } 399 f, err := fr.ReadFrame() 400 if err != nil { 401 t.Fatal(err) 402 } 403 want := &WindowUpdateFrame{ 404 FrameHeader: FrameHeader{ 405 valid: true, 406 Type: 0x8, 407 Flags: 0x0, 408 Length: 0x4, 409 StreamID: 0x1020304, 410 }, 411 Increment: 0x7060504, 412 } 413 if !reflect.DeepEqual(f, want) { 414 t.Errorf("parsed back %#v; want %#v", f, want) 415 } 416 } 417 418 func TestWritePing(t *testing.T) { testWritePing(t, false) } 419 func TestWritePingAck(t *testing.T) { testWritePing(t, true) } 420 421 func testWritePing(t *testing.T, ack bool) { 422 fr, buf := testFramer() 423 if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil { 424 t.Fatal(err) 425 } 426 var wantFlags Flags 427 if ack { 428 wantFlags = FlagPingAck 429 } 430 var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08" 431 if buf.String() != wantEnc { 432 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 433 } 434 435 f, err := fr.ReadFrame() 436 if err != nil { 437 t.Fatal(err) 438 } 439 want := &PingFrame{ 440 FrameHeader: FrameHeader{ 441 valid: true, 442 Type: 0x6, 443 Flags: wantFlags, 444 Length: 0x8, 445 StreamID: 0, 446 }, 447 Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, 448 } 449 if !reflect.DeepEqual(f, want) { 450 t.Errorf("parsed back %#v; want %#v", f, want) 451 } 452 } 453 454 func TestReadFrameHeader(t *testing.T) { 455 tests := []struct { 456 in string 457 want FrameHeader 458 }{ 459 {in: "\x00\x00\x00" + "\x00" + "\x00" + "\x00\x00\x00\x00", want: FrameHeader{}}, 460 {in: "\x01\x02\x03" + "\x04" + "\x05" + "\x06\x07\x08\x09", want: FrameHeader{ 461 Length: 66051, Type: 4, Flags: 5, StreamID: 101124105, 462 }}, 463 // Ignore high bit: 464 {in: "\xff\xff\xff" + "\xff" + "\xff" + "\xff\xff\xff\xff", want: FrameHeader{ 465 Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}}, 466 {in: "\xff\xff\xff" + "\xff" + "\xff" + "\x7f\xff\xff\xff", want: FrameHeader{ 467 Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}}, 468 } 469 for i, tt := range tests { 470 got, err := readFrameHeader(make([]byte, 9), strings.NewReader(tt.in)) 471 if err != nil { 472 t.Errorf("%d. readFrameHeader(%q) = %v", i, tt.in, err) 473 continue 474 } 475 tt.want.valid = true 476 if got != tt.want { 477 t.Errorf("%d. readFrameHeader(%q) = %+v; want %+v", i, tt.in, got, tt.want) 478 } 479 } 480 } 481 482 func TestReadWriteFrameHeader(t *testing.T) { 483 tests := []struct { 484 len uint32 485 typ FrameType 486 flags Flags 487 streamID uint32 488 }{ 489 {len: 0, typ: 255, flags: 1, streamID: 0}, 490 {len: 0, typ: 255, flags: 1, streamID: 1}, 491 {len: 0, typ: 255, flags: 1, streamID: 255}, 492 {len: 0, typ: 255, flags: 1, streamID: 256}, 493 {len: 0, typ: 255, flags: 1, streamID: 65535}, 494 {len: 0, typ: 255, flags: 1, streamID: 65536}, 495 496 {len: 0, typ: 1, flags: 255, streamID: 1}, 497 {len: 255, typ: 1, flags: 255, streamID: 1}, 498 {len: 256, typ: 1, flags: 255, streamID: 1}, 499 {len: 65535, typ: 1, flags: 255, streamID: 1}, 500 {len: 65536, typ: 1, flags: 255, streamID: 1}, 501 {len: 16777215, typ: 1, flags: 255, streamID: 1}, 502 } 503 for _, tt := range tests { 504 fr, buf := testFramer() 505 fr.startWrite(tt.typ, tt.flags, tt.streamID) 506 fr.writeBytes(make([]byte, tt.len)) 507 fr.endWrite() 508 fh, err := ReadFrameHeader(buf) 509 if err != nil { 510 t.Errorf("ReadFrameHeader(%+v) = %v", tt, err) 511 continue 512 } 513 if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID { 514 t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh) 515 } 516 } 517 518 } 519 520 func TestWriteTooLargeFrame(t *testing.T) { 521 fr, _ := testFramer() 522 fr.startWrite(0, 1, 1) 523 fr.writeBytes(make([]byte, 1<<24)) 524 err := fr.endWrite() 525 if err != ErrFrameTooLarge { 526 t.Errorf("endWrite = %v; want errFrameTooLarge", err) 527 } 528 } 529 530 func TestWriteGoAway(t *testing.T) { 531 const debug = "foo" 532 fr, buf := testFramer() 533 if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil { 534 t.Fatal(err) 535 } 536 const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug 537 if buf.String() != wantEnc { 538 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 539 } 540 f, err := fr.ReadFrame() 541 if err != nil { 542 t.Fatal(err) 543 } 544 want := &GoAwayFrame{ 545 FrameHeader: FrameHeader{ 546 valid: true, 547 Type: 0x7, 548 Flags: 0, 549 Length: uint32(4 + 4 + len(debug)), 550 StreamID: 0, 551 }, 552 LastStreamID: 0x01020304, 553 ErrCode: 0x05060708, 554 debugData: []byte(debug), 555 } 556 if !reflect.DeepEqual(f, want) { 557 t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want) 558 } 559 if got := string(f.(*GoAwayFrame).DebugData()); got != debug { 560 t.Errorf("debug data = %q; want %q", got, debug) 561 } 562 } 563 564 func TestWritePushPromise(t *testing.T) { 565 pp := PushPromiseParam{ 566 StreamID: 42, 567 PromiseID: 42, 568 BlockFragment: []byte("abc"), 569 } 570 fr, buf := testFramer() 571 if err := fr.WritePushPromise(pp); err != nil { 572 t.Fatal(err) 573 } 574 const wantEnc = "\x00\x00\x07\x05\x00\x00\x00\x00*\x00\x00\x00*abc" 575 if buf.String() != wantEnc { 576 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 577 } 578 f, err := fr.ReadFrame() 579 if err != nil { 580 t.Fatal(err) 581 } 582 _, ok := f.(*PushPromiseFrame) 583 if !ok { 584 t.Fatalf("got %T; want *PushPromiseFrame", f) 585 } 586 want := &PushPromiseFrame{ 587 FrameHeader: FrameHeader{ 588 valid: true, 589 Type: 0x5, 590 Flags: 0x0, 591 Length: 0x7, 592 StreamID: 42, 593 }, 594 PromiseID: 42, 595 headerFragBuf: []byte("abc"), 596 } 597 if !reflect.DeepEqual(f, want) { 598 t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want) 599 } 600 } 601 602 // test checkFrameOrder and that HEADERS and CONTINUATION frames can't be intermingled. 603 func TestReadFrameOrder(t *testing.T) { 604 head := func(f *Framer, id uint32, end bool) { 605 f.WriteHeaders(HeadersFrameParam{ 606 StreamID: id, 607 BlockFragment: []byte("foo"), // unused, but non-empty 608 EndHeaders: end, 609 }) 610 } 611 cont := func(f *Framer, id uint32, end bool) { 612 f.WriteContinuation(id, end, []byte("foo")) 613 } 614 615 tests := [...]struct { 616 name string 617 w func(*Framer) 618 atLeast int 619 wantErr string 620 }{ 621 0: { 622 w: func(f *Framer) { 623 head(f, 1, true) 624 }, 625 }, 626 1: { 627 w: func(f *Framer) { 628 head(f, 1, true) 629 head(f, 2, true) 630 }, 631 }, 632 2: { 633 wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1", 634 w: func(f *Framer) { 635 head(f, 1, false) 636 head(f, 2, true) 637 }, 638 }, 639 3: { 640 wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1", 641 w: func(f *Framer) { 642 head(f, 1, false) 643 }, 644 }, 645 4: { 646 w: func(f *Framer) { 647 head(f, 1, false) 648 cont(f, 1, true) 649 head(f, 2, true) 650 }, 651 }, 652 5: { 653 wantErr: "got CONTINUATION for stream 2; expected stream 1", 654 w: func(f *Framer) { 655 head(f, 1, false) 656 cont(f, 2, true) 657 head(f, 2, true) 658 }, 659 }, 660 6: { 661 wantErr: "unexpected CONTINUATION for stream 1", 662 w: func(f *Framer) { 663 cont(f, 1, true) 664 }, 665 }, 666 7: { 667 wantErr: "unexpected CONTINUATION for stream 1", 668 w: func(f *Framer) { 669 cont(f, 1, false) 670 }, 671 }, 672 8: { 673 wantErr: "HEADERS frame with stream ID 0", 674 w: func(f *Framer) { 675 head(f, 0, true) 676 }, 677 }, 678 9: { 679 wantErr: "CONTINUATION frame with stream ID 0", 680 w: func(f *Framer) { 681 cont(f, 0, true) 682 }, 683 }, 684 10: { 685 wantErr: "unexpected CONTINUATION for stream 1", 686 atLeast: 5, 687 w: func(f *Framer) { 688 head(f, 1, false) 689 cont(f, 1, false) 690 cont(f, 1, false) 691 cont(f, 1, false) 692 cont(f, 1, true) 693 cont(f, 1, false) 694 }, 695 }, 696 } 697 for i, tt := range tests { 698 buf := new(bytes.Buffer) 699 f := NewFramer(buf, buf) 700 f.AllowIllegalWrites = true 701 tt.w(f) 702 f.WriteData(1, true, nil) // to test transition away from last step 703 704 var err error 705 n := 0 706 var log bytes.Buffer 707 for { 708 var got Frame 709 got, err = f.ReadFrame() 710 fmt.Fprintf(&log, " read %v, %v\n", got, err) 711 if err != nil { 712 break 713 } 714 n++ 715 } 716 if err == io.EOF { 717 err = nil 718 } 719 ok := tt.wantErr == "" 720 if ok && err != nil { 721 t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes()) 722 continue 723 } 724 if !ok && err != ConnectionError(ErrCodeProtocol) { 725 t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes()) 726 continue 727 } 728 if f.errReason != tt.wantErr { 729 t.Errorf("%d. framer eror = %q; want %q\n%s", i, f.errReason, tt.wantErr, log.Bytes()) 730 } 731 if n < tt.atLeast { 732 t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes()) 733 } 734 } 735 }