github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/sink/kafka/options_test.go (about) 1 // Copyright 2023 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package kafka 15 16 import ( 17 "context" 18 "fmt" 19 "net/url" 20 "strconv" 21 "strings" 22 "testing" 23 "time" 24 25 "github.com/IBM/sarama" 26 "github.com/aws/aws-sdk-go/aws" 27 "github.com/pingcap/errors" 28 "github.com/pingcap/tiflow/cdc/model" 29 "github.com/pingcap/tiflow/pkg/config" 30 cerror "github.com/pingcap/tiflow/pkg/errors" 31 "github.com/pingcap/tiflow/pkg/sink/codec/common" 32 "github.com/stretchr/testify/require" 33 ) 34 35 func TestCompleteOptions(t *testing.T) { 36 options := NewOptions() 37 38 // Normal config. 39 uriTemplate := "kafka://127.0.0.1:9092/kafka-test?kafka-version=2.6.0&max-batch-size=5" + 40 "&max-message-bytes=%s&partition-num=1&replication-factor=3" + 41 "&kafka-client-id=unit-test&auto-create-topic=false&compression=gzip&required-acks=1" 42 maxMessageSize := "4096" // 4kb 43 uri := fmt.Sprintf(uriTemplate, maxMessageSize) 44 sinkURI, err := url.Parse(uri) 45 require.NoError(t, err) 46 47 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 48 require.NoError(t, err) 49 require.Equal(t, int32(1), options.PartitionNum) 50 require.Equal(t, int16(3), options.ReplicationFactor) 51 require.Equal(t, "2.6.0", options.Version) 52 require.Equal(t, 4096, options.MaxMessageBytes) 53 require.Equal(t, WaitForLocal, options.RequiredAcks) 54 55 // multiple kafka broker endpoints 56 uri = "kafka://127.0.0.1:9092,127.0.0.1:9091,127.0.0.1:9090/kafka-test?" 57 sinkURI, err = url.Parse(uri) 58 require.NoError(t, err) 59 options = NewOptions() 60 err = options.Apply(model.DefaultChangeFeedID("test"), 61 sinkURI, config.GetDefaultReplicaConfig()) 62 require.NoError(t, err) 63 require.Len(t, options.BrokerEndpoints, 3) 64 65 // Illegal replication-factor. 66 uri = "kafka://127.0.0.1:9092/abc?kafka-version=2.6.0&replication-factor=a" 67 sinkURI, err = url.Parse(uri) 68 require.NoError(t, err) 69 options = NewOptions() 70 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 71 require.Regexp(t, ".*invalid syntax.*", errors.Cause(err)) 72 73 // Illegal max-message-bytes. 74 uri = "kafka://127.0.0.1:9092/abc?kafka-version=2.6.0&max-message-bytes=a" 75 sinkURI, err = url.Parse(uri) 76 require.NoError(t, err) 77 options = NewOptions() 78 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 79 require.Regexp(t, ".*invalid syntax.*", errors.Cause(err)) 80 81 // Illegal partition-num. 82 uri = "kafka://127.0.0.1:9092/abc?kafka-version=2.6.0&partition-num=a" 83 sinkURI, err = url.Parse(uri) 84 require.NoError(t, err) 85 options = NewOptions() 86 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 87 require.Regexp(t, ".*invalid syntax.*", errors.Cause(err)) 88 89 // Out of range partition-num. 90 uri = "kafka://127.0.0.1:9092/abc?kafka-version=2.6.0&partition-num=0" 91 sinkURI, err = url.Parse(uri) 92 require.NoError(t, err) 93 options = NewOptions() 94 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 95 require.Regexp(t, ".*invalid partition num.*", errors.Cause(err)) 96 97 // Unknown required-acks. 98 uri = "kafka://127.0.0.1:9092/abc?kafka-version=2.6.0&required-acks=3" 99 sinkURI, err = url.Parse(uri) 100 require.NoError(t, err) 101 options = NewOptions() 102 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 103 require.Regexp(t, ".*invalid required acks 3.*", errors.Cause(err)) 104 105 // invalid kafka client id 106 uri = "kafka://127.0.0.1:9092/abc?kafka-client-id=^invalid$" 107 sinkURI, err = url.Parse(uri) 108 require.NoError(t, err) 109 options = NewOptions() 110 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 111 require.True(t, cerror.ErrKafkaInvalidClientID.Equal(err)) 112 } 113 114 func TestSetPartitionNum(t *testing.T) { 115 options := NewOptions() 116 err := options.SetPartitionNum(2) 117 require.NoError(t, err) 118 require.Equal(t, int32(2), options.PartitionNum) 119 120 options.PartitionNum = 1 121 err = options.SetPartitionNum(2) 122 require.NoError(t, err) 123 require.Equal(t, int32(1), options.PartitionNum) 124 125 options.PartitionNum = 3 126 err = options.SetPartitionNum(2) 127 require.True(t, cerror.ErrKafkaInvalidPartitionNum.Equal(err)) 128 } 129 130 func TestClientID(t *testing.T) { 131 testCases := []struct { 132 addr string 133 changefeedID string 134 configuredID string 135 hasError bool 136 expected string 137 }{ 138 { 139 "domain:1234", "123-121-121-121", 140 "", false, 141 "TiCDC_producer_domain_1234_default_123-121-121-121", 142 }, 143 { 144 "127.0.0.1:1234", "123-121-121-121", 145 "", false, 146 "TiCDC_producer_127.0.0.1_1234_default_123-121-121-121", 147 }, 148 { 149 "127.0.0.1:1234?:,\"", "123-121-121-121", 150 "", false, 151 "TiCDC_producer_127.0.0.1_1234_____default_123-121-121-121", 152 }, 153 { 154 "中文", "123-121-121-121", 155 "", true, "", 156 }, 157 { 158 "127.0.0.1:1234", 159 "123-121-121-121", "cdc-changefeed-1", false, 160 "cdc-changefeed-1", 161 }, 162 } 163 for _, tc := range testCases { 164 id, err := NewKafkaClientID(tc.addr, 165 model.DefaultChangeFeedID(tc.changefeedID), tc.configuredID) 166 if tc.hasError { 167 require.Error(t, err) 168 } else { 169 require.NoError(t, err) 170 require.Equal(t, tc.expected, id) 171 } 172 } 173 } 174 175 func TestTimeout(t *testing.T) { 176 options := NewOptions() 177 require.Equal(t, 10*time.Second, options.DialTimeout) 178 require.Equal(t, 10*time.Second, options.ReadTimeout) 179 require.Equal(t, 10*time.Second, options.WriteTimeout) 180 181 uri := "kafka://127.0.0.1:9092/kafka-test?dial-timeout=5s&read-timeout=1000ms" + 182 "&write-timeout=2m" 183 sinkURI, err := url.Parse(uri) 184 require.NoError(t, err) 185 186 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 187 require.NoError(t, err) 188 189 require.Equal(t, 5*time.Second, options.DialTimeout) 190 require.Equal(t, 1000*time.Millisecond, options.ReadTimeout) 191 require.Equal(t, 2*time.Minute, options.WriteTimeout) 192 } 193 194 func TestAdjustConfigTopicNotExist(t *testing.T) { 195 // When the topic does not exist, use the broker's configuration to create the topic. 196 adminClient := NewClusterAdminClientMockImpl() 197 defer adminClient.Close() 198 199 options := NewOptions() 200 options.BrokerEndpoints = []string{"127.0.0.1:9092"} 201 202 // topic not exist, `max-message-bytes` = `message.max.bytes` 203 options.MaxMessageBytes = adminClient.GetBrokerMessageMaxBytes() 204 ctx := context.Background() 205 err := AdjustOptions(ctx, adminClient, options, "create-random") 206 require.NoError(t, err) 207 208 saramaConfig, err := NewSaramaConfig(ctx, options) 209 require.NoError(t, err) 210 require.Equal(t, options.MaxMessageBytes, saramaConfig.Producer.MaxMessageBytes) 211 212 realMaxMessageBytes := adminClient.GetBrokerMessageMaxBytes() - maxMessageBytesOverhead 213 require.Equal(t, realMaxMessageBytes, options.MaxMessageBytes) 214 215 // topic not exist, `max-message-bytes` > `message.max.bytes` 216 options.MaxMessageBytes = adminClient.GetBrokerMessageMaxBytes() + 1 217 err = AdjustOptions(ctx, adminClient, options, "create-random1") 218 require.NoError(t, err) 219 220 saramaConfig, err = NewSaramaConfig(ctx, options) 221 require.NoError(t, err) 222 require.Equal(t, options.MaxMessageBytes, saramaConfig.Producer.MaxMessageBytes) 223 224 realMaxMessageBytes = adminClient.GetBrokerMessageMaxBytes() - maxMessageBytesOverhead 225 require.Equal(t, realMaxMessageBytes, options.MaxMessageBytes) 226 227 // topic not exist, `max-message-bytes` < `message.max.bytes` 228 options.MaxMessageBytes = adminClient.GetBrokerMessageMaxBytes() - 1 229 err = AdjustOptions(ctx, adminClient, options, "create-random2") 230 require.NoError(t, err) 231 232 saramaConfig, err = NewSaramaConfig(ctx, options) 233 require.NoError(t, err) 234 require.Equal(t, options.MaxMessageBytes, saramaConfig.Producer.MaxMessageBytes) 235 236 realMaxMessageBytes = adminClient.GetBrokerMessageMaxBytes() - maxMessageBytesOverhead 237 require.Equal(t, realMaxMessageBytes, options.MaxMessageBytes) 238 } 239 240 func TestAdjustConfigTopicExist(t *testing.T) { 241 adminClient := NewClusterAdminClientMockImpl() 242 defer adminClient.Close() 243 244 options := NewOptions() 245 options.BrokerEndpoints = []string{"127.0.0.1:9092"} 246 247 ctx := context.Background() 248 // topic exists, `max-message-bytes` = `max.message.bytes`. 249 options.MaxMessageBytes = adminClient.GetTopicMaxMessageBytes() 250 251 err := AdjustOptions(ctx, adminClient, options, adminClient.GetDefaultMockTopicName()) 252 require.NoError(t, err) 253 254 saramaConfig, err := NewSaramaConfig(ctx, options) 255 require.NoError(t, err) 256 257 maxMessageBytes := adminClient.GetTopicMaxMessageBytes() - maxMessageBytesOverhead 258 require.Equal(t, maxMessageBytes, saramaConfig.Producer.MaxMessageBytes) 259 require.Equal(t, maxMessageBytes, options.MaxMessageBytes) 260 261 // topic exists, `max-message-bytes` > `max.message.bytes` 262 options.MaxMessageBytes = adminClient.GetTopicMaxMessageBytes() + 1 263 264 err = AdjustOptions(ctx, adminClient, options, adminClient.GetDefaultMockTopicName()) 265 require.NoError(t, err) 266 267 saramaConfig, err = NewSaramaConfig(ctx, options) 268 require.NoError(t, err) 269 270 maxMessageBytes = adminClient.GetTopicMaxMessageBytes() - maxMessageBytesOverhead 271 require.Equal(t, maxMessageBytes, saramaConfig.Producer.MaxMessageBytes) 272 require.Equal(t, maxMessageBytes, options.MaxMessageBytes) 273 274 // topic exists, `max-message-bytes` < `max.message.bytes` 275 options.MaxMessageBytes = adminClient.GetTopicMaxMessageBytes() - 1 276 277 err = AdjustOptions(ctx, adminClient, options, adminClient.GetDefaultMockTopicName()) 278 require.NoError(t, err) 279 280 saramaConfig, err = NewSaramaConfig(ctx, options) 281 require.NoError(t, err) 282 283 maxMessageBytes = adminClient.GetTopicMaxMessageBytes() - maxMessageBytesOverhead 284 require.Equal(t, maxMessageBytes, saramaConfig.Producer.MaxMessageBytes) 285 require.Equal(t, maxMessageBytes, options.MaxMessageBytes) 286 287 // When the topic exists, but the topic does not have `max.message.bytes` 288 // create a topic without `max.message.bytes` 289 topicName := "test-topic" 290 detail := &TopicDetail{ 291 Name: topicName, 292 NumPartitions: 3, 293 } 294 err = adminClient.CreateTopic(context.Background(), detail, false) 295 require.NoError(t, err) 296 297 options.MaxMessageBytes = adminClient.GetBrokerMessageMaxBytes() - 1 298 err = AdjustOptions(ctx, adminClient, options, topicName) 299 require.NoError(t, err) 300 301 saramaConfig, err = NewSaramaConfig(ctx, options) 302 require.NoError(t, err) 303 304 // since `max.message.bytes` cannot be found, use broker's `message.max.bytes` instead. 305 maxMessageBytes = adminClient.GetBrokerMessageMaxBytes() - maxMessageBytesOverhead 306 require.Equal(t, maxMessageBytes, saramaConfig.Producer.MaxMessageBytes) 307 308 // When the topic exists, but the topic doesn't have `max.message.bytes` 309 // `max-message-bytes` > `message.max.bytes` 310 options.MaxMessageBytes = adminClient.GetBrokerMessageMaxBytes() + 1 311 312 err = AdjustOptions(ctx, adminClient, options, topicName) 313 require.NoError(t, err) 314 315 saramaConfig, err = NewSaramaConfig(ctx, options) 316 require.NoError(t, err) 317 318 maxMessageBytes = adminClient.GetBrokerMessageMaxBytes() - maxMessageBytesOverhead 319 require.Equal(t, maxMessageBytes, saramaConfig.Producer.MaxMessageBytes) 320 } 321 322 func TestAdjustConfigMinInsyncReplicas(t *testing.T) { 323 adminClient := NewClusterAdminClientMockImpl() 324 defer adminClient.Close() 325 326 options := NewOptions() 327 options.BrokerEndpoints = []string{"127.0.0.1:9092"} 328 329 // Report an error if the replication-factor is less than min.insync.replicas 330 // when the topic does not exist. 331 adminClient.SetMinInsyncReplicas("2") 332 333 ctx := context.Background() 334 err := AdjustOptions( 335 ctx, 336 adminClient, 337 options, 338 "create-new-fail-invalid-min-insync-replicas", 339 ) 340 require.Regexp( 341 t, 342 ".*`replication-factor` 1 is smaller than the `min.insync.replicas` 2 of broker.*", 343 errors.Cause(err), 344 ) 345 346 // topic not exist, and `min.insync.replicas` not found in broker's configuration 347 adminClient.DropBrokerConfig(MinInsyncReplicasConfigName) 348 topicName := "no-topic-no-min-insync-replicas" 349 err = AdjustOptions(ctx, adminClient, options, "no-topic-no-min-insync-replicas") 350 require.Nil(t, err) 351 err = adminClient.CreateTopic(context.Background(), &TopicDetail{ 352 Name: topicName, 353 ReplicationFactor: 1, 354 }, false) 355 require.ErrorIs(t, err, sarama.ErrPolicyViolation) 356 357 // Report an error if the replication-factor is less than min.insync.replicas 358 // when the topic does exist. 359 360 // topic exist, but `min.insync.replicas` not found in topic and broker configuration 361 topicName = "topic-no-options-entry" 362 err = adminClient.CreateTopic(context.Background(), &TopicDetail{ 363 Name: topicName, 364 ReplicationFactor: 3, 365 NumPartitions: 3, 366 }, false) 367 require.Nil(t, err) 368 err = AdjustOptions(ctx, adminClient, options, topicName) 369 require.Nil(t, err) 370 371 // topic found, and have `min.insync.replicas`, but set to 2, larger than `replication-factor`. 372 adminClient.SetMinInsyncReplicas("2") 373 err = AdjustOptions(ctx, adminClient, options, adminClient.GetDefaultMockTopicName()) 374 require.Regexp(t, 375 ".*`replication-factor` 1 is smaller than the `min.insync.replicas` 2 of topic.*", 376 errors.Cause(err), 377 ) 378 } 379 380 func TestSkipAdjustConfigMinInsyncReplicasWhenRequiredAcksIsNotWailAll(t *testing.T) { 381 adminClient := NewClusterAdminClientMockImpl() 382 defer adminClient.Close() 383 384 options := NewOptions() 385 options.BrokerEndpoints = []string{"127.0.0.1:9092"} 386 options.RequiredAcks = WaitForLocal 387 388 // Do not report an error if the replication-factor is less than min.insync.replicas(1<2). 389 adminClient.SetMinInsyncReplicas("2") 390 err := AdjustOptions( 391 context.Background(), 392 adminClient, 393 options, 394 "skip-check-min-insync-replicas", 395 ) 396 require.Nil(t, err, "Should not report an error when `required-acks` is not `all`") 397 } 398 399 func TestCreateProducerFailed(t *testing.T) { 400 options := NewOptions() 401 options.Version = "invalid" 402 options.IsAssignedVersion = true 403 saramaConfig, err := NewSaramaConfig(context.Background(), options) 404 require.Regexp(t, "invalid version.*", errors.Cause(err)) 405 require.Nil(t, saramaConfig) 406 } 407 408 func TestConfigurationCombinations(t *testing.T) { 409 combinations := []struct { 410 uriTemplate string 411 uriParams []interface{} 412 brokerMessageMaxBytes string 413 topicMaxMessageBytes string 414 expectedMaxMessageBytes string 415 }{ 416 // topic not created, 417 // `max-message-bytes` not set, `message.max.bytes` < `max-message-bytes` 418 // expected = min(`max-message-bytes`, `message.max.bytes`) = `message.max.bytes` 419 { 420 "kafka://127.0.0.1:9092/%s", 421 []interface{}{"not-exist-topic"}, 422 BrokerMessageMaxBytes, 423 TopicMaxMessageBytes, 424 BrokerMessageMaxBytes, 425 }, 426 // topic not created, 427 // `max-message-bytes` not set, `message.max.bytes` = `max-message-bytes` 428 // expected = min(`max-message-bytes`, `message.max.bytes`) = `max-message-bytes` 429 { 430 "kafka://127.0.0.1:9092/%s", 431 []interface{}{"not-exist-topic"}, 432 strconv.Itoa(config.DefaultMaxMessageBytes), 433 TopicMaxMessageBytes, 434 strconv.Itoa(config.DefaultMaxMessageBytes), 435 }, 436 // topic not created, 437 // `max-message-bytes` not set, broker `message.max.bytes` > `max-message-bytes` 438 // expected = min(`max-message-bytes`, `message.max.bytes`) = `max-message-bytes` 439 { 440 "kafka://127.0.0.1:9092/%s", 441 []interface{}{"no-params"}, 442 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 443 TopicMaxMessageBytes, 444 strconv.Itoa(config.DefaultMaxMessageBytes), 445 }, 446 447 // topic not created 448 // user set `max-message-bytes` < `message.max.bytes` < default `max-message-bytes` 449 { 450 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 451 []interface{}{"not-created-topic", strconv.Itoa(1024*1024 - 1)}, 452 BrokerMessageMaxBytes, 453 TopicMaxMessageBytes, 454 strconv.Itoa(1024*1024 - 1), 455 }, 456 // topic not created 457 // user set `max-message-bytes` < default `max-message-bytes` < `message.max.bytes` 458 { 459 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 460 []interface{}{"not-created-topic", strconv.Itoa(config.DefaultMaxMessageBytes - 1)}, 461 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 462 TopicMaxMessageBytes, 463 strconv.Itoa(config.DefaultMaxMessageBytes - 1), 464 }, 465 // topic not created 466 // `message.max.bytes` < user set `max-message-bytes` < default `max-message-bytes` 467 { 468 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 469 []interface{}{"not-created-topic", strconv.Itoa(1024*1024 + 1)}, 470 BrokerMessageMaxBytes, 471 TopicMaxMessageBytes, 472 BrokerMessageMaxBytes, 473 }, 474 // topic not created 475 // `message.max.bytes` < default `max-message-bytes` < user set `max-message-bytes` 476 { 477 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 478 []interface{}{"not-created-topic", strconv.Itoa(config.DefaultMaxMessageBytes + 1)}, 479 BrokerMessageMaxBytes, 480 TopicMaxMessageBytes, 481 BrokerMessageMaxBytes, 482 }, 483 // topic not created 484 // default `max-message-bytes` < user set `max-message-bytes` < `message.max.bytes` 485 { 486 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 487 []interface{}{"not-created-topic", strconv.Itoa(config.DefaultMaxMessageBytes + 1)}, 488 strconv.Itoa(config.DefaultMaxMessageBytes + 2), 489 TopicMaxMessageBytes, 490 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 491 }, 492 // topic not created 493 // default `max-message-bytes` < `message.max.bytes` < user set `max-message-bytes` 494 { 495 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 496 []interface{}{"not-created-topic", strconv.Itoa(config.DefaultMaxMessageBytes + 2)}, 497 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 498 TopicMaxMessageBytes, 499 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 500 }, 501 502 // topic created, 503 // `max-message-bytes` not set, topic's `max.message.bytes` < `max-message-bytes` 504 // expected = min(`max-message-bytes`, `max.message.bytes`) = `max.message.bytes` 505 { 506 "kafka://127.0.0.1:9092/%s", 507 []interface{}{DefaultMockTopicName}, 508 BrokerMessageMaxBytes, 509 TopicMaxMessageBytes, 510 TopicMaxMessageBytes, 511 }, 512 // `max-message-bytes` not set, topic created, 513 // topic's `max.message.bytes` = `max-message-bytes` 514 // expected = min(`max-message-bytes`, `max.message.bytes`) = `max-message-bytes` 515 { 516 "kafka://127.0.0.1:9092/%s", 517 []interface{}{DefaultMockTopicName}, 518 BrokerMessageMaxBytes, 519 strconv.Itoa(config.DefaultMaxMessageBytes), 520 strconv.Itoa(config.DefaultMaxMessageBytes), 521 }, 522 // `max-message-bytes` not set, topic created, 523 // topic's `max.message.bytes` > `max-message-bytes` 524 // expected = min(`max-message-bytes`, `max.message.bytes`) = `max-message-bytes` 525 { 526 "kafka://127.0.0.1:9092/%s", 527 []interface{}{DefaultMockTopicName}, 528 BrokerMessageMaxBytes, 529 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 530 strconv.Itoa(config.DefaultMaxMessageBytes), 531 }, 532 533 // topic created 534 // user set `max-message-bytes` < `max.message.bytes` < default `max-message-bytes` 535 { 536 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 537 []interface{}{DefaultMockTopicName, strconv.Itoa(1024*1024 - 1)}, 538 BrokerMessageMaxBytes, 539 TopicMaxMessageBytes, 540 strconv.Itoa(1024*1024 - 1), 541 }, 542 // topic created 543 // user set `max-message-bytes` < default `max-message-bytes` < `max.message.bytes` 544 { 545 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 546 []interface{}{ 547 DefaultMockTopicName, 548 strconv.Itoa(config.DefaultMaxMessageBytes - 1), 549 }, 550 BrokerMessageMaxBytes, 551 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 552 strconv.Itoa(config.DefaultMaxMessageBytes - 1), 553 }, 554 // topic created 555 // `max.message.bytes` < user set `max-message-bytes` < default `max-message-bytes` 556 { 557 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 558 []interface{}{DefaultMockTopicName, strconv.Itoa(1024*1024 + 1)}, 559 BrokerMessageMaxBytes, 560 TopicMaxMessageBytes, 561 TopicMaxMessageBytes, 562 }, 563 // topic created 564 // `max.message.bytes` < default `max-message-bytes` < user set `max-message-bytes` 565 { 566 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 567 []interface{}{ 568 DefaultMockTopicName, 569 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 570 }, 571 BrokerMessageMaxBytes, 572 TopicMaxMessageBytes, 573 TopicMaxMessageBytes, 574 }, 575 // topic created 576 // default `max-message-bytes` < user set `max-message-bytes` < `max.message.bytes` 577 { 578 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 579 []interface{}{ 580 DefaultMockTopicName, 581 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 582 }, 583 BrokerMessageMaxBytes, 584 strconv.Itoa(config.DefaultMaxMessageBytes + 2), 585 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 586 }, 587 // topic created 588 // default `max-message-bytes` < `max.message.bytes` < user set `max-message-bytes` 589 { 590 "kafka://127.0.0.1:9092/%s?max-message-bytes=%s", 591 []interface{}{ 592 DefaultMockTopicName, 593 strconv.Itoa(config.DefaultMaxMessageBytes + 2), 594 }, 595 BrokerMessageMaxBytes, 596 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 597 strconv.Itoa(config.DefaultMaxMessageBytes + 1), 598 }, 599 } 600 601 for _, a := range combinations { 602 BrokerMessageMaxBytes = a.brokerMessageMaxBytes 603 TopicMaxMessageBytes = a.topicMaxMessageBytes 604 605 uri := fmt.Sprintf(a.uriTemplate, a.uriParams...) 606 sinkURI, err := url.Parse(uri) 607 require.Nil(t, err) 608 609 ctx := context.Background() 610 options := NewOptions() 611 err = options.Apply(model.DefaultChangeFeedID("test"), sinkURI, config.GetDefaultReplicaConfig()) 612 require.Nil(t, err) 613 614 changefeed := model.DefaultChangeFeedID("changefeed-test") 615 factory, err := NewMockFactory(options, changefeed) 616 require.NoError(t, err) 617 618 adminClient, err := factory.AdminClient(ctx) 619 require.NoError(t, err) 620 621 topic, ok := a.uriParams[0].(string) 622 require.True(t, ok) 623 require.NotEqual(t, "", topic) 624 err = AdjustOptions(ctx, adminClient, options, topic) 625 require.Nil(t, err) 626 627 encoderConfig := common.NewConfig(config.ProtocolOpen) 628 err = encoderConfig.Apply(sinkURI, &config.ReplicaConfig{ 629 Sink: &config.SinkConfig{ 630 KafkaConfig: &config.KafkaConfig{ 631 LargeMessageHandle: config.NewDefaultLargeMessageHandleConfig(), 632 }, 633 }, 634 }) 635 require.Nil(t, err) 636 encoderConfig.WithMaxMessageBytes(options.MaxMessageBytes) 637 638 err = encoderConfig.Validate() 639 require.Nil(t, err) 640 641 // producer's `MaxMessageBytes` = encoder's `MaxMessageBytes`. 642 require.Equal(t, encoderConfig.MaxMessageBytes, options.MaxMessageBytes) 643 644 adminClient.Close() 645 } 646 } 647 648 func TestMerge(t *testing.T) { 649 uri := "kafka://topic/prefix" 650 sinkURI, err := url.Parse(uri) 651 require.NoError(t, err) 652 replicaConfig := config.GetDefaultReplicaConfig() 653 replicaConfig.Sink.KafkaConfig = &config.KafkaConfig{ 654 PartitionNum: aws.Int32(12), 655 ReplicationFactor: aws.Int16(5), 656 KafkaVersion: aws.String("3.1.2"), 657 MaxMessageBytes: aws.Int(1024 * 1024), 658 Compression: aws.String("gzip"), 659 KafkaClientID: aws.String("test-id"), 660 AutoCreateTopic: aws.Bool(true), 661 DialTimeout: aws.String("1m1s"), 662 WriteTimeout: aws.String("2m1s"), 663 RequiredAcks: aws.Int(1), 664 SASLUser: aws.String("abc"), 665 SASLPassword: aws.String("123"), 666 SASLMechanism: aws.String("plain"), 667 SASLGssAPIAuthType: aws.String("keytab"), 668 SASLGssAPIKeytabPath: aws.String("SASLGssAPIKeytabPath"), 669 SASLGssAPIServiceName: aws.String("service"), 670 SASLGssAPIUser: aws.String("user"), 671 SASLGssAPIPassword: aws.String("pass"), 672 SASLGssAPIRealm: aws.String("realm"), 673 SASLGssAPIDisablePafxfast: aws.Bool(true), 674 EnableTLS: aws.Bool(true), 675 CA: aws.String("ca.pem"), 676 Cert: aws.String("cert.pem"), 677 Key: aws.String("key.pem"), 678 } 679 c := NewOptions() 680 err = c.Apply(model.DefaultChangeFeedID("test"), sinkURI, replicaConfig) 681 require.NoError(t, err) 682 require.Equal(t, int32(12), c.PartitionNum) 683 require.Equal(t, int16(5), c.ReplicationFactor) 684 require.Equal(t, "3.1.2", c.Version) 685 require.Equal(t, 1024*1024, c.MaxMessageBytes) 686 require.Equal(t, "gzip", c.Compression) 687 require.Equal(t, "test-id", c.ClientID) 688 require.Equal(t, true, c.AutoCreate) 689 require.Equal(t, time.Minute+time.Second, c.DialTimeout) 690 require.Equal(t, 2*time.Minute+time.Second, c.WriteTimeout) 691 require.Equal(t, 1, int(c.RequiredAcks)) 692 require.Equal(t, "abc", c.SASL.SASLUser) 693 require.Equal(t, "123", c.SASL.SASLPassword) 694 require.Equal(t, "plain", strings.ToLower(string(c.SASL.SASLMechanism))) 695 require.Equal(t, 2, int(c.SASL.GSSAPI.AuthType)) 696 require.Equal(t, "SASLGssAPIKeytabPath", c.SASL.GSSAPI.KeyTabPath) 697 require.Equal(t, "service", c.SASL.GSSAPI.ServiceName) 698 require.Equal(t, "user", c.SASL.GSSAPI.Username) 699 require.Equal(t, "pass", c.SASL.GSSAPI.Password) 700 require.Equal(t, "realm", c.SASL.GSSAPI.Realm) 701 require.Equal(t, true, c.SASL.GSSAPI.DisablePAFXFAST) 702 require.Equal(t, true, c.EnableTLS) 703 require.Equal(t, "ca.pem", c.Credential.CAPath) 704 require.Equal(t, "cert.pem", c.Credential.CertPath) 705 require.Equal(t, "key.pem", c.Credential.KeyPath) 706 707 // test override 708 uri = "kafka://topic?partition-num=12" + 709 "&replication-factor=5" + 710 "&kafka-version=3.1.2" + 711 "&max-message-bytes=1048576" + 712 "&compression=gzip" + 713 "&kafka-client-id=test-id" + 714 "&auto-create-topic=true" + 715 "&dial-timeout=1m1s" + 716 "&write-timeout=2m1s" + 717 "&required-acks=1" + 718 "&sasl-user=abc" + 719 "&sasl-password=123" + 720 "&sasl-mechanism=plain" + 721 "&sasl-gssapi-auth-type=keytab" + 722 "&sasl-gssapi-keytab-path=SASLGssAPIKeytabPath" + 723 "&sasl-gssapi-service-name=service" + 724 "&sasl-gssapi-user=user" + 725 "&sasl-gssapi-password=pass" + 726 "&sasl-gssapi-realm=realm" + 727 "&sasl-gssapi-disable-pafxfast=true" + 728 "&enable-tls=true" + 729 "&ca=ca.pem" + 730 "&cert=cert.pem" + 731 "&key=key.pem" 732 sinkURI, err = url.Parse(uri) 733 require.NoError(t, err) 734 replicaConfig.Sink.KafkaConfig = &config.KafkaConfig{ 735 PartitionNum: aws.Int32(11), 736 ReplicationFactor: aws.Int16(3), 737 KafkaVersion: aws.String("3.2.2"), 738 MaxMessageBytes: aws.Int(1023 * 1024), 739 Compression: aws.String("none"), 740 KafkaClientID: aws.String("test2-id"), 741 AutoCreateTopic: aws.Bool(false), 742 DialTimeout: aws.String("1m2s"), 743 WriteTimeout: aws.String("2m3s"), 744 RequiredAcks: aws.Int(-1), 745 SASLUser: aws.String("abcd"), 746 SASLPassword: aws.String("1234"), 747 SASLMechanism: aws.String("plain"), 748 SASLGssAPIAuthType: aws.String("user"), 749 SASLGssAPIKeytabPath: aws.String("path"), 750 SASLGssAPIServiceName: aws.String("service2"), 751 SASLGssAPIUser: aws.String("usera"), 752 SASLGssAPIPassword: aws.String("pass2"), 753 SASLGssAPIRealm: aws.String("realm2"), 754 SASLGssAPIDisablePafxfast: aws.Bool(false), 755 EnableTLS: aws.Bool(false), 756 CA: aws.String("ca2.pem"), 757 Cert: aws.String("cert2.pem"), 758 Key: aws.String("key2.pem"), 759 } 760 c = NewOptions() 761 err = c.Apply(model.DefaultChangeFeedID("test"), sinkURI, replicaConfig) 762 require.NoError(t, err) 763 require.Equal(t, int32(12), c.PartitionNum) 764 require.Equal(t, int16(5), c.ReplicationFactor) 765 require.Equal(t, "3.1.2", c.Version) 766 require.Equal(t, 1024*1024, c.MaxMessageBytes) 767 require.Equal(t, "gzip", c.Compression) 768 require.Equal(t, "test-id", c.ClientID) 769 require.Equal(t, true, c.AutoCreate) 770 require.Equal(t, time.Minute+time.Second, c.DialTimeout) 771 require.Equal(t, 2*time.Minute+time.Second, c.WriteTimeout) 772 require.Equal(t, 1, int(c.RequiredAcks)) 773 require.Equal(t, "abc", c.SASL.SASLUser) 774 require.Equal(t, "123", c.SASL.SASLPassword) 775 require.Equal(t, "plain", strings.ToLower(string(c.SASL.SASLMechanism))) 776 require.Equal(t, 2, int(c.SASL.GSSAPI.AuthType)) 777 require.Equal(t, "SASLGssAPIKeytabPath", c.SASL.GSSAPI.KeyTabPath) 778 require.Equal(t, "service", c.SASL.GSSAPI.ServiceName) 779 require.Equal(t, "user", c.SASL.GSSAPI.Username) 780 require.Equal(t, "pass", c.SASL.GSSAPI.Password) 781 require.Equal(t, "realm", c.SASL.GSSAPI.Realm) 782 require.Equal(t, true, c.SASL.GSSAPI.DisablePAFXFAST) 783 require.Equal(t, true, c.EnableTLS) 784 require.Equal(t, "ca.pem", c.Credential.CAPath) 785 require.Equal(t, "cert.pem", c.Credential.CertPath) 786 require.Equal(t, "key.pem", c.Credential.KeyPath) 787 }