View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.unit;
21  
22  
23  import junit.framework.TestCase;
24  import org.apache.commons.io.FileUtils;
25  import org.apache.directory.server.constants.ServerDNConstants;
26  import org.apache.directory.server.core.DefaultDirectoryService;
27  import org.apache.directory.server.core.DirectoryService;
28  import org.apache.directory.server.core.entry.DefaultServerEntry;
29  import org.apache.directory.server.schema.registries.Registries;
30  import org.apache.directory.shared.ldap.ldif.LdifEntry;
31  import org.apache.directory.shared.ldap.ldif.LdifReader;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  import javax.naming.Context;
36  import javax.naming.ldap.InitialLdapContext;
37  import javax.naming.ldap.LdapContext;
38  
39  import java.io.File;
40  import java.io.FileInputStream;
41  import java.io.FileNotFoundException;
42  import java.io.IOException;
43  import java.io.InputStream;
44  import java.util.ArrayList;
45  import java.util.Hashtable;
46  import java.util.List;
47  
48  
49  /**
50   * A simple testcase for testing JNDI provider functionality.
51   *
52   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
53   * @version $Rev: 686082 $
54   */
55  public abstract class AbstractTestCase extends TestCase
56  {
57      public static final Logger LOG = LoggerFactory.getLogger( AbstractTestCase.class );
58  
59      public static final String LDIF = 
60          "dn: uid=akarasulu,ou=users,ou=system\n" + 
61          "cn: Alex Karasulu\n" +
62          "sn: Karasulu\n" + 
63          "givenname: Alex\n" + 
64          "objectclass: top\n" + 
65          "objectclass: person\n" +
66          "objectclass: organizationalPerson\n" + 
67          "objectclass: inetOrgPerson\n" + 
68          "ou: Engineering\n" + 
69          "ou: People\n" +
70          "l: Bogusville\n" + 
71          "uid: akarasulu\n" + 
72          "mail: akarasulu@apache.org\n" +
73          "telephonenumber: +1 408 555 4798\n" + 
74          "facsimiletelephonenumber: +1 408 555 9751\n" + 
75          "roomnumber: 4612\n" +
76          "userpassword: test\n";
77  
78      protected final String username;
79  
80      protected final String password;
81  
82      /** the context root for the system partition */
83      protected LdapContext sysRoot;
84  
85      /** the context root for the schema partition */
86      protected LdapContext schemaRoot;
87      
88      /** the rootDSE context for the server */
89      protected LdapContext rootDSE;
90  
91      /** flag whether to delete database files for each test or not */
92      protected boolean doDelete = true;
93  
94      /** A testEntries of entries as Attributes to add to the DIT for testing */
95      protected List<LdifEntry> testEntries = new ArrayList<LdifEntry>();
96  
97      /** An optional LDIF file path if set and present is read to add more test entries */
98      private String ldifPath;
99  
100     /** Load resources relative to this class */
101     private Class<?> loadClass;
102 
103     private Hashtable<String,Object> overrides = new Hashtable<String,Object>();
104 
105     protected Registries registries;
106 
107     protected DirectoryService service;
108 
109 
110     protected AbstractTestCase( String username, String password ) throws Exception
111     {
112         if ( username == null || password == null )
113         {
114             throw new NullPointerException();
115         }
116 
117         this.username = username;
118         this.password = password;
119         this.service = new DefaultDirectoryService();
120     }
121 
122 
123     /**
124      * Sets the LDIF path as a relative resource path to use with the
125      * loadClass parameter to load the resource.
126      *
127      * @param ldifPath the relative resource path to the LDIF file
128      * @param loadClass the class used to load the LDIF as a resource stream
129      */
130     protected void setLdifPath( String ldifPath, Class<?> loadClass )
131     {
132         this.loadClass = loadClass;
133         this.ldifPath = ldifPath;
134     }
135 
136 
137     /**
138      * Sets the LDIF path to use.  If the path is relative to this class then it
139      * is first tested
140      *
141      * @param ldifPath the path to the LDIF file
142      */
143     protected void setLdifPath( String ldifPath )
144     {
145         this.ldifPath = ldifPath;
146     }
147 
148 
149     /**
150      * Get's the initial context factory for the provider's ou=system context
151      * root.
152      *
153      * @see junit.framework.TestCase#setUp()
154      */
155     protected void setUp() throws Exception
156     {
157         super.setUp();
158 
159         // -------------------------------------------------------------------
160         // Bypass normal startup if changelog has been enabled and the server
161         // has already started.
162         // -------------------------------------------------------------------
163 
164         /// still working on it!!!
165 //        if ( service.getChangeLog().isEnabled() )
166 //        {
167 //            startTag = service.getChangeLog().tag();
168 //
169 //            if ( service.isStarted() )
170 //            {
171 //                return;
172 //            }
173 //        }
174 
175         // -------------------------------------------------------------------
176         // Add a single test entry
177         // -------------------------------------------------------------------
178 
179         LdifReader reader = new LdifReader();
180         List<LdifEntry> entries = reader.parseLdif( LDIF );
181         LdifEntry entry = entries.get(0);
182         testEntries.add( entry );
183 
184         // -------------------------------------------------------------------
185         // Add more from an optional LDIF file if they exist
186         // -------------------------------------------------------------------
187 
188         InputStream in = null;
189         if ( loadClass != null && ldifPath == null )
190         {
191             in = loadClass.getResourceAsStream( getName() + ".ldif" );
192         }
193         else if ( loadClass == null && ldifPath != null )
194         {
195             File ldifFile = new File( ldifPath );
196             if ( ldifFile.exists() )
197             {
198                 //noinspection UnusedAssignment
199                 in = new FileInputStream( ldifPath );
200             }
201             else
202             {
203                 //noinspection UnusedAssignment
204                 in = getClass().getResourceAsStream( ldifPath );
205             }
206             throw new FileNotFoundException( ldifPath );
207         }
208         else if ( loadClass != null )
209         {
210             in = loadClass.getResourceAsStream( ldifPath );
211         }
212 
213         if ( in != null )
214         {
215             for ( LdifEntry ldifEntry:new LdifReader( in ) )
216             {
217                 testEntries.add( ldifEntry );
218             }
219         }
220 
221         // -------------------------------------------------------------------
222         // Add key for extra entries to the testEntries of extras
223         // -------------------------------------------------------------------
224 
225         service.setTestEntries( testEntries );
226         service.setShutdownHookEnabled( false );
227         doDelete( service.getWorkingDirectory() );
228         service.startup();
229         setContextRoots( username, password );
230         registries = service.getRegistries();
231     }
232 
233     
234     /**
235      * Restarts the server without loading data when it has been shutdown.
236      * @throws NamingException if the restart fails
237      */
238     protected void restart() throws Exception
239     {
240         if ( service == null )
241         {
242             service = new DefaultDirectoryService();
243         }
244         service.setShutdownHookEnabled( false );
245         service.startup();
246         setContextRoots( username, password );
247     }
248     
249 
250     /**
251      * Deletes the working directory.
252      *
253      * @param wkdir the working directory to delete
254      * @throws IOException if the working directory cannot be deleted
255      */
256     protected void doDelete( File wkdir ) throws IOException
257     {
258         if ( doDelete )
259         {
260             if ( wkdir.exists() )
261             {
262                 try
263                 {
264                     FileUtils.deleteDirectory( wkdir );
265                 }
266                 catch ( IOException e )
267                 {
268                     LOG.error( "Failed to delete the working directory.", e );
269                 }
270             }
271             if ( wkdir.exists() )
272             {
273                 throw new IOException( "Failed to delete: " + wkdir );
274             }
275         }
276     }
277 
278 
279     /**
280      * Sets and returns the system root.  Values of user and password used to
281      * set the respective JNDI properties.  These values can be overriden by the
282      * overrides properties.
283      *
284      * @param user the username for authenticating as this user
285      * @param passwd the password of the user
286      * @throws NamingException if there is a failure of any kind
287      */
288     protected void setContextRoots( String user, String passwd ) throws Exception
289     {
290         Hashtable<String,Object> env = new Hashtable<String,Object>();
291         env.put(  DirectoryService.JNDI_KEY, service );
292         env.put( Context.SECURITY_PRINCIPAL, user );
293         env.put( Context.SECURITY_CREDENTIALS, passwd );
294         env.put( Context.SECURITY_AUTHENTICATION, "simple" );
295         setContextRoots( env );
296     }
297 
298 
299     /**
300      * Sets the system root taking into account the extras and overrides
301      * properties.  In between these it sets the properties for the working
302      * directory, the provider URL and the JNDI InitialContexFactory to use.
303      *
304      * @param env an environment to use while setting up the system root.
305      * @throws NamingException if there is a failure of any kind
306      */
307     protected void setContextRoots( Hashtable<String,Object> env ) throws Exception
308     {
309         Hashtable<String,Object> envFinal = new Hashtable<String,Object>( env );
310         if ( !envFinal.containsKey( Context.PROVIDER_URL ) )
311         {
312             envFinal.put( Context.PROVIDER_URL, ServerDNConstants.SYSTEM_DN );
313         }
314 
315         envFinal.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.directory.server.core.jndi.CoreContextFactory" );
316         envFinal.putAll( overrides );
317 
318         // We have to initiate the first run as an admin at least.
319         Hashtable<String,Object> adminEnv = new Hashtable<String,Object>( envFinal );
320         adminEnv.put( Context.SECURITY_PRINCIPAL, ServerDNConstants.ADMIN_SYSTEM_DN );
321         adminEnv.put( Context.SECURITY_CREDENTIALS, "secret" );
322         adminEnv.put( Context.SECURITY_AUTHENTICATION, "simple" );
323         adminEnv.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.directory.server.core.jndi.CoreContextFactory" );
324         adminEnv.put( DirectoryService.JNDI_KEY, service );
325         new InitialLdapContext( adminEnv, null );
326 
327         // OK, now let's get an appropriate context.
328         sysRoot = new InitialLdapContext( envFinal, null );
329 
330         envFinal.put( Context.PROVIDER_URL, ServerDNConstants.OU_SCHEMA_DN );
331         schemaRoot = new InitialLdapContext( envFinal, null );
332         
333         envFinal.put( Context.PROVIDER_URL, "" );
334         rootDSE = new InitialLdapContext( envFinal, null );
335     }
336 
337 
338     /**
339      * Overrides default JNDI environment properties.  Please call this method
340      * to override any JNDI environment properties this test case will set.
341      * @param key the key of the hashtable entry to add to the environment
342      * @param value the value of the hashtable entry to add to the environment
343      */
344     protected void overrideEnvironment( String key, Object value )
345     {
346         overrides.put( key, value );
347     }
348 
349 
350     @SuppressWarnings("unchecked")
351     protected Hashtable<String,Object> getOverriddenEnvironment()
352     {
353         return ( Hashtable<String,Object> ) overrides.clone();
354     }
355 
356 
357     /**
358      * Issues a shutdown request to the server.
359      */
360     protected void shutdown()
361     {
362         try
363         {
364             service.shutdown();
365         }
366         catch ( Exception e )
367         {
368             LOG.error( "Encountered an error while shutting down directory service.", e );
369         } 
370         sysRoot = null;
371         Runtime.getRuntime().gc();
372     }
373 
374 
375     /**
376      * Issues a sync request to the server.
377      */
378     protected void sync()
379     {
380         try
381         {
382             service.sync();
383         }
384         catch ( Exception e )
385         {
386             LOG.warn( "Encountered error while syncing.", e );
387         } 
388     }
389 
390     
391     /**
392      * Sets the system context root to null.
393      *
394      * @see junit.framework.TestCase#tearDown()
395      */
396     protected void tearDown() throws Exception
397     {
398         super.tearDown();
399         shutdown();
400         testEntries.clear();
401         ldifPath = null;
402         loadClass = null;
403         overrides.clear();
404         service = new DefaultDirectoryService();
405         doDelete( service.getWorkingDirectory() );
406     }
407 
408 
409     protected void setLoadClass( Class<?> loadClass )
410     {
411         this.loadClass = loadClass;
412     }
413     
414     
415     /**
416      * Inject an ldif String into the server. DN must be relative to the
417      * root.
418      * 
419      * @param ldif the ldif containing entries to add to the server.
420      * @throws NamingException if there is a problem adding the entries from the LDIF
421      */
422     protected void injectEntries( String ldif ) throws Exception
423     {
424         LdifReader reader = new LdifReader();
425         List<LdifEntry> entries = reader.parseLdif( ldif );
426 
427         for ( LdifEntry entry : entries )
428         {
429             service.getAdminSession().add( 
430                 new DefaultServerEntry( service.getRegistries(), entry.getEntry() ) ); 
431         }
432     }
433 }