@@ -392,7 +392,8 @@ static KafkaIO.Read<Integer, Long> mkKafkaReadTransform(
392392 false , /*redistribute*/
393393 false , /*allowDuplicates*/
394394 0 , /*numKeys*/
395- null /*offsetDeduplication*/ );
395+ null , /*offsetDeduplication*/
396+ null /*topics*/ );
396397 }
397398
398399 static KafkaIO .Read <Integer , Long > mkKafkaReadTransformWithOffsetDedup (
@@ -404,7 +405,23 @@ static KafkaIO.Read<Integer, Long> mkKafkaReadTransformWithOffsetDedup(
404405 true , /*redistribute*/
405406 false , /*allowDuplicates*/
406407 100 , /*numKeys*/
407- true /*offsetDeduplication*/ );
408+ true , /*offsetDeduplication*/
409+ null /*topics*/ );
410+ }
411+
412+ static KafkaIO .Read <Integer , Long > mkKafkaReadTransformWithTopics (
413+ int numElements ,
414+ @ Nullable SerializableFunction <KV <Integer , Long >, Instant > timestampFn ,
415+ List <String > topics ) {
416+ return mkKafkaReadTransform (
417+ numElements ,
418+ numElements ,
419+ timestampFn ,
420+ false , /*redistribute*/
421+ false , /*allowDuplicates*/
422+ 0 , /*numKeys*/
423+ null , /*offsetDeduplication*/
424+ topics /*topics*/ );
408425 }
409426
410427 /**
@@ -418,15 +435,21 @@ static KafkaIO.Read<Integer, Long> mkKafkaReadTransform(
418435 @ Nullable Boolean redistribute ,
419436 @ Nullable Boolean withAllowDuplicates ,
420437 @ Nullable Integer numKeys ,
421- @ Nullable Boolean offsetDeduplication ) {
438+ @ Nullable Boolean offsetDeduplication ,
439+ @ Nullable List <String > topics ) {
422440
423441 KafkaIO .Read <Integer , Long > reader =
424442 KafkaIO .<Integer , Long >read ()
425443 .withBootstrapServers (mkKafkaServers )
426- .withTopics (mkKafkaTopics )
444+ .withTopics (topics != null ? topics : mkKafkaTopics )
427445 .withConsumerFactoryFn (
428446 new ConsumerFactoryFn (
429- mkKafkaTopics , 10 , numElements , OffsetResetStrategy .EARLIEST )) // 20 partitions
447+ topics != null
448+ ? topics .stream ().distinct ().collect (Collectors .toList ())
449+ : mkKafkaTopics ,
450+ 10 ,
451+ numElements ,
452+ OffsetResetStrategy .EARLIEST )) // 20 partitions
430453 .withKeyDeserializer (IntegerDeserializer .class )
431454 .withValueDeserializer (LongDeserializer .class );
432455 if (maxNumRecords != null ) {
@@ -648,6 +671,21 @@ public void testUnboundedSource() {
648671 p .run ();
649672 }
650673
674+ @ Test
675+ public void testUnboundedSourceWithDuplicateTopics () {
676+ int numElements = 1000 ;
677+ List <String > topics = ImmutableList .of ("topic_a" , "topic_b" , "topic_a" );
678+
679+ PCollection <Long > input =
680+ p .apply (
681+ mkKafkaReadTransformWithTopics (numElements , new ValueAsTimestampFn (), topics )
682+ .withoutMetadata ())
683+ .apply (Values .create ());
684+
685+ addCountingAsserts (input , numElements );
686+ p .run ();
687+ }
688+
651689 @ Test
652690 public void testRiskyConfigurationWarnsProperly () {
653691 int numElements = 1000 ;
@@ -682,7 +720,8 @@ public void warningsWithAllowDuplicatesEnabledAndCommitOffsets() {
682720 true , /*redistribute*/
683721 true , /*allowDuplicates*/
684722 0 , /*numKeys*/
685- null /*offsetDeduplication*/ )
723+ null , /*offsetDeduplication*/
724+ null /*topics*/ )
686725 .commitOffsetsInFinalize ()
687726 .withConsumerConfigUpdates (
688727 ImmutableMap .of (ConsumerConfig .GROUP_ID_CONFIG , "group_id" ))
@@ -709,7 +748,8 @@ public void noWarningsWithNoAllowDuplicatesAndCommitOffsets() {
709748 true , /*redistribute*/
710749 false , /*allowDuplicates*/
711750 0 , /*numKeys*/
712- null /*offsetDeduplication*/ )
751+ null , /*offsetDeduplication*/
752+ null /*topics*/ )
713753 .commitOffsetsInFinalize ()
714754 .withConsumerConfigUpdates (
715755 ImmutableMap .of (ConsumerConfig .GROUP_ID_CONFIG , "group_id" ))
@@ -737,7 +777,8 @@ public void testNumKeysIgnoredWithRedistributeNotEnabled() {
737777 false , /*redistribute*/
738778 false , /*allowDuplicates*/
739779 0 , /*numKeys*/
740- null /*offsetDeduplication*/ )
780+ null , /*offsetDeduplication*/
781+ null /*topics*/ )
741782 .withRedistributeNumKeys (100 )
742783 .commitOffsetsInFinalize ()
743784 .withConsumerConfigUpdates (
@@ -2109,7 +2150,8 @@ public void testUnboundedSourceStartReadTime() {
21092150 false , /*redistribute*/
21102151 false , /*allowDuplicates*/
21112152 0 , /*numKeys*/
2112- null /*offsetDeduplication*/ )
2153+ null , /*offsetDeduplication*/
2154+ null /*topics*/ )
21132155 .withStartReadTime (new Instant (startTime ))
21142156 .withoutMetadata ())
21152157 .apply (Values .create ());
@@ -2154,7 +2196,8 @@ public void testUnboundedSourceStartReadTimeException() {
21542196 false , /*redistribute*/
21552197 false , /*allowDuplicates*/
21562198 0 , /*numKeys*/
2157- null /*offsetDeduplication*/ )
2199+ null , /*offsetDeduplication*/
2200+ null /*topics*/ )
21582201 .withStartReadTime (new Instant (startTime ))
21592202 .withoutMetadata ())
21602203 .apply (Values .create ());
0 commit comments