@@ -1574,7 +1574,7 @@ public void testGetMessageSequenceRefForBatchMessage() throws Exception {
15741574 assertNull (ref );
15751575
15761576 ref = KafkaConnectSink .getMessageSequenceRefForBatchMessage (
1577- new TopicMessageIdImpl ("topic-0" , new MessageIdImpl (ledgerId , entryId , 0 ))
1577+ new TopicMessageIdImpl ("topic-0" , new MessageIdImpl (ledgerId , entryId , 0 ))
15781578 );
15791579 assertNull (ref );
15801580
@@ -1648,7 +1648,7 @@ private void testCollapsePartitionedTopic(boolean isEnabled,
16481648 props .put ("collapsePartitionedTopics" , Boolean .toString (isEnabled ));
16491649
16501650 KafkaConnectSink sink = new KafkaConnectSink ();
1651- sink .open (props , context );
1651+ sink .open (props , context );
16521652
16531653 AvroSchema <PulsarSchemaToKafkaSchemaTest .StructWithAnnotations > pulsarAvroSchema =
16541654 AvroSchema .of (PulsarSchemaToKafkaSchemaTest .StructWithAnnotations .class );
@@ -1682,6 +1682,67 @@ private void testCollapsePartitionedTopic(boolean isEnabled,
16821682 sink .close ();
16831683 }
16841684
1685+ @ Test
1686+ public void testAckUntilWithCollapsePartitionedTopics () throws Exception {
1687+ testAckUntil (true ,
1688+ "persistent://a/b/fake-topic-partition-0" ,
1689+ "persistent://a/b/fake-topic" ,
1690+ 0 );
1691+ }
1692+
1693+ @ Test
1694+ public void testAckUntilWithoutCollapsePartitionedTopics () throws Exception {
1695+ // Note: Without collapsePartitionedTopics expectedPartition in the committedOffsets will always be 0
1696+ testAckUntil (false ,
1697+ "persistent://a/b/fake-topic-partition-1" ,
1698+ "persistent://a/b/fake-topic-partition-1" ,
1699+ 0 );
1700+ }
1701+
1702+ private void testAckUntil (boolean collapseEnabled ,
1703+ String pulsarTopic ,
1704+ String expectedKafkaTopic ,
1705+ int expectedPartition ) throws Exception {
1706+ // Setup sink with given collapseEnabled value
1707+ props .put ("kafkaConnectorSinkClass" , SchemaedFileStreamSinkConnector .class .getCanonicalName ());
1708+ props .put ("collapsePartitionedTopics" , Boolean .toString (collapseEnabled ));
1709+ KafkaConnectSink sink = new KafkaConnectSink ();
1710+ sink .open (props , context );
1711+
1712+ // Create pulsar record with given pulsarTopic and expectedPartition
1713+ Message msg = mock (MessageImpl .class );
1714+ when (msg .getMessageId ()).thenReturn (new MessageIdImpl (1 , 1 , expectedPartition ));
1715+ when (msg .getValue ()).thenReturn (null );
1716+
1717+ AtomicInteger ackCount = new AtomicInteger (0 );
1718+
1719+ Record <GenericObject > record = PulsarRecord .<GenericObject >builder ()
1720+ .topicName (pulsarTopic )
1721+ .message (msg )
1722+ .ackFunction (ackCount ::incrementAndGet )
1723+ .failFunction (() -> {})
1724+ .build ();
1725+
1726+ // Add the pulsar record to pendingFlushQueue
1727+ sink .pendingFlushQueue .add (record );
1728+
1729+ // Build committedOffsets with the given expectedKafkaTopic and expectedPartition
1730+ Map <TopicPartition , OffsetAndMetadata > committedOffsets = new HashMap <>();
1731+ committedOffsets .put (
1732+ new TopicPartition (expectedKafkaTopic , expectedPartition ),
1733+ new OffsetAndMetadata (sink .getMessageOffset (record ))
1734+ );
1735+
1736+ // Trigger actUntil manually
1737+ sink .ackUntil (record , committedOffsets , Record ::ack );
1738+
1739+ // Assert that the ackFunction runnable of the record is called and pendingFlushQueue is empty
1740+ Assert .assertEquals (ackCount .get (), 1 );
1741+ Assert .assertTrue (sink .pendingFlushQueue .isEmpty ());
1742+
1743+ sink .close ();
1744+ }
1745+
16851746 @ SneakyThrows
16861747 private java .util .Date getDateFromString (String dateInString ) {
16871748 SimpleDateFormat formatter = new SimpleDateFormat ("dd/MM/yyyy hh:mm:ss" );
0 commit comments