github.com/vishvananda/netlink@v1.3.0/ipset_linux_test.go (about) 1 package netlink 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "net" 7 "testing" 8 9 "github.com/vishvananda/netlink/nl" 10 "golang.org/x/sys/unix" 11 ) 12 13 func TestParseIpsetProtocolResult(t *testing.T) { 14 msgBytes, err := ioutil.ReadFile("testdata/ipset_protocol_result") 15 if err != nil { 16 t.Fatalf("reading test fixture failed: %v", err) 17 } 18 19 msg := ipsetUnserialize([][]byte{msgBytes}) 20 if msg.Protocol != 6 { 21 t.Errorf("expected msg.Protocol to equal 6, got %d", msg.Protocol) 22 } 23 } 24 25 func TestParseIpsetListResult(t *testing.T) { 26 msgBytes, err := ioutil.ReadFile("testdata/ipset_list_result") 27 if err != nil { 28 t.Fatalf("reading test fixture failed: %v", err) 29 } 30 31 msg := ipsetUnserialize([][]byte{msgBytes}) 32 if msg.SetName != "clients" { 33 t.Errorf(`expected SetName to equal "clients", got %q`, msg.SetName) 34 } 35 if msg.TypeName != "hash:mac" { 36 t.Errorf(`expected TypeName to equal "hash:mac", got %q`, msg.TypeName) 37 } 38 if msg.Protocol != 6 { 39 t.Errorf("expected Protocol to equal 6, got %d", msg.Protocol) 40 } 41 if msg.References != 0 { 42 t.Errorf("expected References to equal 0, got %d", msg.References) 43 } 44 if msg.NumEntries != 2 { 45 t.Errorf("expected NumEntries to equal 2, got %d", msg.NumEntries) 46 } 47 if msg.HashSize != 1024 { 48 t.Errorf("expected HashSize to equal 1024, got %d", msg.HashSize) 49 } 50 if *msg.Timeout != 3600 { 51 t.Errorf("expected Timeout to equal 3600, got %d", *msg.Timeout) 52 } 53 if msg.MaxElements != 65536 { 54 t.Errorf("expected MaxElements to equal 65536, got %d", msg.MaxElements) 55 } 56 if msg.CadtFlags != nl.IPSET_FLAG_WITH_COMMENT|nl.IPSET_FLAG_WITH_COUNTERS { 57 t.Error("expected CadtFlags to be IPSET_FLAG_WITH_COMMENT and IPSET_FLAG_WITH_COUNTERS") 58 } 59 if len(msg.Entries) != 2 { 60 t.Fatalf("expected 2 Entries, got %d", len(msg.Entries)) 61 } 62 63 // first entry 64 ent := msg.Entries[0] 65 if int(*ent.Timeout) != 3577 { 66 t.Errorf("expected Timeout for first entry to equal 3577, got %d", *ent.Timeout) 67 } 68 if int(*ent.Bytes) != 4121 { 69 t.Errorf("expected Bytes for first entry to equal 4121, got %d", *ent.Bytes) 70 } 71 if int(*ent.Packets) != 42 { 72 t.Errorf("expected Packets for first entry to equal 42, got %d", *ent.Packets) 73 } 74 if ent.Comment != "foo bar" { 75 t.Errorf("unexpected Comment for first entry: %q", ent.Comment) 76 } 77 expectedMAC := net.HardwareAddr{0xde, 0xad, 0x0, 0x0, 0xbe, 0xef} 78 if !bytes.Equal(ent.MAC, expectedMAC) { 79 t.Errorf("expected MAC for first entry to be %s, got %s", expectedMAC.String(), ent.MAC.String()) 80 } 81 82 // second entry 83 ent = msg.Entries[1] 84 expectedMAC = net.HardwareAddr{0x1, 0x2, 0x3, 0x0, 0x1, 0x2} 85 if !bytes.Equal(ent.MAC, expectedMAC) { 86 t.Errorf("expected MAC for second entry to be %s, got %s", expectedMAC.String(), ent.MAC.String()) 87 } 88 } 89 90 func TestIpsetCreateListAddDelDestroy(t *testing.T) { 91 tearDown := setUpNetlinkTest(t) 92 defer tearDown() 93 timeout := uint32(3) 94 err := IpsetCreate("my-test-ipset-1", "hash:ip", IpsetCreateOptions{ 95 Replace: true, 96 Timeout: &timeout, 97 Counters: true, 98 Comments: true, 99 Skbinfo: false, 100 }) 101 if err != nil { 102 t.Fatal(err) 103 } 104 105 err = IpsetCreate("my-test-ipset-2", "hash:net", IpsetCreateOptions{ 106 Replace: true, 107 Timeout: &timeout, 108 Counters: false, 109 Comments: true, 110 Skbinfo: true, 111 }) 112 if err != nil { 113 t.Fatal(err) 114 } 115 116 results, err := IpsetListAll() 117 118 if err != nil { 119 t.Fatal(err) 120 } 121 122 if len(results) != 2 { 123 t.Fatalf("expected 2 IPSets to be created, got %d", len(results)) 124 } 125 126 if results[0].SetName != "my-test-ipset-1" { 127 t.Errorf("expected name to be 'my-test-ipset-1', but got '%s'", results[0].SetName) 128 } 129 130 if results[1].SetName != "my-test-ipset-2" { 131 t.Errorf("expected name to be 'my-test-ipset-2', but got '%s'", results[1].SetName) 132 } 133 134 if results[0].TypeName != "hash:ip" { 135 t.Errorf("expected type to be 'hash:ip', but got '%s'", results[0].TypeName) 136 } 137 138 if results[1].TypeName != "hash:net" { 139 t.Errorf("expected type to be 'hash:net', but got '%s'", results[1].TypeName) 140 } 141 142 if *results[0].Timeout != 3 { 143 t.Errorf("expected timeout to be 3, but got '%d'", *results[0].Timeout) 144 } 145 146 ip := net.ParseIP("10.99.99.99") 147 exist, err := IpsetTest("my-test-ipset-1", &IPSetEntry{ 148 IP: ip, 149 }) 150 if err != nil { 151 t.Fatal(err) 152 } 153 if exist { 154 t.Errorf("entry should not exist before being added: %s", ip.String()) 155 } 156 157 err = IpsetAdd("my-test-ipset-1", &IPSetEntry{ 158 Comment: "test comment", 159 IP: ip, 160 Replace: false, 161 }) 162 163 if err != nil { 164 t.Fatal(err) 165 } 166 167 exist, err = IpsetTest("my-test-ipset-1", &IPSetEntry{ 168 IP: ip, 169 }) 170 if err != nil { 171 t.Fatal(err) 172 } 173 if !exist { 174 t.Errorf("entry should exist after being added: %s", ip.String()) 175 } 176 177 result, err := IpsetList("my-test-ipset-1") 178 179 if err != nil { 180 t.Fatal(err) 181 } 182 183 if len(result.Entries) != 1 { 184 t.Fatalf("expected 1 entry be created, got '%d'", len(result.Entries)) 185 } 186 if result.Entries[0].IP.String() != "10.99.99.99" { 187 t.Fatalf("expected entry to be '10.99.99.99', got '%s'", result.Entries[0].IP.String()) 188 } 189 190 if result.Entries[0].Comment != "test comment" { 191 // This is only supported in the kernel module from revision 2 or 4, so comments may be ignored. 192 t.Logf("expected comment to be 'test comment', got '%s'", result.Entries[0].Comment) 193 } 194 195 err = IpsetDel("my-test-ipset-1", &IPSetEntry{ 196 Comment: "test comment", 197 IP: net.ParseIP("10.99.99.99"), 198 }) 199 if err != nil { 200 t.Fatal(err) 201 } 202 203 result, err = IpsetList("my-test-ipset-1") 204 if err != nil { 205 t.Fatal(err) 206 } 207 208 if len(result.Entries) != 0 { 209 t.Fatalf("expected 0 entries to exist, got %d", len(result.Entries)) 210 } 211 212 err = IpsetDestroy("my-test-ipset-1") 213 if err != nil { 214 t.Fatal(err) 215 } 216 217 err = IpsetDestroy("my-test-ipset-2") 218 if err != nil { 219 t.Fatal(err) 220 } 221 } 222 223 func TestIpsetCreateListAddDelDestroyWithTestCases(t *testing.T) { 224 timeout := uint32(3) 225 protocalTCP := uint8(unix.IPPROTO_TCP) 226 port := uint16(80) 227 228 testCases := []struct { 229 desc string 230 setname string 231 typename string 232 options IpsetCreateOptions 233 entry *IPSetEntry 234 }{ 235 { 236 desc: "Type-hash:ip", 237 setname: "my-test-ipset-1", 238 typename: "hash:ip", 239 options: IpsetCreateOptions{ 240 Replace: true, 241 Timeout: &timeout, 242 Counters: true, 243 Comments: true, 244 Skbinfo: false, 245 }, 246 entry: &IPSetEntry{ 247 Comment: "test comment", 248 IP: net.ParseIP("10.99.99.99"), 249 Replace: false, 250 }, 251 }, 252 { 253 desc: "Type-hash:net", 254 setname: "my-test-ipset-2", 255 typename: "hash:net", 256 options: IpsetCreateOptions{ 257 Replace: true, 258 Timeout: &timeout, 259 Counters: false, 260 Comments: true, 261 Skbinfo: true, 262 }, 263 entry: &IPSetEntry{ 264 Comment: "test comment", 265 IP: net.ParseIP("10.99.99.0"), 266 CIDR: 24, 267 Replace: false, 268 }, 269 }, 270 { 271 desc: "Type-hash:net,net", 272 setname: "my-test-ipset-4", 273 typename: "hash:net,net", 274 options: IpsetCreateOptions{ 275 Replace: true, 276 Timeout: &timeout, 277 Counters: false, 278 Comments: true, 279 Skbinfo: true, 280 }, 281 entry: &IPSetEntry{ 282 Comment: "test comment", 283 IP: net.ParseIP("10.99.99.0"), 284 CIDR: 24, 285 IP2: net.ParseIP("10.99.0.0"), 286 CIDR2: 24, 287 Replace: false, 288 }, 289 }, 290 { 291 desc: "Type-hash:ip,ip", 292 setname: "my-test-ipset-5", 293 typename: "hash:net,net", 294 options: IpsetCreateOptions{ 295 Replace: true, 296 Timeout: &timeout, 297 Counters: false, 298 Comments: true, 299 Skbinfo: true, 300 }, 301 entry: &IPSetEntry{ 302 Comment: "test comment", 303 IP: net.ParseIP("10.99.99.0"), 304 IP2: net.ParseIP("10.99.0.0"), 305 Replace: false, 306 }, 307 }, 308 { 309 desc: "Type-hash:ip,port", 310 setname: "my-test-ipset-6", 311 typename: "hash:ip,port", 312 options: IpsetCreateOptions{ 313 Replace: true, 314 Timeout: &timeout, 315 Counters: false, 316 Comments: true, 317 Skbinfo: true, 318 }, 319 entry: &IPSetEntry{ 320 Comment: "test comment", 321 IP: net.ParseIP("10.99.99.1"), 322 Protocol: &protocalTCP, 323 Port: &port, 324 Replace: false, 325 }, 326 }, 327 { 328 desc: "Type-hash:net,port,net", 329 setname: "my-test-ipset-7", 330 typename: "hash:net,port,net", 331 options: IpsetCreateOptions{ 332 Replace: true, 333 Timeout: &timeout, 334 Counters: false, 335 Comments: true, 336 Skbinfo: true, 337 }, 338 entry: &IPSetEntry{ 339 Comment: "test comment", 340 IP: net.ParseIP("10.99.99.0"), 341 CIDR: 24, 342 IP2: net.ParseIP("10.99.0.0"), 343 CIDR2: 24, 344 Protocol: &protocalTCP, 345 Port: &port, 346 Replace: false, 347 }, 348 }, 349 { 350 desc: "Type-hash:mac", 351 setname: "my-test-ipset-8", 352 typename: "hash:mac", 353 options: IpsetCreateOptions{ 354 Replace: true, 355 Timeout: &timeout, 356 Counters: true, 357 Comments: true, 358 Skbinfo: false, 359 }, 360 entry: &IPSetEntry{ 361 Comment: "test comment", 362 MAC: net.HardwareAddr{0x26, 0x6f, 0x0d, 0x5b, 0xc1, 0x9d}, 363 Replace: false, 364 }, 365 }, 366 { 367 desc: "Type-hash:net,iface", 368 setname: "my-test-ipset-9", 369 typename: "hash:net,iface", 370 options: IpsetCreateOptions{ 371 Replace: true, 372 Timeout: &timeout, 373 Counters: true, 374 Comments: true, 375 Skbinfo: false, 376 }, 377 entry: &IPSetEntry{ 378 Comment: "test comment", 379 IP: net.ParseIP("10.99.99.0"), 380 CIDR: 24, 381 IFace: "eth0", 382 Replace: false, 383 }, 384 }, 385 { 386 desc: "Type-hash:ip,mark", 387 setname: "my-test-ipset-10", 388 typename: "hash:ip,mark", 389 options: IpsetCreateOptions{ 390 Replace: true, 391 Timeout: &timeout, 392 Counters: true, 393 Comments: true, 394 Skbinfo: false, 395 }, 396 entry: &IPSetEntry{ 397 Comment: "test comment", 398 IP: net.ParseIP("10.99.99.0"), 399 Mark: &timeout, 400 Replace: false, 401 }, 402 }, 403 { 404 desc: "Type-hash:net6", 405 setname: "my-test-ipset-11", 406 typename: "hash:net", 407 options: IpsetCreateOptions{ 408 Replace: true, 409 Timeout: &timeout, 410 Counters: false, 411 Comments: true, 412 Skbinfo: true, 413 Family: unix.AF_INET6, 414 }, 415 entry: &IPSetEntry{ 416 Comment: "test comment", 417 IP: net.ParseIP("::1"), 418 CIDR: 128, 419 Replace: false, 420 }, 421 }, 422 { 423 desc: "Type-hash:net6:net6", 424 setname: "my-test-ipset-11", 425 typename: "hash:net,net", 426 options: IpsetCreateOptions{ 427 Replace: true, 428 Timeout: &timeout, 429 Counters: false, 430 Comments: true, 431 Skbinfo: true, 432 Family: unix.AF_INET6, 433 }, 434 entry: &IPSetEntry{ 435 Comment: "test comment", 436 IP: net.ParseIP("::1"), 437 CIDR: 128, 438 IP2: net.ParseIP("::2"), 439 CIDR2: 128, 440 Replace: false, 441 }, 442 }, 443 } 444 445 for _, tC := range testCases { 446 t.Run(tC.desc, func(t *testing.T) { 447 tearDown := setUpNetlinkTest(t) 448 defer tearDown() 449 450 err := IpsetCreate(tC.setname, tC.typename, tC.options) 451 if err != nil { 452 t.Fatal(err) 453 } 454 455 result, err := IpsetList(tC.setname) 456 if err != nil { 457 t.Fatal(err) 458 } 459 460 if result.SetName != tC.setname { 461 t.Errorf("expected name to be '%s', but got '%s'", tC.setname, result.SetName) 462 } 463 464 if result.TypeName != tC.typename { 465 t.Errorf("expected type to be '%s', but got '%s'", tC.typename, result.TypeName) 466 } 467 468 if *result.Timeout != timeout { 469 t.Errorf("expected timeout to be %d, but got '%d'", timeout, *result.Timeout) 470 } 471 472 err = IpsetAdd(tC.setname, tC.entry) 473 474 if err != nil { 475 t.Error(result.Protocol, result.Family) 476 t.Fatal(err) 477 } 478 479 exist, err := IpsetTest(tC.setname, tC.entry) 480 if err != nil { 481 t.Fatal(err) 482 } 483 if !exist { 484 t.Errorf("entry should exist, but 'test' got false, case: %s", tC.desc) 485 } 486 487 result, err = IpsetList(tC.setname) 488 489 if err != nil { 490 t.Fatal(err) 491 } 492 493 if len(result.Entries) != 1 { 494 t.Fatalf("expected 1 entry be created, got '%d'", len(result.Entries)) 495 } 496 497 if tC.entry.IP != nil { 498 if !tC.entry.IP.Equal(result.Entries[0].IP) { 499 t.Fatalf("expected entry to be '%v', got '%v'", tC.entry.IP, result.Entries[0].IP) 500 } 501 } 502 503 if tC.entry.CIDR > 0 { 504 if result.Entries[0].CIDR != tC.entry.CIDR { 505 t.Fatalf("expected cidr to be '%d', got '%d'", tC.entry.CIDR, result.Entries[0].CIDR) 506 } 507 } 508 509 if tC.entry.IP2 != nil { 510 if !tC.entry.IP2.Equal(result.Entries[0].IP2) { 511 t.Fatalf("expected entry.ip2 to be '%v', got '%v'", tC.entry.IP2, result.Entries[0].IP2) 512 } 513 } 514 515 if tC.entry.CIDR2 > 0 { 516 if result.Entries[0].CIDR2 != tC.entry.CIDR2 { 517 t.Fatalf("expected cidr2 to be '%d', got '%d'", tC.entry.CIDR2, result.Entries[0].CIDR2) 518 } 519 } 520 521 if tC.entry.Port != nil { 522 if *result.Entries[0].Protocol != *tC.entry.Protocol { 523 t.Fatalf("expected protocol to be '%d', got '%d'", *tC.entry.Protocol, *result.Entries[0].Protocol) 524 } 525 if *result.Entries[0].Port != *tC.entry.Port { 526 t.Fatalf("expected port to be '%d', got '%d'", *tC.entry.Port, *result.Entries[0].Port) 527 } 528 } 529 530 if tC.entry.MAC != nil { 531 if result.Entries[0].MAC.String() != tC.entry.MAC.String() { 532 t.Fatalf("expected mac to be '%v', got '%v'", tC.entry.MAC, result.Entries[0].MAC) 533 } 534 } 535 536 if tC.entry.IFace != "" { 537 if result.Entries[0].IFace != tC.entry.IFace { 538 t.Fatalf("expected iface to be '%v', got '%v'", tC.entry.IFace, result.Entries[0].IFace) 539 } 540 } 541 542 if tC.entry.Mark != nil { 543 if *result.Entries[0].Mark != *tC.entry.Mark { 544 t.Fatalf("expected mark to be '%v', got '%v'", *tC.entry.Mark, *result.Entries[0].Mark) 545 } 546 } 547 548 if result.Entries[0].Comment != tC.entry.Comment { 549 // This is only supported in the kernel module from revision 2 or 4, so comments may be ignored. 550 t.Logf("expected comment to be '%s', got '%s'", tC.entry.Comment, result.Entries[0].Comment) 551 } 552 553 err = IpsetDel(tC.setname, tC.entry) 554 if err != nil { 555 t.Fatal(err) 556 } 557 558 exist, err = IpsetTest(tC.setname, tC.entry) 559 if err != nil { 560 t.Fatal(err) 561 } 562 if exist { 563 t.Errorf("entry should be deleted, but 'test' got true, case: %s", tC.desc) 564 } 565 566 result, err = IpsetList(tC.setname) 567 if err != nil { 568 t.Fatal(err) 569 } 570 571 if len(result.Entries) != 0 { 572 t.Fatalf("expected 0 entries to exist, got %d", len(result.Entries)) 573 } 574 575 err = IpsetDestroy(tC.setname) 576 if err != nil { 577 t.Fatal(err) 578 } 579 }) 580 } 581 } 582 583 func TestIpsetBitmapCreateListWithTestCases(t *testing.T) { 584 timeout := uint32(3) 585 586 testCases := []struct { 587 desc string 588 setname string 589 typename string 590 options IpsetCreateOptions 591 entry *IPSetEntry 592 }{ 593 { 594 desc: "Type-bitmap:port", 595 setname: "my-test-ipset-11", 596 typename: "bitmap:port", 597 options: IpsetCreateOptions{ 598 Replace: true, 599 Timeout: &timeout, 600 Counters: true, 601 Comments: false, 602 Skbinfo: false, 603 PortFrom: 100, 604 PortTo: 600, 605 }, 606 entry: &IPSetEntry{ 607 Comment: "test comment", 608 IP: net.ParseIP("10.99.99.0"), 609 CIDR: 26, 610 Mark: &timeout, 611 Replace: false, 612 }, 613 }, 614 } 615 616 for _, tC := range testCases { 617 t.Run(tC.desc, func(t *testing.T) { 618 tearDown := setUpNetlinkTest(t) 619 defer tearDown() 620 621 err := IpsetCreate(tC.setname, tC.typename, tC.options) 622 if err != nil { 623 t.Fatal(err) 624 } 625 626 result, err := IpsetList(tC.setname) 627 if err != nil { 628 t.Fatal(err) 629 } 630 631 if tC.typename == "bitmap:port" { 632 if result.PortFrom != tC.options.PortFrom || result.PortTo != tC.options.PortTo { 633 t.Fatalf("expected port range %d-%d, got %d-%d", tC.options.PortFrom, tC.options.PortTo, result.PortFrom, result.PortTo) 634 } 635 } else if tC.typename == "bitmap:ip" { 636 if result.IPFrom == nil || result.IPTo == nil || result.IPFrom.Equal(tC.options.IPFrom) || result.IPTo.Equal(tC.options.IPTo) { 637 t.Fatalf("expected ip range %v-%v, got %v-%v", tC.options.IPFrom, tC.options.IPTo, result.IPFrom, result.IPTo) 638 } 639 } 640 641 }) 642 } 643 } 644 645 func TestIpsetSwap(t *testing.T) { 646 tearDown := setUpNetlinkTest(t) 647 defer tearDown() 648 649 ipset1 := "my-test-ipset-swap-1" 650 ipset2 := "my-test-ipset-swap-2" 651 652 err := IpsetCreate(ipset1, "hash:ip", IpsetCreateOptions{ 653 Replace: true, 654 }) 655 if err != nil { 656 t.Fatal(err) 657 } 658 defer func() { 659 _ = IpsetDestroy(ipset1) 660 }() 661 662 err = IpsetCreate(ipset2, "hash:ip", IpsetCreateOptions{ 663 Replace: true, 664 }) 665 if err != nil { 666 t.Fatal(err) 667 } 668 defer func() { 669 _ = IpsetDestroy(ipset2) 670 }() 671 672 err = IpsetAdd(ipset1, &IPSetEntry{ 673 IP: net.ParseIP("10.99.99.99"), 674 }) 675 if err != nil { 676 t.Fatal(err) 677 } 678 679 assertHasOneEntry := func(name string) { 680 result, err := IpsetList(name) 681 if err != nil { 682 t.Fatal(err) 683 } 684 if len(result.Entries) != 1 { 685 t.Fatalf("expected 1 entry be created, got '%d'", len(result.Entries)) 686 } 687 if result.Entries[0].IP.String() != "10.99.99.99" { 688 t.Fatalf("expected entry to be '10.99.99.99', got '%s'", result.Entries[0].IP.String()) 689 } 690 } 691 692 assertIsEmpty := func(name string) { 693 result, err := IpsetList(name) 694 if err != nil { 695 t.Fatal(err) 696 } 697 if len(result.Entries) != 0 { 698 t.Fatalf("expected 0 entry be created, got '%d'", len(result.Entries)) 699 } 700 } 701 702 assertHasOneEntry(ipset1) 703 assertIsEmpty(ipset2) 704 705 err = IpsetSwap(ipset1, ipset2) 706 if err != nil { 707 t.Fatal(err) 708 } 709 710 assertIsEmpty(ipset1) 711 assertHasOneEntry(ipset2) 712 } 713 714 func nextIP(ip net.IP) { 715 for j := len(ip) - 1; j >= 0; j-- { 716 ip[j]++ 717 if ip[j] > 0 { 718 break 719 } 720 } 721 } 722 723 // TestIpsetMaxElements tests that we can create an ipset containing 724 // 128k elements, which is double the default size (64k elements). 725 func TestIpsetMaxElements(t *testing.T) { 726 tearDown := setUpNetlinkTest(t) 727 defer tearDown() 728 729 ipsetName := "my-test-ipset-max" 730 maxElements := uint32(128 << 10) 731 732 err := IpsetCreate(ipsetName, "hash:ip", IpsetCreateOptions{ 733 Replace: true, 734 MaxElements: maxElements, 735 }) 736 if err != nil { 737 t.Fatal(err) 738 } 739 defer func() { 740 _ = IpsetDestroy(ipsetName) 741 }() 742 743 ip := net.ParseIP("10.0.0.0") 744 for i := uint32(0); i < maxElements; i++ { 745 err = IpsetAdd(ipsetName, &IPSetEntry{ 746 IP: ip, 747 }) 748 if err != nil { 749 t.Fatal(err) 750 } 751 nextIP(ip) 752 } 753 754 result, err := IpsetList(ipsetName) 755 if err != nil { 756 t.Fatal(err) 757 } 758 if len(result.Entries) != int(maxElements) { 759 t.Fatalf("expected '%d' entry be created, got '%d'", maxElements, len(result.Entries)) 760 } 761 }