directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Directory Server v1.5 > 4.2. Using ApacheDS for unit tests
Date Sat, 06 Mar 2010 00:04:00 GMT
<html>
<head>
    <base href="http://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1519/1/1/_/styles/combined.css?spaceKey=DIRxSRVx11&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background-color: white" bgcolor="white">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
     <h2><a href="http://cwiki.apache.org/confluence/display/DIRxSRVx11/4.2.+Using+ApacheDS+for+unit+tests">4.2.
Using ApacheDS for unit tests</a></h2>
     <h4>Page <b>edited</b> by             <a href="http://cwiki.apache.org/confluence/display/~elecharny">Emmanuel
Lécharny</a>
    </h4>
     
          <br/>
     <div class="notificationGreySide">
         <style type='text/css'>/*<![CDATA[*/
table.ScrollbarTable  {border: none;padding: 3px;width: 100%;padding: 3px;margin: 0px;background-color:
#f0f0f0}
table.ScrollbarTable td.ScrollbarPrevIcon {text-align: center;width: 16px;border: none;}
table.ScrollbarTable td.ScrollbarPrevName {text-align: left;border: none;}
table.ScrollbarTable td.ScrollbarParent {text-align: center;border: none;}
table.ScrollbarTable td.ScrollbarNextName {text-align: right;border: none;}
table.ScrollbarTable td.ScrollbarNextIcon {text-align: center;width: 16px;border: none;}

/*]]>*/</style><div class="Scrollbar"><table class='ScrollbarTable'><tr><td
class='ScrollbarPrevIcon'><a href="/confluence/display/DIRxSRVx11/4.1.+Embedding+ApacheDS+into+an+application"><img
border='0' align='middle' src='/confluence/images/icons/back_16.gif' width='16' height='16'></a></td><td
width='33%' class='ScrollbarPrevName'><a href="/confluence/display/DIRxSRVx11/4.1.+Embedding+ApacheDS+into+an+application">4.1.
Embedding ApacheDS into an application</a>&nbsp;</td><td width='33%' class='ScrollbarParent'><sup><a
href="/confluence/display/DIRxSRVx11/4.+Embedding+ApacheDS"><img border='0' align='middle'
src='/confluence/images/icons/up_16.gif' width='8' height='8'></a></sup><a
href="/confluence/display/DIRxSRVx11/4.+Embedding+ApacheDS">4. Embedding ApacheDS</a></td><td
width='33%' class='ScrollbarNextName'>&nbsp;<a href="/confluence/display/DIRxSRVx11/4.3.+Embedding+ApacheDS+as+a+Web+Application">4.3.
Embedding ApacheDS as a Web Application</a></td><td class='ScrollbarNextIcon'><a
href="/confluence/display/DIRxSRVx11/4.3.+Embedding+ApacheDS+as+a+Web+Application"><img
border='0' align='middle' src='/confluence/images/icons/forwd_16.gif' width='16' height='16'></a></td></tr></table></div>

<div class='panelMacro'><table class='warningMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/forbidden.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td><p>This page
describes how to define your own unit tests, using ApacheDS 1.5.6.</p></td></tr></table></div>

<h1><a name="4.2.UsingApacheDSforunittests-UsingApacheDSforunittests"></a>Using
ApacheDS for unit tests</h1>

<p>The idea is to use ADS as an embedded server for Ldap junit tests. We will build
an environment in which it will be convenient to test Ldap applications.</p>

<p>We also want to avoid launching the server for every test, as it's an expensive operation.
We have built ApacheDS so that you can start a server, inject some data, launch a test, then
revert the data and go on to another test. At the end of the tests, the server is stopped.</p>


<h2><a name="4.2.UsingApacheDSforunittests-Firststeps"></a>First steps</h2>

<p>We have two choices : either we launch the server totally embedded, without having
to communicate with it using the Ldap Protocol, or we want to use the server as a remote server,
with Ldap protocol in the middle (it can be useful if one want to test specific applications).
In both cases, the server is started and stopped by the unit test.</p>

<p>We will simply launch only one server (if one want to test referrals, it might be
necessary to initialize 2 or more servers)</p>

<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td><p>We are using JUnit 4.7</p></td></tr></table></div>

<p>We have to define a layout for the files and directory we will use in this tutorial.
Let's use the <b>maven</b> layout :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/
|
+--src
    |
    +--test
        |
        +--java      : we will put all the sources into <span class="code-keyword">this</span>
directory
        |
        +--resources : we will put the resources files into <span class="code-keyword">this</span>
directory
</pre>
</div></div>


<h2><a name="4.2.UsingApacheDSforunittests-Creatingablanktest"></a>Creating
a blank test</h2>

<p>So let's define the framework we need for a simple unit test, using a server which
will be invoked through socket (the first free port above 1023 will be used). This first test
will do a search operation on a server.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">package</span> org.apache.directory.server.test;

<span class="code-keyword">import</span> <span class="code-keyword">static</span>
org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
<span class="code-keyword">import</span> <span class="code-keyword">static</span>
org.junit.Assert.assertTrue;

<span class="code-keyword">import</span> javax.naming.NamingEnumeration;
<span class="code-keyword">import</span> javax.naming.directory.SearchControls;
<span class="code-keyword">import</span> javax.naming.directory.SearchResult;
<span class="code-keyword">import</span> javax.naming.ldap.LdapContext;

<span class="code-keyword">import</span> org.apache.directory.server.annotations.CreateLdapServer;
<span class="code-keyword">import</span> org.apache.directory.server.annotations.CreateTransport;
<span class="code-keyword">import</span> org.apache.directory.server.core.integ.AbstractLdapTestUnit;
<span class="code-keyword">import</span> org.apache.directory.server.core.integ.FrameworkRunner;
<span class="code-keyword">import</span> org.apache.directory.server.ldap.LdapServer;
<span class="code-keyword">import</span> org.junit.Test;
<span class="code-keyword">import</span> org.junit.runner.RunWith;

/**
 * Tests
 * 
 * @author &lt;a href=<span class="code-quote">"mailto:dev@directory.apache.org"</span>&gt;Apache
Directory Project&lt;/a&gt;
 * @version $Rev$, $Date$
 */
@RunWith(FrameworkRunner.class)
@CreateLdapServer(
    transports =
      { 
        @CreateTransport(protocol = <span class="code-quote">"LDAP"</span>) 
      })
<span class="code-keyword">public</span> class SearchTests <span class="code-keyword">extends</span>
AbstractLdapTestUnit
{
    <span class="code-keyword">public</span> <span class="code-keyword">static</span>
LdapServer ldapServer;

    @Test
    <span class="code-keyword">public</span> void testSearchAllAttrs() <span
class="code-keyword">throws</span> Exception
    {
        LdapContext ctx = ( LdapContext ) getWiredContext( ldapServer, <span class="code-keyword">null</span>
).lookup( <span class="code-quote">"ou=system"</span> );

        SearchControls controls = <span class="code-keyword">new</span> SearchControls();
        controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
        controls.setReturningAttributes( <span class="code-keyword">new</span>
<span class="code-object">String</span>[]
            { <span class="code-quote">"+"</span>, <span class="code-quote">"*"</span>
} );

        NamingEnumeration&lt;SearchResult&gt; res = ctx.search( <span class="code-quote">"",
"</span>(ObjectClass=*)", controls );

        assertTrue( res.hasMore() );

        <span class="code-keyword">while</span> ( res.hasMoreElements() )
        {
            SearchResult result = ( SearchResult ) res.next();

            <span class="code-object">System</span>.out.println( result.getName()
);
        }
    }
}
</pre>
</div></div>

<p>In order to have this test running, you will need to declare some libraries. The
best solution is clearly to define a pom.xml file for that purpose. Here it is :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
&lt;?xml version=<span class="code-quote">"1.0"</span> encoding=<span class="code-quote">"UTF-8"</span>?&gt;
&lt;project xmlns=<span class="code-quote">"http:<span class="code-comment">//maven.apache.org/POM/4.0.0"</span>
xmlns:xsi=<span class="code-quote">"http://www.w3.org/2001/XMLSchema-instance"</span>
xsi:schemaLocation=<span class="code-quote">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"</span>&gt;
</span>  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;groupId&gt;org.apache.directory.server&lt;/groupId&gt;
  &lt;artifactId&gt;apacheds-unit-test&lt;/artifactId&gt;
  &lt;version&gt;1.5.5-SNAPSHOT&lt;/version&gt;
  &lt;name&gt;ApacheDS Server Unit&lt;/name&gt;
  &lt;packaging&gt;jar&lt;/packaging&gt;  

  &lt;description&gt;
    Unit test <span class="code-keyword">for</span> ApacheDS Server JNDI Provider
  &lt;/description&gt;

  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;junit&lt;/groupId&gt;
      &lt;artifactId&gt;junit&lt;/artifactId&gt;
      &lt;version&gt;4.7&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;log4j&lt;/groupId&gt;
      &lt;artifactId&gt;log4j&lt;/artifactId&gt;
      &lt;version&gt;1.2.14&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
      &lt;artifactId&gt;slf4j-log4j12&lt;/artifactId&gt;
      &lt;version&gt;1.5.10&lt;/version&gt;
      &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.directory.server&lt;/groupId&gt;
      &lt;artifactId&gt;apacheds-all&lt;/artifactId&gt;
      &lt;version&gt;1.5.6-SNAPSHOT&lt;/version&gt;
    &lt;/dependency&gt;  

    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.directory.server&lt;/groupId&gt;
      &lt;artifactId&gt;apacheds-server-integ&lt;/artifactId&gt;
      &lt;version&gt;1.5.6-SNAPSHOT&lt;/version&gt;
    &lt;/dependency&gt;  

    &lt;dependency&gt;
      &lt;groupId&gt;org.apache.directory.server&lt;/groupId&gt;
      &lt;artifactId&gt;apacheds-core-integ&lt;/artifactId&gt;
      &lt;version&gt;1.5.6-SNAPSHOT&lt;/version&gt;
    &lt;/dependency&gt;  

    &lt;dependency&gt;
      &lt;groupId&gt;commons-io&lt;/groupId&gt;
      &lt;artifactId&gt;commons-io&lt;/artifactId&gt;
      &lt;version&gt;1.4&lt;/version&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;

  &lt;build&gt;
    &lt;pluginManagement&gt;
      &lt;plugins&gt;
        &lt;plugin&gt;
          &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
          &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
          &lt;version&gt;2.0.2&lt;/version&gt;
          &lt;configuration&gt;
            &lt;source&gt;1.5&lt;/source&gt;
            &lt;target&gt;1.5&lt;/target&gt;

            &lt;optimize&gt;<span class="code-keyword">true</span>&lt;/optimize&gt;
            &lt;showDeprecations&gt;<span class="code-keyword">true</span>&lt;/showDeprecations&gt;
            &lt;encoding&gt;ISO-8859-1&lt;/encoding&gt;
          &lt;/configuration&gt;
        &lt;/plugin&gt;
        &lt;plugin&gt;
          &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
          &lt;configuration&gt;
            &lt;argLine&gt;-Xmx1024m&lt;/argLine&gt;
          &lt;/configuration&gt;
        &lt;/plugin&gt;
      &lt;/plugins&gt;
    &lt;/pluginManagement&gt;
  &lt;/build&gt;
&lt;/project&gt;
</pre>
</div></div>

<p>Is that it ? Pretty much. All you have to do now is to run the test, using a Java
5 JVM and Maven 2.0.9 :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
#user:~/ws-ads-1.5.4/UnitTest$ mvn test
[INFO] Scanning <span class="code-keyword">for</span> projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building ApacheDS Server Unit
[INFO]    task-segment: [test]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using <span class="code-keyword">default</span> encoding to copy filtered
resources.
[INFO] [compiler:compile]
[INFO] No sources to compile
[INFO] [resources:testResources]
[INFO] Using <span class="code-keyword">default</span> encoding to copy filtered
resources.
[INFO] [compiler:testCompile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [surefire:test]
[INFO] Surefire report directory: /home/elecharny/ws-ads-1.5.4/UnitTest/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running SimpleTest
log4j:WARN No appenders could be found <span class="code-keyword">for</span> logger
(org.apache.directory.server.integ.SiRunner).
log4j:WARN Please initialize the log4j system properly.
Ldap service started.
Ldap service stopped.
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.114 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10 seconds
[INFO] Finished at: Fri Nov 21 15:40:32 CET 2008
[INFO] Final Memory: 11M/83M
[INFO] ------------------------------------------------------------------------
#user:~/ws-ads-1.5.4/UnitTest$ 
</pre>
</div></div>

<p>You have written your very first test using the test framework provided in ADS 1.5.5
!</p>

<p>Here are the test files :<br/>
<span class="error">&#91;^SearchTests.java&#93;</span><br/>
<a href="/confluence/download/attachments/55238/pom.xml?version=1">pom.xml</a></p>

<h3><a name="4.2.UsingApacheDSforunittests-Testdescription"></a>Test description</h3>

<p>Ok, we have a running test, but when it comes to write your own, you need a bit more
information. Let's try to explain the different parts of this test.</p>

<h4><a name="4.2.UsingApacheDSforunittests-Annotations"></a>Annotations</h4>
<p>The first interesting part is the annotations we are using. As we said, the server
is launched automatically, and we are using the ChangeLog mechanism to restore the base in
a pristine state between each test. This is done with annotations.</p>

<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Annotation </th>
<th class='confluenceTh'> Parameter </th>
<th class='confluenceTh'> Default value </th>
<th class='confluenceTh'> Description </th>
</tr>
<tr>
<td class='confluenceTd'> @RunWith </td>
<td class='confluenceTd'> FrameworkRunner.class </td>
<td class='confluenceTd'> none </td>
<td class='confluenceTd'> Run the test with the defined Runner, instead of the default
JUNIT one.<br/>
This is mandatory to add this annotation, as it determinate the way the server<br/>
will be clean when each test has run </td>
</tr>
<tr>
<td class='confluenceTd'> @CreateLdapServer </td>
<td class='confluenceTd'> transports </td>
<td class='confluenceTd'> none </td>
<td class='confluenceTd'> Create the LdapServer that will be used for the tests </td>
</tr>
<tr>
<td class='confluenceTd'> @CreateTransports </td>
<td class='confluenceTd'> protocol </td>
<td class='confluenceTd'> none </td>
<td class='confluenceTd'> Define the transport to use </td>
</tr>
<tr>
<td class='confluenceTd'> @ApplyLdifs </td>
<td class='confluenceTd'> A list of entries in a LDIF format </td>
<td class='confluenceTd'> none </td>
<td class='confluenceTd'> This is one of the most interesting new feature :<br/>
you can define the data you need to be present when the server is started, they will be injected<br/>
before the first test is run (it will also depend on the CleanupLevel). </td>
</tr>
<tr>
<td class='confluenceTd'> @ApplyLdifFiles </td>
<td class='confluenceTd'> A list of files containing LDIF entries </td>
<td class='confluenceTd'> none </td>
<td class='confluenceTd'> Give sthe list of files to be injected<br/>
into the server before the tests are run. </td>
</tr>
</tbody></table>

<h4><a name="4.2.UsingApacheDSforunittests-Serverstartup"></a>Server startup</h4>

<p>As you can see in the test, there is no place where you tell the server to be started.
This is done by the FrameworkRunner. When the tests are all done, the server is also automatically
shutdown, and all the created files are removed. </p>

<p>The initialization will update a static <b>ldapServer</b> instance which
is declared in the inherited AbstractLdapTestUnit class.</p>

<p>You just have to focus on writing your own tests !</p>

<h5><a name="4.2.UsingApacheDSforunittests-WritingyourowntestusingJNDI"></a>Writing
your own test using JNDI</h5>

<p>All the LDAP operation are supported, you just have to use the JNDI API to write
your tests. The only difference is the way you get a context : you have to use one of those
methods :</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/**
 * Creates a JNDI LdapContext with a connection over the wire using the 
 * SUN LDAP provider.  The connection is made using the administrative 
 * user as the principalDN.  The context is to the rootDSE.
 *
 * @param ldapServer the LDAP server to get the connection to
 * @<span class="code-keyword">return</span> an LdapContext as the administrative
user to the RootDSE
 * @<span class="code-keyword">throws</span> Exception <span class="code-keyword">if</span>
there are problems creating the context
 */
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
LdapContext getWiredContext( LdapServer ldapServer )

/**
 * Creates a JNDI LdapContext with a connection over the wire using the 
 * SUN LDAP provider.  The connection is made using the administrative 
 * user as the principalDN.  The context is to the rootDSE.
 *
 * @param ldapServer the LDAP server to get the connection to
 * @<span class="code-keyword">return</span> an LdapContext as the administrative
user to the RootDSE
 * @<span class="code-keyword">throws</span> Exception <span class="code-keyword">if</span>
there are problems creating the context
 */
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
LdapContext getWiredContext( LdapServer ldapServer, Control[] controls )

/**
 * Creates a JNDI LdapContext with a connection over the wire using the 
 * SUN LDAP provider.  The connection is made using the administrative 
 * user as the principalDN.  The context is to the rootDSE.
 *
 * @param ldapServer the LDAP server to get the connection to
 * @<span class="code-keyword">return</span> an LdapContext as the administrative
user to the RootDSE
 * @<span class="code-keyword">throws</span> Exception <span class="code-keyword">if</span>
there are problems creating the context
 */
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
LdapContext getWiredContext( LdapServer ldapServer, <span class="code-object">String</span>
principalDn, <span class="code-object">String</span> password )
</pre>
</div></div>

<p>That's it ! Everything else is just pure JNDI</p>

<h5><a name="4.2.UsingApacheDSforunittests-WritingyourowntestsusingtheNetscapeAPI"></a>Writing
your own tests using the Netscape API</h5>

<p>If you don't like JNDI, or prefer to use the Netscape API (LdapSdk-4.1), you have
two major differences :</p>
<ul class="alternate" type="square">
	<li>first you have to add this API jar into the dependencies in the pom.xml file</li>
	<li>second you will use the getWiredConnection() method instead of the getWiredContext().</li>
</ul>


<p>The API is :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
LDAPConnection getWiredConnection( LdapServer ldapServer )
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
LDAPConnection getWiredConnection( LdapServer ldapServer, <span class="code-object">String</span>
principalDn, <span class="code-object">String</span> password )
</pre>
</div></div>

<p>Both methods are similar to the getWiredContext which has been described before,
except that they return a LdapConnection instance.</p>


<div class='panelMacro'><table class='warningMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/forbidden.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td><p>Starting
here, the document has to be reviewed...</p></td></tr></table></div>

<h3><a name="4.2.UsingApacheDSforunittests-Creatingourownpartition"></a>Creating
our own partition</h3>

<p>At the moment, we have created a server which is not totally empty : one partition
is created by default, the system partition. We won't use it for our tests, so we will need
to create our own partition to play with. Let's call it 'o=sevenseas' (<b>o</b>
stands for <b>organization</b>)</p>

<p>The setUp() method will be completed with all the needed instruction to create a
new partition</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">import</span> java.io.File;
<span class="code-keyword">import</span> java.util.HashSet;
<span class="code-keyword">import</span> java.util.Hashtable;
<span class="code-keyword">import</span> java.util.Set;

<span class="code-keyword">import</span> javax.naming.Context;
<span class="code-keyword">import</span> javax.naming.InitialContext;
<span class="code-keyword">import</span> javax.naming.NamingException;
<span class="code-keyword">import</span> javax.naming.directory.Attribute;
<span class="code-keyword">import</span> javax.naming.directory.Attributes;
<span class="code-keyword">import</span> javax.naming.directory.BasicAttribute;
<span class="code-keyword">import</span> javax.naming.directory.BasicAttributes;
<span class="code-keyword">import</span> javax.naming.directory.DirContext;

<span class="code-keyword">import</span> org.apache.directory.server.core.configuration.MutablePartitionConfiguration;
<span class="code-keyword">import</span> org.apache.directory.server.unit.AbstractServerTest;
...

    /**
     * Initialize the server.
     */
    <span class="code-keyword">public</span> void setUp() <span class="code-keyword">throws</span>
Exception
    {
        <span class="code-comment">// Add partition 'sevenSeas'
</span>        MutablePartitionConfiguration pcfg = <span class="code-keyword">new</span>
MutablePartitionConfiguration();
        pcfg.setName( <span class="code-quote">"sevenSeas"</span> );
        pcfg.setSuffix( <span class="code-quote">"o=sevenseas"</span> );

        <span class="code-comment">// Create some indices
</span>        Set&lt;<span class="code-object">String</span>&gt;
indexedAttrs = <span class="code-keyword">new</span> HashSet&lt;<span class="code-object">String</span>&gt;();
        indexedAttrs.add( <span class="code-quote">"objectClass"</span> );
        indexedAttrs.add( <span class="code-quote">"o"</span> );
        pcfg.setIndexedAttributes( indexedAttrs );

        <span class="code-comment">// Create a first entry associated to the partition
</span>        Attributes attrs = <span class="code-keyword">new</span>
BasicAttributes( <span class="code-keyword">true</span> );

        <span class="code-comment">// First, the objectClass attribute
</span>        Attribute attr = <span class="code-keyword">new</span> BasicAttribute(
<span class="code-quote">"objectClass"</span> );
        attr.add( <span class="code-quote">"top"</span> );
        attr.add( <span class="code-quote">"organization"</span> );
        attrs.put( attr );

        <span class="code-comment">// The the 'Organization' attribute
</span>        attr = <span class="code-keyword">new</span> BasicAttribute(
<span class="code-quote">"o"</span> );
        attr.add( <span class="code-quote">"sevenseas"</span> );
        attrs.put( attr );

        <span class="code-comment">// Associate <span class="code-keyword">this</span>
entry to the partition
</span>        pcfg.setContextEntry( attrs );

        <span class="code-comment">// As we can create more than one partition, we must
store
</span>        <span class="code-comment">// each created partition in a Set before
initialization
</span>        Set&lt;MutablePartitionConfiguration&gt; pcfgs = <span class="code-keyword">new</span>
HashSet&lt;MutablePartitionConfiguration&gt;();
        pcfgs.add( pcfg );

        configuration.setContextPartitionConfigurations( pcfgs );

        <span class="code-comment">// Create a working directory
</span>        File workingDirectory = <span class="code-keyword">new</span>
File( <span class="code-quote">"server-work"</span> );
        configuration.setWorkingDirectory( workingDirectory );

        <span class="code-comment">// Now, let's call the upper class which is responsible
<span class="code-keyword">for</span> the
</span>        <span class="code-comment">// partitions creation
</span>        <span class="code-keyword">super</span>.setUp();
   }
</pre>
</div></div>
<p>Ok, now the partition <b>sevenseas</b> should be created. How can we
be sure of that ? let's write a test to replace the emptytest() method :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/**
     * Test that the partition has been correctly created
     */
    <span class="code-keyword">public</span> void testPartition() <span class="code-keyword">throws</span>
NamingException
    {
        Hashtable&lt;<span class="code-object">Object</span>, <span class="code-object">Object</span>&gt;
env = <span class="code-keyword">new</span> Hashtable&lt;<span class="code-object">Object</span>,
<span class="code-object">Object</span>&gt;( configuration.toJndiEnvironment()
);

        <span class="code-comment">// Create a <span class="code-keyword">new</span>
context pointing to the overseas partition
</span>        env.put( Context.PROVIDER_URL, <span class="code-quote">"o=sevenSeas"</span>
);
        env.put( Context.SECURITY_PRINCIPAL, <span class="code-quote">"uid=admin,ou=system"</span>
);
        env.put( Context.SECURITY_CREDENTIALS, <span class="code-quote">"secret"</span>
);
        env.put( Context.SECURITY_AUTHENTICATION, <span class="code-quote">"simple"</span>
);
        env.put( Context.INITIAL_CONTEXT_FACTORY, <span class="code-quote">"org.apache.directory.server.jndi.ServerContextFactory"</span>
);

        <span class="code-comment">// Let's open a connection on <span class="code-keyword">this</span>
partition
</span>        InitialContext initialContext = <span class="code-keyword">new</span>
InitialContext( env );

        <span class="code-comment">// We should be able to read it
</span>        DirContext appRoot = ( DirContext ) initialContext.lookup( "" );
        assertNotNull( appRoot );

        <span class="code-comment">// Let's get the entry associated to the top level
</span>        Attributes attributes = appRoot.getAttributes( "" );
        assertNotNull( attributes );
        assertEquals( <span class="code-quote">"sevenseas"</span>, attributes.get(
<span class="code-quote">"o"</span> ).get() );

        Attribute attribute = attributes.get( <span class="code-quote">"objectClass"</span>
);
        assertNotNull( attribute );
        assertTrue( attribute.contains( <span class="code-quote">"top"</span>
) );
        assertTrue( attribute.contains( <span class="code-quote">"organization"</span>
) );
        <span class="code-comment">// Ok, everything is fine
</span>    }
</pre>
</div></div>
<p>The test should succeed. Is that all ? Well, almost. As you can see, a working space
has been created ( "server-work", at the end of the setup). Do we have to take care of this
working space? No. It has been cleaned by the super class &#33;</p>

<p>So everything is fine, the partition is up and running, you are ready to add more
tests.</p>

<p>One line in the logs is interesting :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
3879 [main] INFO org.apache.directory.server.jndi.ServerContextFactory -
LDIF load directory not specified.  No LDIF files will be loaded.
</pre>
</div></div>
<p>The setup has tried to load an LDIF file to inject some data into the partition,
but as we didn't specify any Ldif file to be loaded, nothing has been done. let's add some
data &#33;</p>

<h3><a name="4.2.UsingApacheDSforunittests-Addingsomedataintothepartition"></a>Adding
some data into the partition</h3>

<p>The <b>AbstractServerTest</b> class provide a method called <b>importLdif(
InputStream in )</b>. It allows you to inject some entries into the newly created partition.
How d we use it?</p>

<p>First, we need to have a valid LDIF file containing your entries. We will create
two branches in our <b>sevenseas</b> organization :</p>
<ul>
	<li>one for groups</li>
	<li>one for people</li>
</ul>


<p>Here is the ldif file we will create :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
dn: ou=groups,o=sevenSeas
objectClass: organizationalUnit
objectClass: top
ou: groups
description: Contains entries which describe groups (crews, <span class="code-keyword">for</span>
instance)

dn: ou=people,o=sevenSeas
objectClass: organizationalUnit
objectClass: top
ou: people
description: Contains entries which describe persons (seamen)
</pre>
</div></div>
<p>Save it as a text file into a directory where we will be able to read it directly.
But where?</p>

<p>We have created the test into a directory src/test/java/org/apache/directory/demo.
This is the <b>maven</b> way to organized the sources, as seen before. Let's create
another directory for the resources : src/test/resources/org/apache/directory/demo. Tis is
the place where we will save the ldif file.</p>

<p>Now, to let the server know about the ldif file, just add this line <em>after</em>
the call to the <b>setup()</b> method :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
...
        <span class="code-comment">// Now, let's call the upper class which is responsible
<span class="code-keyword">for</span> the
</span>        <span class="code-comment">// partitions creation
</span>        <span class="code-keyword">super</span>.setUp();

        <span class="code-comment">// Load a demo ldif file
</span>        importLdif( <span class="code-keyword">this</span>.getClass().getResourceAsStream(
<span class="code-quote">"demo.ldif"</span> ) );
    }
