Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# embedded-ldap-junit
[![Build Status](https://github.com/zapodot/embedded-ldap-junit/actions/workflows/maven.yml/badge.svg)](https://github.com/zapodot/embedded-ldap-junit/actions/workflows/maven.yml) [![codecov](https://codecov.io/gh/zapodot/embedded-ldap-junit/branch/master/graph/badge.svg?token=2jm8uT1bJg)](https://codecov.io/gh/zapodot/embedded-ldap-junit) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.zapodot/embedded-ldap-junit/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.zapodot/embedded-ldap-junit) [![Libraries.io for GitHub](https://img.shields.io/librariesio/github/zapodot/embedded-ldap-junit.svg)](https://libraries.io/github/zapodot/embedded-ldap-junit) [![GitHub](https://img.shields.io/github/license/zapodot/embedded-ldap-junit)](https://github.com/zapodot/embedded-ldap-junit/blob/master/LICENSE) [![Analytics](https://ga-beacon.appspot.com/UA-40926073-2/embedded-ldap-junit/README.md)](https://github.com/igrigorik/ga-beacon)

A [JUnit Rule](//github.com/junit-team/junit/wiki/Rules) for running an embedded LDAP server in your JUnit test based on the wonderful [UnboundID LDAP SDK](https://www.ldap.com/unboundid-ldap-sdk-for-java). Inspired by the [Embedded Database JUnit Rule](//github.com/zapodot/embedded-db-junit).
A [JUnit 4 Rule](//github.com/junit-team/junit/wiki/Rules) and [JUnit 5 Extension](https://junit.org/junit5/docs/current/user-guide/#extensions) for running an embedded LDAP server in your JUnit test based on the wonderful [UnboundID LDAP SDK](https://www.ldap.com/unboundid-ldap-sdk-for-java). Inspired by the [Embedded Database JUnit Rule](//github.com/zapodot/embedded-db-junit).

## Why?
* you want to test your LDAP integration code without affecting your LDAP server
Expand Down Expand Up @@ -29,7 +29,9 @@ See [releases](//github.com/zapodot/embedded-ldap-junit/releases)
</dependency>
```

### Add to Junit test
### Add to JUnit test

#### JUnit 4
```java
import com.unboundid.ldap.sdk.LDAPInterface;
import javax.naming.Context;
Expand Down Expand Up @@ -79,3 +81,19 @@ public void testContext() throws Exception {
assertNotNull(user);
}
```

#### JUnit 5
For JUnit 5 tests, simply use `EmbeddedLdapExtensionBuilder` instead of `EmbeddedLdapRuleBuilder`:

```java
@RegisterExtension
public EmbeddedLdapExtension embeddedLdapRule = EmbeddedLdapExtensionBuilder
.newInstance()
.usingDomainDsn("dc=example,dc=com")
.importingLdifs("example.ldif")
.build();

...
```

Both JUnit 4 and JUnit 5 builders share the same API, as do the rule and the extension.
57 changes: 57 additions & 0 deletions embedded-ldap-core/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<artifactId>embedded-ldap-parent</artifactId>
<groupId>org.zapodot</groupId>
<version>0.9-SNAPSHOT</version>
</parent>

<artifactId>embedded-ldap-core</artifactId>

<dependencies>
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<version>${unboundid-ldapsdk.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>${byte-buddy.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPInterface;
import org.junit.rules.TestRule;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;

/**
* A JUnit rule that may be used as either a @Rule or a @ClassRule
*/
public interface EmbeddedLdapRule extends TestRule {
public interface EmbeddedLdapServer {

/**
* For tests depending on the UnboundID LDAP SDK. Returns a proxied version of an Unboundid interface that will be
Expand Down Expand Up @@ -57,9 +53,8 @@ public interface EmbeddedLdapRule extends TestRule {
* </p>
*
* @return the port number that the embedded server is listening to
* @see org.zapodot.junit.ldap.EmbeddedLdapRuleBuilder#bindingToAddress(String)
* @see org.zapodot.junit.ldap.internal.AbstractEmbeddedLdapBuilder#bindingToAddress(String)
*/
int embeddedServerPort();


}
108 changes: 43 additions & 65 deletions ...t/junit/ldap/EmbeddedLdapRuleBuilder.java → ...internal/AbstractEmbeddedLdapBuilder.java
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.zapodot.junit.ldap;
package org.zapodot.junit.ldap.internal;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
Expand All @@ -8,8 +8,6 @@
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.schema.Schema;
import com.unboundid.ldif.LDIFException;
import org.zapodot.junit.ldap.internal.AuthenticationConfiguration;
import org.zapodot.junit.ldap.internal.EmbeddedLdapRuleImpl;

import javax.net.ssl.SSLSocketFactory;
import java.io.File;
Expand All @@ -23,9 +21,10 @@
import java.util.Objects;

/**
* A builder providing a fluent way of defining EmbeddedLdapRule instances
* A builder providing a fluent way of defining EmbeddedLdapRule
* or EmbeddedLdapExtension instances.
*/
public class EmbeddedLdapRuleBuilder {
public abstract class AbstractEmbeddedLdapBuilder<Self extends AbstractEmbeddedLdapBuilder<Self>> {

public static final String DEFAULT_DOMAIN = "dc=example,dc=com";
public static final String DEFAULT_BIND_DSN = "cn=Directory manager";
Expand All @@ -35,11 +34,11 @@ public class EmbeddedLdapRuleBuilder {
public static final int MAX_PORT_EXCLUSIVE = 65535;
private List<String> domainDsn = new LinkedList<>();

private String bindDSN = DEFAULT_BIND_DSN;
protected String bindDSN = DEFAULT_BIND_DSN;

private String bindCredentials = DEFAULT_BIND_CREDENTIALS;

private List<String> ldifsToImport = new LinkedList<>();
protected List<String> ldifsToImport = new LinkedList<>();

private List<String> schemaLdifs = new LinkedList<>();

Expand All @@ -49,156 +48,135 @@ public class EmbeddedLdapRuleBuilder {

private InetAddress bindAddress = InetAddress.getLoopbackAddress();

private AuthenticationConfiguration authenticationConfiguration;
protected AuthenticationConfiguration authenticationConfiguration;

private InMemoryListenerConfig listenerConfig = null;

private boolean useTls = false;
private SSLSocketFactory socketFactory = null;
protected boolean useTls = false;
protected SSLSocketFactory socketFactory = null;

private Integer maxSizeLimit = null;

public EmbeddedLdapRuleBuilder() {
}

/**
* Creates a new builder
*
* @return a new EmbeddedLdapRuleBuilder instance
*/
public static EmbeddedLdapRuleBuilder newInstance() {
return new EmbeddedLdapRuleBuilder();
}

/**
* Sets a domainDsn to be used. May be multiple values. If not set, it will default to the value of the {@link #DEFAULT_DOMAIN DEFAULT_DOMAIN} field
*
* @param domainDsn a valid DSN string
* @return same EmbeddedLdapRuleBuilder instance with the domainDsn field set
* @return same builder instance with the domainDsn field set
*/
public EmbeddedLdapRuleBuilder usingDomainDsn(final String domainDsn) {
public Self usingDomainDsn(final String domainDsn) {
this.domainDsn.add(domainDsn);
return this;
return getThis();
}

/**
* Sets the DSN to bind to when authenticating. If not set, it will default to the value of the {@link #DEFAULT_BIND_DSN DEFAULT_BIND_DSN} field
*
* @param bindDSN a valid DSN string
* @return same EmbeddedLdapRuleBuilder instance with the bindDSN field set
* @return same builder instance with the bindDSN field set
*/
public EmbeddedLdapRuleBuilder usingBindDSN(final String bindDSN) {
public Self usingBindDSN(final String bindDSN) {
this.bindDSN = bindDSN;
return this;
return getThis();
}

/**
* Sets the credentials to be used to authenticate. If not set, it will default to the value of the {@link #DEFAULT_BIND_CREDENTIALS DEFAULT_BIND_CREDENTIALS} field
*
* @param bindCredentials a password string
* @return same EmbeddedLdapRuleBuilder instance with the bindCredentials field set
* @return same builder instance with the bindCredentials field set
*/
public EmbeddedLdapRuleBuilder usingBindCredentials(final String bindCredentials) {
public Self usingBindCredentials(final String bindCredentials) {
this.bindCredentials = bindCredentials;
return this;
return getThis();
}

/**
* Sets the port that the in-memory LDAP server will bind to. If not set, an available port will be picked automatically
*
* @param port a port number
* @return same EmbeddedLdapRuleBuilder instance with the port field set
* @return same builder instance with the port field set
* @throws IllegalArgumentException if the provided value for port is not between @{link MIN_PORT_EXCLUSIVE}
* and @{MAX_PORT_EXCLUSIVE} (exclusive)
*/
public EmbeddedLdapRuleBuilder bindingToPort(final int port) {
public Self bindingToPort(final int port) {
if ((port < MIN_PORT_EXCLUSIVE) || (port > MAX_PORT_EXCLUSIVE)) {
throw new IllegalArgumentException(String.format("Value \"%s\" is not a valid port number", port));
}
this.bindPort = Integer.valueOf(port);
return this;
return getThis();
}

/**
* Allows the listening address for the embedded LDAP server to be set. If not set it will bind to <em>localhost/127.0.0.1</em>.
*
* @param address a valid hostname or textual representation of an IP address
* @return same EmbeddedLdapRuleBuilder instance with the bindAddress field set
* @return same builder instance with the bindAddress field set
* @throws IllegalArgumentException if the value provided for \"address\" is invalid
*/
public EmbeddedLdapRuleBuilder bindingToAddress(final String address) {
public Self bindingToAddress(final String address) {
Objects.requireNonNull(address);
try {
final InetAddress addressByName = InetAddress.getByName(address);
this.bindAddress = addressByName;
} catch (UnknownHostException e) {
throw new IllegalArgumentException(String.format("Unknown host address \"%s\"", address), e);
}
return this;
return getThis();
}

public EmbeddedLdapRuleBuilder withMaxSizeLimit(final int maxSizeLimit) {
public Self withMaxSizeLimit(final int maxSizeLimit) {
this.maxSizeLimit = Integer.valueOf(maxSizeLimit);
return this;
return getThis();
}

/**
* Avoid adding UnboundID's default schema that contains the most common LDAP elements defined through various RFC's.
*
* @return same EmbeddedLdapRuleBuilder instance with the withoutDefaultSchema field set to FALSE
* @return same builder instance with the withoutDefaultSchema field set to FALSE
*/
public EmbeddedLdapRuleBuilder withoutDefaultSchema() {
public Self withoutDefaultSchema() {
this.addDefaultSchema = false;
return this;
return getThis();
}

/**
* Define schemas to be used for the server. If not defined, UnboundID will set up a default schema.
*
* @param ldifSchemaFiles LDIF-files containing schema element definitions
* @return same EmbeddedLdapRuleBuilder with the given LDIF-files added to the internal schema file collection.
* @return same builder with the given LDIF-files added to the internal schema file collection.
*/
public EmbeddedLdapRuleBuilder withSchema(final String... ldifSchemaFiles) {
public Self withSchema(final String... ldifSchemaFiles) {
this.schemaLdifs.addAll(Arrays.asList(ldifSchemaFiles));
return this;
return getThis();
}

/**
* Specify one or more LDIF resources to be imported on startup.
*
* @param ldifFiles LDIF-files to import
* @return same EmbeddedLdapRuleBuilder instance with the provided ldifFiles added to the list of LDIF files to import
* @return same builder instance with the provided ldifFiles added to the list of LDIF files to import
*/
public EmbeddedLdapRuleBuilder importingLdifs(final String... ldifFiles) {
public Self importingLdifs(final String... ldifFiles) {
if (ldifFiles != null) {
ldifsToImport.addAll(Arrays.asList(ldifFiles));
}
return this;
return getThis();
}

public EmbeddedLdapRuleBuilder withListener(InMemoryListenerConfig listenerConfig) {
public Self withListener(InMemoryListenerConfig listenerConfig) {
this.listenerConfig = listenerConfig;
return this;
return getThis();
}

public EmbeddedLdapRuleBuilder useTls(boolean useTls) {
public Self useTls(boolean useTls) {
this.useTls = useTls;
return this;
return getThis();
}

/**
* Creates a new rule based on the information that was previously provided
*
* @return a new EmbeddedLdapRule instance
*/
public EmbeddedLdapRule build() {
Objects.requireNonNull(bindDSN, "\"bindDSN\" can not be null");
return EmbeddedLdapRuleImpl.createForConfiguration(createInMemoryServerConfiguration(),
authenticationConfiguration,
ldifsToImport, useTls, socketFactory);
}
protected abstract Self getThis();

private InMemoryDirectoryServerConfig createInMemoryServerConfiguration() {
protected InMemoryDirectoryServerConfig createInMemoryServerConfiguration() {
try {
final InMemoryDirectoryServerConfig inMemoryDirectoryServerConfig =
new InMemoryDirectoryServerConfig(domainDsnArray());
Expand Down Expand Up @@ -278,8 +256,8 @@ public File apply(final String input) {
}));
}

public EmbeddedLdapRuleBuilder withSocketFactory(SSLSocketFactory socketFactory) {
public Self withSocketFactory(SSLSocketFactory socketFactory) {
this.socketFactory = socketFactory;
return this;
return getThis();
}
}
File renamed without changes.
Loading