github.com/confluentinc/confluent-kafka-go@v1.9.2/kafka/adminapi_test.go (about) 1 /** 2 * Copyright 2018 Confluent Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package kafka 18 19 import ( 20 "context" 21 "strings" 22 "testing" 23 "time" 24 ) 25 26 // TestAdminAPIWithDefaultValue tests CreateTopics with default 27 // NumPartitions and ReplicationFactor values 28 func TestAdminAPIWithDefaultValue(t *testing.T) { 29 if !testconfRead() { 30 t.Skipf("Missing testconf.json") 31 } 32 33 topic := "testWithDefaultValue" 34 35 conf := ConfigMap{"bootstrap.servers": testconf.Brokers} 36 if err := conf.updateFromTestconf(); err != nil { 37 t.Fatalf("Failed to update test configuration: %v\n", err) 38 } 39 40 expDuration, err := time.ParseDuration("30s") 41 if err != nil { 42 t.Fatalf("Failed to Parse Duration: %s", err) 43 } 44 45 adminClient, err := NewAdminClient(&conf) 46 if err != nil { 47 t.Fatalf("Failed to create AdminClient %v", err) 48 } 49 50 ctx, cancel := context.WithTimeout(context.Background(), expDuration) 51 defer cancel() 52 res, err := adminClient.CreateTopics( 53 ctx, 54 []TopicSpecification{ 55 { 56 Topic: topic, 57 NumPartitions: -1, 58 ReplicationFactor: -1, 59 }, 60 }) 61 if err != nil { 62 adminClient.Close() 63 t.Fatalf("Failed to create topics %v\n", err) 64 } 65 t.Logf("Succeed to create topic %v\n", res) 66 67 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 68 defer cancel() 69 res, err = adminClient.DeleteTopics(ctx, []string{topic}) 70 if err != nil { 71 adminClient.Close() 72 t.Fatalf("Failed to delete topic %v, err: %v", topic, err) 73 } 74 t.Logf("Succeed to delete topic %v\n", res) 75 76 adminClient.Close() 77 } 78 79 func testAdminAPIsCreateACLs(what string, a *AdminClient, t *testing.T) { 80 var res []CreateACLResult 81 var err error 82 var ctx context.Context 83 var cancel context.CancelFunc 84 var expDuration time.Duration 85 var expDurationLonger time.Duration 86 var expError string 87 var invalidTests []ACLBindings 88 89 checkFail := func(res []CreateACLResult, err error) { 90 if res != nil || err == nil { 91 t.Fatalf("Expected CreateACLs to fail, but got result: %v, err: %v", res, err) 92 } 93 } 94 95 testACLBindings := ACLBindings{ 96 { 97 Type: ResourceTopic, 98 Name: "mytopic", 99 ResourcePatternType: ResourcePatternTypeLiteral, 100 Principal: "User:myuser", 101 Host: "*", 102 Operation: ACLOperationAll, 103 PermissionType: ACLPermissionTypeAllow, 104 }, 105 } 106 107 copyACLBindings := func() ACLBindings { 108 return append(ACLBindings{}, testACLBindings...) 109 } 110 111 t.Logf("AdminClient API - ACLs testing on %s: %s", a, what) 112 expDuration, err = time.ParseDuration("0.1s") 113 if err != nil { 114 t.Fatalf("%s", err) 115 } 116 117 // nil aclBindings 118 res, err = a.CreateACLs(ctx, nil) 119 checkFail(res, err) 120 expError = "Expected non-nil slice of ACLBinding structs" 121 if err.Error() != expError { 122 t.Fatalf("Expected error \"%s\", received: \"%v\"", expError, err.Error()) 123 } 124 125 // empty aclBindings 126 res, err = a.CreateACLs(ctx, ACLBindings{}) 127 checkFail(res, err) 128 expError = "Expected non-empty slice of ACLBinding structs" 129 if err.Error() != expError { 130 t.Fatalf("Expected error \"%s\", received: \"%v\"", expError, err.Error()) 131 } 132 133 // Correct input, fail with timeout 134 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 135 defer cancel() 136 137 res, err = a.CreateACLs(ctx, testACLBindings) 138 checkFail(res, err) 139 if ctx.Err() != context.DeadlineExceeded { 140 t.Fatalf("Expected DeadlineExceeded, not %v, %v", ctx.Err(), err) 141 } 142 143 // request timeout comes before context deadline 144 expDurationLonger, err = time.ParseDuration("0.2s") 145 if err != nil { 146 t.Fatalf("%s", err) 147 } 148 149 ctx, cancel = context.WithTimeout(context.Background(), expDurationLonger) 150 defer cancel() 151 152 res, err = a.CreateACLs(ctx, testACLBindings, SetAdminRequestTimeout(expDuration)) 153 checkFail(res, err) 154 expError = "Failed while waiting for controller: Local: Timed out" 155 if err.Error() != expError { 156 t.Fatalf("Expected error \"%s\", received: \"%v\"", expError, err.Error()) 157 } 158 159 // Invalid ACL bindings 160 invalidTests = []ACLBindings{copyACLBindings(), copyACLBindings()} 161 invalidTests[0][0].Type = ResourceUnknown 162 invalidTests[1][0].Type = ResourceAny 163 expError = ": Invalid resource type" 164 for _, invalidACLBindings := range invalidTests { 165 res, err = a.CreateACLs(ctx, invalidACLBindings) 166 checkFail(res, err) 167 if !strings.HasSuffix(err.Error(), expError) { 168 t.Fatalf("Expected an error ending with \"%s\", received: \"%s\"", expError, err.Error()) 169 } 170 } 171 172 suffixes := []string{ 173 ": Invalid resource pattern type", 174 ": Invalid resource pattern type", 175 ": Invalid resource pattern type", 176 ": Invalid operation", 177 ": Invalid operation", 178 ": Invalid permission type", 179 ": Invalid permission type", 180 ": Invalid resource name", 181 ": Invalid principal", 182 ": Invalid host", 183 } 184 nInvalidTests := len(suffixes) 185 invalidTests = make([]ACLBindings, nInvalidTests) 186 for i := 0; i < nInvalidTests; i++ { 187 invalidTests[i] = copyACLBindings() 188 } 189 invalidTests[0][0].ResourcePatternType = ResourcePatternTypeUnknown 190 invalidTests[1][0].ResourcePatternType = ResourcePatternTypeMatch 191 invalidTests[2][0].ResourcePatternType = ResourcePatternTypeAny 192 invalidTests[3][0].Operation = ACLOperationUnknown 193 invalidTests[4][0].Operation = ACLOperationAny 194 invalidTests[5][0].PermissionType = ACLPermissionTypeUnknown 195 invalidTests[6][0].PermissionType = ACLPermissionTypeAny 196 invalidTests[7][0].Name = "" 197 invalidTests[8][0].Principal = "" 198 invalidTests[9][0].Host = "" 199 200 for i, invalidACLBindings := range invalidTests { 201 res, err = a.CreateACLs(ctx, invalidACLBindings) 202 checkFail(res, err) 203 if !strings.HasSuffix(err.Error(), suffixes[i]) { 204 t.Fatalf("Expected an error ending with \"%s\", received: \"%s\"", suffixes[i], err.Error()) 205 } 206 } 207 } 208 209 func testAdminAPIsDescribeACLs(what string, a *AdminClient, t *testing.T) { 210 var res *DescribeACLsResult 211 var err error 212 var ctx context.Context 213 var cancel context.CancelFunc 214 var expDuration time.Duration 215 var expDurationLonger time.Duration 216 var expError string 217 218 checkFail := func(res *DescribeACLsResult, err error) { 219 if res != nil || err == nil { 220 t.Fatalf("Expected DescribeACLs to fail, but got result: %v, err: %v", res, err) 221 } 222 } 223 224 aclBindingsFilter := ACLBindingFilter{ 225 Type: ResourceTopic, 226 ResourcePatternType: ResourcePatternTypeLiteral, 227 Operation: ACLOperationAll, 228 PermissionType: ACLPermissionTypeAllow, 229 } 230 231 t.Logf("AdminClient API - ACLs testing on %s: %s", a, what) 232 expDuration, err = time.ParseDuration("0.1s") 233 if err != nil { 234 t.Fatalf("%s", err) 235 } 236 237 // Correct input, fail with timeout 238 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 239 defer cancel() 240 241 res, err = a.DescribeACLs(ctx, aclBindingsFilter) 242 checkFail(res, err) 243 if ctx.Err() != context.DeadlineExceeded { 244 t.Fatalf("Expected DeadlineExceeded, not %v, %v", ctx.Err(), err) 245 } 246 247 // request timeout comes before context deadline 248 expDurationLonger, err = time.ParseDuration("0.2s") 249 if err != nil { 250 t.Fatalf("%s", err) 251 } 252 253 ctx, cancel = context.WithTimeout(context.Background(), expDurationLonger) 254 defer cancel() 255 256 res, err = a.DescribeACLs(ctx, aclBindingsFilter, SetAdminRequestTimeout(expDuration)) 257 checkFail(res, err) 258 expError = "Failed while waiting for controller: Local: Timed out" 259 if err.Error() != expError { 260 t.Fatalf("Expected error \"%s\", received: \"%v\"", expError, err.Error()) 261 } 262 263 // Invalid ACL binding filters 264 suffixes := []string{ 265 ": Invalid resource pattern type", 266 ": Invalid operation", 267 ": Invalid permission type", 268 } 269 nInvalidTests := len(suffixes) 270 invalidTests := make(ACLBindingFilters, nInvalidTests) 271 for i := 0; i < nInvalidTests; i++ { 272 invalidTests[i] = aclBindingsFilter 273 } 274 invalidTests[0].ResourcePatternType = ResourcePatternTypeUnknown 275 invalidTests[1].Operation = ACLOperationUnknown 276 invalidTests[2].PermissionType = ACLPermissionTypeUnknown 277 278 for i, invalidACLBindingFilter := range invalidTests { 279 res, err = a.DescribeACLs(ctx, invalidACLBindingFilter) 280 checkFail(res, err) 281 if !strings.HasSuffix(err.Error(), suffixes[i]) { 282 t.Fatalf("Expected an error ending with \"%s\", received: \"%s\"", suffixes[i], err.Error()) 283 } 284 } 285 286 // ACL binding filters are valid with empty strings, 287 // matching any value 288 validTests := [3]ACLBindingFilter{} 289 for i := 0; i < len(validTests); i++ { 290 validTests[i] = aclBindingsFilter 291 } 292 validTests[0].Name = "" 293 validTests[1].Principal = "" 294 validTests[2].Host = "" 295 296 for _, validACLBindingFilter := range validTests { 297 res, err = a.DescribeACLs(ctx, validACLBindingFilter) 298 checkFail(res, err) 299 if ctx.Err() != context.DeadlineExceeded { 300 t.Fatalf("Expected DeadlineExceeded, not %v, %v", ctx.Err(), err) 301 } 302 } 303 } 304 305 func testAdminAPIsDeleteACLs(what string, a *AdminClient, t *testing.T) { 306 var res []DeleteACLsResult 307 var err error 308 var ctx context.Context 309 var cancel context.CancelFunc 310 var expDuration time.Duration 311 var expDurationLonger time.Duration 312 var expError string 313 314 checkFail := func(res []DeleteACLsResult, err error) { 315 if res != nil || err == nil { 316 t.Fatalf("Expected DeleteACL to fail, but got result: %v, err: %v", res, err) 317 } 318 } 319 320 aclBindingsFilters := ACLBindingFilters{ 321 { 322 Type: ResourceTopic, 323 ResourcePatternType: ResourcePatternTypeLiteral, 324 Operation: ACLOperationAll, 325 PermissionType: ACLPermissionTypeAllow, 326 }, 327 } 328 329 copyACLBindingFilters := func() ACLBindingFilters { 330 return append(ACLBindingFilters{}, aclBindingsFilters...) 331 } 332 333 t.Logf("AdminClient API - ACLs testing on %s: %s", a, what) 334 expDuration, err = time.ParseDuration("0.1s") 335 if err != nil { 336 t.Fatalf("%s", err) 337 } 338 339 // nil aclBindingFilters 340 res, err = a.DeleteACLs(ctx, nil) 341 checkFail(res, err) 342 expError = "Expected non-nil slice of ACLBindingFilter structs" 343 if err.Error() != expError { 344 t.Fatalf("Expected error \"%s\", received: \"%v\"", expError, err.Error()) 345 } 346 347 // empty aclBindingFilters 348 res, err = a.DeleteACLs(ctx, ACLBindingFilters{}) 349 checkFail(res, err) 350 expError = "Expected non-empty slice of ACLBindingFilter structs" 351 if err.Error() != expError { 352 t.Fatalf("Expected error \"%s\", received: \"%v\"", expError, err.Error()) 353 } 354 355 // Correct input, fail with timeout 356 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 357 defer cancel() 358 359 res, err = a.DeleteACLs(ctx, aclBindingsFilters) 360 checkFail(res, err) 361 if ctx.Err() != context.DeadlineExceeded { 362 t.Fatalf("Expected DeadlineExceeded, not %v, %v", ctx.Err(), err) 363 } 364 365 // request timeout comes before context deadline 366 expDurationLonger, err = time.ParseDuration("0.2s") 367 if err != nil { 368 t.Fatalf("%s", err) 369 } 370 371 ctx, cancel = context.WithTimeout(context.Background(), expDurationLonger) 372 defer cancel() 373 374 res, err = a.DeleteACLs(ctx, aclBindingsFilters, SetAdminRequestTimeout(expDuration)) 375 checkFail(res, err) 376 expError = "Failed while waiting for controller: Local: Timed out" 377 if err.Error() != expError { 378 t.Fatalf("Expected error \"%s\", received: \"%v\"", expError, err.Error()) 379 } 380 381 // Invalid ACL binding filters 382 suffixes := []string{ 383 ": Invalid resource pattern type", 384 ": Invalid operation", 385 ": Invalid permission type", 386 } 387 nInvalidTests := len(suffixes) 388 invalidTests := make([]ACLBindingFilters, nInvalidTests) 389 for i := 0; i < nInvalidTests; i++ { 390 invalidTests[i] = copyACLBindingFilters() 391 } 392 invalidTests[0][0].ResourcePatternType = ResourcePatternTypeUnknown 393 invalidTests[1][0].Operation = ACLOperationUnknown 394 invalidTests[2][0].PermissionType = ACLPermissionTypeUnknown 395 396 for i, invalidACLBindingFilters := range invalidTests { 397 res, err = a.DeleteACLs(ctx, invalidACLBindingFilters) 398 checkFail(res, err) 399 if !strings.HasSuffix(err.Error(), suffixes[i]) { 400 t.Fatalf("Expected an error ending with \"%s\", received: \"%s\"", suffixes[i], err.Error()) 401 } 402 } 403 404 // ACL binding filters are valid with empty strings, 405 // matching any value 406 validTests := [3]ACLBindingFilters{} 407 for i := 0; i < len(validTests); i++ { 408 validTests[i] = copyACLBindingFilters() 409 } 410 validTests[0][0].Name = "" 411 validTests[1][0].Principal = "" 412 validTests[2][0].Host = "" 413 414 for _, validACLBindingFilters := range validTests { 415 res, err = a.DeleteACLs(ctx, validACLBindingFilters) 416 checkFail(res, err) 417 if ctx.Err() != context.DeadlineExceeded { 418 t.Fatalf("Expected DeadlineExceeded, not %v, %v", ctx.Err(), err) 419 } 420 } 421 } 422 423 func testAdminAPIs(what string, a *AdminClient, t *testing.T) { 424 t.Logf("AdminClient API testing on %s: %s", a, what) 425 426 expDuration, err := time.ParseDuration("0.1s") 427 if err != nil { 428 t.Fatalf("%s", err) 429 } 430 431 confStrings := map[string]string{ 432 "some.topic.config": "unchecked", 433 "these.are.verified": "on the broker", 434 "and.this.is": "just", 435 "a": "unit test"} 436 437 // Correct input, fail with timeout 438 ctx, cancel := context.WithTimeout(context.Background(), expDuration) 439 defer cancel() 440 res, err := a.CreateTopics( 441 ctx, 442 []TopicSpecification{ 443 { 444 Topic: "mytopic", 445 NumPartitions: 7, 446 ReplicationFactor: 3, 447 }, 448 { 449 Topic: "mytopic2", 450 NumPartitions: 2, 451 ReplicaAssignment: [][]int32{ 452 []int32{1, 2, 3}, 453 []int32{3, 2, 1}, 454 }, 455 }, 456 { 457 Topic: "mytopic3", 458 NumPartitions: 10000, 459 ReplicationFactor: 90, 460 Config: confStrings, 461 }, 462 }) 463 if res != nil || err == nil { 464 t.Fatalf("Expected CreateTopics to fail, but got result: %v, err: %v", res, err) 465 } 466 if ctx.Err() != context.DeadlineExceeded { 467 t.Fatalf("Expected DeadlineExceeded, not %v, %v", ctx.Err(), err) 468 } 469 470 // Incorrect input, fail with ErrInvalidArg 471 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 472 defer cancel() 473 res, err = a.CreateTopics( 474 ctx, 475 []TopicSpecification{ 476 { 477 // Must not specify both ReplicationFactor and ReplicaAssignment 478 Topic: "mytopic", 479 NumPartitions: 2, 480 ReplicationFactor: 3, 481 ReplicaAssignment: [][]int32{ 482 []int32{1, 2, 3}, 483 []int32{3, 2, 1}, 484 }, 485 }, 486 }) 487 if res != nil || err == nil { 488 t.Fatalf("Expected CreateTopics to fail, but got result: %v, err: %v", res, err) 489 } 490 if ctx.Err() != nil { 491 t.Fatalf("Did not expect context to fail: %v", ctx.Err()) 492 } 493 if err.(Error).Code() != ErrInvalidArg { 494 t.Fatalf("Expected ErrInvalidArg, not %v", err) 495 } 496 497 // Incorrect input, fail with ErrInvalidArg 498 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 499 defer cancel() 500 res, err = a.CreateTopics( 501 ctx, 502 []TopicSpecification{ 503 { 504 // ReplicaAssignment must be same length as Numpartitions 505 Topic: "mytopic", 506 NumPartitions: 7, 507 ReplicaAssignment: [][]int32{ 508 []int32{1, 2, 3}, 509 []int32{3, 2, 1}, 510 }, 511 }, 512 }) 513 if res != nil || err == nil { 514 t.Fatalf("Expected CreateTopics to fail, but got result: %v, err: %v", res, err) 515 } 516 if ctx.Err() != nil { 517 t.Fatalf("Did not expect context to fail: %v", ctx.Err()) 518 } 519 if err.(Error).Code() != ErrInvalidArg { 520 t.Fatalf("Expected ErrInvalidArg, not %v", err) 521 } 522 523 // Correct input, using options 524 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 525 defer cancel() 526 res, err = a.CreateTopics( 527 ctx, 528 []TopicSpecification{ 529 { 530 Topic: "mytopic4", 531 NumPartitions: 9, 532 ReplicaAssignment: [][]int32{ 533 []int32{1}, 534 []int32{2}, 535 []int32{3}, 536 []int32{4}, 537 []int32{1}, 538 []int32{2}, 539 []int32{3}, 540 []int32{4}, 541 []int32{1}, 542 }, 543 Config: map[string]string{ 544 "some.topic.config": "unchecked", 545 "these.are.verified": "on the broker", 546 "and.this.is": "just", 547 "a": "unit test", 548 }, 549 }, 550 }, 551 SetAdminValidateOnly(false)) 552 if res != nil || err == nil { 553 t.Fatalf("Expected CreateTopics to fail, but got result: %v, err: %v", res, err) 554 } 555 if ctx.Err() != context.DeadlineExceeded { 556 t.Fatalf("Expected DeadlineExceeded, not %v", ctx.Err()) 557 } 558 559 // 560 // Remaining APIs 561 // Timeout code is identical for all APIs, no need to test 562 // them for each API. 563 // 564 565 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 566 defer cancel() 567 res, err = a.CreatePartitions( 568 ctx, 569 []PartitionsSpecification{ 570 { 571 Topic: "topic", 572 IncreaseTo: 19, 573 ReplicaAssignment: [][]int32{ 574 []int32{3234522}, 575 []int32{99999}, 576 }, 577 }, 578 { 579 Topic: "topic2", 580 IncreaseTo: 2, 581 ReplicaAssignment: [][]int32{ 582 []int32{99999}, 583 }, 584 }, 585 }) 586 if res != nil || err == nil { 587 t.Fatalf("Expected CreatePartitions to fail, but got result: %v, err: %v", res, err) 588 } 589 if ctx.Err() != context.DeadlineExceeded { 590 t.Fatalf("Expected DeadlineExceeded, not %v", ctx.Err()) 591 } 592 593 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 594 defer cancel() 595 res, err = a.DeleteTopics( 596 ctx, 597 []string{"topic1", "topic2"}) 598 if res != nil || err == nil { 599 t.Fatalf("Expected DeleteTopics to fail, but got result: %v, err: %v", res, err) 600 } 601 if ctx.Err() != context.DeadlineExceeded { 602 t.Fatalf("Expected DeadlineExceeded, not %v for error %v", ctx.Err(), err) 603 } 604 605 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 606 defer cancel() 607 cres, err := a.AlterConfigs( 608 ctx, 609 []ConfigResource{{Type: ResourceTopic, Name: "topic"}}) 610 if cres != nil || err == nil { 611 t.Fatalf("Expected AlterConfigs to fail, but got result: %v, err: %v", cres, err) 612 } 613 if ctx.Err() != context.DeadlineExceeded { 614 t.Fatalf("Expected DeadlineExceeded, not %v", ctx.Err()) 615 } 616 617 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 618 defer cancel() 619 cres, err = a.DescribeConfigs( 620 ctx, 621 []ConfigResource{{Type: ResourceTopic, Name: "topic"}}) 622 if cres != nil || err == nil { 623 t.Fatalf("Expected DescribeConfigs to fail, but got result: %v, err: %v", cres, err) 624 } 625 if ctx.Err() != context.DeadlineExceeded { 626 t.Fatalf("Expected DeadlineExceeded, not %v", ctx.Err()) 627 } 628 629 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 630 defer cancel() 631 clusterID, err := a.ClusterID(ctx) 632 if err == nil { 633 t.Fatalf("Expected ClusterID to fail, but got result: %v", clusterID) 634 } 635 if ctx.Err() != context.DeadlineExceeded || err != context.DeadlineExceeded { 636 t.Fatalf("Expected DeadlineExceeded, not %v", ctx.Err()) 637 } 638 639 ctx, cancel = context.WithTimeout(context.Background(), expDuration) 640 defer cancel() 641 controllerID, err := a.ControllerID(ctx) 642 if err == nil { 643 t.Fatalf("Expected ControllerID to fail, but got result: %v", controllerID) 644 } 645 if ctx.Err() != context.DeadlineExceeded || err != context.DeadlineExceeded { 646 t.Fatalf("Expected DeadlineExceeded, not %v", ctx.Err()) 647 } 648 649 testAdminAPIsCreateACLs(what, a, t) 650 testAdminAPIsDescribeACLs(what, a, t) 651 testAdminAPIsDeleteACLs(what, a, t) 652 } 653 654 // TestAdminAPIs dry-tests most Admin APIs, no broker is needed. 655 func TestAdminAPIs(t *testing.T) { 656 657 a, err := NewAdminClient(&ConfigMap{}) 658 if err != nil { 659 t.Fatalf("%s", err) 660 } 661 662 testAdminAPIs("Non-derived, no config", a, t) 663 a.Close() 664 665 a, err = NewAdminClient(&ConfigMap{"retries": 1234}) 666 if err != nil { 667 t.Fatalf("%s", err) 668 } 669 670 testAdminAPIs("Non-derived, config", a, t) 671 a.Close() 672 673 // Test derived clients 674 c, err := NewConsumer(&ConfigMap{"group.id": "test"}) 675 if err != nil { 676 t.Fatalf("%s", err) 677 } 678 defer c.Close() 679 680 a, err = NewAdminClientFromConsumer(c) 681 if err != nil { 682 t.Fatalf("%s", err) 683 } 684 685 if !strings.Contains(a.String(), c.String()) { 686 t.Fatalf("Expected derived client %s to have similar name to parent %s", a, c) 687 } 688 689 testAdminAPIs("Derived from consumer", a, t) 690 a.Close() 691 692 a, err = NewAdminClientFromConsumer(c) 693 if err != nil { 694 t.Fatalf("%s", err) 695 } 696 697 if !strings.Contains(a.String(), c.String()) { 698 t.Fatalf("Expected derived client %s to have similar name to parent %s", a, c) 699 } 700 701 testAdminAPIs("Derived from same consumer", a, t) 702 a.Close() 703 704 p, err := NewProducer(&ConfigMap{}) 705 if err != nil { 706 t.Fatalf("%s", err) 707 } 708 defer p.Close() 709 710 a, err = NewAdminClientFromProducer(p) 711 if err != nil { 712 t.Fatalf("%s", err) 713 } 714 715 if !strings.Contains(a.String(), p.String()) { 716 t.Fatalf("Expected derived client %s to have similar name to parent %s", a, p) 717 } 718 719 testAdminAPIs("Derived from Producer", a, t) 720 a.Close() 721 722 a, err = NewAdminClientFromProducer(p) 723 if err != nil { 724 t.Fatalf("%s", err) 725 } 726 727 if !strings.Contains(a.String(), p.String()) { 728 t.Fatalf("Expected derived client %s to have similar name to parent %s", a, p) 729 } 730 731 testAdminAPIs("Derived from same Producer", a, t) 732 a.Close() 733 }