</pre>
</div></div>
<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td><p>This is important to
add the import after the setup : you can't import data while the partition has not been created
...</p></td></tr></table></div>
<p>The <b>getResourceAsStream</b> call will automatically read the file
from the resources directory, based on the current class package.</p>

<p>How can we be sure that the data has been imported ? Let's do a search request &#33;</p>

<h3><a name="4.2.UsingApacheDSforunittests-Cleanupthecode"></a>Cleanup the
code</h3>

<p>Before that, let's do some cleanup. The context creation is something we will have
to do in each test. We should create a common method called every time to avoid duplicating
this code. Let's create this method :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/**
     * Create a context pointing to a partition
     */
    <span class="code-keyword">private</span> DirContext createContext( <span
class="code-object">String</span> partition ) <span class="code-keyword">throws</span>
NamingException
    {
        <span class="code-comment">// Create a environment container
</span>        Hashtable&lt;<span class="code-object">Object</span>,
<span class="code-object">Object</span>&gt; env =
            <span class="code-keyword">new</span> Hashtable&lt;<span class="code-object">Object</span>,
<span class="code-object">Object</span>&gt;( configuration.toJndiEnvironment()
);

        <span class="code-comment">// Create a <span class="code-keyword">new</span>
context pointing to the partition
</span>        env.put( Context.PROVIDER_URL, partition );
        env.put( Context.SECURITY_PRINCIPAL, <span class="code-quote">"uid=admin,ou=system"</span>
);
        env.put( Context.SECURITY_CREDENTIALS, <span class="code-quote">"secret"</span>
);
        env.put( Context.SECURITY_AUTHENTICATION, <span class="code-quote">"simple"</span>
);
        env.put( Context.INITIAL_CONTEXT_FACTORY,
                    <span class="code-quote">"org.apache.directory.server.jndi.ServerContextFactory"</span>
);

        <span class="code-comment">// Let's open a connection on <span class="code-keyword">this</span>
partition
</span>        InitialContext initialContext = <span class="code-keyword">new</span>
InitialContext( env );

        <span class="code-comment">// We should be able to read it
</span>        DirContext appRoot = ( DirContext ) initialContext.lookup( "" );
        assertNotNull( appRoot );

        <span class="code-keyword">return</span> appRoot;
    }
