github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/internal/x/net/dns/dnsmessage/message_test.go (about) 1 // Copyright 2009 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 dnsmessage 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 "strings" 12 "testing" 13 ) 14 15 func mustNewName(name string) Name { 16 n, err := NewName(name) 17 if err != nil { 18 panic(err) 19 } 20 return n 21 } 22 23 func (m *Message) String() string { 24 s := fmt.Sprintf("Message: %#v\n", &m.Header) 25 if len(m.Questions) > 0 { 26 s += "-- Questions\n" 27 for _, q := range m.Questions { 28 s += fmt.Sprintf("%#v\n", q) 29 } 30 } 31 if len(m.Answers) > 0 { 32 s += "-- Answers\n" 33 for _, a := range m.Answers { 34 s += fmt.Sprintf("%#v\n", a) 35 } 36 } 37 if len(m.Authorities) > 0 { 38 s += "-- Authorities\n" 39 for _, ns := range m.Authorities { 40 s += fmt.Sprintf("%#v\n", ns) 41 } 42 } 43 if len(m.Additionals) > 0 { 44 s += "-- Additionals\n" 45 for _, e := range m.Additionals { 46 s += fmt.Sprintf("%#v\n", e) 47 } 48 } 49 return s 50 } 51 52 func TestNameString(t *testing.T) { 53 want := "foo" 54 name := mustNewName(want) 55 if got := fmt.Sprint(name); got != want { 56 t.Errorf("got fmt.Sprint(%#v) = %s, want = %s", name, got, want) 57 } 58 } 59 60 func TestQuestionPackUnpack(t *testing.T) { 61 want := Question{ 62 Name: mustNewName("."), 63 Type: TypeA, 64 Class: ClassINET, 65 } 66 buf, err := want.pack(make([]byte, 1, 50), map[string]int{}, 1) 67 if err != nil { 68 t.Fatal("Packing failed:", err) 69 } 70 var p Parser 71 p.msg = buf 72 p.header.questions = 1 73 p.section = sectionQuestions 74 p.off = 1 75 got, err := p.Question() 76 if err != nil { 77 t.Fatalf("Unpacking failed: %v\n%s", err, string(buf[1:])) 78 } 79 if p.off != len(buf) { 80 t.Errorf("Unpacked different amount than packed: got n = %d, want = %d", p.off, len(buf)) 81 } 82 if !reflect.DeepEqual(got, want) { 83 t.Errorf("Got = %+v, want = %+v", got, want) 84 } 85 } 86 87 func TestName(t *testing.T) { 88 tests := []string{ 89 "", 90 ".", 91 "google..com", 92 "google.com", 93 "google..com.", 94 "google.com.", 95 ".google.com.", 96 "www..google.com.", 97 "www.google.com.", 98 } 99 100 for _, test := range tests { 101 n, err := NewName(test) 102 if err != nil { 103 t.Errorf("Creating name for %q: %v", test, err) 104 continue 105 } 106 if ns := n.String(); ns != test { 107 t.Errorf("Got %#v.String() = %q, want = %q", n, ns, test) 108 continue 109 } 110 } 111 } 112 113 func TestNamePackUnpack(t *testing.T) { 114 tests := []struct { 115 in string 116 want string 117 err error 118 }{ 119 {"", "", errNonCanonicalName}, 120 {".", ".", nil}, 121 {"google..com", "", errNonCanonicalName}, 122 {"google.com", "", errNonCanonicalName}, 123 {"google..com.", "", errZeroSegLen}, 124 {"google.com.", "google.com.", nil}, 125 {".google.com.", "", errZeroSegLen}, 126 {"www..google.com.", "", errZeroSegLen}, 127 {"www.google.com.", "www.google.com.", nil}, 128 } 129 130 for _, test := range tests { 131 in := mustNewName(test.in) 132 want := mustNewName(test.want) 133 buf, err := in.pack(make([]byte, 0, 30), map[string]int{}, 0) 134 if err != test.err { 135 t.Errorf("Packing of %q: got err = %v, want err = %v", test.in, err, test.err) 136 continue 137 } 138 if test.err != nil { 139 continue 140 } 141 var got Name 142 n, err := got.unpack(buf, 0) 143 if err != nil { 144 t.Errorf("Unpacking for %q failed: %v", test.in, err) 145 continue 146 } 147 if n != len(buf) { 148 t.Errorf( 149 "Unpacked different amount than packed for %q: got n = %d, want = %d", 150 test.in, 151 n, 152 len(buf), 153 ) 154 } 155 if got != want { 156 t.Errorf("Unpacking packing of %q: got = %#v, want = %#v", test.in, got, want) 157 } 158 } 159 } 160 161 func TestIncompressibleName(t *testing.T) { 162 name := mustNewName("example.com.") 163 compression := map[string]int{} 164 buf, err := name.pack(make([]byte, 0, 100), compression, 0) 165 if err != nil { 166 t.Fatal("First packing failed:", err) 167 } 168 buf, err = name.pack(buf, compression, 0) 169 if err != nil { 170 t.Fatal("Second packing failed:", err) 171 } 172 var n1 Name 173 off, err := n1.unpackCompressed(buf, 0, false /* allowCompression */) 174 if err != nil { 175 t.Fatal("Unpacking incompressible name without pointers failed:", err) 176 } 177 var n2 Name 178 if _, err := n2.unpackCompressed(buf, off, false /* allowCompression */); err != errCompressedSRV { 179 t.Errorf("Unpacking compressed incompressible name with pointers: got err = %v, want = %v", err, errCompressedSRV) 180 } 181 } 182 183 func checkErrorPrefix(err error, prefix string) bool { 184 e, ok := err.(*nestedError) 185 return ok && e.s == prefix 186 } 187 188 func TestHeaderUnpackError(t *testing.T) { 189 wants := []string{ 190 "id", 191 "bits", 192 "questions", 193 "answers", 194 "authorities", 195 "additionals", 196 } 197 var buf []byte 198 var h header 199 for _, want := range wants { 200 n, err := h.unpack(buf, 0) 201 if n != 0 || !checkErrorPrefix(err, want) { 202 t.Errorf("got h.unpack([%d]byte, 0) = %d, %v, want = 0, %s", len(buf), n, err, want) 203 } 204 buf = append(buf, 0, 0) 205 } 206 } 207 208 func TestParserStart(t *testing.T) { 209 const want = "unpacking header" 210 var p Parser 211 for i := 0; i <= 1; i++ { 212 _, err := p.Start([]byte{}) 213 if !checkErrorPrefix(err, want) { 214 t.Errorf("got p.Start(nil) = _, %v, want = _, %s", err, want) 215 } 216 } 217 } 218 219 func TestResourceNotStarted(t *testing.T) { 220 tests := []struct { 221 name string 222 fn func(*Parser) error 223 }{ 224 {"CNAMEResource", func(p *Parser) error { _, err := p.CNAMEResource(); return err }}, 225 {"MXResource", func(p *Parser) error { _, err := p.MXResource(); return err }}, 226 {"NSResource", func(p *Parser) error { _, err := p.NSResource(); return err }}, 227 {"PTRResource", func(p *Parser) error { _, err := p.PTRResource(); return err }}, 228 {"SOAResource", func(p *Parser) error { _, err := p.SOAResource(); return err }}, 229 {"TXTResource", func(p *Parser) error { _, err := p.TXTResource(); return err }}, 230 {"SRVResource", func(p *Parser) error { _, err := p.SRVResource(); return err }}, 231 {"AResource", func(p *Parser) error { _, err := p.AResource(); return err }}, 232 {"AAAAResource", func(p *Parser) error { _, err := p.AAAAResource(); return err }}, 233 } 234 235 for _, test := range tests { 236 if err := test.fn(&Parser{}); err != ErrNotStarted { 237 t.Errorf("got _, %v = p.%s(), want = _, %v", err, test.name, ErrNotStarted) 238 } 239 } 240 } 241 242 func TestDNSPackUnpack(t *testing.T) { 243 wants := []Message{ 244 { 245 Questions: []Question{ 246 { 247 Name: mustNewName("."), 248 Type: TypeAAAA, 249 Class: ClassINET, 250 }, 251 }, 252 Answers: []Resource{}, 253 Authorities: []Resource{}, 254 Additionals: []Resource{}, 255 }, 256 largeTestMsg(), 257 } 258 for i, want := range wants { 259 b, err := want.Pack() 260 if err != nil { 261 t.Fatalf("%d: packing failed: %v", i, err) 262 } 263 var got Message 264 err = got.Unpack(b) 265 if err != nil { 266 t.Fatalf("%d: unpacking failed: %v", i, err) 267 } 268 if !reflect.DeepEqual(got, want) { 269 t.Errorf("%d: got = %+v, want = %+v", i, &got, &want) 270 } 271 } 272 } 273 274 func TestDNSAppendPackUnpack(t *testing.T) { 275 wants := []Message{ 276 { 277 Questions: []Question{ 278 { 279 Name: mustNewName("."), 280 Type: TypeAAAA, 281 Class: ClassINET, 282 }, 283 }, 284 Answers: []Resource{}, 285 Authorities: []Resource{}, 286 Additionals: []Resource{}, 287 }, 288 largeTestMsg(), 289 } 290 for i, want := range wants { 291 b := make([]byte, 2, 514) 292 b, err := want.AppendPack(b) 293 if err != nil { 294 t.Fatalf("%d: packing failed: %v", i, err) 295 } 296 b = b[2:] 297 var got Message 298 err = got.Unpack(b) 299 if err != nil { 300 t.Fatalf("%d: unpacking failed: %v", i, err) 301 } 302 if !reflect.DeepEqual(got, want) { 303 t.Errorf("%d: got = %+v, want = %+v", i, &got, &want) 304 } 305 } 306 } 307 308 func TestSkipAll(t *testing.T) { 309 msg := largeTestMsg() 310 buf, err := msg.Pack() 311 if err != nil { 312 t.Fatal("Packing large test message:", err) 313 } 314 var p Parser 315 if _, err := p.Start(buf); err != nil { 316 t.Fatal(err) 317 } 318 319 tests := []struct { 320 name string 321 f func() error 322 }{ 323 {"SkipAllQuestions", p.SkipAllQuestions}, 324 {"SkipAllAnswers", p.SkipAllAnswers}, 325 {"SkipAllAuthorities", p.SkipAllAuthorities}, 326 {"SkipAllAdditionals", p.SkipAllAdditionals}, 327 } 328 for _, test := range tests { 329 for i := 1; i <= 3; i++ { 330 if err := test.f(); err != nil { 331 t.Errorf("Call #%d to %s(): %v", i, test.name, err) 332 } 333 } 334 } 335 } 336 337 func TestSkipEach(t *testing.T) { 338 msg := smallTestMsg() 339 340 buf, err := msg.Pack() 341 if err != nil { 342 t.Fatal("Packing test message:", err) 343 } 344 var p Parser 345 if _, err := p.Start(buf); err != nil { 346 t.Fatal(err) 347 } 348 349 tests := []struct { 350 name string 351 f func() error 352 }{ 353 {"SkipQuestion", p.SkipQuestion}, 354 {"SkipAnswer", p.SkipAnswer}, 355 {"SkipAuthority", p.SkipAuthority}, 356 {"SkipAdditional", p.SkipAdditional}, 357 } 358 for _, test := range tests { 359 if err := test.f(); err != nil { 360 t.Errorf("First call: got %s() = %v, want = %v", test.name, err, nil) 361 } 362 if err := test.f(); err != ErrSectionDone { 363 t.Errorf("Second call: got %s() = %v, want = %v", test.name, err, ErrSectionDone) 364 } 365 } 366 } 367 368 func TestSkipAfterRead(t *testing.T) { 369 msg := smallTestMsg() 370 371 buf, err := msg.Pack() 372 if err != nil { 373 t.Fatal("Packing test message:", err) 374 } 375 var p Parser 376 if _, err := p.Start(buf); err != nil { 377 t.Fatal(err) 378 } 379 380 tests := []struct { 381 name string 382 skip func() error 383 read func() error 384 }{ 385 {"Question", p.SkipQuestion, func() error { _, err := p.Question(); return err }}, 386 {"Answer", p.SkipAnswer, func() error { _, err := p.Answer(); return err }}, 387 {"Authority", p.SkipAuthority, func() error { _, err := p.Authority(); return err }}, 388 {"Additional", p.SkipAdditional, func() error { _, err := p.Additional(); return err }}, 389 } 390 for _, test := range tests { 391 if err := test.read(); err != nil { 392 t.Errorf("Got %s() = _, %v, want = _, %v", test.name, err, nil) 393 } 394 if err := test.skip(); err != ErrSectionDone { 395 t.Errorf("Got Skip%s() = %v, want = %v", test.name, err, ErrSectionDone) 396 } 397 } 398 } 399 400 func TestSkipNotStarted(t *testing.T) { 401 var p Parser 402 403 tests := []struct { 404 name string 405 f func() error 406 }{ 407 {"SkipAllQuestions", p.SkipAllQuestions}, 408 {"SkipAllAnswers", p.SkipAllAnswers}, 409 {"SkipAllAuthorities", p.SkipAllAuthorities}, 410 {"SkipAllAdditionals", p.SkipAllAdditionals}, 411 } 412 for _, test := range tests { 413 if err := test.f(); err != ErrNotStarted { 414 t.Errorf("Got %s() = %v, want = %v", test.name, err, ErrNotStarted) 415 } 416 } 417 } 418 419 func TestTooManyRecords(t *testing.T) { 420 const recs = int(^uint16(0)) + 1 421 tests := []struct { 422 name string 423 msg Message 424 want error 425 }{ 426 { 427 "Questions", 428 Message{ 429 Questions: make([]Question, recs), 430 }, 431 errTooManyQuestions, 432 }, 433 { 434 "Answers", 435 Message{ 436 Answers: make([]Resource, recs), 437 }, 438 errTooManyAnswers, 439 }, 440 { 441 "Authorities", 442 Message{ 443 Authorities: make([]Resource, recs), 444 }, 445 errTooManyAuthorities, 446 }, 447 { 448 "Additionals", 449 Message{ 450 Additionals: make([]Resource, recs), 451 }, 452 errTooManyAdditionals, 453 }, 454 } 455 456 for _, test := range tests { 457 if _, got := test.msg.Pack(); got != test.want { 458 t.Errorf("Packing %d %s: got = %v, want = %v", recs, test.name, got, test.want) 459 } 460 } 461 } 462 463 func TestVeryLongTxt(t *testing.T) { 464 want := Resource{ 465 ResourceHeader{ 466 Name: mustNewName("foo.bar.example.com."), 467 Type: TypeTXT, 468 Class: ClassINET, 469 }, 470 &TXTResource{[]string{ 471 "", 472 "", 473 "foo bar", 474 "", 475 "www.example.com", 476 "www.example.com.", 477 strings.Repeat(".", 255), 478 }}, 479 } 480 buf, err := want.pack(make([]byte, 0, 8000), map[string]int{}, 0) 481 if err != nil { 482 t.Fatal("Packing failed:", err) 483 } 484 var got Resource 485 off, err := got.Header.unpack(buf, 0) 486 if err != nil { 487 t.Fatal("Unpacking ResourceHeader failed:", err) 488 } 489 body, n, err := unpackResourceBody(buf, off, got.Header) 490 if err != nil { 491 t.Fatal("Unpacking failed:", err) 492 } 493 got.Body = body 494 if n != len(buf) { 495 t.Errorf("Unpacked different amount than packed: got n = %d, want = %d", n, len(buf)) 496 } 497 if !reflect.DeepEqual(got, want) { 498 t.Errorf("Got = %#v, want = %#v", got, want) 499 } 500 } 501 502 func TestTooLongTxt(t *testing.T) { 503 rb := TXTResource{[]string{strings.Repeat(".", 256)}} 504 if _, err := rb.pack(make([]byte, 0, 8000), map[string]int{}, 0); err != errStringTooLong { 505 t.Errorf("Packing TXTRecord with 256 character string: got err = %v, want = %v", err, errStringTooLong) 506 } 507 } 508 509 func TestStartAppends(t *testing.T) { 510 buf := make([]byte, 2, 514) 511 wantBuf := []byte{4, 44} 512 copy(buf, wantBuf) 513 514 b := NewBuilder(buf, Header{}) 515 b.EnableCompression() 516 517 buf, err := b.Finish() 518 if err != nil { 519 t.Fatal("Building failed:", err) 520 } 521 if got, want := len(buf), headerLen+2; got != want { 522 t.Errorf("Got len(buf} = %d, want = %d", got, want) 523 } 524 if string(buf[:2]) != string(wantBuf) { 525 t.Errorf("Original data not preserved, got = %v, want = %v", buf[:2], wantBuf) 526 } 527 } 528 529 func TestStartError(t *testing.T) { 530 tests := []struct { 531 name string 532 fn func(*Builder) error 533 }{ 534 {"Questions", func(b *Builder) error { return b.StartQuestions() }}, 535 {"Answers", func(b *Builder) error { return b.StartAnswers() }}, 536 {"Authorities", func(b *Builder) error { return b.StartAuthorities() }}, 537 {"Additionals", func(b *Builder) error { return b.StartAdditionals() }}, 538 } 539 540 envs := []struct { 541 name string 542 fn func() *Builder 543 want error 544 }{ 545 {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted}, 546 {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone}, 547 } 548 549 for _, env := range envs { 550 for _, test := range tests { 551 if got := test.fn(env.fn()); got != env.want { 552 t.Errorf("got Builder{%s}.Start%s = %v, want = %v", env.name, test.name, got, env.want) 553 } 554 } 555 } 556 } 557 558 func TestBuilderResourceError(t *testing.T) { 559 tests := []struct { 560 name string 561 fn func(*Builder) error 562 }{ 563 {"CNAMEResource", func(b *Builder) error { return b.CNAMEResource(ResourceHeader{}, CNAMEResource{}) }}, 564 {"MXResource", func(b *Builder) error { return b.MXResource(ResourceHeader{}, MXResource{}) }}, 565 {"NSResource", func(b *Builder) error { return b.NSResource(ResourceHeader{}, NSResource{}) }}, 566 {"PTRResource", func(b *Builder) error { return b.PTRResource(ResourceHeader{}, PTRResource{}) }}, 567 {"SOAResource", func(b *Builder) error { return b.SOAResource(ResourceHeader{}, SOAResource{}) }}, 568 {"TXTResource", func(b *Builder) error { return b.TXTResource(ResourceHeader{}, TXTResource{}) }}, 569 {"SRVResource", func(b *Builder) error { return b.SRVResource(ResourceHeader{}, SRVResource{}) }}, 570 {"AResource", func(b *Builder) error { return b.AResource(ResourceHeader{}, AResource{}) }}, 571 {"AAAAResource", func(b *Builder) error { return b.AAAAResource(ResourceHeader{}, AAAAResource{}) }}, 572 } 573 574 envs := []struct { 575 name string 576 fn func() *Builder 577 want error 578 }{ 579 {"sectionNotStarted", func() *Builder { return &Builder{section: sectionNotStarted} }, ErrNotStarted}, 580 {"sectionHeader", func() *Builder { return &Builder{section: sectionHeader} }, ErrNotStarted}, 581 {"sectionQuestions", func() *Builder { return &Builder{section: sectionQuestions} }, ErrNotStarted}, 582 {"sectionDone", func() *Builder { return &Builder{section: sectionDone} }, ErrSectionDone}, 583 } 584 585 for _, env := range envs { 586 for _, test := range tests { 587 if got := test.fn(env.fn()); got != env.want { 588 t.Errorf("got Builder{%s}.%s = %v, want = %v", env.name, test.name, got, env.want) 589 } 590 } 591 } 592 } 593 594 func TestFinishError(t *testing.T) { 595 var b Builder 596 want := ErrNotStarted 597 if _, got := b.Finish(); got != want { 598 t.Errorf("got Builder{}.Finish() = %v, want = %v", got, want) 599 } 600 } 601 602 func TestBuilder(t *testing.T) { 603 msg := largeTestMsg() 604 want, err := msg.Pack() 605 if err != nil { 606 t.Fatal("Packing without builder:", err) 607 } 608 609 b := NewBuilder(nil, msg.Header) 610 b.EnableCompression() 611 612 if err := b.StartQuestions(); err != nil { 613 t.Fatal("b.StartQuestions():", err) 614 } 615 for _, q := range msg.Questions { 616 if err := b.Question(q); err != nil { 617 t.Fatalf("b.Question(%#v): %v", q, err) 618 } 619 } 620 621 if err := b.StartAnswers(); err != nil { 622 t.Fatal("b.StartAnswers():", err) 623 } 624 for _, a := range msg.Answers { 625 switch a.Header.Type { 626 case TypeA: 627 if err := b.AResource(a.Header, *a.Body.(*AResource)); err != nil { 628 t.Fatalf("b.AResource(%#v): %v", a, err) 629 } 630 case TypeNS: 631 if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil { 632 t.Fatalf("b.NSResource(%#v): %v", a, err) 633 } 634 case TypeCNAME: 635 if err := b.CNAMEResource(a.Header, *a.Body.(*CNAMEResource)); err != nil { 636 t.Fatalf("b.CNAMEResource(%#v): %v", a, err) 637 } 638 case TypeSOA: 639 if err := b.SOAResource(a.Header, *a.Body.(*SOAResource)); err != nil { 640 t.Fatalf("b.SOAResource(%#v): %v", a, err) 641 } 642 case TypePTR: 643 if err := b.PTRResource(a.Header, *a.Body.(*PTRResource)); err != nil { 644 t.Fatalf("b.PTRResource(%#v): %v", a, err) 645 } 646 case TypeMX: 647 if err := b.MXResource(a.Header, *a.Body.(*MXResource)); err != nil { 648 t.Fatalf("b.MXResource(%#v): %v", a, err) 649 } 650 case TypeTXT: 651 if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil { 652 t.Fatalf("b.TXTResource(%#v): %v", a, err) 653 } 654 case TypeAAAA: 655 if err := b.AAAAResource(a.Header, *a.Body.(*AAAAResource)); err != nil { 656 t.Fatalf("b.AAAAResource(%#v): %v", a, err) 657 } 658 case TypeSRV: 659 if err := b.SRVResource(a.Header, *a.Body.(*SRVResource)); err != nil { 660 t.Fatalf("b.SRVResource(%#v): %v", a, err) 661 } 662 } 663 } 664 665 if err := b.StartAuthorities(); err != nil { 666 t.Fatal("b.StartAuthorities():", err) 667 } 668 for _, a := range msg.Authorities { 669 if err := b.NSResource(a.Header, *a.Body.(*NSResource)); err != nil { 670 t.Fatalf("b.NSResource(%#v): %v", a, err) 671 } 672 } 673 674 if err := b.StartAdditionals(); err != nil { 675 t.Fatal("b.StartAdditionals():", err) 676 } 677 for _, a := range msg.Additionals { 678 if err := b.TXTResource(a.Header, *a.Body.(*TXTResource)); err != nil { 679 t.Fatalf("b.TXTResource(%#v): %v", a, err) 680 } 681 } 682 683 got, err := b.Finish() 684 if err != nil { 685 t.Fatal("b.Finish():", err) 686 } 687 if !bytes.Equal(got, want) { 688 t.Fatalf("Got from Builder: %#v\nwant = %#v", got, want) 689 } 690 } 691 692 func TestResourcePack(t *testing.T) { 693 for _, tt := range []struct { 694 m Message 695 err error 696 }{ 697 { 698 Message{ 699 Questions: []Question{ 700 { 701 Name: mustNewName("."), 702 Type: TypeAAAA, 703 Class: ClassINET, 704 }, 705 }, 706 Answers: []Resource{{ResourceHeader{}, nil}}, 707 }, 708 &nestedError{"packing Answer", errNilResouceBody}, 709 }, 710 { 711 Message{ 712 Questions: []Question{ 713 { 714 Name: mustNewName("."), 715 Type: TypeAAAA, 716 Class: ClassINET, 717 }, 718 }, 719 Authorities: []Resource{{ResourceHeader{}, (*NSResource)(nil)}}, 720 }, 721 &nestedError{"packing Authority", 722 &nestedError{"ResourceHeader", 723 &nestedError{"Name", errNonCanonicalName}, 724 }, 725 }, 726 }, 727 { 728 Message{ 729 Questions: []Question{ 730 { 731 Name: mustNewName("."), 732 Type: TypeA, 733 Class: ClassINET, 734 }, 735 }, 736 Additionals: []Resource{{ResourceHeader{}, nil}}, 737 }, 738 &nestedError{"packing Additional", errNilResouceBody}, 739 }, 740 } { 741 _, err := tt.m.Pack() 742 if !reflect.DeepEqual(err, tt.err) { 743 t.Errorf("got %v for %v; want %v", err, tt.m, tt.err) 744 } 745 } 746 } 747 748 func benchmarkParsingSetup() ([]byte, error) { 749 name := mustNewName("foo.bar.example.com.") 750 msg := Message{ 751 Header: Header{Response: true, Authoritative: true}, 752 Questions: []Question{ 753 { 754 Name: name, 755 Type: TypeA, 756 Class: ClassINET, 757 }, 758 }, 759 Answers: []Resource{ 760 { 761 ResourceHeader{ 762 Name: name, 763 Class: ClassINET, 764 }, 765 &AResource{[4]byte{}}, 766 }, 767 { 768 ResourceHeader{ 769 Name: name, 770 Class: ClassINET, 771 }, 772 &AAAAResource{[16]byte{}}, 773 }, 774 { 775 ResourceHeader{ 776 Name: name, 777 Class: ClassINET, 778 }, 779 &CNAMEResource{name}, 780 }, 781 { 782 ResourceHeader{ 783 Name: name, 784 Class: ClassINET, 785 }, 786 &NSResource{name}, 787 }, 788 }, 789 } 790 791 buf, err := msg.Pack() 792 if err != nil { 793 return nil, fmt.Errorf("msg.Pack(): %v", err) 794 } 795 return buf, nil 796 } 797 798 func benchmarkParsing(tb testing.TB, buf []byte) { 799 var p Parser 800 if _, err := p.Start(buf); err != nil { 801 tb.Fatal("p.Start(buf):", err) 802 } 803 804 for { 805 _, err := p.Question() 806 if err == ErrSectionDone { 807 break 808 } 809 if err != nil { 810 tb.Fatal("p.Question():", err) 811 } 812 } 813 814 for { 815 h, err := p.AnswerHeader() 816 if err == ErrSectionDone { 817 break 818 } 819 if err != nil { 820 panic(err) 821 } 822 823 switch h.Type { 824 case TypeA: 825 if _, err := p.AResource(); err != nil { 826 tb.Fatal("p.AResource():", err) 827 } 828 case TypeAAAA: 829 if _, err := p.AAAAResource(); err != nil { 830 tb.Fatal("p.AAAAResource():", err) 831 } 832 case TypeCNAME: 833 if _, err := p.CNAMEResource(); err != nil { 834 tb.Fatal("p.CNAMEResource():", err) 835 } 836 case TypeNS: 837 if _, err := p.NSResource(); err != nil { 838 tb.Fatal("p.NSResource():", err) 839 } 840 default: 841 tb.Fatalf("unknown type: %T", h) 842 } 843 } 844 } 845 846 func BenchmarkParsing(b *testing.B) { 847 buf, err := benchmarkParsingSetup() 848 if err != nil { 849 b.Fatal(err) 850 } 851 852 b.ReportAllocs() 853 for i := 0; i < b.N; i++ { 854 benchmarkParsing(b, buf) 855 } 856 } 857 858 func TestParsingAllocs(t *testing.T) { 859 buf, err := benchmarkParsingSetup() 860 if err != nil { 861 t.Fatal(err) 862 } 863 864 if allocs := testing.AllocsPerRun(100, func() { benchmarkParsing(t, buf) }); allocs > 0.5 { 865 t.Errorf("Allocations during parsing: got = %f, want ~0", allocs) 866 } 867 } 868 869 func benchmarkBuildingSetup() (Name, []byte) { 870 name := mustNewName("foo.bar.example.com.") 871 buf := make([]byte, 0, packStartingCap) 872 return name, buf 873 } 874 875 func benchmarkBuilding(tb testing.TB, name Name, buf []byte) { 876 bld := NewBuilder(buf, Header{Response: true, Authoritative: true}) 877 878 if err := bld.StartQuestions(); err != nil { 879 tb.Fatal("bld.StartQuestions():", err) 880 } 881 q := Question{ 882 Name: name, 883 Type: TypeA, 884 Class: ClassINET, 885 } 886 if err := bld.Question(q); err != nil { 887 tb.Fatalf("bld.Question(%+v): %v", q, err) 888 } 889 890 hdr := ResourceHeader{ 891 Name: name, 892 Class: ClassINET, 893 } 894 if err := bld.StartAnswers(); err != nil { 895 tb.Fatal("bld.StartQuestions():", err) 896 } 897 898 ar := AResource{[4]byte{}} 899 if err := bld.AResource(hdr, ar); err != nil { 900 tb.Fatalf("bld.AResource(%+v, %+v): %v", hdr, ar, err) 901 } 902 903 aaar := AAAAResource{[16]byte{}} 904 if err := bld.AAAAResource(hdr, aaar); err != nil { 905 tb.Fatalf("bld.AAAAResource(%+v, %+v): %v", hdr, aaar, err) 906 } 907 908 cnr := CNAMEResource{name} 909 if err := bld.CNAMEResource(hdr, cnr); err != nil { 910 tb.Fatalf("bld.CNAMEResource(%+v, %+v): %v", hdr, cnr, err) 911 } 912 913 nsr := NSResource{name} 914 if err := bld.NSResource(hdr, nsr); err != nil { 915 tb.Fatalf("bld.NSResource(%+v, %+v): %v", hdr, nsr, err) 916 } 917 918 if _, err := bld.Finish(); err != nil { 919 tb.Fatal("bld.Finish():", err) 920 } 921 } 922 923 func BenchmarkBuilding(b *testing.B) { 924 name, buf := benchmarkBuildingSetup() 925 b.ReportAllocs() 926 for i := 0; i < b.N; i++ { 927 benchmarkBuilding(b, name, buf) 928 } 929 } 930 931 func TestBuildingAllocs(t *testing.T) { 932 name, buf := benchmarkBuildingSetup() 933 if allocs := testing.AllocsPerRun(100, func() { benchmarkBuilding(t, name, buf) }); allocs > 0.5 { 934 t.Errorf("Allocations during building: got = %f, want ~0", allocs) 935 } 936 } 937 938 func smallTestMsg() Message { 939 name := mustNewName("example.com.") 940 return Message{ 941 Header: Header{Response: true, Authoritative: true}, 942 Questions: []Question{ 943 { 944 Name: name, 945 Type: TypeA, 946 Class: ClassINET, 947 }, 948 }, 949 Answers: []Resource{ 950 { 951 ResourceHeader{ 952 Name: name, 953 Type: TypeA, 954 Class: ClassINET, 955 }, 956 &AResource{[4]byte{127, 0, 0, 1}}, 957 }, 958 }, 959 Authorities: []Resource{ 960 { 961 ResourceHeader{ 962 Name: name, 963 Type: TypeA, 964 Class: ClassINET, 965 }, 966 &AResource{[4]byte{127, 0, 0, 1}}, 967 }, 968 }, 969 Additionals: []Resource{ 970 { 971 ResourceHeader{ 972 Name: name, 973 Type: TypeA, 974 Class: ClassINET, 975 }, 976 &AResource{[4]byte{127, 0, 0, 1}}, 977 }, 978 }, 979 } 980 } 981 982 func BenchmarkPack(b *testing.B) { 983 msg := largeTestMsg() 984 985 b.ReportAllocs() 986 987 for i := 0; i < b.N; i++ { 988 if _, err := msg.Pack(); err != nil { 989 b.Fatal(err) 990 } 991 } 992 } 993 994 func BenchmarkAppendPack(b *testing.B) { 995 msg := largeTestMsg() 996 buf := make([]byte, 0, packStartingCap) 997 998 b.ReportAllocs() 999 1000 for i := 0; i < b.N; i++ { 1001 if _, err := msg.AppendPack(buf[:0]); err != nil { 1002 b.Fatal(err) 1003 } 1004 } 1005 } 1006 1007 func largeTestMsg() Message { 1008 name := mustNewName("foo.bar.example.com.") 1009 return Message{ 1010 Header: Header{Response: true, Authoritative: true}, 1011 Questions: []Question{ 1012 { 1013 Name: name, 1014 Type: TypeA, 1015 Class: ClassINET, 1016 }, 1017 }, 1018 Answers: []Resource{ 1019 { 1020 ResourceHeader{ 1021 Name: name, 1022 Type: TypeA, 1023 Class: ClassINET, 1024 }, 1025 &AResource{[4]byte{127, 0, 0, 1}}, 1026 }, 1027 { 1028 ResourceHeader{ 1029 Name: name, 1030 Type: TypeA, 1031 Class: ClassINET, 1032 }, 1033 &AResource{[4]byte{127, 0, 0, 2}}, 1034 }, 1035 { 1036 ResourceHeader{ 1037 Name: name, 1038 Type: TypeAAAA, 1039 Class: ClassINET, 1040 }, 1041 &AAAAResource{[16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}, 1042 }, 1043 { 1044 ResourceHeader{ 1045 Name: name, 1046 Type: TypeCNAME, 1047 Class: ClassINET, 1048 }, 1049 &CNAMEResource{mustNewName("alias.example.com.")}, 1050 }, 1051 { 1052 ResourceHeader{ 1053 Name: name, 1054 Type: TypeSOA, 1055 Class: ClassINET, 1056 }, 1057 &SOAResource{ 1058 NS: mustNewName("ns1.example.com."), 1059 MBox: mustNewName("mb.example.com."), 1060 Serial: 1, 1061 Refresh: 2, 1062 Retry: 3, 1063 Expire: 4, 1064 MinTTL: 5, 1065 }, 1066 }, 1067 { 1068 ResourceHeader{ 1069 Name: name, 1070 Type: TypePTR, 1071 Class: ClassINET, 1072 }, 1073 &PTRResource{mustNewName("ptr.example.com.")}, 1074 }, 1075 { 1076 ResourceHeader{ 1077 Name: name, 1078 Type: TypeMX, 1079 Class: ClassINET, 1080 }, 1081 &MXResource{ 1082 7, 1083 mustNewName("mx.example.com."), 1084 }, 1085 }, 1086 { 1087 ResourceHeader{ 1088 Name: name, 1089 Type: TypeSRV, 1090 Class: ClassINET, 1091 }, 1092 &SRVResource{ 1093 8, 1094 9, 1095 11, 1096 mustNewName("srv.example.com."), 1097 }, 1098 }, 1099 }, 1100 Authorities: []Resource{ 1101 { 1102 ResourceHeader{ 1103 Name: name, 1104 Type: TypeNS, 1105 Class: ClassINET, 1106 }, 1107 &NSResource{mustNewName("ns1.example.com.")}, 1108 }, 1109 { 1110 ResourceHeader{ 1111 Name: name, 1112 Type: TypeNS, 1113 Class: ClassINET, 1114 }, 1115 &NSResource{mustNewName("ns2.example.com.")}, 1116 }, 1117 }, 1118 Additionals: []Resource{ 1119 { 1120 ResourceHeader{ 1121 Name: name, 1122 Type: TypeTXT, 1123 Class: ClassINET, 1124 }, 1125 &TXTResource{[]string{"So Long, and Thanks for All the Fish"}}, 1126 }, 1127 { 1128 ResourceHeader{ 1129 Name: name, 1130 Type: TypeTXT, 1131 Class: ClassINET, 1132 }, 1133 &TXTResource{[]string{"Hamster Huey and the Gooey Kablooie"}}, 1134 }, 1135 }, 1136 } 1137 }