Skip to content

Commit b38c9e1

Browse files
authored
GH-3182: Properly reset bean in the MockIntCtx (#3190)
* GH-3182: Properly reset bean in the MockIntCtx Fixes #3182 The `MockIntegrationContext.resetBeans()` doesn't really restore a state of endpoint beans: the handle/source is applied only after start for that endpoint * Stop endpoints in the `MockIntegrationContext.resetBeans()` is they are running currently * Start them back only if their `autoStartup == true` * Clear only those beans which names are provided for the `resetBeans()` **Cherry-pick to 5.2.x** * * Ensure that only provided beans are reset
1 parent ea8c454 commit b38c9e1

File tree

2 files changed

+77
-23
lines changed

2 files changed

+77
-23
lines changed

spring-integration-test/src/main/java/org/springframework/integration/test/context/MockIntegrationContext.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2019 the original author or authors.
2+
* Copyright 2017-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
2727
import org.springframework.beans.factory.BeanFactoryAware;
2828
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2929
import org.springframework.context.Lifecycle;
30+
import org.springframework.context.SmartLifecycle;
3031
import org.springframework.integration.core.MessageProducer;
3132
import org.springframework.integration.core.MessageSource;
3233
import org.springframework.integration.endpoint.IntegrationConsumer;
@@ -97,6 +98,11 @@ public void resetBeans(String... beanNames) {
9798
.forEach(e -> {
9899
Object endpoint = this.beanFactory.getBean(e.getKey());
99100
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(endpoint);
101+
SmartLifecycle lifecycle = null;
102+
if (endpoint instanceof SmartLifecycle && ((SmartLifecycle) endpoint).isRunning()) {
103+
lifecycle = (SmartLifecycle) endpoint;
104+
lifecycle.stop();
105+
}
100106
if (endpoint instanceof SourcePollingChannelAdapter) {
101107
directFieldAccessor.setPropertyValue("source", e.getValue());
102108
}
@@ -108,9 +114,19 @@ else if (endpoint instanceof ReactiveStreamsConsumer) {
108114
else if (endpoint instanceof IntegrationConsumer) {
109115
directFieldAccessor.setPropertyValue(HANDLER, e.getValue());
110116
}
117+
if (lifecycle != null && lifecycle.isAutoStartup()) {
118+
lifecycle.start();
119+
}
111120
});
112121

113-
this.beans.clear();
122+
if (!ObjectUtils.isEmpty(beanNames)) {
123+
for (String name : beanNames) {
124+
this.beans.remove(name);
125+
}
126+
}
127+
else {
128+
this.beans.clear();
129+
}
114130
}
115131

116132
/**

spring-integration-test/src/test/java/org/springframework/integration/test/mock/MockMessageHandlerTests.java

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2019 the original author or authors.
2+
* Copyright 2017-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,23 +17,26 @@
1717
package org.springframework.integration.test.mock;
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
2021
import static org.assertj.core.api.Assertions.fail;
22+
import static org.mockito.ArgumentMatchers.any;
2123
import static org.mockito.Mockito.spy;
2224
import static org.mockito.Mockito.verify;
2325
import static org.springframework.integration.test.mock.MockIntegration.mockMessageHandler;
2426

2527
import java.util.List;
28+
import java.util.Map;
2629

27-
import org.junit.After;
28-
import org.junit.Test;
29-
import org.junit.runner.RunWith;
30+
import org.junit.jupiter.api.AfterEach;
31+
import org.junit.jupiter.api.Test;
3032
import org.mockito.ArgumentCaptor;
3133
import org.reactivestreams.Subscriber;
3234

3335
import org.springframework.beans.factory.annotation.Autowired;
3436
import org.springframework.context.ApplicationContext;
3537
import org.springframework.context.annotation.Bean;
3638
import org.springframework.context.annotation.Configuration;
39+
import org.springframework.integration.annotation.EndpointId;
3740
import org.springframework.integration.annotation.Poller;
3841
import org.springframework.integration.annotation.ServiceActivator;
3942
import org.springframework.integration.channel.DirectChannel;
@@ -42,6 +45,7 @@
4245
import org.springframework.integration.endpoint.ReactiveStreamsConsumer;
4346
import org.springframework.integration.expression.ValueExpression;
4447
import org.springframework.integration.handler.ExpressionEvaluatingMessageHandler;
48+
import org.springframework.integration.handler.LoggingHandler;
4549
import org.springframework.integration.support.MessageBuilder;
4650
import org.springframework.integration.test.context.MockIntegrationContext;
4751
import org.springframework.integration.test.context.SpringIntegrationTest;
@@ -56,15 +60,15 @@
5660
import org.springframework.messaging.support.GenericMessage;
5761
import org.springframework.test.annotation.DirtiesContext;
5862
import org.springframework.test.context.ContextConfiguration;
59-
import org.springframework.test.context.junit4.SpringRunner;
63+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
6064

6165
/**
6266
* @author Artem Bilan
6367
* @author Yicheng Feng
6468
*
6569
* @since 5.0
6670
*/
67-
@RunWith(SpringRunner.class)
71+
@SpringJUnitConfig
6872
@ContextConfiguration(classes = MockMessageHandlerTests.Config.class)
6973
@SpringIntegrationTest
7074
@DirtiesContext
@@ -97,10 +101,10 @@ public class MockMessageHandlerTests {
97101
@Autowired
98102
private ArgumentCaptor<Message<?>> messageArgumentCaptor;
99103

100-
@After
104+
@AfterEach
101105
public void tearDown() {
102106
this.mockIntegrationContext.resetBeans();
103-
results.purge(null);
107+
this.results.purge(null);
104108
}
105109

106110
@Test
@@ -181,8 +185,7 @@ public void testMockRawHandler() {
181185
ArgumentCaptor<Message<?>> messageArgumentCaptor = MockIntegration.messageArgumentCaptor();
182186
MessageHandler mockMessageHandler =
183187
spy(mockMessageHandler(messageArgumentCaptor))
184-
.handleNext(m -> {
185-
});
188+
.handleNext(m -> { });
186189

187190
String endpointId = "rawHandlerConsumer";
188191
this.mockIntegrationContext.substituteMessageHandlerFor(endpointId, mockMessageHandler);
@@ -201,25 +204,22 @@ public void testMockRawHandler() {
201204

202205
this.mockIntegrationContext.resetBeans(endpointId);
203206

204-
mockMessageHandler =
207+
MessageHandler mockMessageHandler2 =
205208
mockMessageHandler()
206209
.handleNextAndReply(m -> m);
207210

208-
try {
209-
this.mockIntegrationContext.substituteMessageHandlerFor(endpointId, mockMessageHandler);
210-
fail("IllegalStateException expected");
211-
}
212-
catch (Exception e) {
213-
assertThat(e).isInstanceOf(IllegalStateException.class);
214-
assertThat(e.getMessage()).contains("with replies can't replace simple MessageHandler");
215-
}
211+
212+
assertThatIllegalStateException()
213+
.isThrownBy(() ->
214+
this.mockIntegrationContext.substituteMessageHandlerFor(endpointId, mockMessageHandler2))
215+
.withMessageContaining("with replies can't replace simple MessageHandler");
216216

217217
this.mockIntegrationContext.resetBeans();
218218

219219
assertThat(TestUtils.getPropertyValue(endpoint, "handler", MessageHandler.class))
220-
.isNotSameAs(mockMessageHandler);
220+
.isNotSameAs(mockMessageHandler2);
221221
assertThat(TestUtils.getPropertyValue(endpoint, "subscriber", Subscriber.class))
222-
.isNotSameAs(mockMessageHandler);
222+
.isNotSameAs(mockMessageHandler2);
223223
}
224224

225225
/**
@@ -238,6 +238,37 @@ public void testHandlerSubstitutionWithOutputChannel() {
238238
assertThat(list.size()).isEqualTo(2);
239239
}
240240

241+
@Autowired
242+
private MessageChannel logChannel;
243+
244+
@Test
245+
@SuppressWarnings("unchecked")
246+
public void testMockIntegrationContextReset() {
247+
MockMessageHandler mockMessageHandler = mockMessageHandler();
248+
mockMessageHandler.handleNext(message -> { });
249+
250+
this.mockIntegrationContext.substituteMessageHandlerFor("logEndpoint", mockMessageHandler);
251+
252+
String endpointId = "mockMessageHandlerTests.Config.myService.serviceActivator";
253+
this.mockIntegrationContext.substituteMessageHandlerFor(endpointId, mockMessageHandler);
254+
255+
this.logChannel.send(new GenericMessage<>(1));
256+
257+
this.mockIntegrationContext.resetBeans("logEndpoint");
258+
259+
this.logChannel.send(new GenericMessage<>(2));
260+
261+
verify(mockMessageHandler).handleMessage(any(Message.class));
262+
263+
assertThat(TestUtils.getPropertyValue(this.mockIntegrationContext, "beans", Map.class)).hasSize(1);
264+
265+
assertThat(
266+
TestUtils.getPropertyValue(
267+
this.context.getBean("mockMessageHandlerTests.Config.myService.serviceActivator"), "handler"))
268+
.isSameAs(mockMessageHandler);
269+
}
270+
271+
241272
@Configuration
242273
@EnableIntegration
243274
public static class Config {
@@ -301,6 +332,13 @@ public MessageHandler handleNextInput() {
301332
});
302333
}
303334

335+
@Bean
336+
@EndpointId("logEndpoint")
337+
@ServiceActivator(inputChannel = "logChannel")
338+
public MessageHandler logHandler() {
339+
return new LoggingHandler(LoggingHandler.Level.FATAL);
340+
}
341+
304342
}
305343

306344
}

0 commit comments

Comments
 (0)