19
19
import static org .assertj .core .api .Assertions .assertThat ;
20
20
import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
21
21
import static org .mockito .ArgumentMatchers .any ;
22
+ import static org .mockito .BDDMockito .given ;
23
+ import static org .mockito .BDDMockito .willAnswer ;
22
24
import static org .mockito .Mockito .mock ;
23
25
import static org .mockito .Mockito .times ;
24
26
import static org .mockito .Mockito .verify ;
29
31
import java .util .HashMap ;
30
32
import java .util .List ;
31
33
import java .util .Map ;
34
+ import java .util .concurrent .atomic .AtomicBoolean ;
32
35
33
36
import org .apache .kafka .clients .consumer .Consumer ;
34
37
import org .apache .kafka .clients .consumer .ConsumerRecord ;
35
38
import org .apache .kafka .clients .consumer .ConsumerRecords ;
36
39
import org .apache .kafka .common .TopicPartition ;
37
40
import org .junit .jupiter .api .Test ;
38
41
42
+ import org .springframework .kafka .KafkaException ;
39
43
import org .springframework .util .backoff .FixedBackOff ;
40
44
41
45
/**
@@ -62,6 +66,7 @@ void recover() {
62
66
ConsumerRecords <?, ?> records = new ConsumerRecords <>(map );
63
67
Consumer <?, ?> consumer = mock (Consumer .class );
64
68
MessageListenerContainer container = mock (MessageListenerContainer .class );
69
+ given (container .isRunning ()).willReturn (true );
65
70
eh .handle (new RuntimeException (), records , consumer , container , () -> {
66
71
this .invoked ++;
67
72
throw new RuntimeException ();
@@ -90,6 +95,7 @@ void successOnRetry() {
90
95
ConsumerRecords <?, ?> records = new ConsumerRecords <>(map );
91
96
Consumer <?, ?> consumer = mock (Consumer .class );
92
97
MessageListenerContainer container = mock (MessageListenerContainer .class );
98
+ given (container .isRunning ()).willReturn (true );
93
99
eh .handle (new RuntimeException (), records , consumer , container , () -> this .invoked ++);
94
100
assertThat (this .invoked ).isEqualTo (1 );
95
101
assertThat (recovered ).hasSize (0 );
@@ -116,6 +122,7 @@ void recoveryFails() {
116
122
ConsumerRecords <?, ?> records = new ConsumerRecords <>(map );
117
123
Consumer <?, ?> consumer = mock (Consumer .class );
118
124
MessageListenerContainer container = mock (MessageListenerContainer .class );
125
+ given (container .isRunning ()).willReturn (true );
119
126
assertThatExceptionOfType (RuntimeException .class ).isThrownBy (() ->
120
127
eh .handle (new RuntimeException (), records , consumer , container , () -> {
121
128
this .invoked ++;
@@ -131,4 +138,31 @@ void recoveryFails() {
131
138
verify (consumer ).seek (new TopicPartition ("foo" , 1 ), 0L );
132
139
}
133
140
141
+ @ Test
142
+ void exitOnContainerStop () {
143
+ this .invoked = 0 ;
144
+ List <ConsumerRecord <?, ?>> recovered = new ArrayList <>();
145
+ FallbackBatchErrorHandler eh = new FallbackBatchErrorHandler (new FixedBackOff (0 , 99999 ), (cr , ex ) -> {
146
+ recovered .add (cr );
147
+ });
148
+ Map <TopicPartition , List <ConsumerRecord <Object , Object >>> map = new HashMap <>();
149
+ map .put (new TopicPartition ("foo" , 0 ),
150
+ Collections .singletonList (new ConsumerRecord <>("foo" , 0 , 0L , "foo" , "bar" )));
151
+ map .put (new TopicPartition ("foo" , 1 ),
152
+ Collections .singletonList (new ConsumerRecord <>("foo" , 1 , 0L , "foo" , "bar" )));
153
+ ConsumerRecords <?, ?> records = new ConsumerRecords <>(map );
154
+ Consumer <?, ?> consumer = mock (Consumer .class );
155
+ MessageListenerContainer container = mock (MessageListenerContainer .class );
156
+ AtomicBoolean stopped = new AtomicBoolean (true );
157
+ willAnswer (inv -> stopped .get ()).given (container ).isRunning ();
158
+ assertThatExceptionOfType (KafkaException .class ).isThrownBy (() ->
159
+ eh .handle (new RuntimeException (), records , consumer , container , () -> {
160
+ this .invoked ++;
161
+ stopped .set (false );
162
+ throw new RuntimeException ();
163
+ })
164
+ ).withMessage ("Container stopped during retries" );
165
+ assertThat (this .invoked ).isEqualTo (1 );
166
+ }
167
+
134
168
}
0 commit comments