1919import static org .assertj .core .api .Assertions .allOf ;
2020import static org .assertj .core .api .Assertions .assertThat ;
2121import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
22+ import static org .mockito .ArgumentMatchers .any ;
23+ import static org .mockito .BDDMockito .given ;
24+ import static org .mockito .BDDMockito .willAnswer ;
2225import static org .mockito .Mockito .mock ;
2326import static org .springframework .kafka .test .assertj .KafkaConditions .key ;
2427import static org .springframework .kafka .test .assertj .KafkaConditions .keyValue ;
4144
4245import org .apache .kafka .clients .consumer .Consumer ;
4346import org .apache .kafka .clients .consumer .ConsumerRecord ;
47+ import org .apache .kafka .clients .producer .Callback ;
4448import org .apache .kafka .clients .producer .Producer ;
4549import org .apache .kafka .clients .producer .ProducerConfig ;
4650import org .apache .kafka .clients .producer .ProducerRecord ;
7579import org .springframework .messaging .support .MessageBuilder ;
7680import org .springframework .util .concurrent .ListenableFuture ;
7781import org .springframework .util .concurrent .ListenableFutureCallback ;
82+ import org .springframework .util .concurrent .SettableListenableFuture ;
7883
7984/**
8085 * @author Gary Russell
@@ -317,7 +322,7 @@ public void onSuccess(ProducerRecord<Integer, String> record, RecordMetadata rec
317322 @ Test
318323 void testWithCallback () throws Exception {
319324 Map <String , Object > senderProps = KafkaTestUtils .producerProps (embeddedKafka );
320- ProducerFactory <Integer , String > pf = new DefaultKafkaProducerFactory <>(senderProps );
325+ DefaultKafkaProducerFactory <Integer , String > pf = new DefaultKafkaProducerFactory <>(senderProps );
321326 KafkaTemplate <Integer , String > template = new KafkaTemplate <>(pf , true );
322327 template .setDefaultTopic (INT_KEY_TOPIC );
323328 ListenableFuture <SendResult <Integer , String >> future = template .sendDefault ("foo" );
@@ -339,7 +344,66 @@ public void onFailure(Throwable ex) {
339344 });
340345 assertThat (KafkaTestUtils .getSingleRecord (consumer , INT_KEY_TOPIC )).has (value ("foo" ));
341346 assertThat (latch .await (10 , TimeUnit .SECONDS )).isTrue ();
342- pf .createProducer ().close ();
347+ pf .destroy ();
348+ }
349+
350+ @ SuppressWarnings ("unchecked" )
351+ @ Test
352+ void testWithCallbackFailure () throws Exception {
353+ Producer <Integer , String > producer = mock (Producer .class );
354+ willAnswer (inv -> {
355+ Callback callback = inv .getArgument (1 );
356+ callback .onCompletion (null , new RuntimeException ("test" ));
357+ return new SettableListenableFuture <RecordMetadata >();
358+ }).given (producer ).send (any (), any ());
359+ ProducerFactory <Integer , String > pf = mock (ProducerFactory .class );
360+ given (pf .createProducer ()).willReturn (producer );
361+ KafkaTemplate <Integer , String > template = new KafkaTemplate <>(pf );
362+ ListenableFuture <SendResult <Integer , String >> future = template .send ("foo" , 1 , "bar" );
363+ final CountDownLatch latch = new CountDownLatch (1 );
364+ final AtomicReference <SendResult <Integer , String >> theResult = new AtomicReference <>();
365+ AtomicReference <String > value = new AtomicReference <>();
366+ future .addCallback (new KafkaSendCallback <Integer , String >() {
367+
368+ @ Override
369+ public void onSuccess (SendResult <Integer , String > result ) {
370+ }
371+
372+ @ Override
373+ public void onFailure (KafkaProducerException ex ) {
374+ ProducerRecord <Integer , String > failed = ex .getFailedProducerRecord ();
375+ value .set (failed .value ());
376+ latch .countDown ();
377+ }
378+
379+ });
380+ assertThat (latch .await (10 , TimeUnit .SECONDS )).isTrue ();
381+ assertThat (value .get ()).isEqualTo ("bar" );
382+ }
383+
384+ @ SuppressWarnings ("unchecked" )
385+ @ Test
386+ void testWithCallbackFailureFunctional () throws Exception {
387+ Producer <Integer , String > producer = mock (Producer .class );
388+ willAnswer (inv -> {
389+ Callback callback = inv .getArgument (1 );
390+ callback .onCompletion (null , new RuntimeException ("test" ));
391+ return new SettableListenableFuture <RecordMetadata >();
392+ }).given (producer ).send (any (), any ());
393+ ProducerFactory <Integer , String > pf = mock (ProducerFactory .class );
394+ given (pf .createProducer ()).willReturn (producer );
395+ KafkaTemplate <Integer , String > template = new KafkaTemplate <>(pf );
396+ ListenableFuture <SendResult <Integer , String >> future = template .send ("foo" , 1 , "bar" );
397+ final CountDownLatch latch = new CountDownLatch (1 );
398+ final AtomicReference <SendResult <Integer , String >> theResult = new AtomicReference <>();
399+ AtomicReference <String > value = new AtomicReference <>();
400+ future .addCallback (result -> { }, (KafkaFailureCallback <Integer , String >) ex -> {
401+ ProducerRecord <Integer , String > failed = ex .getFailedProducerRecord ();
402+ value .set (failed .value ());
403+ latch .countDown ();
404+ });
405+ assertThat (latch .await (10 , TimeUnit .SECONDS )).isTrue ();
406+ assertThat (value .get ()).isEqualTo ("bar" );
343407 }
344408
345409 @ Test
0 commit comments