11/*
2- * Copyright 2017-2019 the original author or authors.
2+ * Copyright 2017-2020 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
7777import org .springframework .kafka .core .ProducerFactory ;
7878import org .springframework .kafka .core .ProducerFactoryUtils ;
7979import org .springframework .kafka .event .ConsumerStoppedEvent ;
80+ import org .springframework .kafka .listener .ContainerProperties .AckMode ;
81+ import org .springframework .kafka .support .Acknowledgment ;
8082import org .springframework .kafka .support .DefaultKafkaHeaderMapper ;
8183import org .springframework .kafka .support .KafkaHeaders ;
8284import org .springframework .kafka .support .TopicPartitionOffset ;
@@ -128,21 +130,28 @@ public static void setup() {
128130
129131 @ Test
130132 public void testConsumeAndProduceTransactionKTM () throws Exception {
131- testConsumeAndProduceTransactionGuts (false , false );
133+ testConsumeAndProduceTransactionGuts (false , false , AckMode . RECORD );
132134 }
133135
134136 @ Test
135137 public void testConsumeAndProduceTransactionKCTM () throws Exception {
136- testConsumeAndProduceTransactionGuts (true , false );
138+ testConsumeAndProduceTransactionGuts (true , false , AckMode . RECORD );
137139 }
138140
139141 @ Test
140142 public void testConsumeAndProduceTransactionHandleError () throws Exception {
141- testConsumeAndProduceTransactionGuts (false , true );
143+ testConsumeAndProduceTransactionGuts (false , true , AckMode .RECORD );
144+ }
145+
146+ @ Test
147+ public void testConsumeAndProduceTransactionKTMManual () throws Exception {
148+ testConsumeAndProduceTransactionGuts (false , false , AckMode .MANUAL_IMMEDIATE );
142149 }
143150
144151 @ SuppressWarnings ({ "rawtypes" , "unchecked" })
145- private void testConsumeAndProduceTransactionGuts (boolean chained , boolean handleError ) throws Exception {
152+ private void testConsumeAndProduceTransactionGuts (boolean chained , boolean handleError , AckMode ackMode )
153+ throws Exception {
154+
146155 Consumer consumer = mock (Consumer .class );
147156 final TopicPartition topicPartition = new TopicPartition ("foo" , 0 );
148157 willAnswer (i -> {
@@ -152,14 +161,15 @@ private void testConsumeAndProduceTransactionGuts(boolean chained, boolean handl
152161 }).given (consumer ).subscribe (any (Collection .class ), any (ConsumerRebalanceListener .class ));
153162 ConsumerRecords records = new ConsumerRecords (Collections .singletonMap (topicPartition ,
154163 Collections .singletonList (new ConsumerRecord <>("foo" , 0 , 0 , "key" , "value" ))));
164+ ConsumerRecords empty = new ConsumerRecords (Collections .emptyMap ());
155165 final AtomicBoolean done = new AtomicBoolean ();
156166 willAnswer (i -> {
157167 if (done .compareAndSet (false , true )) {
158168 return records ;
159169 }
160170 else {
161171 Thread .sleep (500 );
162- return null ;
172+ return empty ;
163173 }
164174 }).given (consumer ).poll (any (Duration .class ));
165175 ConsumerFactory cf = mock (ConsumerFactory .class );
@@ -183,15 +193,38 @@ private void testConsumeAndProduceTransactionGuts(boolean chained, boolean handl
183193 ptm = new ChainedKafkaTransactionManager (new SomeOtherTransactionManager (), tm );
184194 }
185195 ContainerProperties props = new ContainerProperties ("foo" );
196+ props .setAckMode (ackMode );
186197 props .setGroupId ("group" );
187198 props .setTransactionManager (ptm );
188199 final KafkaTemplate template = new KafkaTemplate (pf );
189- props .setMessageListener ((MessageListener ) m -> {
190- template .send ("bar" , "baz" );
191- if (handleError ) {
192- throw new RuntimeException ("fail" );
200+ if (AckMode .MANUAL_IMMEDIATE .equals (ackMode )) {
201+ class AckListener implements AcknowledgingMessageListener {
202+ // not a lambda https://bugs.openjdk.java.net/browse/JDK-8074381
203+
204+ @ Override
205+ public void onMessage (ConsumerRecord data , Acknowledgment acknowledgment ) {
206+ template .send ("bar" , "baz" );
207+ if (handleError ) {
208+ throw new RuntimeException ("fail" );
209+ }
210+ acknowledgment .acknowledge ();
211+ }
212+
213+ @ Override
214+ public void onMessage (Object data ) {
215+ }
216+
193217 }
194- });
218+ props .setMessageListener (new AckListener ());
219+ }
220+ else {
221+ props .setMessageListener ((MessageListener ) m -> {
222+ template .send ("bar" , "baz" );
223+ if (handleError ) {
224+ throw new RuntimeException ("fail" );
225+ }
226+ });
227+ }
195228 KafkaMessageListenerContainer container = new KafkaMessageListenerContainer <>(cf , props );
196229 container .setBeanName ("commit" );
197230 if (handleError ) {
0 commit comments