</pre>
</div></div>
<p>This method is added into the body of the test class. This method is very simple
and quite straightforward : we just create an initial context pointing to the requested partition,
and return a directory context on this partition. It takes a parameter, the partition name.</p>

<p>Let's modify the test partition method :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/**
     * Test that the partition has been correctly created
     */
    <span class="code-keyword">public</span> void testPartition() <span class="code-keyword">throws</span>
NamingException
    {
        DirContext appRoot = createContext( <span class="code-quote">"o=sevenSeas"</span>
);

        <span class="code-comment">// Let's get the entry associated to the top level
</span>        Attributes attributes = appRoot.getAttributes( "" );
        ...
</pre>
</div></div>
<p>We just replaced the first lines by a call to the newly created createContext() method.</p>

<p>If you launch the unit test, it should still be ok.</p>

<h3><a name="4.2.UsingApacheDSforunittests-Searchingforentries"></a>Searching
for entries</h3>

<p>This is really simple. What we will do is to search for the imported entries. Let's
go directly to the code. We will  add a new unit test</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/**
     * Test that the ldif data has correctly been imported
     */
    <span class="code-keyword">public</span> void testImport() <span class="code-keyword">throws</span>
NamingException
    {
        <span class="code-comment">// Searching <span class="code-keyword">for</span>
all
</span>        Set&lt;<span class="code-object">String</span>&gt;
result = searchDNs( <span class="code-quote">"(ObjectClass=*)"</span>, <span
class="code-quote">"o=sevenSeas"</span>, "",
                                          SearchControls.ONELEVEL_SCOPE );

        assertTrue( result.contains( <span class="code-quote">"ou=groups,o=sevenSeas"</span>
) );
        assertTrue( result.contains( <span class="code-quote">"ou=people,o=sevenSeas"</span>
) );
    }
</pre>
</div></div>
<p>Here, we are looking for all the entries starting at the top level of the partition,
within the level. We should only get two entries.</p>

<p>It's not enough : the searchDNs() method does not exist. It is a private method we
have created to avoid duplicating some code all over the unit tests. Here is its code :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
/**
     * Performs a single level search from a root base and
     * returns the set of DNs found.
     */
    <span class="code-keyword">private</span> Set&lt;<span class="code-object">String</span>&gt;
searchDNs( <span class="code-object">String</span> filter, <span class="code-object">String</span>
partition, <span class="code-object">String</span> base, <span class="code-object">int</span>
scope )
       <span class="code-keyword">throws</span> NamingException
    {
        DirContext appRoot = createContext( partition );

        SearchControls controls = <span class="code-keyword">new</span> SearchControls();
        controls.setSearchScope( scope );
        NamingEnumeration result = appRoot.search( base, filter, controls );

        <span class="code-comment">// collect all results
</span>        HashSet&lt;<span class="code-object">String</span>&gt;
entries = <span class="code-keyword">new</span> HashSet&lt;<span class="code-object">String</span>&gt;();

        <span class="code-keyword">while</span> ( result.hasMore() )
        {
            SearchResult entry = ( SearchResult ) result.next();
            entries.add( entry.getName() );
        }

        <span class="code-keyword">return</span> entries;
    }
</pre>
</div></div>
<p>As for the test partiton, we call the createContext() method, then we just do some
JNDI magic :</p>
<ul>
	<li>creating a SearchControl,</li>
	<li>setting the scope,</li>
	<li>calling the serach</li>
	<li>and gathering the returned DN if any</li>
</ul>


<p>If the test is successful, you get the imported DNs &#33;</p>

<h3><a name="4.2.UsingApacheDSforunittests-Addingyourownschema"></a>Adding
your own schema</h3>

<div class='panelMacro'><table class='warningMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/forbidden.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td><b>Work in progress</b><br
/><p>This paragraph is totally outdated. It should be rewriten from scratch &#33;</p></td></tr></table></div>
<p>Ok, let's go deeper into the server configuration. Working with default schema is
fine, but some point, you may want to use your own ObjectClasses and AttributeTypes. let's
assume you have created them, and that you have been throw the process of generating the class
files for it (this process is described in <a href="http://cwiki.apache.org/confluence/display/DIRxSRVx10/Custom+Schema"
rel="nofollow">Custom Schema</a>) into a new package (org.apache.directory.demo.schema)
where all the generated files will be put.</p>

<p>You will just have to add those lines at the end of the setUp() method (just before
the call to the super() method) :</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
...
<span class="code-keyword">import</span> org.apache.directory.server.core.configuration.MutablePartitionConfiguration;
<span class="code-keyword">import</span> org.apache.directory.server.core.schema.bootstrap.AbstractBootstrapSchema;
<span class="code-keyword">import</span> org.apache.directory.server.unit.AbstractServerTest;

<span class="code-keyword">import</span> org.apache.directory.demo.schema.DemoSchema;

...
        ...
        <span class="code-comment">///
</span>        <span class="code-comment">/// add the Demo schema
</span>        <span class="code-comment">///
</span>        Set&lt;AbstractBootstrapSchema&gt; schemas = configuration.getBootstrapSchemas();
        schemas.add( <span class="code-keyword">new</span> DemoSchema() );

        configuration.setBootstrapSchemas(schemas);


        <span class="code-comment">// Now, let's call the upper class which is responsible
<span class="code-keyword">for</span> the
</span>        <span class="code-comment">// partitions creation
</span>        <span class="code-keyword">super</span>.setUp();
    }
