Commit d5a197fe authored by Madhura Bhave's avatar Madhura Bhave

Support random actuator port in SpringBootTest

This commit changes @SpringBootTest(randomPort = true) to
generate a random port for the actuator endpoints if the
management server runs on a different port from the main
server.

Closes gh-4424
parent 01e61d88
...@@ -6491,6 +6491,10 @@ test method by default. However, as using this arrangement with either `RANDOM_P ...@@ -6491,6 +6491,10 @@ test method by default. However, as using this arrangement with either `RANDOM_P
run in separate threads and, thus, in separate transactions. Any transaction initiated on run in separate threads and, thus, in separate transactions. Any transaction initiated on
the server does not roll back in this case. the server does not roll back in this case.
NOTE: `@SpringBootTest` with `webEnvironment = WebEnvironment.RANDOM_PORT` will also
start the management server on a separate random port if your application uses a different
port for the management server.
[[boot-features-testing-spring-boot-applications-detecting-web-app-type]] [[boot-features-testing-spring-boot-applications-detecting-web-app-type]]
......
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.test.web;
import java.util.Objects;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.test.context.support.TestPropertySourceUtils;
/**
* {@link EnvironmentPostProcessor} implementation to start the management context on a
* random port if the main server's port is 0 and the management context is expected on a
* different port.
*
* @author Madhura Bhave
* @since 2.1.0
*/
public class SpringBootTestRandomPortEnvironmentPostProcessor
implements EnvironmentPostProcessor {
private static final String MANAGEMENT_PORT_PROPERTY = "management.server.port";
private static final String SERVER_PORT_PROPERTY = "server.port";
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
MapPropertySource source = (MapPropertySource) environment.getPropertySources()
.get(TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME);
if (isTestServerPortRandom(source)) {
if (source.getProperty(MANAGEMENT_PORT_PROPERTY) == null) {
String managementPort = getPort(environment, MANAGEMENT_PORT_PROPERTY,
null);
String serverPort = getPort(environment, SERVER_PORT_PROPERTY, "8080");
if (managementPort != null && !managementPort.equals("-1")) {
if (!managementPort.equals(serverPort)) {
source.getSource().put(MANAGEMENT_PORT_PROPERTY, "0");
}
else {
source.getSource().put(MANAGEMENT_PORT_PROPERTY, "");
}
}
}
}
}
private boolean isTestServerPortRandom(MapPropertySource source) {
return (source != null && "0".equals(source.getProperty(SERVER_PORT_PROPERTY)));
}
private String getPort(ConfigurableEnvironment environment, String property,
String defaultValue) {
return environment.getPropertySources().stream()
.filter((source) -> !source.getName().equals(
TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME))
.map((source) -> (String) source.getProperty(property))
.filter(Objects::nonNull).findFirst().orElse(defaultValue);
}
}
...@@ -11,3 +11,7 @@ org.springframework.boot.test.web.reactive.server.WebTestClientContextCustomizer ...@@ -11,3 +11,7 @@ org.springframework.boot.test.web.reactive.server.WebTestClientContextCustomizer
org.springframework.test.context.TestExecutionListener=\ org.springframework.test.context.TestExecutionListener=\
org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener,\ org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener,\
org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.test.web.SpringBootTestRandomPortEnvironmentPostProcessor
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.test.web;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SpringBootTestRandomPortEnvironmentPostProcessor}.
*
* @author Madhura Bhave
*/
public class SpringBootTestRandomPortEnvironmentPostProcessorTests {
private SpringBootTestRandomPortEnvironmentPostProcessor postProcessor = new SpringBootTestRandomPortEnvironmentPostProcessor();
private MockEnvironment environment;
private MutablePropertySources propertySources;
@Before
public void setup() {
this.environment = new MockEnvironment();
this.propertySources = this.environment.getPropertySources();
}
@Test
public void postProcessWhenServerAndManagementPortIsZeroInTestPropertySource() {
addTestPropertySource("0", "0");
this.environment.setProperty("management.server.port", "0");
this.postProcessor.postProcessEnvironment(this.environment, null);
assertThat(this.environment.getProperty("server.port")).isEqualTo("0");
assertThat(this.environment.getProperty("management.server.port")).isEqualTo("0");
}
@Test
public void postProcessWhenTestServerAndTestManagementPortAreNonZero() {
addTestPropertySource("8080", "8081");
this.environment.setProperty("server.port", "8080");
this.environment.setProperty("management.server.port", "8081");
this.postProcessor.postProcessEnvironment(this.environment, null);
assertThat(this.environment.getProperty("server.port")).isEqualTo("8080");
assertThat(this.environment.getProperty("management.server.port"))
.isEqualTo("8081");
}
@Test
public void postProcessWhenTestServerPortIsZeroAndTestManagementPortIsNotNull() {
addTestPropertySource("0", "8080");
this.postProcessor.postProcessEnvironment(this.environment, null);
assertThat(this.environment.getProperty("server.port")).isEqualTo("0");
assertThat(this.environment.getProperty("management.server.port"))
.isEqualTo("8080");
}
@Test
public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNull() {
addTestPropertySource("0", null);
this.postProcessor.postProcessEnvironment(this.environment, null);
assertThat(this.environment.getProperty("server.port")).isEqualTo("0");
assertThat(this.environment.getProperty("management.server.port"))
.isEqualTo(null);
}
@Test
public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndSameInProduction() {
addTestPropertySource("0", null);
Map<String, Object> other = new HashMap<>();
other.put("server.port", "8081");
other.put("management.server.port", "8081");
MapPropertySource otherSource = new MapPropertySource("other", other);
this.propertySources.addLast(otherSource);
this.postProcessor.postProcessEnvironment(this.environment, null);
assertThat(this.environment.getProperty("server.port")).isEqualTo("0");
assertThat(this.environment.getProperty("management.server.port")).isEqualTo("");
}
@Test
public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndDefaultSameInProduction() {
// mgmt port is 8080 which means its on the same port as main server since that is
// null in app properties
addTestPropertySource("0", null);
Map<String, Object> other = new HashMap<>();
other.put("management.server.port", "8080");
MapPropertySource otherSource = new MapPropertySource("other", other);
this.propertySources.addLast(otherSource);
this.postProcessor.postProcessEnvironment(this.environment, null);
assertThat(this.environment.getProperty("server.port")).isEqualTo("0");
assertThat(this.environment.getProperty("management.server.port")).isEqualTo("");
}
@Test
public void postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndDifferentInProduction() {
addTestPropertySource("0", null);
Map<String, Object> other = new HashMap<>();
other.put("management.server.port", "8081");
MapPropertySource otherSource = new MapPropertySource("other", other);
this.propertySources.addLast(otherSource);
this.postProcessor.postProcessEnvironment(this.environment, null);
assertThat(this.environment.getProperty("server.port")).isEqualTo("0");
assertThat(this.environment.getProperty("management.server.port")).isEqualTo("0");
}
@Test
public void postProcessWhenTestServerPortIsZeroAndManagementPortMinusOne() {
addTestPropertySource("0", null);
Map<String, Object> other = new HashMap<>();
other.put("management.server.port", "-1");
MapPropertySource otherSource = new MapPropertySource("other", other);
this.propertySources.addLast(otherSource);
this.postProcessor.postProcessEnvironment(this.environment, null);
assertThat(this.environment.getProperty("server.port")).isEqualTo("0");
assertThat(this.environment.getProperty("management.server.port"))
.isEqualTo("-1");
}
private void addTestPropertySource(String serverPort, String managementPort) {
Map<String, Object> source = new HashMap<>();
source.put("server.port", serverPort);
source.put("management.server.port", managementPort);
MapPropertySource inlineTestSource = new MapPropertySource(
TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME, source);
this.propertySources.addFirst(inlineTestSource);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment