From 2df3646e90342fe7c4a83694efd3d04f81fbd975 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 22 Aug 2015 18:58:55 +0200 Subject: [PATCH] Let Jetty pick its own available port In an attempt to make our Jetty-based integration tests more robust, this commit discontinues use of SocketUtils for picking a random, available port and instead lets the Jetty Server pick its own port. --- .../client/AbstractJettyServerTestCase.java | 22 +++++++--- .../WebRequestDataBinderIntegrationTests.java | 44 +++++++++---------- .../client/AbstractJettyServerTestCase.java | 37 +++++++++++----- .../RequestPartIntegrationTests.java | 19 +++++--- .../web/socket/JettyWebSocketTestServer.java | 14 +++--- 5 files changed, 85 insertions(+), 51 deletions(-) diff --git a/spring-web/src/test/java/org/springframework/http/client/AbstractJettyServerTestCase.java b/spring-web/src/test/java/org/springframework/http/client/AbstractJettyServerTestCase.java index 1991eb16a0..24ec768827 100644 --- a/spring-web/src/test/java/org/springframework/http/client/AbstractJettyServerTestCase.java +++ b/spring-web/src/test/java/org/springframework/http/client/AbstractJettyServerTestCase.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.Map; + import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -28,31 +29,34 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; + import org.junit.AfterClass; -import static org.junit.Assert.assertEquals; import org.junit.BeforeClass; -import org.springframework.util.SocketUtils; import org.springframework.util.StreamUtils; +import static org.junit.Assert.*; + /** * @author Arjen Poutsma + * @author Sam Brannen */ public abstract class AbstractJettyServerTestCase { - protected static String baseUrl; - private static Server jettyServer; + protected static String baseUrl; @BeforeClass public static void startJettyServer() throws Exception { - int port = SocketUtils.findAvailableTcpPort(); - jettyServer = new Server(port); - baseUrl = "http://localhost:" + port; + + // Let server pick its own random, available port. + jettyServer = new Server(0); ServletContextHandler handler = new ServletContextHandler(); handler.setContextPath("/"); @@ -71,6 +75,10 @@ public abstract class AbstractJettyServerTestCase { jettyServer.setHandler(handler); jettyServer.start(); + + Connector[] connectors = jettyServer.getConnectors(); + NetworkConnector connector = (NetworkConnector) connectors[0]; + baseUrl = "http://localhost:" + connector.getLocalPort(); } @AfterClass diff --git a/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderIntegrationTests.java b/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderIntegrationTests.java index e6b0ed64e7..40c65ba737 100644 --- a/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderIntegrationTests.java +++ b/spring-web/src/test/java/org/springframework/web/bind/support/WebRequestDataBinderIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 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. @@ -25,11 +25,13 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; + import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -39,7 +41,6 @@ import org.springframework.http.MediaType; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import org.springframework.util.SocketUtils; import org.springframework.web.client.RestTemplate; import org.springframework.web.context.request.ServletWebRequest; @@ -47,36 +48,30 @@ import static org.junit.Assert.*; /** * @author Brian Clozel + * @author Sam Brannen */ public class WebRequestDataBinderIntegrationTests { + private static Server jettyServer; + + private static final PartsServlet partsServlet = new PartsServlet(); + + private static final PartListServlet partListServlet = new PartListServlet(); + + private final RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); + protected static String baseUrl; protected static MediaType contentType; - private static Server jettyServer; - - private RestTemplate template; - - private static PartsServlet partsServlet; - - private static PartListServlet partListServlet; - - - @Before - public void createTemplate() { - template = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); - } @BeforeClass public static void startJettyServer() throws Exception { - int port = SocketUtils.findAvailableTcpPort(); - jettyServer = new Server(port); - baseUrl = "http://localhost:" + port; - ServletContextHandler handler = new ServletContextHandler(); - partsServlet = new PartsServlet(); - partListServlet = new PartListServlet(); + // Let server pick its own random, available port. + jettyServer = new Server(0); + + ServletContextHandler handler = new ServletContextHandler(); MultipartConfigElement multipartConfig = new MultipartConfigElement(""); @@ -87,8 +82,13 @@ public class WebRequestDataBinderIntegrationTests { holder = new ServletHolder(partListServlet); holder.getRegistration().setMultipartConfig(multipartConfig); handler.addServlet(holder, "/partlist"); + jettyServer.setHandler(handler); jettyServer.start(); + + Connector[] connectors = jettyServer.getConnectors(); + NetworkConnector connector = (NetworkConnector) connectors[0]; + baseUrl = "http://localhost:" + connector.getLocalPort(); } @AfterClass diff --git a/spring-web/src/test/java/org/springframework/web/client/AbstractJettyServerTestCase.java b/spring-web/src/test/java/org/springframework/web/client/AbstractJettyServerTestCase.java index 5f54060ba9..adf5449f0a 100644 --- a/spring-web/src/test/java/org/springframework/web/client/AbstractJettyServerTestCase.java +++ b/spring-web/src/test/java/org/springframework/web/client/AbstractJettyServerTestCase.java @@ -33,47 +33,58 @@ import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; + import org.junit.AfterClass; import org.junit.BeforeClass; import org.springframework.http.MediaType; import org.springframework.util.FileCopyUtils; -import org.springframework.util.SocketUtils; import static org.junit.Assert.*; /** * @author Arjen Poutsma + * @author Sam Brannen */ public class AbstractJettyServerTestCase { protected static final String helloWorld = "H\u00e9llo W\u00f6rld"; - protected static final int port = SocketUtils.findAvailableTcpPort(); + protected static final MediaType textContentType = new MediaType("text", "plain", + Collections.singletonMap("charset", "UTF-8")); - protected static final String baseUrl = "http://localhost:" + port; + protected static final MediaType jsonContentType = new MediaType("application", + "json", Collections.singletonMap("charset", "utf-8")); - protected static final MediaType textContentType = new MediaType("text", "plain", Collections.singletonMap("charset", "UTF-8")); + private static Server jettyServer; - protected static final MediaType jsonContentType = new MediaType("application", "json", Collections.singletonMap("charset", "utf-8")); + protected static int port; + + protected static String baseUrl; - private static final Server jettyServer = new Server(port); @BeforeClass public static void startJettyServer() throws Exception { + + // Let server pick its own random, available port. + jettyServer = new Server(0); + ServletContextHandler handler = new ServletContextHandler(); byte[] bytes = helloWorld.getBytes("utf-8"); handler.addServlet(new ServletHolder(new GetServlet(bytes, textContentType)), "/get"); handler.addServlet(new ServletHolder(new GetServlet(new byte[0], textContentType)), "/get/nothing"); handler.addServlet(new ServletHolder(new GetServlet(bytes, null)), "/get/nocontenttype"); handler.addServlet( - new ServletHolder(new PostServlet(helloWorld, baseUrl + "/post/1", bytes, textContentType)), + new ServletHolder(new PostServlet(helloWorld, "/post/1", bytes, textContentType)), "/post"); handler.addServlet( - new ServletHolder(new JsonPostServlet(baseUrl + "/jsonpost/1", jsonContentType)), + new ServletHolder(new JsonPostServlet("/jsonpost/1", jsonContentType)), "/jsonpost"); handler.addServlet(new ServletHolder(new StatusCodeServlet(204)), "/status/nocontent"); handler.addServlet(new ServletHolder(new StatusCodeServlet(304)), "/status/notmodified"); @@ -86,8 +97,14 @@ public class AbstractJettyServerTestCase { handler.addServlet( new ServletHolder(new PutServlet(helloWorld, bytes, textContentType)), "/put"); + jettyServer.setHandler(handler); jettyServer.start(); + + Connector[] connectors = jettyServer.getConnectors(); + NetworkConnector connector = (NetworkConnector) connectors[0]; + port = connector.getLocalPort(); + baseUrl = "http://localhost:" + port; } @AfterClass @@ -179,7 +196,7 @@ public class AbstractJettyServerTestCase { String body = FileCopyUtils.copyToString(request.getReader()); assertEquals("Invalid request body", s, body); response.setStatus(HttpServletResponse.SC_CREATED); - response.setHeader("Location", location); + response.setHeader("Location", baseUrl + location); response.setContentLength(buf.length); response.setContentType(contentType.toString()); FileCopyUtils.copy(buf, response.getOutputStream()); @@ -205,7 +222,7 @@ public class AbstractJettyServerTestCase { assertNotNull("No content-type", request.getContentType()); String body = FileCopyUtils.copyToString(request.getReader()); response.setStatus(HttpServletResponse.SC_CREATED); - response.setHeader("Location", location); + response.setHeader("Location", baseUrl +location); response.setContentType(contentType.toString()); byte[] bytes = body.getBytes("utf-8"); response.setContentLength(bytes.length);; diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartIntegrationTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartIntegrationTests.java index 812629b48c..a1bc88b761 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartIntegrationTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartIntegrationTests.java @@ -16,8 +16,6 @@ package org.springframework.web.servlet.mvc.method.annotation; -import static org.junit.Assert.*; - import java.net.URI; import java.nio.charset.Charset; import java.util.ArrayList; @@ -26,9 +24,12 @@ import java.util.List; import javax.servlet.MultipartConfigElement; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; + import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; @@ -52,7 +53,6 @@ import org.springframework.http.converter.support.AllEncompassingFormHttpMessage import org.springframework.stereotype.Controller; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import org.springframework.util.SocketUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestPart; @@ -66,11 +66,14 @@ import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import static org.junit.Assert.*; + /** * Test access to parts of a multipart request with {@link RequestPart}. * * @author Rossen Stoyanchev * @author Brian Clozel + * @author Sam Brannen */ public class RequestPartIntegrationTests { @@ -83,10 +86,10 @@ public class RequestPartIntegrationTests { @BeforeClass public static void startServer() throws Exception { - int port = SocketUtils.findAvailableTcpPort(); - baseUrl = "http://localhost:" + port; - server = new Server(port); + // Let server pick its own random, available port. + server = new Server(0); + ServletContextHandler handler = new ServletContextHandler(); handler.setContextPath("/"); @@ -105,6 +108,10 @@ public class RequestPartIntegrationTests { server.setHandler(handler); server.start(); + + Connector[] connectors = server.getConnectors(); + NetworkConnector connector = (NetworkConnector) connectors[0]; + baseUrl = "http://localhost:" + connector.getLocalPort(); } @Before diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/JettyWebSocketTestServer.java b/spring-websocket/src/test/java/org/springframework/web/socket/JettyWebSocketTestServer.java index 876ad17c4c..28e8aff865 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/JettyWebSocketTestServer.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/JettyWebSocketTestServer.java @@ -17,18 +17,17 @@ package org.springframework.web.socket; import java.util.EnumSet; - import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.ServletContext; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.NetworkConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.springframework.util.Assert; -import org.springframework.util.SocketUtils; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; @@ -49,8 +48,8 @@ public class JettyWebSocketTestServer implements WebSocketTestServer { @Override public void setup() { - this.port = SocketUtils.findAvailableTcpPort(); - this.jettyServer = new Server(this.port); + // Let server pick its own random, available port. + this.jettyServer = new Server(0); } @Override @@ -60,7 +59,6 @@ public class JettyWebSocketTestServer implements WebSocketTestServer { @Override public void deployConfig(WebApplicationContext wac, Filter... filters) { - Assert.state(this.port != -1, "setup() was never called."); ServletHolder servletHolder = new ServletHolder(new DispatcherServlet(wac)); this.contextHandler = new ServletContextHandler(); this.contextHandler.addServlet(servletHolder, "/"); @@ -87,6 +85,10 @@ public class JettyWebSocketTestServer implements WebSocketTestServer { @Override public void start() throws Exception { this.jettyServer.start(); + + Connector[] connectors = jettyServer.getConnectors(); + NetworkConnector connector = (NetworkConnector) connectors[0]; + this.port = connector.getLocalPort(); } @Override