Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better inheritance support for @Nested when using @SpringIntegration #9492

Open
mtomik opened this issue Sep 19, 2024 · 3 comments
Open

Better inheritance support for @Nested when using @SpringIntegration #9492

mtomik opened this issue Sep 19, 2024 · 3 comments

Comments

@mtomik
Copy link

mtomik commented Sep 19, 2024

Expected Behavior

I have @SpringIntegration(noAutoStartup = {"*"}) defined in abstract class that holds all integration tests to disable all IntegrationFlows by default

When @nested class is used in some test, same configuration (@SpringIntegration(noAutoStartup = {"*"})) is applied to that nested class as well

Current Behavior

class annotated with @nested doesn't have that annotation inherited, that leads to starting all IntegrationFlows during test, that is not intended

Context

Without this feature, it leads to unexpected IntegrationFlow startup

sample for demonstration:

@SpringIntegrationTest(noAutoStartup = {"*"})
class AbstractIntegrationTest {}


class SomeIntegrationTest extends AbstractIntegrationTest {

    // all beans autoStarted just because of this  
    @Nested
    class SomeNestedTest {
        
        @Test 
        void test() {}
    }
} 

workaround:

  1. Have IT profile defined and used when running integration tests
  2. Define IntegrationFlow beans with non-"IT" profile ( @Profile("!it") )

Thanks guys for any feedback on this.

@mtomik mtomik added status: waiting-for-triage The issue need to be evaluated and its future decided type: enhancement labels Sep 19, 2024
@artembilan artembilan added this to the 6.4.0-RC1 milestone Sep 19, 2024
@artembilan artembilan added in: testing and removed status: waiting-for-triage The issue need to be evaluated and its future decided labels Sep 19, 2024
@artembilan
Copy link
Member

Can you share, please, the whole test class to play with?
Or, if you have in mind the solution, consider to contribute it alongside with the mentioned test class to cover: https://github.com/spring-projects/spring-integration/blob/main/CONTRIBUTING.adoc
Thanks

@artembilan
Copy link
Member

Looks like there is something like @NestedTestConfiguration in Spring Framework, but I'm not sure how it works: https://docs.spring.io/spring-framework/reference/testing/annotations/integration-junit-jupiter.html#integration-testing-annotations-nestedtestconfiguration.

So, would be great to have some real test to play with.
Thanks again.

@mtomik
Copy link
Author

mtomik commented Sep 24, 2024

Hey,
sorry for the late reply.

I have spent some time looking to this and there are few things that I found out:

  1. issue is AnnotatedElementUtils used in SpringIntegrationTestExecutionListener. There should be TestContextAnnotationUtils that is able to find annotations in enclosing class. In provided zip, you can find test FixAnnotationFindIntegrationTest that is demonstrating that difference
  2. Null check for MockIntegrationContext (NPE is thrown) in SpringIntegrationTestExecutionListener. I didn't check it further, why that context is missing there.

In provided zip, I have overridden that listener and added both fixes
bugfix.zip

One thing that I still didn't figure out is one error when you run WithNestedClassStartedIntegrationTest. I am not sure why it is trying to reconnect there, when your Listener stopped that SimpleMessageListenerContainer. That is causing unnecessary try to connect to MQ.. Same thing occurs, when you run WithoutNestedClassStoppedIntegrationTest and
WithoutNestedClassStartedIntegrationTest in this order.

024-09-24T01:39:30.210+02:00 ERROR 150141 --- [bugfix] [erContainer#0-2] o.s.a.r.l.SimpleMessageListenerContainer : Failed to check/redeclare auto-delete queue(s).

org.springframework.amqp.AmqpIOException: java.io.IOException
	at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.java:70) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:622) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createConnection(CachingConnectionFactory.java:726) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.createBareChannel(CachingConnectionFactory.java:671) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.getCachedChannelProxy(CachingConnectionFactory.java:644) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory.getChannel(CachingConnectionFactory.java:533) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$ChannelCachingConnectionProxy.createChannel(CachingConnectionFactory.java:1486) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:2255) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2222) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2202) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.core.RabbitAdmin.getQueueInfo(RabbitAdmin.java:467) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.core.RabbitAdmin.getQueueProperties(RabbitAdmin.java:451) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.attemptDeclarations(AbstractMessageListenerContainer.java:1960) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.redeclareElementsIfNecessary(AbstractMessageListenerContainer.java:1924) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.initialize(SimpleMessageListenerContainer.java:1479) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1320) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: java.io.IOException: null
	at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:140) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:136) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:406) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1251) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:1198) ~[amqp-client-5.21.0.jar:5.21.0]
	at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.connectAddresses(AbstractConnectionFactory.java:668) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.connect(AbstractConnectionFactory.java:637) ~[spring-rabbit-3.1.7.jar:3.1.7]
	at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.java:584) ~[spring-rabbit-3.1.7.jar:3.1.7]
	... 15 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: connection error
	at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:552) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:336) ~[amqp-client-5.21.0.jar:5.21.0]
	... 20 common frames omitted
Caused by: java.io.EOFException: null
	at java.base/java.io.DataInputStream.readUnsignedByte(DataInputStream.java:297) ~[na:na]
	at com.rabbitmq.client.impl.Frame.readFrom(Frame.java:91) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.client.impl.SocketFrameHandler.readFrame(SocketFrameHandler.java:199) ~[amqp-client-5.21.0.jar:5.21.0]
	at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:687) ~[amqp-client-5.21.0.jar:5.21.0]
	... 1 common frames omitted

I have also opened PR to fix related issues

onobc added a commit to mtomik/spring-integration that referenced this issue Sep 24, 2024
…ntext

Switches `MockIntegrationContextCustomizerFactory` to use
`TestContextAnnotationUtils` in order to properly support
`@NestedTestConfiguration` semantics.

Adds an integration test with a base class and several
`@Nested` inner test classes to verify the various
permutations of `@SpringIntegrationTest` inherit/override
behavior when used w/ `@NestedTestConfiguration`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants