66import static org .mockito .ArgumentMatchers .eq ;
77import static org .mockito .Mockito .mock ;
88import static org .mockito .Mockito .never ;
9+ import static org .mockito .Mockito .timeout ;
910import static org .mockito .Mockito .times ;
1011import static org .mockito .Mockito .verify ;
1112import static org .mockito .Mockito .when ;
1920import com .jashmore .sqs .resolver .MessageResolver ;
2021import org .junit .Rule ;
2122import org .junit .Test ;
23+ import org .junit .rules .ExpectedException ;
2224import org .mockito .ArgumentMatchers ;
2325import org .mockito .Mock ;
2426import org .mockito .junit .MockitoJUnit ;
2527import org .mockito .junit .MockitoRule ;
2628import software .amazon .awssdk .services .sqs .model .Message ;
2729
2830import java .lang .reflect .Method ;
31+ import java .util .concurrent .CompletableFuture ;
32+ import java .util .concurrent .TimeUnit ;
33+ import java .util .concurrent .atomic .AtomicBoolean ;
2934
35+ @ SuppressWarnings ( {"WeakerAccess" , "unused" })
3036public class DefaultMessageProcessorTest {
31- private static final String QUEUE_URL = "queueUrl" ;
37+ private static final QueueProperties QUEUE_PROPERTIES = QueueProperties
38+ .builder ()
39+ .queueUrl ("queueUrl" )
40+ .build ();
3241 private static final DefaultMessageProcessorTest BEAN = new DefaultMessageProcessorTest ();
3342
3443 @ Rule
3544 public MockitoRule mockitoRule = MockitoJUnit .rule ();
3645
46+ @ Rule
47+ public ExpectedException expectedException = ExpectedException .none ();
48+
3749 @ Mock
3850 private ArgumentResolverService argumentResolverService ;
3951
@@ -44,34 +56,26 @@ public class DefaultMessageProcessorTest {
4456 public void forEachParameterInMethodTheArgumentIsResolved () {
4557 // arrange
4658 final Method method = getMethodWithAcknowledge ();
47- final QueueProperties queueProperties = QueueProperties
48- .builder ()
49- .queueUrl (QUEUE_URL )
50- .build ();
5159 final Message message = Message .builder ().build ();
52- final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , queueProperties , messageResolver , method , BEAN );
53- when (argumentResolverService .resolveArgument (eq (queueProperties ), any (MethodParameter .class ), eq (message )))
60+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
61+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
5462 .thenReturn ("payload" )
5563 .thenReturn ("payload2" );
5664
5765 // act
5866 processor .processMessage (message );
5967
6068 // assert
61- verify (argumentResolverService , times (2 )).resolveArgument (eq (queueProperties ), any (MethodParameter .class ), eq (message ));
69+ verify (argumentResolverService , times (2 )).resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message ));
6270 }
6371
6472 @ Test
6573 public void anyParameterUnableToBeResolvedWillThrowAnError () {
6674 // arrange
6775 final Method method = getMethodWithAcknowledge ();
68- final QueueProperties queueProperties = QueueProperties
69- .builder ()
70- .queueUrl (QUEUE_URL )
71- .build ();
7276 final Message message = Message .builder ().build ();
73- final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , queueProperties , messageResolver , method , BEAN );
74- when (argumentResolverService .resolveArgument (eq (queueProperties ), any (MethodParameter .class ), eq (message )))
77+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
78+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
7579 .thenThrow (new ArgumentResolutionException ("Error resolving" ));
7680
7781 // act
@@ -89,13 +93,9 @@ public void methodWillBeInvokedWithArgumentsResolved() {
8993 // arrange
9094 final Method method = getMethodWithAcknowledge ();
9195 final DefaultMessageProcessorTest mockProcessor = mock (DefaultMessageProcessorTest .class );
92- final QueueProperties queueProperties = QueueProperties
93- .builder ()
94- .queueUrl (QUEUE_URL )
95- .build ();
9696 final Message message = Message .builder ().build ();
97- final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , queueProperties , messageResolver , method , mockProcessor );
98- when (argumentResolverService .resolveArgument (eq (queueProperties ), any (MethodParameter .class ), eq (message )))
97+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , mockProcessor );
98+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
9999 .thenReturn ("payload" )
100100 .thenReturn ("payload2" );
101101
@@ -110,13 +110,9 @@ public void methodWillBeInvokedWithArgumentsResolved() {
110110 public void methodWithAcknowledgeParameterWillNotDeleteMessageOnSuccess () {
111111 // arrange
112112 final Method method = getMethodWithAcknowledge ();
113- final QueueProperties queueProperties = QueueProperties
114- .builder ()
115- .queueUrl (QUEUE_URL )
116- .build ();
117113 final Message message = Message .builder ().build ();
118- final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , queueProperties , messageResolver , method , BEAN );
119- when (argumentResolverService .resolveArgument (eq (queueProperties ), any (MethodParameter .class ), eq (message )))
114+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
115+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
120116 .thenReturn ("payload" );
121117
122118 // act
@@ -130,13 +126,9 @@ public void methodWithAcknowledgeParameterWillNotDeleteMessageOnSuccess() {
130126 public void methodWithoutAcknowledgeParameterWillDeleteMessageOnSuccess () {
131127 // arrange
132128 final Method method = getMethodWithNoAcknowledge ();
133- final QueueProperties queueProperties = QueueProperties
134- .builder ()
135- .queueUrl (QUEUE_URL )
136- .build ();
137129 final Message message = Message .builder ().receiptHandle ("handle" ).build ();
138- final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , queueProperties , messageResolver , method , BEAN );
139- when (argumentResolverService .resolveArgument (eq (queueProperties ), any (MethodParameter .class ), eq (message )))
130+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
131+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
140132 .thenReturn ("payload" );
141133
142134 // act
@@ -151,13 +143,9 @@ public void methodWithoutAcknowledgeParameterWillDeleteMessageOnSuccess() {
151143 public void methodWithoutAcknowledgeThatThrowsExceptionDoesNotDeleteMessage () {
152144 // arrange
153145 final Method method = getMethodThatThrowsException ();
154- final QueueProperties queueProperties = QueueProperties
155- .builder ()
156- .queueUrl (QUEUE_URL )
157- .build ();
158146 final Message message = Message .builder ().receiptHandle ("handle" ).build ();
159- final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , queueProperties , messageResolver , method , BEAN );
160- when (argumentResolverService .resolveArgument (eq (queueProperties ), any (MethodParameter .class ), eq (message )))
147+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
148+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
161149 .thenReturn ("payload" );
162150
163151 // act
@@ -170,17 +158,95 @@ public void methodWithoutAcknowledgeThatThrowsExceptionDoesNotDeleteMessage() {
170158 }
171159 }
172160
173- @ SuppressWarnings ("unused" )
161+ @ Test
162+ public void methodReturningCompletableFutureWillResolveMessageWhenFutureResolved () throws Exception {
163+ // arrange
164+ final Method method = DefaultMessageProcessorTest .class .getMethod ("methodReturningCompletableFuture" , CompletableFuture .class );
165+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
166+ final Message message = Message .builder ().receiptHandle ("handle" ).build ();
167+ final CompletableFuture <Object > future = new CompletableFuture <>();
168+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
169+ .thenReturn (future );
170+
171+ // act
172+ CompletableFuture .runAsync (() -> processor .processMessage (message ));
173+
174+ // assert
175+ verify (messageResolver , never ()).resolveMessage (message );
176+ future .complete ("value" );
177+ verify (messageResolver , timeout (100 )).resolveMessage (message );
178+ }
179+
180+ @ Test
181+ public void methodReturningCompletableFutureWillNotResolveMessageWhenFutureRejected () throws Exception {
182+ // arrange
183+ final Method method = DefaultMessageProcessorTest .class .getMethod ("methodReturningCompletableFuture" , CompletableFuture .class );
184+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
185+ final Message message = Message .builder ().receiptHandle ("handle" ).build ();
186+ final CompletableFuture <Object > future = new CompletableFuture <>();
187+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
188+ .thenReturn (future );
189+
190+ // act
191+ CompletableFuture .runAsync (() -> processor .processMessage (message ));
192+ future .completeExceptionally (new RuntimeException ("Excepted Exception" ));
193+ Thread .sleep (100 ); // make sure it doesn't resolve
194+
195+ // assert
196+ verify (messageResolver , never ()).resolveMessage (message );
197+ }
198+
199+ @ Test
200+ public void methodReturningCompletableFutureThatReturnsNullWillThrowMessageProcessingException () throws Exception {
201+ // arrange
202+ final Method method = DefaultMessageProcessorTest .class .getMethod ("methodReturningCompletableFuture" , CompletableFuture .class );
203+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
204+ final Message message = Message .builder ().receiptHandle ("handle" ).build ();
205+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
206+ .thenReturn (null );
207+ expectedException .expect (MessageProcessingException .class );
208+
209+ // act
210+ processor .processMessage (message );
211+ }
212+
213+ @ Test
214+ public void threadInterruptedWhileGettingMessageWillThrowException () throws Exception {
215+ // arrange
216+ final Method method = DefaultMessageProcessorTest .class .getMethod ("methodReturningCompletableFuture" , CompletableFuture .class );
217+ final MessageProcessor processor = new DefaultMessageProcessor (argumentResolverService , QUEUE_PROPERTIES , messageResolver , method , BEAN );
218+ final Message message = Message .builder ().receiptHandle ("handle" ).build ();
219+ final CompletableFuture <Object > future = new CompletableFuture <>();
220+ when (argumentResolverService .resolveArgument (eq (QUEUE_PROPERTIES ), any (MethodParameter .class ), eq (message )))
221+ .thenReturn (future );
222+
223+ // act
224+ final AtomicBoolean exceptionThrown = new AtomicBoolean (false );
225+ CompletableFuture .runAsync (() -> {
226+ try {
227+ Thread .currentThread ().interrupt (); // interrupt the thread so the InterruptedException will be thrown while blocking on the future
228+ processor .processMessage (message );
229+ } catch (final MessageProcessingException messageProcessingException ) {
230+ exceptionThrown .set (true );
231+ }
232+ }).get (1 , TimeUnit .SECONDS );
233+
234+ // assert
235+ assertThat (exceptionThrown ).isTrue ();
236+ }
237+
174238 public void methodWithNoAcknowledge (@ Payload String payload , @ Payload String payloadTwo ) {
175239
176240 }
177241
178- @ SuppressWarnings ( {"unused" , "WeakerAccess" })
179242 public void methodWithAcknowledge (Acknowledge acknowledge , @ Payload String payload , @ Payload String payloadTwo ) {
180243
181244 }
182245
183- @ SuppressWarnings ("unused" )
246+ public CompletableFuture <?> methodReturningCompletableFuture (CompletableFuture <?> futureToReturn ) {
247+ return futureToReturn ;
248+ }
249+
184250 public void methodThatThrowsException (@ Payload String payload ) {
185251 throw new RuntimeException ("error" );
186252 }
0 commit comments