java - tutorial - Prueba JUnit con Embedded Tomcat Server, ¿cómo especificar puertos automáticos para ambos conectores http y https?
spring boot test repository (2)
No lo he intentado pero desde el código parece
Puede
setRedirectPort
después de que se haya iniciado el servidorPuede usar
Connector.getLocalPort
para obtener un puerto real
Así que creo que podrías intentar agregar algo como
mTomcat.start(); // <-- your existing code
defaultConnector.setRedirectPort(SSLConnector.getLocalPort())
Descripción
Hice una prueba JUnit que se enfoca en tratar de probar una llamada a un servicio web SOAP.
Estoy utilizando un servidor tomcat integrado para mi prueba con el fin de ejecutar mi prueba con un servidor simulado.
También estoy usando conectores http y https.
Necesito usar puertos automáticos para estos dos conectores porque la prueba se está ejecutando en un servidor Jenkins y no puedo usar el puerto 443 o 8443 ya que ya están ocupados.
Entiendo que usar el puerto 0 como puerto estándar resultará en tomcat usando la asignación automática de puertos pero no puedo usarlo con ambos conectores.
Comportamiento esperado
Me gustaría utilizar la asignación de puertos automática también para mi conector ssl personalizado.
¿Es posible hacerlo de alguna manera?
Código de muestra
Aquí está el código para mi instancia de tomcat:
@Before
public void setup() throws Throwable {
File tomcatWorkingDir = new File(mWorkingDir);
//Empty the target/tomcat-working-dir directory if it exist
//Create the directory otherwise
if(tomcatWorkingDir.exists() && tomcatWorkingDir.isDirectory()){
LOGGER.info("cleaning tomcat-working-dir directory");
FileUtils.cleanDirectory(new File(mWorkingDir));
} else {
LOGGER.info("create tomcat-working-dir directory");
tomcatWorkingDir.mkdir();
}
LOGGER.info("disabling ssl certification validation");
//Disable JVM ssl sockets connection
disableJVMCertificate();
//Add server certificate
createServerCertificate();
//Custom SSL Connector
Connector SSLConnector = getSSLConnector();
mTomcat = new Tomcat();
//Standard http startup port
mTomcat.setPort(0);
//Set up base directory
//Otherwise, tomcat would use the current directory
mTomcat.setBaseDir(mWorkingDir);
LOGGER.info("setting the ssl connector in TOMCAT");
Service service = mTomcat.getService();
service.addConnector(SSLConnector);
//Redirect current port
Connector defaultConnector = mTomcat.getConnector();
defaultConnector.setRedirectPort(SERVER_HTTPS_PORT);
//Configure the way WAR are managed by the engine
mTomcat.getHost().setAutoDeploy(true);
mTomcat.getHost().setDeployOnStartup(true);
//Add mock server into our webApp
String servletName = "/server";
File webApp = new File(mWorkingDir,"../../../ws-mock-server/src/main/webapp");
mTomcat.addWebapp(mTomcat.getHost(), servletName, webApp.getAbsolutePath());
//start tomcat
LOGGER.info("starting TOMCAT");
mTomcat.start();
}
y aquí para mi conector ssl personalizado.
private static Connector getSSLConnector(){
Connector connector = new Connector();
connector.setPort(SERVER_HTTPS_PORT);
connector.setSecure(true);
//Http protocol Http11AprProtocol
connector.setAttribute("protocol", "org.apache.coyote.http11.Http11AprProtocol");
//Maximum threads allowedd on this instance of tomcat
connector.setAttribute("maxThreads","200");
connector.setAttribute("SSLEnabled", true);
//No client Authentification is required in order to connect
connector.setAttribute("clientAuth", false);
//SSL TLSv1 protocol
connector.setAttribute("sslProtocol","TLS");
//Ciphers configuration describing how server will encrypt his messages
//A common cipher suite need to exist between server and client in an ssl
//communication in order for the handshake to succeed
connector.setAttribute("ciphers","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
LOGGER.info("setting keystore file");
//Here an absolute file path is needed in order to properly set up the keystore attribute
connector.setAttribute("keystoreFile",new File(".").getAbsolutePath().replace("//", "/")+"/"+mWorkingDir+"/server.jks");
LOGGER.info("setting keystore pass");
connector.setAttribute("keystorePass","changeit");
return connector;
}
Tengo dos soluciones para este problema:
Seleccione el puerto SSL manualmente
El constructor ServerSocket (0) selecciona automáticamente un puerto libre. El Tomcat usa este método también.
try (ServerSocket testSocket = new ServerSocket(0)) {
int randomFreePort = testSocket.getLocalPort();
sslConnector.setPort(randomFreePort);
defaultConnector.setRedirectPort( randomFreePort);
} // At this point the testSocket.close() called
tomcat.start();
Lo sé, hay una probabilidad de que otro proceso asigne el mismo puerto entre testSocket.close()
y tomcat.start()
, pero puede detectar esta situación con LifecycleState.FAILED.equals(sslConnector.getState())
prueba.
Use oyentes del ciclo de vida
Los conectores Tomcat son conscientes del ciclo de vida, por lo que se le notificará sobre los eventos ''before_init'' y ''after_init''. Tomcat inicializa los conectores en el orden cuando los agregó al Servicio.
- Agregue el conector ssl.
- Agrega un conector http. (Ese será el conector ''predeterminado''. No llame al
mTomcat.getConnector()
porque obtiene el primero o crea un nuevo conector.) - Cuando se completa la inicialización del conector ssl, puede obtener el puerto elegido con la llamada getLocalPort () .
- Antes de la inicialización del conector http, llame al setRedirectPort
Ejemplo completo:
Tomcat mTomcat = new Tomcat();
Connector sslConnector = getSSLConnector();
mTomcat.getService().addConnector(sslConnector);
Connector defaultConnector = new Connector();
defaultConnector.setPort(0);
mTomcat.getService().addConnector(defaultConnector);
// Do the rest of the Tomcat setup
AtomicInteger sslPort = new AtomicInteger();
sslConnector.addLifecycleListener(event->{
if( "after_init".equals(event.getType()) )
sslPort.set(sslConnector.getLocalPort());
});
defaultConnector.addLifecycleListener(event->{
if( "before_init".equals(event.getType()) )
defaultConnector.setRedirectPort(sslPort.get());
});
mTomcat.start();