1
1
package org .reactivecommons .async .impl ;
2
2
3
+ import com .fasterxml .jackson .core .JsonProcessingException ;
4
+ import com .fasterxml .jackson .databind .ObjectMapper ;
3
5
import lombok .Data ;
4
- import org .assertj .core .api .Assertions ;
5
- import org .junit .Before ;
6
6
import org .junit .Test ;
7
+ import org .junit .runner .RunWith ;
8
+ import org .mockito .ArgumentCaptor ;
7
9
import org .mockito .Mock ;
10
+ import org .mockito .junit .MockitoJUnitRunner ;
8
11
import org .reactivecommons .api .domain .Command ;
12
+ import org .reactivecommons .async .api .AsyncQuery ;
13
+ import org .reactivecommons .async .api .From ;
14
+ import org .reactivecommons .async .impl .communications .Message ;
9
15
import org .reactivecommons .async .impl .communications .ReactiveMessageSender ;
10
16
import org .reactivecommons .async .impl .config .BrokerConfig ;
11
17
import org .reactivecommons .async .impl .converters .MessageConverter ;
14
20
import org .reactivecommons .async .impl .reply .ReactiveReplyRouter ;
15
21
import org .reactivestreams .Publisher ;
16
22
import reactor .core .publisher .Flux ;
23
+ import reactor .core .publisher .Mono ;
24
+ import reactor .core .publisher .UnicastProcessor ;
17
25
import reactor .rabbitmq .OutboundMessage ;
18
26
import reactor .rabbitmq .OutboundMessageResult ;
19
27
import reactor .rabbitmq .Sender ;
28
+ import reactor .test .StepVerifier ;
29
+ import reactor .util .concurrent .Queues ;
20
30
21
31
import java .util .List ;
32
+ import java .util .Map ;
22
33
import java .util .UUID ;
23
34
import java .util .concurrent .Semaphore ;
24
35
import java .util .concurrent .ThreadLocalRandom ;
25
36
import java .util .stream .Collectors ;
26
37
import java .util .stream .IntStream ;
27
38
28
- import static org .junit .jupiter .api .Assertions .*;
39
+ import static org .assertj .core .api .Assertions .assertThat ;
40
+ import static org .mockito .ArgumentMatchers .*;
41
+ import static org .mockito .Mockito .*;
42
+ import static org .reactivecommons .async .impl .Headers .*;
29
43
44
+
45
+ @ RunWith (MockitoJUnitRunner .class )
30
46
public class RabbitDirectAsyncGatewayTest {
31
47
32
48
private final BrokerConfig config = new BrokerConfig ();
33
-
49
+ private final Semaphore semaphore = new Semaphore (0 );
50
+ private final MessageConverter converter = new JacksonMessageConverter (new DefaultObjectMapperSupplier ().get ());
34
51
@ Mock
35
52
private ReactiveReplyRouter router ;
36
-
37
53
@ Mock
38
- private MessageConverter converter ;
39
-
54
+ private ReactiveMessageSender senderMock ;
40
55
private RabbitDirectAsyncGateway asyncGateway ;
41
- private final Semaphore semaphore = new Semaphore (0 );
42
56
43
- @ Before
44
- public void init () {
45
- ReactiveMessageSender sender = getReactiveMessageSender ();
57
+ public void init (ReactiveMessageSender sender ) {
46
58
asyncGateway = new RabbitDirectAsyncGateway (config , router , sender , "exchange" , converter );
47
59
}
48
60
49
61
@ Test
50
62
public void shouldSendInOptimalTime () throws InterruptedException {
63
+ init (getReactiveMessageSender ());
64
+
51
65
int messageCount = 40000 ;
52
66
final Flux <Command <DummyMessage >> messages = createMessagesHot (messageCount );
53
- final Flux <Void > target = messages . flatMap ( dummyMessageCommand -> asyncGateway . sendCommand ( dummyMessageCommand , "testTarget" )
54
- . doOnSuccess ( aVoid -> semaphore . release ()));
55
-
67
+ final Flux <Void > target =
68
+ messages . flatMap ( dummyMessageCommand -> asyncGateway . sendCommand ( dummyMessageCommand , "testTarget" )
69
+ . doOnSuccess ( aVoid -> semaphore . release ()));
56
70
57
71
final long init = System .currentTimeMillis ();
58
72
target .subscribe ();
59
73
semaphore .acquire (messageCount );
60
74
final long end = System .currentTimeMillis ();
61
75
62
76
final long total = end - init ;
63
- final double microsPerMessage = ((total + 0.0 )/ messageCount )* 1000 ;
77
+ final double microsPerMessage = ((total + 0.0 ) / messageCount ) * 1000 ;
64
78
System .out .println ("Message count: " + messageCount );
65
79
System .out .println ("Total Execution Time: " + total + "ms" );
66
80
System .out .println ("Microseconds per message: " + microsPerMessage + "us" );
67
- Assertions .assertThat (microsPerMessage ).isLessThan (150 );
81
+ assertThat (microsPerMessage ).isLessThan (150 );
82
+ }
83
+
84
+ @ Test
85
+ @ SuppressWarnings ("unchecked" )
86
+ public void shouldReplyQuery () {
87
+ // Arrange
88
+ senderMock ();
89
+
90
+ From from = new From ();
91
+ from .setReplyID ("replyId" );
92
+ from .setCorrelationID ("correlationId" );
93
+ DummyMessage response = new DummyMessage ();
94
+ // Act
95
+ Mono <Void > result = asyncGateway .reply (response , from );
96
+ // Assert
97
+ StepVerifier .create (result ).verifyComplete ();
98
+ ArgumentCaptor <Map <String , Object >> headersCaptor = ArgumentCaptor .forClass (Map .class );
99
+ verify (senderMock , times (1 ))
100
+ .sendNoConfirm (eq (response ), eq ("globalReply" ), eq ("replyId" ), headersCaptor .capture (), anyBoolean ());
101
+ assertThat (headersCaptor .getValue ().get (CORRELATION_ID )).isEqualTo ("correlationId" );
102
+ }
103
+
104
+ @ Test
105
+ @ SuppressWarnings ("unchecked" )
106
+ public void shouldReplyQueryWithout () {
107
+ // Arrange
108
+ senderMock ();
109
+
110
+ From from = new From ();
111
+ from .setReplyID ("replyId" );
112
+ from .setCorrelationID ("correlationId" );
113
+ // Act
114
+ Mono <Void > result = asyncGateway .reply (null , from );
115
+ // Assert
116
+ StepVerifier .create (result ).verifyComplete ();
117
+ ArgumentCaptor <Map <String , Object >> headersCaptor = ArgumentCaptor .forClass (Map .class );
118
+ verify (senderMock , times (1 ))
119
+ .sendNoConfirm (eq (null ), eq ("globalReply" ), eq ("replyId" ), headersCaptor .capture (), anyBoolean ());
120
+ assertThat (headersCaptor .getValue ().get (CORRELATION_ID )).isEqualTo ("correlationId" );
121
+ assertThat (headersCaptor .getValue ().get (COMPLETION_ONLY_SIGNAL )).isEqualTo (Boolean .TRUE .toString ());
122
+ }
123
+
124
+ @ Test
125
+ @ SuppressWarnings ("unchecked" )
126
+ public void shouldHandleRequestReply () throws JsonProcessingException {
127
+ // Arrange
128
+ senderMock ();
129
+ mockReply ();
130
+
131
+ String queryName = "my.query" ;
132
+ String targetName = "app-target" ;
133
+ AsyncQuery <DummyMessage > query = new AsyncQuery <>(queryName , new DummyMessage ());
134
+ // Act
135
+ Mono <DummyMessage > result = asyncGateway .requestReply (query , targetName , DummyMessage .class );
136
+ // Assert
137
+ StepVerifier .create (result )
138
+ .assertNext (res -> assertThat (res .getName ()).startsWith ("Daniel" ))
139
+ .verifyComplete ();
140
+ ArgumentCaptor <Map <String , Object >> headersCaptor = ArgumentCaptor .forClass (Map .class );
141
+ verify (senderMock , times (1 ))
142
+ .sendNoConfirm (eq (query ), eq ("exchange" ), eq ("app-target.query" ), headersCaptor .capture (),
143
+ anyBoolean ());
144
+ assertThat (headersCaptor .getValue ().get (REPLY_ID ).toString ().length ()).isEqualTo (32 );
145
+ assertThat (headersCaptor .getValue ().get (CORRELATION_ID ).toString ().length ()).isEqualTo (32 );
146
+ }
147
+
148
+ private void senderMock () {
149
+ init (senderMock );
150
+ when (senderMock .sendNoConfirm (any (), anyString (), anyString (), anyMap (), anyBoolean ()))
151
+ .thenReturn (Mono .empty ());
152
+ }
153
+
154
+ private void mockReply () throws JsonProcessingException {
155
+ Message message = mock (Message .class );
156
+ ObjectMapper mapper = new ObjectMapper ();
157
+ when (message .getBody ()).thenReturn (mapper .writeValueAsString (new DummyMessage ()).getBytes ());
158
+ final UnicastProcessor <Message > processor = UnicastProcessor .create (Queues .<Message >one ().get ());
159
+ processor .onNext (message );
160
+ processor .onComplete ();
161
+ when (router .register (anyString ())).thenReturn (processor .singleOrEmpty ());
68
162
}
69
163
70
164
private ReactiveMessageSender getReactiveMessageSender () {
71
- MessageConverter messageConverter = new JacksonMessageConverter (new DefaultObjectMapperSupplier ().get ());
72
165
Sender sender = new StubSender ();
73
- ReactiveMessageSender reactiveSender = new ReactiveMessageSender (sender , "sourceApplication" , messageConverter , null );
74
- return reactiveSender ;
166
+ return new ReactiveMessageSender (sender , "sourceApplication" , converter , null );
167
+ }
168
+
169
+ private Flux <Command <DummyMessage >> createMessagesHot (int count ) {
170
+ final List <Command <DummyMessage >> commands = IntStream .range (0 , count ).mapToObj (value -> new Command <>("app" +
171
+ ".command.test" , UUID .randomUUID ().toString (), new DummyMessage ())).collect (Collectors .toList ());
172
+ return Flux .fromIterable (commands );
75
173
}
76
174
77
175
static class StubSender extends Sender {
@@ -80,15 +178,14 @@ static class StubSender extends Sender {
80
178
public <OMSG extends OutboundMessage > Flux <OutboundMessageResult <OMSG >> sendWithTypedPublishConfirms (Publisher <OMSG > messages ) {
81
179
return Flux .from (messages ).map (omsg -> new OutboundMessageResult <>(omsg , true ));
82
180
}
83
- }
84
-
85
181
86
- private Flux <Command <DummyMessage >> createMessagesHot (int count ) {
87
- final List <Command <DummyMessage >> commands = IntStream .range (0 , count ).mapToObj (value -> new Command <>("app.command.test" , UUID .randomUUID ().toString (), new DummyMessage ())).collect (Collectors .toList ());
88
- return Flux .fromIterable (commands );
182
+ @ Override
183
+ @ SuppressWarnings ("rawtypes" )
184
+ public Flux <OutboundMessageResult > sendWithPublishConfirms (Publisher <OutboundMessage > messages ) {
185
+ return Flux .from (messages ).map (omsg -> new OutboundMessageResult <>(omsg , true ));
186
+ }
89
187
}
90
188
91
-
92
189
@ Data
93
190
static class DummyMessage {
94
191
private String name = "Daniel" + ThreadLocalRandom .current ().nextLong ();
0 commit comments