spring-attic / spring-cloud-aws

All development has moved to https://github.com/awspring/spring-cloud-aws Integration for Amazon Web Services APIs with Spring
https://awspring.io/
Apache License 2.0
590 stars 375 forks source link

@SQSListener and @SpyBean are not working together? #651

Closed azapasnik closed 3 years ago

azapasnik commented 4 years ago

Hey everyone. I have a simple spring boot application with AWS SQS integration. In integration tests I tried to spy on method annotated with @SqsListener annotation and got a behavior where bean sometimes wasn't spied.

You can take a look at sample project here: https://github.com/Sanych/aws-sqs-spybean-troubleshooting

run mvn clean verify

In this log one may notice, that 2 out of 3 test method were spied successfully:

2020-09-06 15:39:23.597  INFO 18372 --- [           main] com.aws.test.demo.SQSListenerIT          : Started SQSListenerIT in 0.813 seconds (JVM running for 24.024)
2020-09-06 15:39:23.604  WARN 18372 --- [           main] com.aws.test.demo.SQSListenerIT          : calling class com.aws.test.demo.SQSListener$MockitoMock$1506819983
2020-09-06 15:39:23.604  WARN 18372 --- [           main] com.aws.test.demo.SQSListenerIT          : sendMessage to queue: test 1
2020-09-06 15:39:23.810  WARN 18372 --- [enerContainer-2] com.aws.test.demo.SQSListener            : id: class com.aws.test.demo.SQSListener$MockitoMock$1506819983, received: 'test 1'
2020-09-06 15:39:23.929  WARN 18372 --- [           main] com.aws.test.demo.SQSListenerIT          : calling class com.aws.test.demo.SQSListener$MockitoMock$1506819983
2020-09-06 15:39:23.929  WARN 18372 --- [           main] com.aws.test.demo.SQSListenerIT          : sendMessage to queue: test 2
2020-09-06 15:39:24.052  WARN 18372 --- [enerContainer-2] com.aws.test.demo.SQSListener            : id: class com.aws.test.demo.SQSListener, received: 'test 2'
2020-09-06 15:39:29.148  WARN 18372 --- [           main] com.aws.test.demo.SQSListenerIT          : calling class com.aws.test.demo.SQSListener$MockitoMock$1506819983
2020-09-06 15:39:29.148  WARN 18372 --- [           main] com.aws.test.demo.SQSListenerIT          : sendMessage to queue: test 3
2020-09-06 15:39:29.175  WARN 18372 --- [enerContainer-2] com.aws.test.demo.SQSListener            : id: class com.aws.test.demo.SQSListener$MockitoMock$1506819983, received: 'test 3'
[ERROR] Tests run: 3, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 6.468 s <<< FAILURE! - in com.aws.test.demo.SQSListenerIT
[ERROR] test2  Time elapsed: 5.218 s  <<< ERROR!
org.awaitility.core.ConditionTimeoutException:
Assertion condition defined as a lambda expression in com.aws.test.demo.SQSListenerIT
Wanted but not invoked:
SQSListener.listen(<any string>);
-> at com.aws.test.demo.SQSListenerIT.lambda$sendMessageFromFileAndWaitForListenerToRead$0(SQSListenerIT.java:57)
Actually, there were zero interactions with this mock.
 within 5 seconds.
        at com.aws.test.demo.SQSListenerIT.sendMessageFromFileAndWaitForListenerToRead(SQSListenerIT.java:57)
        at com.aws.test.demo.SQSListenerIT.test2(SQSListenerIT.java:42)
Caused by: org.mockito.exceptions.verification.WantedButNotInvoked:

Wanted but not invoked:
SQSListener.listen(<any string>);
-> at com.aws.test.demo.SQSListenerIT.lambda$sendMessageFromFileAndWaitForListenerToRead$0(SQSListenerIT.java:57)
Actually, there were zero interactions with this mock.
        at com.aws.test.demo.SQSListenerIT.lambda$sendMessageFromFileAndWaitForListenerToRead$0(SQSListenerIT.java:57)
maciejwalkowiak commented 4 years ago

The issue is not with spying, but with having multiple different applications contexts that compete for messages. In case of your example - if you run SQSListenerIT individually, all tests pass. If you run tests through Maven, they will randomly fail as you described. That's because DemoApplicationIT runs first, creates application context with not-spied SQSListener, then SQSListenerIT test runs and creates another application context, this time with spied SQSListener. Both of these listeners listen to the same queue, so test will fail randomly.

One way to overcome this issue is to create and use a set of new SQS queues with unique names for each new application context.