</pre>
</div></div>
<p>If we launch the test, nothing special will happen, except that the test will succeed.
That's not very impressive...</p>

<h2><a name="4.2.UsingApacheDSforunittests-Conclusion"></a>Conclusion</h2>

<p>Ok, this tutorial was a short one, but you get everything you need to play with Apache
Directory Server as a Unit Test Engine for your Ldap application. Just create your own partition,
define your schema, import your ldif file, and add all the tests you need. it's as simple
as explained <img class="emoticon" src="/confluence/images/icons/emoticons/smile.gif" height="20"
width="20" align="absmiddle" alt="" border="0"/></p>

<p>If you have any problem, just feel free to post a mail to users@directory.apache.org,
we will be there to help &#33;</p>

<h2><a name="4.2.UsingApacheDSforunittests-Resources"></a>Resources</h2>

<ul>
	<li><a href="http://directory.apache.org/community%26resources/embedding-apacheds.html"
rel="nofollow">Embedding ApacheDS - Conference Materials </a></li>
</ul>

     </div>
     <div id="commentsSection" class="wiki-content pageSection">
       <div style="float: right;">
            <a href="http://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
       </div>

       <a href="http://cwiki.apache.org/confluence/display/DIRxSRVx11/4.2.+Using+ApacheDS+for+unit+tests">View
Online</a>
       |
       <a href="http://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=55238&revisedVersion=13&originalVersion=12">View
Change</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message