diff --git a/src/main/java/org/kiwiproject/dropwizard/util/server/DropwizardConnectors.java b/src/main/java/org/kiwiproject/dropwizard/util/server/DropwizardConnectors.java index ac7ab9f..e1cd2c8 100644 --- a/src/main/java/org/kiwiproject/dropwizard/util/server/DropwizardConnectors.java +++ b/src/main/java/org/kiwiproject/dropwizard/util/server/DropwizardConnectors.java @@ -1,22 +1,33 @@ package org.kiwiproject.dropwizard.util.server; +import static com.google.common.base.Preconditions.checkState; import static java.util.function.Function.identity; import static java.util.stream.Collectors.toMap; import static org.kiwiproject.base.KiwiPreconditions.checkArgumentNotNull; import static org.kiwiproject.base.KiwiStrings.format; +import static org.kiwiproject.collect.KiwiLists.first; import com.google.common.annotations.VisibleForTesting; +import io.dropwizard.core.Configuration; import io.dropwizard.core.server.DefaultServerFactory; import io.dropwizard.core.server.ServerFactory; import io.dropwizard.jetty.ConnectorFactory; import io.dropwizard.jetty.HttpConnectorFactory; import io.dropwizard.jetty.HttpsConnectorFactory; + +import lombok.Getter; +import lombok.experimental.Accessors; import lombok.experimental.UtilityClass; import lombok.extern.slf4j.Slf4j; +import org.kiwiproject.registry.model.Port; +import org.kiwiproject.registry.model.Port.PortType; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; /** * Utility class that assists with setting up the server connectors in Dropwizard. @@ -29,13 +40,27 @@ public class DropwizardConnectors { * Enum defining the possible options for a connector type in Dropwizard. */ public enum ConnectorType { - HTTP, HTTPS; + HTTP("http"), HTTPS("https"); + + /** + * The scheme (in a URL) for this type of connector. + */ + @Getter + @Accessors(fluent = true) + final String scheme; + + ConnectorType(String scheme) { + this.scheme = scheme; + } /** * Given an {@link HttpConnectorFactory} instance, determine whether it is for HTTP or HTTPS. * * @param factory the instance * @return the ConnectorType + * @implNote Assumes there is only {@link HttpConnectorFactory} and one + * subclass, {@link HttpsConnectorFactory}. This is what has existed in Dropwizard for many + * years now. HTTPS is returned for {@link HttpsConnectorFactory}, and HTTP for anything else. */ static ConnectorType forHttpConnectorFactory(HttpConnectorFactory factory) { checkArgumentNotNull(factory, "factory cannot be null"); @@ -48,6 +73,21 @@ static ConnectorType forHttpConnectorFactory(HttpConnectorFactory factory) { } } + /** + * Requires that the given {@link Configuration} contains a {@link ServerFactory} that is + * a {@link DefaultServerFactory}. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @return the server factory from the configuration if it is an instance of {@link DefaultServerFactory} + * @throws IllegalStateException if serverFactory is not a {@link DefaultServerFactory} + */ + public static DefaultServerFactory requireDefaultServerFactory(C configuration) { + checkArgumentNotNull(configuration, "configuration is required"); + + return requireDefaultServerFactory(configuration.getServerFactory()); + } + /** * Requires that the given {@link ServerFactory} is in fact a {@link DefaultServerFactory}. * @@ -68,6 +108,231 @@ public static DefaultServerFactory requireDefaultServerFactory(ServerFactory ser throw new IllegalStateException(error); } + /** + * Get all the ports. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @return a list of all the ports in the Dropwizard configuration + */ + public static List getPorts(C configuration) { + var serverFactory = requireDefaultServerFactory(configuration); + return getPorts(serverFactory); + } + + /** + * Get all the ports. + * + * @param serverFactory the {@link DefaultServerFactory} to get the ports from + * @return a list of all the ports in the server factory + */ + public static List getPorts(DefaultServerFactory serverFactory) { + return Stream.of(getApplicationPorts(serverFactory), getAdminPorts(serverFactory)) + .flatMap(Collection::stream) + .toList(); + } + + /** + * Get the single application port. If there is more than one, throw an exception. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @return the single application port + * @throws IllegalStateException if there is more than one application port + */ + public static Port getOnlyApplicationPort(C configuration) { + var serverFactory = requireDefaultServerFactory(configuration); + return getOnlyApplicationPort(serverFactory); + } + + /** + * Get the single application port. If there is more than one, throw an exception. + * + * @param serverFactory the {@link DefaultServerFactory} to get the single application port from + * @return the application port + * @throws IllegalStateException if there is more than one port + */ + public static Port getOnlyApplicationPort(DefaultServerFactory serverFactory) { + var applicationPorts = getApplicationPorts(serverFactory); + checkExactlyOnePort("application", applicationPorts); + return first(applicationPorts); + } + + /** + * Find only the application ports. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @return the application ports + */ + public static List getApplicationPorts(C configuration) { + var serverFactory = requireDefaultServerFactory(configuration); + return getApplicationPorts(serverFactory); + } + + /** + * Find only the application ports. + * + * @param serverFactory the {@link DefaultServerFactory} to get the application ports from + * @return the application ports + */ + public static List getApplicationPorts(DefaultServerFactory serverFactory) { + return getPorts(serverFactory, PortType.APPLICATION); + } + + /** + * Get the single admin port. If there is more than one, throw an exception. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @return the admin port + * @throws IllegalStateException if there is more than one admin port + */ + public static Port getOnlyAdminPort(C configuration) { + var serverFactory = requireDefaultServerFactory(configuration); + return getOnlyAdminPort(serverFactory); + } + + /** + * Get the single admin port. If there is more than one, throw an exception. + * + * @param serverFactory the {@link DefaultServerFactory} to get single admin port from + * @return the admin port + * @throws IllegalStateException if there is more than one admin port + */ + public static Port getOnlyAdminPort(DefaultServerFactory serverFactory) { + var adminPorts = getAdminPorts(serverFactory); + checkExactlyOnePort("admin", adminPorts); + return first(adminPorts); + } + + private static void checkExactlyOnePort(String portType, List ports) { + var numPorts = ports.size(); + checkState(numPorts == 1, "expected only one %s port but found %s", portType, numPorts); + } + + /** + * Find only the admin ports. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @return the admin ports + */ + public static List getAdminPorts(C configuration) { + var serverFactory = requireDefaultServerFactory(configuration); + return getPorts(serverFactory, PortType.ADMIN); + } + + /** + * Find only the admin ports. + * + * @param serverFactory the {@link DefaultServerFactory} to get the admin ports from + * @return the admin ports + */ + public static List getAdminPorts(DefaultServerFactory serverFactory) { + return getPorts(serverFactory, PortType.ADMIN); + } + + /** + * Find all the {@link Port}s having the given type. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @param portType the type of port to find + * @return a list containing the matched ports + */ + public static List getPorts(C configuration, PortType portType) { + var serverFactory = requireDefaultServerFactory(configuration); + return getPorts(serverFactory, portType); + } + + /** + * Find all the {@link Port}s having the given type. + * + * @param serverFactory the {@link DefaultServerFactory} to get the ports from + * @param portType the type of port to find + * @return a list containing the matched ports + */ + public static List getPorts(DefaultServerFactory serverFactory, PortType portType) { + return Arrays.stream(ConnectorType.values()) + .map(connectorType -> getPort(serverFactory, portType, connectorType)) + .flatMap(Optional::stream) + .toList(); + } + + /** + * Get the {@link Port} having the given type and connector type. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @param portType the type of port to find + * @param connectorType the connector type to find + * @return an {@link Optional} containing the matching port or {@code Optional#empty()} + */ + public static Optional getPort(C configuration, + PortType portType, + ConnectorType connectorType) { + var serverFactory = requireDefaultServerFactory(configuration); + return getPort(serverFactory, portType, connectorType); + } + + /** + * Get the {@link Port} having the given type and connector type. + * + * @param serverFactory the {@link DefaultServerFactory} to get the ports from + * @param portType the type of port to find + * @param connectorType the connector type to find + * @return an {@link Optional} containing the matching port or {@code Optional#empty()} + */ + public static Optional getPort(DefaultServerFactory serverFactory, + PortType portType, + ConnectorType connectorType) { + + Optional port = (portType == PortType.APPLICATION) ? + getApplicationPort(serverFactory, connectorType) : getAdminPort(serverFactory, connectorType); + + return port.map(portNum -> newPort(portType, connectorType, portNum)); + } + + /** + * Get the application port from the given Dropwizard configuration that has the given connector type. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @param connectorType the connector type to find + * @return an {@link Optional} containing the matching port number or {@code Optional#empty()} + */ + public static Optional getApplicationPort(C configuration, ConnectorType connectorType) { + var defaultServerFactory = requireDefaultServerFactory(configuration); + return getApplicationPort(defaultServerFactory, connectorType); + } + + /** + * Get the admin port from the given Dropwizard configuration that has the given connector type. + * + * @param the type of the Dropwizard Configuration + * @param configuration the Dropwizard configuration + * @param connectorType the connector type to find + * @return an {@link Optional} containing the matching port number or {@code Optional#empty()} + */ + public static Optional getAdminPort(C configuration, ConnectorType connectorType) { + var defaultServerFactory = requireDefaultServerFactory(configuration); + return getAdminPort(defaultServerFactory, connectorType); + } + + /** + * Create a new {@link Port} instance. + * + * @param portType the type of port + * @param connectorType the connector type for the port + * @param portNumber the port number + * @return a new Port instance + */ + public static Port newPort(PortType portType, ConnectorType connectorType, Integer portNumber) { + checkArgumentNotNull(portNumber, "portNumber must not be null"); + return Port.of(portNumber, portType, Port.Security.fromScheme(connectorType.name())); + } + /** * Determines the application port for the Dropwizard server that matches the given connectorType * diff --git a/src/test/java/org/kiwiproject/dropwizard/util/server/DropwizardConnectorsTest.java b/src/test/java/org/kiwiproject/dropwizard/util/server/DropwizardConnectorsTest.java index 5956efa..e9f76b8 100644 --- a/src/test/java/org/kiwiproject/dropwizard/util/server/DropwizardConnectorsTest.java +++ b/src/test/java/org/kiwiproject/dropwizard/util/server/DropwizardConnectorsTest.java @@ -2,9 +2,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; import com.codahale.metrics.MetricRegistry; +import io.dropwizard.core.Configuration; import io.dropwizard.core.server.DefaultServerFactory; import io.dropwizard.core.server.ServerFactory; import io.dropwizard.core.server.SimpleServerFactory; @@ -19,17 +22,22 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.MethodSource; import org.kiwiproject.dropwizard.util.server.DropwizardConnectors.ConnectorType; +import org.kiwiproject.registry.model.Port; +import org.kiwiproject.registry.model.Port.PortType; import java.util.List; +import java.util.Locale; import java.util.stream.Stream; @DisplayName("DropwizardConnectors") class DropwizardConnectorsTest { @Nested - class GetDefaultServerFactory { + class RequireDefaultServerFactory { @Test void throwsIllegalStateException_WhenServerFactory_IsNotInstanceOfDefaultServerFactory() { ServerFactory factory = new SimpleServerFactory(); @@ -39,9 +47,16 @@ void throwsIllegalStateException_WhenServerFactory_IsNotInstanceOfDefaultServerF .hasMessageEndingWith("SimpleServerFactory)"); } + @Test + void throwsIllegalArgumentException_WhenConfiguration_IsNull() { + assertThatThrownBy(() -> DropwizardConnectors.requireDefaultServerFactory((Configuration) null)) + .isExactlyInstanceOf(IllegalArgumentException.class) + .hasMessage("configuration is required"); + } + @Test void throwsIllegalArgumentException_WhenServerFactory_IsNull() { - assertThatThrownBy(() -> DropwizardConnectors.requireDefaultServerFactory(null)) + assertThatThrownBy(() -> DropwizardConnectors.requireDefaultServerFactory((DefaultServerFactory) null)) .isExactlyInstanceOf(IllegalArgumentException.class) .hasMessage("ServerFactory is required"); } @@ -56,6 +71,260 @@ void shouldReturnGivenServerFactory_WhenInstanceOfDefaultServerFactory() { } } + @Nested + class GetAllPorts { + + @Test + void shouldFindAllPorts() { + var serverFactory = new DefaultServerFactory(); + var httpsAppConnector = newConnectorFactory(ConnectorType.HTTPS, 9090); + var httpAppConnector = newConnectorFactory(ConnectorType.HTTP, 19000); + var httpsAdminConnector = newConnectorFactory(ConnectorType.HTTPS, 9091); + var httpAdminConnector = newConnectorFactory(ConnectorType.HTTP, 19001); + serverFactory.setApplicationConnectors(List.of(httpsAppConnector, httpAppConnector)); + serverFactory.setAdminConnectors(List.of(httpsAdminConnector, httpAdminConnector)); + + var config = newConfiguration(serverFactory); + + var ports = DropwizardConnectors.getPorts(config); + + assertThat(ports) + .describedAs("Application ports should come first, and HTTP ports should be listed first") + .extracting(Port::getNumber) + .containsExactly(19000, 9090, 19001, 9091); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getPorts(config)); + } + } + + @Nested + class GetOnlyApplicationPort { + + @Test + void shouldGetTheSingleApplicationPort() { + var serverFactory = newDefaultServerFactory(ConnectorType.HTTPS, 25000, 50000); + var config = newConfiguration(serverFactory); + + var port = DropwizardConnectors.getOnlyApplicationPort(config); + + assertAll( + () -> assertThat(port.getNumber()).isEqualTo(25000), + () -> assertThat(port.getType()).isEqualTo(PortType.APPLICATION), + () -> assertThat(port.getSecure()).isEqualTo(Port.Security.SECURE) + ); + } + + @Test + void shouldThrowIllegalStateWhenMoreThanOneApplicationPort() { + var serverFactory = new DefaultServerFactory(); + var httpsAppConnector = newConnectorFactory(ConnectorType.HTTPS, 9090); + var httpAppConnector = newConnectorFactory(ConnectorType.HTTP, 19000); + var httpAdminConnector = newConnectorFactory(ConnectorType.HTTP, 19001); + serverFactory.setApplicationConnectors(List.of(httpsAppConnector, httpAppConnector)); + serverFactory.setAdminConnectors(List.of(httpAdminConnector)); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getOnlyApplicationPort(serverFactory)); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getOnlyApplicationPort(config)); + } + } + + @Nested + class GetApplicationPorts { + + @Test + void shouldFindOnlyAdminPorts() { + var applicationPortNumber = 9090; + var adminPortNumber = 9095; + var serverFactory = newDefaultServerFactory(ConnectorType.HTTPS, applicationPortNumber, adminPortNumber); + var config = newConfiguration(serverFactory); + + var adminPorts = DropwizardConnectors.getApplicationPorts(config); + assertThat(adminPorts).extracting(Port::getNumber).containsExactly(applicationPortNumber); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getApplicationPorts(config)); + } + } + + @Nested + class GetOnlyAdminPort { + + @Test + void shouldGetTheSingleAdminPort() { + var serverFactory = newDefaultServerFactory(ConnectorType.HTTP, 25000, 50000); + var config = newConfiguration(serverFactory); + + var port = DropwizardConnectors.getOnlyAdminPort(config); + + assertAll( + () -> assertThat(port.getNumber()).isEqualTo(50000), + () -> assertThat(port.getType()).isEqualTo(PortType.ADMIN), + () -> assertThat(port.getSecure()).isEqualTo(Port.Security.NOT_SECURE) + ); + } + + @Test + void shouldThrowIllegalStateWhenMoreThanOneAdminPort() { + var serverFactory = new DefaultServerFactory(); + var httpsAppConnector = newConnectorFactory(ConnectorType.HTTPS, 9090); + var httpsAdminConnector = newConnectorFactory(ConnectorType.HTTPS, 19000); + var httpAdminConnector = newConnectorFactory(ConnectorType.HTTP, 19001); + serverFactory.setApplicationConnectors(List.of(httpsAppConnector)); + serverFactory.setAdminConnectors(List.of(httpsAdminConnector, httpAdminConnector)); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getOnlyAdminPort(serverFactory)); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getOnlyAdminPort(config)); + } + } + + @Nested + class GetAdminPorts { + + @Test + void shouldFindOnlyAdminPorts() { + var applicationPortNumber = 9090; + var adminPortNumber = 9095; + var serverFactory = newDefaultServerFactory(ConnectorType.HTTPS, applicationPortNumber, adminPortNumber); + var config = newConfiguration(serverFactory); + + var adminPorts = DropwizardConnectors.getAdminPorts(config); + assertThat(adminPorts).extracting(Port::getNumber).containsExactly(adminPortNumber); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getAdminPorts(config)); + } + } + + @Nested + class GetPortsOfType { + + @ParameterizedTest + @EnumSource(ConnectorType.class) + void shouldFindExpectedPorts(ConnectorType connectorType) { + var applicationPortNumber = 9090; + var adminPortNumber = 9095; + var serverFactory = newDefaultServerFactory(connectorType, applicationPortNumber, adminPortNumber); + var config = newConfiguration(serverFactory); + + assertAll( + () -> assertThat(DropwizardConnectors.getPorts(config, PortType.APPLICATION)) + .extracting(Port::getNumber) + .containsExactly(applicationPortNumber), + () -> assertThat(DropwizardConnectors.getPorts(config, PortType.ADMIN)) + .extracting(Port::getNumber) + .containsExactly(adminPortNumber) + ); + } + + @Test + void shouldFindAllPorts() { + var serverFactory = new DefaultServerFactory(); + var httpsAppConnector = newConnectorFactory(ConnectorType.HTTPS, 9090); + var httpAppConnector = newConnectorFactory(ConnectorType.HTTP, 19000); + var httpAdminConnector = newConnectorFactory(ConnectorType.HTTP, 19001); + serverFactory.setApplicationConnectors(List.of(httpsAppConnector, httpAppConnector)); + serverFactory.setAdminConnectors(List.of(httpAdminConnector)); + + var applicationPorts = DropwizardConnectors.getPorts(serverFactory, PortType.APPLICATION); + var adminPorts = DropwizardConnectors.getPorts(serverFactory, PortType.ADMIN); + + assertAll( + () -> assertThat(applicationPorts) + .describedAs("HTTP ports should be listed first") + .extracting(Port::getNumber) + .containsExactly(19000, 9090), + () -> assertThat(adminPorts) + .extracting(Port::getNumber) + .containsExactlyInAnyOrder(19001) + ); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getPorts(config, PortType.APPLICATION)); + } + } + + @Nested + class GetPort { + + @ParameterizedTest + @CsvSource(textBlock = """ + HTTP, APPLICATION, 8900 + HTTP, ADMIN, 15000 + HTTPS, APPLICATION, 27500 + HTTPS, ADMIN, 10900 + """) + void shouldFindExpectedPort(ConnectorType connectorType, PortType portType, int portNumber) { + var applicationPortNumber = (portType == PortType.APPLICATION) ? portNumber : 8080; + var adminPortNumber = (portType == PortType.ADMIN) ? portNumber : 8081; + + var serverFactory = newDefaultServerFactory(connectorType, applicationPortNumber, adminPortNumber); + var config = newConfiguration(serverFactory); + + var port = DropwizardConnectors.getPort(config, portType, connectorType).orElseThrow(); + + assertAll( + () -> assertThat(port.getNumber()).isEqualTo(portNumber), + () -> assertThat(port.getType()).isEqualTo(portType), + () -> assertThat(port.getScheme()).isEqualTo(connectorType.scheme()) + ); + } + + @Test + void shouldReturnEmptyOptionalWhenPortNotFound() { + var serverFactory = newDefaultServerFactory(ConnectorType.HTTP, 9090, 9091); + + assertAll( + () -> assertThat(DropwizardConnectors.getPort(serverFactory, PortType.APPLICATION, ConnectorType.HTTPS)).isEmpty(), + () -> assertThat(DropwizardConnectors.getPort(serverFactory, PortType.ADMIN, ConnectorType.HTTPS)).isEmpty() + ); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getPort(config, PortType.APPLICATION, ConnectorType.HTTPS)); + } + } + @Nested class GetApplicationPort { @@ -107,6 +376,27 @@ void shouldSelectLastConnectorFactoryWhenGivenMoreThanOne() { .describedAs("should always choose the port from the last ConnectorFactory") .hasValue(8003); } + + @ParameterizedTest + @CsvSource(textBlock = """ + HTTP, 8900 + HTTPS, 10900 + """) + void shouldAcceptConfiguration(ConnectorType connectorType, int applicationPortNumber) { + var serverFactory = newDefaultServerFactory(connectorType, applicationPortNumber, 37000); + var config = newConfiguration(serverFactory); + + var port = DropwizardConnectors.getApplicationPort(config, connectorType); + assertThat(port).hasValue(applicationPortNumber); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getApplicationPort(config, ConnectorType.HTTPS)); + } } @Nested @@ -160,6 +450,53 @@ void shouldSelectLastConnectorFactoryWhenGivenMoreThanOne() { .describedAs("should always choose the port from the last ConnectorFactory") .hasValue(8003); } + + @ParameterizedTest + @CsvSource(textBlock = """ + HTTP, 8900 + HTTPS, 10900 + """) + void shouldAcceptConfiguration(ConnectorType connectorType, int adminPortNumber) { + var serverFactory = newDefaultServerFactory(connectorType, 8000, adminPortNumber); + var config = newConfiguration(serverFactory); + + var port = DropwizardConnectors.getAdminPort(config, connectorType); + assertThat(port).hasValue(adminPortNumber); + } + + @Test + void shouldRequireConfigurationToHaveDefaultServerFactory() { + var config = newConfigurationWithSimpleServerFactory(); + + assertThatIllegalStateException() + .isThrownBy(() -> DropwizardConnectors.getAdminPort(config, ConnectorType.HTTPS)); + } + } + + private static DefaultServerFactory newDefaultServerFactory(ConnectorType connectorType, + int applicationPortNumber, + int adminPortNumber) { + + var applicationConnectorFactory = newConnectorFactory(connectorType, applicationPortNumber); + var adminConnectorFactory = newConnectorFactory(connectorType, adminPortNumber); + + var serverFactory = new DefaultServerFactory(); + serverFactory.setApplicationConnectors(List.of(applicationConnectorFactory)); + serverFactory.setAdminConnectors(List.of(adminConnectorFactory)); + + return serverFactory; + } + + private static HttpConnectorFactory newConnectorFactory(ConnectorType connectorType, + int portNumber) { + var factory = newConnectorFactory(connectorType); + factory.setPort(portNumber); + return factory; + } + + private static HttpConnectorFactory newConnectorFactory(ConnectorType connectorType) { + return (connectorType == ConnectorType.HTTPS) ? + new HttpsConnectorFactory() : new HttpConnectorFactory(); } private static List buildHttpsConnectorFactories() { @@ -175,6 +512,16 @@ private static List buildHttpsConnectorFactories() { return List.of(httpsConnector1, httpsConnector2, httpsConnector3); } + private static Configuration newConfigurationWithSimpleServerFactory() { + return newConfiguration(new SimpleServerFactory()); + } + + private static Configuration newConfiguration(ServerFactory serverFactory) { + var config = new Configuration(); + config.setServerFactory(serverFactory); + return config; + } + @Nested class ConnectorTypeEnum { @@ -201,6 +548,13 @@ void shouldReturnHTTPS_GivenHttpsConnectorFactory(HttpConnectorFactory factory) assertThat(ConnectorType.forHttpConnectorFactory(factory)).isEqualTo(ConnectorType.HTTPS); } } + + @ParameterizedTest + @EnumSource(ConnectorType.class) + void shouldReturnExpectedScheme(ConnectorType connectorType) { + assertThat(connectorType.scheme()) + .isEqualTo(connectorType.name().toLowerCase(Locale.ENGLISH)); + } } static Stream httpConnectorFactories() { @@ -223,4 +577,34 @@ static class CustomHttpConnectorFactory extends HttpConnectorFactory { static class CustomHttpsConnectorFactory extends HttpsConnectorFactory { } + @Nested + class NewPort { + + @Test + void shouldRequirePortNumber() { + assertThatIllegalArgumentException() + .isThrownBy(() -> DropwizardConnectors.newPort(PortType.APPLICATION, ConnectorType.HTTPS, null)) + .withMessage("portNumber must not be null"); + } + + @ParameterizedTest + @CsvSource(textBlock = """ + APPLICATION, HTTP, 9900 + APPLICATION, HTTPS, 7500 + ADMIN, HTTP, 14500 + ADMIN, HTTPS, 29500 + """) + void shouldCreateNewPort(PortType portType, ConnectorType connectorType, int portNumber) { + var port = DropwizardConnectors.newPort(portType, connectorType, portNumber); + + var expectedSecure = (connectorType == ConnectorType.HTTPS) ? + Port.Security.SECURE : Port.Security.NOT_SECURE; + + assertAll( + () -> assertThat(port.getType()).isEqualTo(portType), + () -> assertThat(port.getSecure()).isEqualTo(expectedSecure), + () -> assertThat(port.getNumber()).isEqualTo(portNumber) + ); + } + } }