1
1
/*
2
- * Copyright 2017 the original author or authors.
2
+ * Copyright 2017-2018 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
20
20
21
21
import java .util .Collections ;
22
22
import java .util .Map ;
23
+ import java .util .concurrent .BlockingQueue ;
24
+ import java .util .concurrent .CountDownLatch ;
25
+ import java .util .concurrent .TimeUnit ;
23
26
24
27
import org .apache .kafka .clients .consumer .ConsumerConfig ;
25
28
import org .apache .kafka .clients .consumer .KafkaConsumer ;
29
+ import org .apache .kafka .clients .producer .ProducerConfig ;
26
30
import org .junit .Test ;
31
+ import org .junit .runner .RunWith ;
32
+
33
+ import org .springframework .beans .factory .annotation .Autowired ;
34
+ import org .springframework .context .annotation .Configuration ;
35
+ import org .springframework .kafka .listener .KafkaMessageListenerContainer ;
36
+ import org .springframework .kafka .listener .MessageListener ;
37
+ import org .springframework .kafka .listener .config .ContainerProperties ;
38
+ import org .springframework .kafka .support .SendResult ;
39
+ import org .springframework .kafka .test .context .EmbeddedKafka ;
40
+ import org .springframework .kafka .test .rule .KafkaEmbedded ;
41
+ import org .springframework .kafka .test .utils .KafkaTestUtils ;
42
+ import org .springframework .kafka .transaction .KafkaTransactionManager ;
43
+ import org .springframework .test .context .junit4 .SpringRunner ;
44
+ import org .springframework .util .concurrent .ListenableFuture ;
27
45
28
46
/**
29
47
* @author Gary Russell
30
48
* @since 1.0.6
31
49
*
32
50
*/
51
+ @ EmbeddedKafka (topics = { "txCache1" , "txCache2" , "txCacheSendFromListener" },
52
+ brokerProperties = {
53
+ "transaction.state.log.replication.factor=1" ,
54
+ "transaction.state.log.min.isr=1" }
55
+ )
56
+ @ RunWith (SpringRunner .class )
33
57
public class DefaultKafkaConsumerFactoryTests {
34
58
59
+ @ Autowired
60
+ private KafkaEmbedded embeddedKafka ;
61
+
35
62
@ Test
36
63
public void testClientId () {
37
64
Map <String , Object > configs = Collections .singletonMap (ConsumerConfig .CLIENT_ID_CONFIG , "foo" );
38
- DefaultKafkaConsumerFactory <String , String > factory = new DefaultKafkaConsumerFactory <String , String >(configs ) {
65
+ DefaultKafkaConsumerFactory <String , String > factory =
66
+ new DefaultKafkaConsumerFactory <String , String >(configs ) {
39
67
40
68
@ Override
41
69
protected KafkaConsumer <String , String > createKafkaConsumer (Map <String , Object > configs ) {
@@ -47,4 +75,87 @@ protected KafkaConsumer<String, String> createKafkaConsumer(Map<String, Object>
47
75
factory .createConsumer ("-1" );
48
76
}
49
77
78
+ @ SuppressWarnings ("unchecked" )
79
+ @ Test
80
+ public void testNestedTxProducerIsCached () throws Exception {
81
+ Map <String , Object > producerProps = KafkaTestUtils .producerProps (this .embeddedKafka );
82
+ producerProps .put (ProducerConfig .RETRIES_CONFIG , 1 );
83
+ DefaultKafkaProducerFactory <Integer , String > pf = new DefaultKafkaProducerFactory <>(producerProps );
84
+ KafkaTemplate <Integer , String > template = new KafkaTemplate <>(pf );
85
+ DefaultKafkaProducerFactory <Integer , String > pfTx = new DefaultKafkaProducerFactory <>(producerProps );
86
+ pfTx .setTransactionIdPrefix ("fooTx." );
87
+ KafkaTemplate <Integer , String > templateTx = new KafkaTemplate <>(pfTx );
88
+ Map <String , Object > consumerProps = KafkaTestUtils .consumerProps ("txCache1Group" , "false" , this .embeddedKafka );
89
+ consumerProps .put (ConsumerConfig .AUTO_OFFSET_RESET_CONFIG , "earliest" );
90
+ DefaultKafkaConsumerFactory <Integer , String > cf = new DefaultKafkaConsumerFactory <>(consumerProps );
91
+ ContainerProperties containerProps = new ContainerProperties ("txCache1" );
92
+ CountDownLatch latch = new CountDownLatch (1 );
93
+ containerProps .setMessageListener ((MessageListener <Integer , String >) r -> {
94
+ templateTx .executeInTransaction (t -> t .send ("txCacheSendFromListener" , "bar" ));
95
+ templateTx .executeInTransaction (t -> t .send ("txCacheSendFromListener" , "baz" ));
96
+ latch .countDown ();
97
+ });
98
+ KafkaTransactionManager <Integer , String > tm = new KafkaTransactionManager <>(pfTx );
99
+ containerProps .setTransactionManager (tm );
100
+ KafkaMessageListenerContainer <Integer , String > container = new KafkaMessageListenerContainer <>(cf ,
101
+ containerProps );
102
+ container .start ();
103
+ try {
104
+ ListenableFuture <SendResult <Integer , String >> future = template .send ("txCache1" , "foo" );
105
+ future .get ();
106
+ assertThat (KafkaTestUtils .getPropertyValue (pf , "cache" , BlockingQueue .class )).hasSize (0 );
107
+ assertThat (latch .await (30 , TimeUnit .SECONDS )).isTrue ();
108
+ assertThat (KafkaTestUtils .getPropertyValue (pfTx , "cache" , BlockingQueue .class )).hasSize (1 );
109
+ }
110
+ finally {
111
+ container .stop ();
112
+ pf .destroy ();
113
+ pfTx .destroy ();
114
+ }
115
+ }
116
+
117
+ @ SuppressWarnings ("unchecked" )
118
+ @ Test
119
+ public void testContainerTxProducerIsNotCached () throws Exception {
120
+ Map <String , Object > producerProps = KafkaTestUtils .producerProps (this .embeddedKafka );
121
+ producerProps .put (ProducerConfig .RETRIES_CONFIG , 1 );
122
+ DefaultKafkaProducerFactory <Integer , String > pf = new DefaultKafkaProducerFactory <>(producerProps );
123
+ KafkaTemplate <Integer , String > template = new KafkaTemplate <>(pf );
124
+ DefaultKafkaProducerFactory <Integer , String > pfTx = new DefaultKafkaProducerFactory <>(producerProps );
125
+ pfTx .setTransactionIdPrefix ("fooTx." );
126
+ KafkaTemplate <Integer , String > templateTx = new KafkaTemplate <>(pfTx );
127
+ Map <String , Object > consumerProps = KafkaTestUtils .consumerProps ("txCache2Group" , "false" , this .embeddedKafka );
128
+ consumerProps .put (ConsumerConfig .AUTO_OFFSET_RESET_CONFIG , "earliest" );
129
+ DefaultKafkaConsumerFactory <Integer , String > cf = new DefaultKafkaConsumerFactory <>(consumerProps );
130
+ ContainerProperties containerProps = new ContainerProperties ("txCache2" );
131
+ CountDownLatch latch = new CountDownLatch (1 );
132
+ containerProps .setMessageListener ((MessageListener <Integer , String >) r -> {
133
+ templateTx .send ("txCacheSendFromListener" , "bar" );
134
+ templateTx .send ("txCacheSendFromListener" , "baz" );
135
+ latch .countDown ();
136
+ });
137
+ KafkaTransactionManager <Integer , String > tm = new KafkaTransactionManager <>(pfTx );
138
+ containerProps .setTransactionManager (tm );
139
+ KafkaMessageListenerContainer <Integer , String > container = new KafkaMessageListenerContainer <>(cf ,
140
+ containerProps );
141
+ container .start ();
142
+ try {
143
+ ListenableFuture <SendResult <Integer , String >> future = template .send ("txCache2" , "foo" );
144
+ future .get ();
145
+ assertThat (KafkaTestUtils .getPropertyValue (pf , "cache" , BlockingQueue .class )).hasSize (0 );
146
+ assertThat (latch .await (30 , TimeUnit .SECONDS )).isTrue ();
147
+ assertThat (KafkaTestUtils .getPropertyValue (pfTx , "cache" , BlockingQueue .class )).hasSize (0 );
148
+ }
149
+ finally {
150
+ container .stop ();
151
+ pf .destroy ();
152
+ pfTx .destroy ();
153
+ }
154
+ }
155
+
156
+ @ Configuration
157
+ public static class Config {
158
+
159
+ }
160
+
50
161
}
0 commit comments