Motivation
Interldap is in Java. We choose this language for the number of framework available, the diversity and width of its community, the open-source orientation of many Java communities, and many other good or bad reasons.One of them is the possibility (and ease) to deliver really nice and integrated full stack of softwares : you can create demo package so that the user only have to have a Java environment enable, and then just launch the demo : it brings it own in memory test database, its own server, etc. Maven is a great tools for that (when it want to play nice) : download sources, run "mvn jetty:run", test.One other is the ease of doing Unit Tests. Eventually, unit test have to be done. It's better if the test environment is simple to set up.For a long time, InterLDAP had a real problem to achieve these two points. Well, as the name suggest, it heavily relays upon LDAP directories, more precisely open source LDAP directory. Well, who said OpenLDAP ?Open LDAP has a lot of quality, and for a long, the first of them was that it was "open". But using OpenLDAP as a directory for testing an Java LDAP framework and/or application is quite a burden. And it forces a potential tester to install/configure something not exactly simple in his computer. Again, not the best way to ease the things.But the wind of times blows, and it brings some really interesting thing, as FOSS LDAP directories totally written in Java. These directories - apart from being potential alternatives to the de fait monopole of OpenLDAP - could resolve our two concerns:- ease unit/integration test of our Java application;
- ease the test of Java LDAP application : just download&test, no third software installation and configuration, possibility to use a temporary directory...
This document need a full rewrite, the things are evolving quite quickly in the OpenDS corner. It seems that the 1.0.0 version that should be out in a near future (falls 2007 ?) will bring a lot of facilities to embedded OpenDS (most are in place in the 1.0.0-beta4 release of august, the 26th). Neil A. Wilson's blog already gives some information on that point, especially with this presentation (pdf)
The candidates
As far as I know, there is two Open Source LDAP directories available at this time: The two of them are LDAP directories written in Java, implementing LDAPv3 protocol, open source. Apache DS is a pure community contributed softawre, OpenDS is a Sun project, with Sun management, managing Sun teams.We test the two of them with the only goal of using them as an embedded directory for testing and demo purpose. So, for us, here, things like scaling capabilities, ease of management, reliabilty, security, replication, or all the kind of thing an LDAP admin will put #1 in his “must have” list are not relevant.The two candidates have a really welcoming community, and the developers are very reactive. The two communities found that using their directory as a (vulgar) testing tool was almost a perversion, but they help me to bring the things up and running. I found the ApacheDS documentation (again, for my purpose) really better than OpenDS ones (I continually loose myself in the OpenDS wiki), but for OpenDS defence, OpenDS is in alpha version (0.8), ApacheDS as already two stable version (1.0.x and 1.5.x). Finally, we choose to go OpenDS because ApacheDS do not support some extended control (especially proxy auth control (RFC 4370) on which most of our pooling API lays), but without that, we would have chosen ApacheDS.Downloading and testing the source code
All the following example are used in Ldap core simple implementation. The source code is available with that command:$ svn co svn://svn.forge.objectweb.org/svnroot/interldap/interldap-core-simple/trunk interldap-core-simple
$ cd interldap-core-simple $ mvn test
$ mvn install:install-file -DgroupId=org.opends -DartifactId=opends -DgeneratePom=true -Dversion=0.9.0-b001 -Dpackaging=jar -Dfile=/path/to/OpenDS.jar $ mvn install:install-file -DgroupId=berkeleydb -DartifactId=je -DgeneratePom=true -Dversion=3.2.23 -Dpackaging=jar -Dfile=path/to/je.jar
$ wget https://svn.sourceforge.net/svnroot/springframework/repos/repo-ext/com/sun/ldapbp/1.0/ldapbp-1.0.jar
$ mvn install:install-file -DgroupId=com.sun -DartifactId=ldapbp -DgeneratePom=true -Dversion=1.0 -Dpackaging=jar -Dfile=/path/toldapbp-1.0.jarUnit test for Java LDAP application
So, in the two following parts, I will show how it is possible to use these directories for test unit purpose, or nonetheless, how we achieve that.We use Maven 2 for build and depency management, Spring for a large part of configuration, and we want to test a DAO based on Spring-LDAP.We use a standard Maven 2 tree structure :src
|- main
| `- java
| `- ldap.dao
| |- IldapDao.java
| `- SpringLdapDao.java
`- test
|- java
| `- ldap
| |- util
| | `- EmbeddedJavaLdapServer.java
| `- dao
| `- TestSpringLdapDao.java
|
`- resources
`- ldap
|- util
| `- [server resources]
`- dao
`- [Spring conf for test DAO]LDAP Unit test with ApacheDS and Spring
This use case for ApacheDS is really well documented, so the main work was to follow what is written in Using ApacheDS for unit test . The doc is great, but we had to modify the procedure a little, because we use Spring (and so Spring test) in our application. So I just change the main class of the tutorial to be “EmbeddedApacheDs.java” (see : EmbeddedApacheDs.java ). This class has a setUp() method which set up the directory (ah ah, how original it is :), and inits a first partition named “dc=interldap,dc=org”. It also add the base element for that partition.It's used in TestSpringELdapEntryDao_ApacheDS.java just as that://launch the ldap server ldapServer.setUp();//import ldif InputStream is = ldapServer.getClass().getResourceAsStream("bootstrap_test.ldif");if(null == is) { throw new RuntimeException("The boostrap LDIF file has not been found"); }ldapServer.importLdif(is);
LDAP Unit test with OpenDS and Spring
This part was a little harder to achieve. The documentation on OpenDS wiki on this topic is really light, but the mailing list gives a good starting point with the thread Open DS as an embedded LDAP server to unit test app . This thread point the class “org.opends.server.TestCaseUtils.java” wich take care of set-up an environment for an OpenDS instance.I will explain in the following paragraph what are the main piece of configuration to take care of.Directory structure
OpenDS need a directory structure with a read/write access to work. These directories are used to store data, locks, logs, etc. This is the minimal directory structure (that I found, perhaps it's not relevant in all cases) !opends-root-directory|-- config| |-- config.ldif| |-- schema| `-- upgrade|-- db|-- locks`-- logs
Configuration Files
OpenDS needs some configuration file to bootstrap :- config.ldif : the main OpenDS config file, explains here ;
- standards schema : these file describe the standard schema supported by OpenDS ;
- “config upgrade” files : these files do not seem to be mandatory, but OpenDS complain if they are not present.
opends-root-directory||-- config| |-- config.ldif| |-- schema| | |-- 00-core.ldif| | |-- 01-pwpolicy.ldif| | |-- 02-config.ldif| | |-- 03-changelog.ldif| | |-- 03-rfc2713.ldif| | |-- 03-rfc2714.ldif| | |-- 03-rfc2739.ldif| | |-- 03-rfc2926.ldif| | |-- 03-rfc3112.ldif| | |-- 03-rfc3712.ldif| | |-- 03-uddiv3.ldif| | `-- 04-rfc2307bis.ldif| `-- upgrade| |-- config.ldif.1918| |-- schema.ldif.1918| `-- schema.ldif.current|-- db|-- locks`-- logs
Bootstrap algorithm
The start up algorithm is quite simple :- create the working directory structure ;
- get the singleton instance of directory server ;
- bootstrap the server ;
- set-up with initial config the server ;
- start the server.
public static void startServer() throws Exception {
// copy to r/w location and init directory structure
//this funcion
initOpendsDirectory(“path/to/config/directories/to/copy/from”, ”/path/to/working/directory”); String configClass = "org.opends.server.extensions.ConfigFileHandler"; DirectoryServer directoryServer = DirectoryServer.getInstance();
directoryServer.bootstrapServer(); directoryServer.initializeConfiguration(configClass,”/path/to/working/directory/config/config.ldif”);
directoryServer.startServer();
}private static void initOpendsDirectory(String copyFromConfigDirectory,
String targetRootDirectory) throws IOException {
File workingDirectory = new File(targetRootDirectory);
// delete recursively workingDirectory
if (workingDirectory.exists()) {
FileUtils.deleteDirectory(workingDirectory);
}
if (workingDirectory.exists()) {
throw new IOException("Failed to delete: " + workingDirectory);
}
if (!workingDirectory.mkdirs()) {
throw new IOException("Failed to create:" + workingDirectory);
} // copy config & schema
FileUtils.copyDirectory(new File(copyFromConfigDirectory), new File(targetRootDirectory , CONFIG_DIR)); // create missing directories
// db backend, logs, locks
String[] subDirectories = { "db", "ldif", "locks", "logs" };
for (String s : subDirectories) {
new File(workingDirectory, s).mkdir();
}
}Just a word about Back-ends
OpenDS use several back-ends to store data. It is identified by its ID, and need to be initialised before being used. The default config.ldif file set-up a standard, Berkeley DB JE enabled back-end, identified by “userRoot”. For the test, it might be useful to have an in-memory back-up that can be re-initialised between two tests.This code enable a memory back-end :public static void initializeTestBackend(boolean createBaseEntry) throws Exception {
MemoryBackend memoryBackend = null;
DN baseDN = DN.decode(“base.dn.for.test”);
if (memoryBackend == null) {
memoryBackend = new MemoryBackend();
memoryBackend.setBackendID("test");
memoryBackend.setBaseDNs(new DN[] { baseDN });
memoryBackend.initializeBackend();
DirectoryServer.registerBackend(memoryBackend);
} memoryBackend.clearMemoryBackend(); if (createBaseEntry) {
Entry e = createEntry(baseDN);
memoryBackend.addEntry(e, null);
}
}
PDF
History

