diff --git a/test-support/src/main/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServer.java b/test-support/src/main/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServer.java index 81e5a01c8..b764493ce 100644 --- a/test-support/src/main/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServer.java +++ b/test-support/src/main/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServer.java @@ -21,6 +21,9 @@ import com.unboundid.ldap.listener.InMemoryListenerConfig; import com.unboundid.ldap.sdk.DN; import com.unboundid.ldap.sdk.Entry; +import com.unboundid.ldap.sdk.LDAPException; + +import org.springframework.util.Assert; /** * Helper class for embedded Unboundid ldap server. @@ -28,14 +31,23 @@ * @author Eddu Melendez * @since 2.1.0 */ -public final class EmbeddedLdapServer { +public final class EmbeddedLdapServer implements AutoCloseable { - private InMemoryDirectoryServer directoryServer; + private final InMemoryDirectoryServer directoryServer; - private EmbeddedLdapServer(InMemoryDirectoryServer directoryServer) { + /** + * Construct an {@link EmbeddedLdapServer} using the provided + * {@link InMemoryDirectoryServer}. + * + * @since 3.3 + */ + public EmbeddedLdapServer(InMemoryDirectoryServer directoryServer) { this.directoryServer = directoryServer; } + /** + * Creates and starts new embedded LDAP server. + */ public static EmbeddedLdapServer newEmbeddedServer(String defaultPartitionName, String defaultPartitionSuffix, int port) throws Exception { InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(defaultPartitionSuffix); @@ -56,7 +68,37 @@ public static EmbeddedLdapServer newEmbeddedServer(String defaultPartitionName, return new EmbeddedLdapServer(directoryServer); } - public void shutdown() throws Exception { + /** + * Starts the embedded LDAP server. + * + * @since 3.3 + */ + public void start() { + Assert.isTrue(this.directoryServer.getListenPort() == -1, "The server has already been started."); + try { + this.directoryServer.startListening(); + } + catch (LDAPException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Closes the embedded LDAP server and releases resource, closing existing + * connections. + * + * @since 3.3 + */ + @Override + public void close() { + this.directoryServer.shutDown(true); + } + + /** + * @deprecated Use {@link #close()} instead. + */ + @Deprecated(since = "3.3") + public void shutdown() { this.directoryServer.shutDown(true); } diff --git a/test-support/src/main/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServerFactoryBean.java b/test-support/src/main/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServerFactoryBean.java index b5f244041..360a68679 100644 --- a/test-support/src/main/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServerFactoryBean.java +++ b/test-support/src/main/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServerFactoryBean.java @@ -53,7 +53,7 @@ protected EmbeddedLdapServer createInstance() throws Exception { @Override protected void destroyInstance(EmbeddedLdapServer instance) throws Exception { - instance.shutdown(); + instance.close(); } } diff --git a/test-support/src/main/java/org/springframework/ldap/test/unboundid/LdapTestUtils.java b/test-support/src/main/java/org/springframework/ldap/test/unboundid/LdapTestUtils.java index 1bfed95b7..9ec82ed37 100644 --- a/test-support/src/main/java/org/springframework/ldap/test/unboundid/LdapTestUtils.java +++ b/test-support/src/main/java/org/springframework/ldap/test/unboundid/LdapTestUtils.java @@ -92,7 +92,7 @@ public static void startEmbeddedServer(int port, String defaultPartitionSuffix, */ public static void shutdownEmbeddedServer() throws Exception { if (embeddedServer != null) { - embeddedServer.shutdown(); + embeddedServer.close(); embeddedServer = null; } } diff --git a/test-support/src/test/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServerTests.java b/test-support/src/test/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServerTests.java new file mode 100644 index 000000000..22bc987cf --- /dev/null +++ b/test-support/src/test/java/org/springframework/ldap/test/unboundid/EmbeddedLdapServerTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2005-2025 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 + * + * https://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.ldap.test.unboundid; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +import com.unboundid.ldap.listener.InMemoryDirectoryServer; +import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig; +import com.unboundid.ldap.listener.InMemoryListenerConfig; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +public class EmbeddedLdapServerTests { + + @Test + public void shouldStartAndCloseServer() throws Exception { + int port = getFreePort(); + assertThat(isPortOpen(port)).isFalse(); + + EmbeddedLdapServer server = EmbeddedLdapServer.newEmbeddedServer("jayway", "dc=jayway,dc=se", port); + assertThat(isPortOpen(port)).isTrue(); + + server.close(); + assertThat(isPortOpen(port)).isFalse(); + } + + @Test + public void shouldStartAndAutoCloseServer() throws Exception { + int port = getFreePort(); + assertThat(isPortOpen(port)).isFalse(); + + try (EmbeddedLdapServer ignored = EmbeddedLdapServer.newEmbeddedServer("jayway", "dc=jayway,dc=se", port)) { + assertThat(isPortOpen(port)).isTrue(); + } + assertThat(isPortOpen(port)).isFalse(); + } + + @Test + public void shouldStartAndCloseServerViaLdapTestUtils() throws Exception { + int port = getFreePort(); + assertThat(isPortOpen(port)).isFalse(); + + LdapTestUtils.startEmbeddedServer(port, "dc=jayway,dc=se", "jayway"); + assertThat(isPortOpen(port)).isTrue(); + + LdapTestUtils.shutdownEmbeddedServer(); + assertThat(isPortOpen(port)).isFalse(); + } + + @Test + public void startWhenNewEmbeddedServerThenException() throws Exception { + int port = getFreePort(); + EmbeddedLdapServer server = EmbeddedLdapServer.newEmbeddedServer("jayway", "dc=jayway,dc=se", port); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(server::start); + } + + @Test + public void startWhenUnstartedThenWorks() throws Exception { + int port = getFreePort(); + InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=jayway,dc=se"); + config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("LDAP", port)); + InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config); + try (EmbeddedLdapServer server = new EmbeddedLdapServer(ds)) { + server.start(); + assertThat(isPortOpen(port)).isTrue(); + } + } + + @Test + public void startWhenAlreadyStartedThenFails() throws Exception { + int port = getFreePort(); + InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=jayway,dc=se"); + config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("LDAP", port)); + InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config); + try (EmbeddedLdapServer server = new EmbeddedLdapServer(ds)) { + server.start(); + assertThat(isPortOpen(port)).isTrue(); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(server::start); + } + } + + static boolean isPortOpen(int port) { + try (Socket ignored = new Socket("localhost", port)) { + return true; + } + catch (IOException ex) { + return false; + } + } + + static int getFreePort() throws IOException { + try (ServerSocket serverSocket = new ServerSocket(0)) { + return serverSocket.getLocalPort(); + } + } + +}