Skip to content

Commit

Permalink
Minimise our usage of SocketUtils.findAvailableTcpPort
Browse files Browse the repository at this point in the history
Closes gh-9382
  • Loading branch information
wilkinsona committed Jun 9, 2017
1 parent 1086851 commit f7e9ec5
Show file tree
Hide file tree
Showing 26 changed files with 434 additions and 278 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
package org.springframework.boot.actuate.autoconfigure;

import java.io.FileNotFoundException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.URI;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -67,19 +65,18 @@
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testutil.Matched;
import org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerException;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequest;
Expand All @@ -88,7 +85,6 @@
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Controller;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.SocketUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
Expand Down Expand Up @@ -134,7 +130,6 @@ public void setUp() {
@After
public void cleanUp() throws Exception {
this.applicationContext.close();
assertAllClosed();
}

@Test
Expand All @@ -146,8 +141,6 @@ public void onSamePort() throws Exception {
this.applicationContext.refresh();
assertContent("/controller", ports.get().server, "controlleroutput");
assertContent("/endpoint", ports.get().server, "endpointoutput");
assertContent("/controller", ports.get().management, null);
assertContent("/endpoint", ports.get().management, null);
assertThat(hasHeader("/endpoint", ports.get().server, "X-Application-Context"))
.isFalse();
assertThat(this.applicationContext.containsBean("applicationContextIdFilter"))
Expand Down Expand Up @@ -274,25 +267,6 @@ public void onDifferentPortInWebServer() throws Exception {
assertContent("/endpoint", ports.get().management, null);
}

@Test
public void onRandomPort() throws Exception {
TestPropertyValues.of("management.port=0", "management.security.enabled=false")
.applyTo(this.applicationContext);
this.applicationContext.register(RootConfig.class, EndpointConfig.class,
BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class);
GrabManagementPort grabManagementPort = new GrabManagementPort(
this.applicationContext);
this.applicationContext.addApplicationListener(grabManagementPort);
this.applicationContext.refresh();
int managementPort = grabManagementPort.getWebServer().getPort();
assertThat(managementPort).isNotEqualTo(ports.get().server);
assertContent("/controller", ports.get().server, "controlleroutput");
assertContent("/endpoint", ports.get().server, null);
assertContent("/controller", managementPort, null);
assertContent("/endpoint", managementPort, "endpointoutput");
}

@Test
public void onDifferentPortWithPrimaryFailure() throws Exception {
TestPropertyValues.of("management.port=" + ports.get().management)
Expand Down Expand Up @@ -340,20 +314,22 @@ public void specificPortsViaProperties() throws Exception {
}

@Test
public void specificPortsViaPropertiesWithClash() throws Exception {
int managementPort = ports.get().management;
try (ServerSocket serverSocket = new ServerSocket()) {
serverSocket.bind(new InetSocketAddress(managementPort));
TestPropertyValues
.of("server.port:" + ports.get().server,
"management.port:" + ports.get().management)
.applyTo(this.applicationContext);
this.applicationContext.register(RootConfig.class, EndpointConfig.class,
BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class);
this.thrown.expect(WebServerException.class);
this.applicationContext.refresh();
}
public void managementContextFailureCausesMainContextFailure() throws Exception {
TestPropertyValues
.of("server.port:" + ports.get().server,
"management.port:" + ports.get().management)
.applyTo(this.applicationContext);
this.applicationContext.register(RootConfig.class, EndpointConfig.class,
BaseConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class);
this.applicationContext.addApplicationListener(
(ApplicationListener<ContextRefreshedEvent>) (event) -> {
if (event.getApplicationContext().getParent() != null) {
throw new RuntimeException();
}
});
this.thrown.expect(RuntimeException.class);
this.applicationContext.refresh();
}

@Test
Expand Down Expand Up @@ -671,13 +647,6 @@ private void endpointEnabledOverride(String name, Class<? extends MvcEndpoint> t
assertThat(this.applicationContext.getBeansOfType(type)).hasSize(1);
}

private void assertAllClosed() throws Exception {
assertContent("/controller", ports.get().server, null);
assertContent("/endpoint", ports.get().server, null);
assertContent("/controller", ports.get().management, null);
assertContent("/endpoint", ports.get().management, null);
}

private void assertHttpsContent(String url, int port, Object expected)
throws Exception {
assertContent("https", url, port, expected);
Expand Down Expand Up @@ -733,9 +702,9 @@ public boolean hasHeader(String url, int port, String header) throws Exception {

private static class Ports {

final int server = SocketUtils.findAvailableTcpPort();
int server = 0;

final int management = SocketUtils.findAvailableTcpPort();
int management = 0;

}

Expand All @@ -758,6 +727,19 @@ public TestController testController() {
return new TestController();
}

@Bean
public ApplicationListener<WebServerInitializedEvent> serverPortListener() {
return (event) -> {
int port = event.getWebServer().getPort();
if (event.getApplicationContext().getParent() == null) {
ports.get().server = port;
}
else {
ports.get().management = port;
}
};
}

}

@Configuration
Expand Down Expand Up @@ -886,30 +868,6 @@ public Class<? extends Endpoint> getEndpointType() {

}

private static class GrabManagementPort
implements ApplicationListener<ServletWebServerInitializedEvent> {

private ApplicationContext rootContext;

private WebServer webServer;

GrabManagementPort(ApplicationContext rootContext) {
this.rootContext = rootContext;
}

@Override
public void onApplicationEvent(ServletWebServerInitializedEvent event) {
if (event.getApplicationContext() != this.rootContext) {
this.webServer = event.getWebServer();
}
}

public WebServer getWebServer() {
return this.webServer;
}

}

private static class SpecificServletWebServerFactory
extends TomcatServletWebServerFactory {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.SocketUtils;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
Expand Down Expand Up @@ -347,9 +346,7 @@ static class TomcatConfiguration {

@Bean
public TomcatServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(SocketUtils.findAvailableTcpPort(40000));
return factory;
return new TomcatServletWebServerFactory(0);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.SocketUtils;

import static org.assertj.core.api.Assertions.assertThat;

Expand Down Expand Up @@ -55,9 +54,7 @@ static class Config {

@Bean
public TomcatServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(SocketUtils.findAvailableTcpPort(40000));
return factory;
return new TomcatServletWebServerFactory(0);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.writer.Delta;
import org.springframework.util.SocketUtils;

import static org.assertj.core.api.Assertions.assertThat;

Expand All @@ -40,12 +39,10 @@
*/
public class StatsdMetricWriterTests {

private int port = SocketUtils.findAvailableTcpPort();

private DummyStatsDServer server = new DummyStatsDServer(this.port);
private DummyStatsDServer server = new DummyStatsDServer(0);

private StatsdMetricWriter writer = new StatsdMetricWriter("me", "localhost",
this.port);
this.server.getPort());

@After
public void close() {
Expand Down Expand Up @@ -84,15 +81,15 @@ public void setTimerMetric() throws Exception {

@Test
public void nullPrefix() throws Exception {
this.writer = new StatsdMetricWriter("localhost", this.port);
this.writer = new StatsdMetricWriter("localhost", this.server.getPort());
this.writer.set(new Metric<>("gauge.foo", 3L));
this.server.waitForMessage();
assertThat(this.server.messagesReceived().get(0)).isEqualTo("gauge.foo:3|g");
}

@Test
public void periodPrefix() throws Exception {
this.writer = new StatsdMetricWriter("my.", "localhost", this.port);
this.writer = new StatsdMetricWriter("my.", "localhost", this.server.getPort());
this.writer.set(new Metric<>("gauge.foo", 3L));
this.server.waitForMessage();
assertThat(this.server.messagesReceived().get(0)).isEqualTo("my.gauge.foo:3|g");
Expand Down Expand Up @@ -129,6 +126,10 @@ private static final class DummyStatsDServer implements Runnable {
new Thread(this).start();
}

int getPort() {
return this.server.getLocalPort();
}

public void stop() {
this.server.close();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@

package org.springframework.boot.autoconfigure.elasticsearch.jest;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -26,22 +30,28 @@
import io.searchbox.client.http.JestHttpClient;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.util.SocketUtils;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -105,12 +115,12 @@ public void proxyHostWithoutPort() {

@Test
public void jestCanCommunicateWithElasticsearchInstance() throws IOException {
int port = SocketUtils.findAvailableTcpPort();
load(ElasticsearchAutoConfiguration.class,
new File("target/elastic/logs").mkdirs();
load(HttpPortConfiguration.class,
"spring.data.elasticsearch.properties.path.home:target/elastic",
"spring.data.elasticsearch.properties.http.enabled:true",
"spring.data.elasticsearch.properties.http.port:" + port,
"spring.elasticsearch.jest.uris:http://localhost:" + port);
"spring.data.elasticsearch.properties.http.port:0",
"spring.data.elasticsearch.properties.node.portsfile:true");
JestClient client = this.context.getBean(JestClient.class);
Map<String, String> source = new HashMap<>();
source.put("a", "alpha");
Expand Down Expand Up @@ -182,4 +192,53 @@ Gson getGson() {

}

@Configuration
@Import(ElasticsearchAutoConfiguration.class)
static class HttpPortConfiguration {

@Bean
public static BeanPostProcessor portPropertyConfigurer() {
return new PortPropertyConfigurer();
}

private static final class PortPropertyConfigurer
implements BeanPostProcessor, ApplicationContextAware {

private ConfigurableApplicationContext applicationContext;

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof NodeClient) {
this.applicationContext.getBean(JestProperties.class)
.setUris(Arrays.asList("http://localhost:" + readHttpPort()));
}
return bean;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}

private int readHttpPort() {
try {
for (String line : Files
.readAllLines(Paths.get("target/elastic/logs/http.ports"))) {
if (line.startsWith("127.0.0.1")) {
return Integer
.parseInt(line.substring(line.indexOf(":") + 1));
}
}
throw new FatalBeanException("HTTP port not found");
}
catch (IOException ex) {
throw new FatalBeanException("Failed to read HTTP port", ex);
}
}
}

}

}
Loading

0 comments on commit f7e9ec5

Please sign in to comment.