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.partition.impl.btree.jdbm;
21  
22  
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import org.junit.Before;
26  import org.junit.After;
27  import org.junit.Test;
28  import static org.junit.Assert.*;
29  import org.apache.commons.io.FileUtils;
30  import org.apache.directory.server.schema.bootstrap.*;
31  import org.apache.directory.server.schema.registries.*;
32  import org.apache.directory.server.schema.SerializableComparator;
33  import org.apache.directory.server.core.entry.DefaultServerEntry;
34  import org.apache.directory.server.xdbm.IndexNotFoundException;
35  import org.apache.directory.server.xdbm.IndexEntry;
36  import org.apache.directory.server.xdbm.Index;
37  import org.apache.directory.server.xdbm.IndexCursor;
38  import org.apache.directory.server.xdbm.tools.StoreUtils;
39  import org.apache.directory.server.core.cursor.Cursor;
40  import org.apache.directory.server.core.entry.ServerEntry;
41  import org.apache.directory.server.core.entry.ServerModification;
42  import org.apache.directory.server.core.entry.DefaultServerAttribute;
43  import org.apache.directory.server.core.entry.ServerAttribute;
44  import org.apache.directory.server.constants.ApacheSchemaConstants;
45  import org.apache.directory.shared.ldap.name.LdapDN;
46  import org.apache.directory.shared.ldap.constants.SchemaConstants;
47  import org.apache.directory.shared.ldap.schema.AttributeType;
48  import org.apache.directory.shared.ldap.entry.ModificationOperation;
49  import org.apache.directory.shared.ldap.entry.Modification;
50  import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException;
51  import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
52  import org.apache.directory.shared.ldap.name.Rdn;
53  
54  import javax.naming.directory.Attributes;
55  import java.lang.reflect.Method;
56  import java.io.File;
57  import java.util.ArrayList;
58  import java.util.List;
59  import java.util.Set;
60  import java.util.HashSet;
61  import java.util.Iterator;
62  
63  
64  /**
65   * Unit test cases for JdbmStore
66   *
67   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
68   * @version $$Rev$$
69   */
70  @SuppressWarnings("unchecked")
71  public class JdbmStoreTest
72  {
73      private static final Logger LOG = LoggerFactory.getLogger( JdbmStoreTest.class.getSimpleName() );
74  
75      File wkdir;
76      JdbmStore<ServerEntry> store;
77      Registries registries = null;
78      AttributeTypeRegistry attributeRegistry;
79  
80  
81      public JdbmStoreTest() throws Exception
82      {
83          // setup the standard registries
84          BootstrapSchemaLoader loader = new BootstrapSchemaLoader();
85          OidRegistry oidRegistry = new DefaultOidRegistry();
86          registries = new DefaultRegistries( "bootstrap", loader, oidRegistry );
87          SerializableComparator.setRegistry( registries.getComparatorRegistry() );
88  
89          // load essential bootstrap schemas
90          Set<Schema> bootstrapSchemas = new HashSet<Schema>();
91          bootstrapSchemas.add( new ApachemetaSchema() );
92          bootstrapSchemas.add( new ApacheSchema() );
93          bootstrapSchemas.add( new CoreSchema() );
94          bootstrapSchemas.add( new SystemSchema() );
95          loader.loadWithDependencies( bootstrapSchemas, registries );
96          attributeRegistry = registries.getAttributeTypeRegistry();
97      }
98  
99  
100     @Before
101     public void createStore() throws Exception
102     {
103         destroyStore();
104 
105         // setup the working directory for the store
106         wkdir = File.createTempFile( getClass().getSimpleName(), "db" );
107         wkdir.delete();
108         wkdir = new File( wkdir.getParentFile(), getClass().getSimpleName() );
109         wkdir.mkdirs();
110 
111         // initialize the store
112         store = new JdbmStore<ServerEntry>();
113         store.setName( "example" );
114         store.setCacheSize( 10 );
115         store.setWorkingDirectory( wkdir );
116         store.setSyncOnWrite( false );
117 
118         store.addIndex( new JdbmIndex( SchemaConstants.OU_AT_OID ) );
119         store.addIndex( new JdbmIndex( SchemaConstants.UID_AT_OID ) );
120         StoreUtils.loadExampleData( store, registries );
121         LOG.debug( "Created new store" );
122     }
123 
124 
125     @After
126     public void destroyStore() throws Exception
127     {
128         if ( store != null )
129         {
130             store.destroy();
131         }
132 
133         store = null;
134         
135         if ( wkdir != null )
136         {
137             FileUtils.deleteDirectory( wkdir );
138         }
139 
140         wkdir = null;
141     }
142 
143 
144     @Test
145     public void testSimplePropertiesUnlocked() throws Exception
146     {
147         JdbmStore<Attributes> store = new JdbmStore<Attributes>();
148         store.setSyncOnWrite( true ); // for code coverage
149         
150         assertNull( store.getAliasIndex() );
151         store.setAliasIndex( new JdbmIndex<String,Attributes>( "alias" ) );
152         assertNotNull( store.getAliasIndex() );
153 
154         assertEquals( JdbmStore.DEFAULT_CACHE_SIZE, store.getCacheSize() );
155         store.setCacheSize( 24 );
156         assertEquals( 24, store.getCacheSize() );
157 
158         assertNull( store.getPresenceIndex() );
159         store.setPresenceIndex( new JdbmIndex<String,Attributes>( "existence" ) );
160         assertNotNull( store.getPresenceIndex() );
161 
162         assertNull( store.getOneLevelIndex() );
163         store.setOneLevelIndex( new JdbmIndex<Long,Attributes>( "hierarchy" ) );
164         assertNotNull( store.getOneLevelIndex() );
165         
166         assertNull( store.getSubLevelIndex() );
167         store.setSubLevelIndex( new JdbmIndex<Long,Attributes>( "sublevel" ) );
168         assertNotNull( store.getSubLevelIndex() );
169 
170         assertNull( store.getName() );
171         store.setName( "foo" );
172         assertEquals( "foo", store.getName() );
173 
174         assertNull( store.getNdnIndex() );
175         store.setNdnIndex( new JdbmIndex<String,Attributes>( "ndn" ) );
176         assertNotNull( store.getNdnIndex() );
177 
178         assertNull( store.getOneAliasIndex() );
179         store.setOneAliasIndex( new JdbmIndex<Long,Attributes>( "oneAlias" ) );
180         assertNotNull( store.getNdnIndex() );
181 
182         assertNull( store.getSubAliasIndex() );
183         store.setSubAliasIndex( new JdbmIndex<Long,Attributes>( "subAlias" ) );
184         assertNotNull( store.getSubAliasIndex() );
185 
186         assertNull( store.getSuffixDn() );
187         store.setSuffixDn( "dc=example,dc=com" );
188         assertEquals( "dc=example,dc=com", store.getSuffixDn() );
189 
190         assertNull( store.getUpdnIndex() );
191         store.setUpdnIndex( new JdbmIndex<String,Attributes>( "updn" ) );
192         assertNotNull( store.getUpdnIndex() );
193 
194         assertNull( store.getUpSuffix() );
195         assertNull( store.getSuffix() );
196 
197         assertEquals( 0, store.getUserIndices().size() );
198         Set<Index<?,Attributes>> set = new HashSet<Index<?,Attributes>>();
199         set.add( new JdbmIndex<Object,Attributes>( "foo" ) );
200         store.setUserIndices( set );
201         assertEquals( set.size(), store.getUserIndices().size() );
202 
203         assertNull( store.getWorkingDirectory() );
204         store.setWorkingDirectory( new File( "." ) );
205         assertEquals( new File( "." ), store.getWorkingDirectory() );
206 
207         assertFalse( store.isInitialized() );
208         assertTrue( store.isSyncOnWrite() );
209         store.setSyncOnWrite( false );
210         assertFalse( store.isSyncOnWrite() );
211 
212         store.sync();
213         store.destroy();
214     }
215 
216 
217     @Test
218     public void testSimplePropertiesLocked() throws Exception
219     {
220         assertNotNull( store.getAliasIndex() );
221         try { store.setAliasIndex( new JdbmIndex<String,ServerEntry>( "alias" ) ); fail(); }
222         catch( IllegalStateException e ) {}
223 
224         assertEquals( 10, store.getCacheSize() );
225         try { store.setCacheSize( 24 ); }
226         catch( IllegalStateException e ) {}
227 
228         assertNotNull( store.getPresenceIndex() );
229         try { store.setPresenceIndex( new JdbmIndex<String,ServerEntry>( "existence" ) ); fail(); }
230         catch( IllegalStateException e ) {}
231 
232         assertNotNull( store.getOneLevelIndex() );
233         try { store.setOneLevelIndex( new JdbmIndex<Long,ServerEntry>( "hierarchy" ) ); fail(); }
234         catch( IllegalStateException e ) {}
235 
236         assertNotNull( store.getSubLevelIndex() );
237         try { store.setSubLevelIndex( new JdbmIndex<Long,ServerEntry>( "sublevel" ) ); fail(); }
238         catch( IllegalStateException e ) {}
239         
240         assertNotNull( store.getName() );
241         try { store.setName( "foo" ); fail(); }
242         catch( IllegalStateException e ) {}
243 
244         assertNotNull( store.getNdnIndex() );
245         try { store.setNdnIndex( new JdbmIndex<String,ServerEntry>( "ndn" ) ); fail(); }
246         catch( IllegalStateException e ) {}
247 
248         assertNotNull( store.getOneAliasIndex() );
249         try { store.setOneAliasIndex( new JdbmIndex<Long,ServerEntry>( "oneAlias" ) ); fail(); }
250         catch( IllegalStateException e ) {}
251 
252         assertNotNull( store.getSubAliasIndex() );
253         try { store.setSubAliasIndex( new JdbmIndex<Long,ServerEntry>( "subAlias" ) ); fail(); }
254         catch( IllegalStateException e ) {}
255 
256         assertNotNull( store.getSuffixDn() );
257         try { store.setSuffixDn( "dc=example,dc=com" ); fail(); }
258         catch( IllegalStateException e ) {}
259 
260         assertNotNull( store.getUpdnIndex() );
261         try { store.setUpdnIndex( new JdbmIndex<String,ServerEntry>( "updn" ) ); fail(); }
262         catch( IllegalStateException e ) {}
263         Iterator<String> systemIndices = store.systemIndices();
264         for ( int ii = 0; ii < 8; ii++ )
265         {
266             assertTrue( systemIndices.hasNext() );
267             assertNotNull( systemIndices.next() );
268         }
269         assertFalse( systemIndices.hasNext() );
270         assertNotNull( store.getSystemIndex( ApacheSchemaConstants.APACHE_ALIAS_AT ) );
271         try { store.getSystemIndex( "bogus" ); fail(); }
272         catch ( IndexNotFoundException e ) {}
273         try { store.getSystemIndex( "dc" ); fail(); }
274         catch ( IndexNotFoundException e ) {}
275 
276         assertNotNull( store.getUpSuffix() );
277         assertNotNull( store.getSuffix() );
278 
279         assertEquals( 2, store.getUserIndices().size() );
280         assertFalse( store.hasUserIndexOn( "dc" ) );
281         assertTrue( store.hasUserIndexOn( SchemaConstants.OU_AT ) );
282         assertTrue( store.hasSystemIndexOn( ApacheSchemaConstants.APACHE_ALIAS_AT ) );
283         Iterator<String> userIndices = store.userIndices();
284         assertTrue( userIndices.hasNext() );
285         assertNotNull( userIndices.next() );
286         assertTrue( userIndices.hasNext() );        
287         assertNotNull( userIndices.next() );
288         assertFalse( userIndices.hasNext() );        
289         assertNotNull( store.getUserIndex( SchemaConstants.OU_AT ) );
290         try { store.getUserIndex( "bogus" ); fail(); }
291         catch ( IndexNotFoundException e ) {}
292         try { store.getUserIndex( "dc" ); fail(); }
293         catch ( IndexNotFoundException e ) {}
294 
295         assertNotNull( store.getWorkingDirectory() );
296         try { store.setWorkingDirectory( new File( "." ) ); fail(); }
297         catch( IllegalStateException e ) {}
298 
299         assertTrue( store.isInitialized() );
300         assertFalse( store.isSyncOnWrite() );
301 
302         store.sync();
303     }
304 
305 
306     @Test
307     public void testPersistentProperties() throws Exception
308     {
309         assertNull( store.getProperty( "foo" ) );
310         store.setProperty( "foo", "bar" );
311         assertEquals( "bar", store.getProperty( "foo" ) );
312     }
313 
314 
315     @Test
316     public void testFreshStore() throws Exception
317     {
318         LdapDN dn = new LdapDN( "o=Good Times Co." );
319         dn.normalize( attributeRegistry.getNormalizerMapping() );
320         assertEquals( 1L, ( long ) store.getEntryId( dn.toNormName() ) );
321         assertEquals( 11, store.count() );
322         assertEquals( "o=Good Times Co.", store.getEntryUpdn( dn.toNormName() ) );
323         assertEquals( dn.toNormName(), store.getEntryDn( 1L ) );
324         assertEquals( dn.getUpName(), store.getEntryUpdn( 1L ) );
325 
326         // note that the suffix entry returns 0 for it's parent which does not exist
327         assertEquals( 0L, ( long ) store.getParentId( dn.toNormName() ) );
328         assertNull( store.getParentId( 0L ) );
329 
330         // should NOW be allowed
331         store.delete( 1L ); 
332     }
333 
334 
335     @Test
336     public void testEntryOperations() throws Exception
337     {
338         assertEquals( 3, store.getChildCount( 1L ) );
339 
340         Cursor<IndexEntry<Long,ServerEntry>> cursor = store.list( 1L );
341         assertNotNull( cursor );
342         cursor.beforeFirst();
343         assertTrue( cursor.next() );
344         assertEquals( 2L, ( long ) cursor.get().getId() );
345         assertTrue( cursor.next() );
346         assertEquals( 3, store.getChildCount( 1L ) );
347         
348         store.delete( 2L );
349         assertEquals( 2, store.getChildCount( 1L ) );
350         assertEquals( 10, store.count() );
351         
352         // add an alias and delete to test dropAliasIndices method
353         LdapDN dn = new LdapDN( "commonName=Jack Daniels,ou=Apache,ou=Board of Directors,o=Good Times Co." );
354         dn.normalize( attributeRegistry.getNormalizerMapping() );
355         DefaultServerEntry entry = new DefaultServerEntry( registries, dn );
356         entry.add( "objectClass", "top", "alias", "extensibleObject" );
357         entry.add( "ou", "Apache" );
358         entry.add( "commonName",  "Jack Daniels");
359         entry.add( "aliasedObjectName", "cn=Jack Daniels,ou=Engineering,o=Good Times Co." );
360         store.add( dn, entry );
361         
362         store.delete( 12L ); // drops the alias indices
363         
364     }
365     
366 
367     @Test
368     public void testSubLevelIndex() throws Exception
369     {
370       Index idx = store.getSubLevelIndex();
371       
372       assertEquals( 19, idx.count() );
373       
374       Cursor<IndexEntry<Long,Attributes>> cursor = idx.forwardCursor( 2L );
375       
376       assertTrue( cursor.next() );
377       assertEquals( 2, ( long ) cursor.get().getId() );
378       
379       assertTrue( cursor.next() );
380       assertEquals( 5, ( long ) cursor.get().getId() );
381       
382       assertTrue( cursor.next() );
383       assertEquals( 6, ( long ) cursor.get().getId() );
384 
385       assertFalse( cursor.next() );
386       
387       idx.drop( 5L );
388       
389       cursor = idx.forwardCursor( 2L );
390 
391       assertTrue( cursor.next() );
392       assertEquals( 2, ( long ) cursor.get().getId() );
393       
394       assertTrue( cursor.next() );
395       assertEquals( 6, ( long ) cursor.get().getId() );
396       
397       assertFalse( cursor.next() );
398       
399       // dn id 12
400       LdapDN martinDn = new LdapDN( "cn=Marting King,ou=Sales,o=Good Times Co." );
401       martinDn.normalize( attributeRegistry.getNormalizerMapping() );
402       DefaultServerEntry entry = new DefaultServerEntry( registries, martinDn );
403       entry.add( "objectClass", "top", "person", "organizationalPerson" );
404       entry.add( "ou", "Sales" );
405       entry.add( "cn",  "Martin King");
406       store.add( martinDn, entry );
407       
408       cursor = idx.forwardCursor( 2L);
409       cursor.afterLast();
410       assertTrue( cursor.previous() );
411       assertEquals( 12, ( long ) cursor.get().getId() );
412       
413       LdapDN newParentDn = new LdapDN( "ou=Board of Directors,o=Good Times Co." );
414       newParentDn.normalize( attributeRegistry.getNormalizerMapping() );
415       
416       store.move( martinDn, newParentDn );
417       cursor = idx.forwardCursor( 3L);
418       cursor.afterLast();
419       assertTrue( cursor.previous() );
420       assertEquals( 12, ( long ) cursor.get().getId() );
421       
422       // dn id 13
423       LdapDN marketingDn = new LdapDN( "ou=Marketing,ou=Sales,o=Good Times Co." );
424       marketingDn.normalize( attributeRegistry.getNormalizerMapping() );
425       entry = new DefaultServerEntry( registries, marketingDn );
426       entry.add( "objectClass", "top", "organizationalUnit" );
427       entry.add( "ou", "Marketing" );
428       store.add( marketingDn, entry );
429 
430       // dn id 14
431       LdapDN jimmyDn = new LdapDN( "cn=Jimmy Wales,ou=Marketing, ou=Sales,o=Good Times Co." );
432       jimmyDn.normalize( attributeRegistry.getNormalizerMapping() );
433       entry = new DefaultServerEntry( registries, jimmyDn );
434       entry.add( "objectClass", "top", "person", "organizationalPerson" );
435       entry.add( "ou", "Marketing" );
436       entry.add( "cn",  "Jimmy Wales");
437       store.add( jimmyDn, entry );
438       
439       store.move( marketingDn, newParentDn );
440 
441       cursor = idx.forwardCursor( 3L);
442       cursor.afterLast();
443 
444       assertTrue( cursor.previous() );
445       assertEquals( 14, ( long ) cursor.get().getId() );
446       
447       assertTrue( cursor.previous() );
448       assertEquals( 13, ( long ) cursor.get().getId() );
449 
450       assertTrue( cursor.previous() );
451       assertEquals( 12, ( long ) cursor.get().getId() );
452 
453       assertTrue( cursor.previous() );
454       assertEquals( 10, ( long ) cursor.get().getId() );
455 
456       assertTrue( cursor.previous() );
457       assertEquals( 9, ( long ) cursor.get().getId() );
458 
459       assertTrue( cursor.previous() );
460       assertEquals( 7, ( long ) cursor.get().getId() );
461 
462       assertTrue( cursor.previous() );
463       assertEquals( 3, ( long ) cursor.get().getId() );
464       
465       assertFalse( cursor.previous() );
466     }
467    
468     
469     @Test
470     public void testConvertIndex() throws Exception
471     {
472         Index nonJdbmIndex = new Index()
473         {
474 
475             public void add( Object attrVal, Long id ) throws Exception { }
476 
477             public void close() throws Exception { }
478 
479             public int count() throws Exception
480             {
481                 return 0;
482             }
483 
484             public int count( Object attrVal ) throws Exception
485             {
486                 return 0;
487             }
488 
489             public void drop( Long id ) throws Exception { }
490 
491             public void drop( Object attrVal, Long id ) throws Exception { }
492 
493             public IndexCursor forwardCursor() throws Exception
494             {
495                 return null;
496             }
497 
498             public IndexCursor forwardCursor( Object key ) throws Exception
499             {
500                 return null;
501             }
502 
503             public Long forwardLookup( Object attrVal ) throws Exception
504             {
505                 return null;
506             }
507 
508             public Cursor forwardValueCursor( Object key ) throws Exception
509             {
510                 return null;
511             }
512 
513 
514             public boolean forward( Object attrVal ) throws Exception
515             {
516                 return false;
517             }
518 
519 
520             public boolean forward( Object attrVal, Long id ) throws Exception
521             {
522                 return false;
523             }
524 
525 
526             public boolean reverse( Long id ) throws Exception
527             {
528                 return false;
529             }
530 
531 
532             public boolean reverse( Long id, Object attrVal ) throws Exception
533             {
534                 return false;
535             }
536 
537 
538             public boolean forwardGreaterOrEq( Object attrVal ) throws Exception
539             {
540                 return false;
541             }
542 
543 
544             public boolean forwardGreaterOrEq( Object attrVal, Long id ) throws Exception
545             {
546                 return false;
547             }
548 
549 
550             public boolean reverseGreaterOrEq( Long id ) throws Exception
551             {
552                 return false;
553             }
554 
555 
556             public boolean reverseGreaterOrEq( Long id, Object attrVal ) throws Exception
557             {
558                 return false;
559             }
560 
561 
562             public boolean forwardLessOrEq( Object attrVal ) throws Exception
563             {
564                 return false;
565             }
566 
567 
568             public boolean forwardLessOrEq( Object attrVal, Long id ) throws Exception
569             {
570                 return false;
571             }
572 
573 
574             public boolean reverseLessOrEq( Long id ) throws Exception
575             {
576                 return false;
577             }
578 
579 
580             public boolean reverseLessOrEq( Long id, Object attrVal ) throws Exception
581             {
582                 return false;
583             }
584 
585 
586             public AttributeType getAttribute()
587             {
588                 return null;
589             }
590 
591             public String getAttributeId()
592             {
593                 return "ou";
594             }
595 
596             public int getCacheSize()
597             {
598                 return 10;
599             }
600 
601             public Object getNormalized( Object attrVal ) throws Exception
602             {
603                 return null;
604             }
605 
606             public File getWkDirPath()
607             {
608                 return new File(".");
609             }
610 
611             public int greaterThanCount( Object attrVal ) throws Exception
612             {
613                 return 0;
614             }
615 
616             public boolean isCountExact()
617             {
618                 return false;
619             }
620 
621             public int lessThanCount( Object attrVal ) throws Exception
622             {
623                 return 0;
624             }
625 
626             public IndexCursor reverseCursor() throws Exception
627             {
628                 return null;
629             }
630 
631             public IndexCursor reverseCursor( Long id ) throws Exception
632             {
633                 return null;
634             }
635 
636             public Object reverseLookup( Long id ) throws Exception
637             {
638                 return null;
639             }
640 
641             public Cursor reverseValueCursor( Long id ) throws Exception
642             {
643                 return null;
644             }
645 
646             public void setAttributeId( String attributeId ) { }
647 
648             public void setCacheSize( int cacheSize ) { }
649 
650             public void setWkDirPath( File wkDirPath ) { }
651 
652             public void sync() throws Exception { }
653             
654         };
655         
656         Method convertIndex = store.getClass().getDeclaredMethod( "convertIndex", Index.class );
657         convertIndex.setAccessible( true );
658         Object obj = convertIndex.invoke( store, nonJdbmIndex );
659         
660         assertNotNull( obj );
661         assertEquals( JdbmIndex.class, obj.getClass() );
662     }
663     
664     
665     @Test( expected = LdapNameNotFoundException.class )
666     public void testAddWithoutParentId() throws Exception
667     {
668         LdapDN dn = new LdapDN( "cn=Marting King,ou=Not Present,o=Good Times Co." );
669         dn.normalize( attributeRegistry.getNormalizerMapping() );
670         DefaultServerEntry entry = new DefaultServerEntry( registries, dn );
671         entry.add( "objectClass", "top", "person", "organizationalPerson" );
672         entry.add( "ou", "Not Present" );
673         entry.add( "cn",  "Martin King");
674         store.add( dn, entry );
675     }
676     
677     
678     @Test( expected = LdapSchemaViolationException.class )
679     public void testAddWithoutObjectClass() throws Exception
680     {
681         LdapDN dn = new LdapDN( "cn=Martin King,ou=Sales,o=Good Times Co." );
682         dn.normalize( attributeRegistry.getNormalizerMapping() );
683         DefaultServerEntry entry = new DefaultServerEntry( registries, dn );
684         entry.add( "ou", "Sales" );
685         entry.add( "cn",  "Martin King");
686         store.add( dn, entry );
687     }
688         
689     
690     @Test
691     public void testModifyAddOUAttrib() throws Exception
692     {
693         LdapDN dn = new LdapDN( "cn=JOhnny WAlkeR,ou=Sales,o=Good Times Co." );
694         dn.normalize( attributeRegistry.getNormalizerMapping() );
695 
696         List<Modification> mods = new ArrayList<Modification>();
697         ServerAttribute attrib = new DefaultServerAttribute( SchemaConstants.OU_AT,
698             attributeRegistry.lookup( SchemaConstants.OU_AT_OID ) );
699         attrib.add( "Engineering" );
700         
701         Modification add = new ServerModification( ModificationOperation.ADD_ATTRIBUTE, attrib );
702         
703         mods.add( add );
704         
705         store.modify( dn, mods );
706     }
707     
708     
709     @Test
710     public void testRename() throws Exception
711     {
712         LdapDN dn = new LdapDN( "cn=Pivate Ryan,ou=Engineering,o=Good Times Co." );
713         dn.normalize( attributeRegistry.getNormalizerMapping() );
714         DefaultServerEntry entry = new DefaultServerEntry( registries, dn );
715         entry.add( "objectClass", "top", "person", "organizationalPerson" );
716         entry.add( "ou", "Engineering" );
717         entry.add( "cn",  "Private Ryan");
718 
719         store.add( dn, entry );
720         
721         Rdn rdn = new Rdn("sn=James");
722         
723         store.rename( dn, rdn, true );
724     }
725     
726     
727     @Test
728     public void testMove() throws Exception
729     {
730         LdapDN childDn = new LdapDN( "cn=Pivate Ryan,ou=Engineering,o=Good Times Co." );
731         childDn.normalize( attributeRegistry.getNormalizerMapping() );
732         DefaultServerEntry childEntry = new DefaultServerEntry( registries, childDn );
733         childEntry.add( "objectClass", "top", "person", "organizationalPerson" );
734         childEntry.add( "ou", "Engineering" );
735         childEntry.add( "cn",  "Private Ryan");
736 
737         store.add( childDn, childEntry );
738 
739         LdapDN parentDn = new LdapDN( "ou=Sales,o=Good Times Co." );
740         parentDn.normalize( attributeRegistry.getNormalizerMapping() );
741 
742         Rdn rdn = new Rdn("cn=Ryan");
743 
744         store.move( childDn, parentDn, rdn, true );
745 
746         // to drop the alias indices   
747         childDn = new LdapDN( "commonName=Jim Bean,ou=Apache,ou=Board of Directors,o=Good Times Co." );
748         childDn.normalize( attributeRegistry.getNormalizerMapping() );
749         
750         parentDn = new LdapDN( "ou=Engineering,o=Good Times Co." );
751         parentDn.normalize( attributeRegistry.getNormalizerMapping() );
752         
753         assertEquals( 3, store.getSubAliasIndex().count() );
754         
755         store.move( childDn, parentDn);
756         
757         assertEquals( 4, store.getSubAliasIndex().count() );
758     }
759     
760     
761     @Test
762     public void testModifyAdd() throws Exception
763     {
764         LdapDN dn = new LdapDN( "cn=JOhnny WAlkeR,ou=Sales,o=Good Times Co." );
765         dn.normalize( attributeRegistry.getNormalizerMapping() );
766 
767         List<Modification> mods = new ArrayList<Modification>();
768         ServerAttribute attrib = new DefaultServerAttribute( SchemaConstants.SURNAME_AT,
769             attributeRegistry.lookup( SchemaConstants.SURNAME_AT ) );
770         
771         String attribVal = "Walker";
772         attrib.add( attribVal );
773         
774         Modification add = new ServerModification( ModificationOperation.ADD_ATTRIBUTE, attrib );
775         mods.add( add );
776         
777         ServerEntry lookedup = store.lookup( store.getEntryId( dn.toNormName() ) );
778 
779         store.modify( dn, mods );
780         assertTrue( lookedup.get( "sn" ).contains( attribVal ) );
781         
782         // testing the store.modify( dn, mod, entry ) API
783         ServerEntry entry = new DefaultServerEntry( registries, dn );
784         attribVal = "+1974045779";
785         entry.add( "telephoneNumber", attribVal );
786         
787         store.modify( dn, ModificationOperation.ADD_ATTRIBUTE, entry );
788         lookedup = store.lookup( store.getEntryId( dn.toNormName() ) );
789         assertTrue( lookedup.get( "telephoneNumber" ).contains( attribVal ) );
790     }
791     
792     
793     @Test
794     public void testModifyReplace() throws Exception
795     {
796         LdapDN dn = new LdapDN( "cn=JOhnny WAlkeR,ou=Sales,o=Good Times Co." );
797         dn.normalize( attributeRegistry.getNormalizerMapping() );
798 
799         List<Modification> mods = new ArrayList<Modification>();
800         ServerAttribute attrib = new DefaultServerAttribute( SchemaConstants.SN_AT,
801             attributeRegistry.lookup( SchemaConstants.SN_AT_OID ) );
802         
803         String attribVal = "Johnny";
804         attrib.add( attribVal );
805         
806         Modification add = new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE, attrib );
807         mods.add( add );
808         
809         ServerEntry lookedup = store.lookup( store.getEntryId( dn.toNormName() ) );
810         
811         assertEquals( "WAlkeR", lookedup.get( "sn" ).get().get() ); // before replacing
812         
813         store.modify( dn, mods );
814         assertEquals( attribVal, lookedup.get( "sn" ).get().get() );
815         
816         // testing the store.modify( dn, mod, entry ) API
817         ServerEntry entry = new DefaultServerEntry( registries, dn );
818         attribVal = "JWalker";
819         entry.add( "sn", attribVal );
820         
821         store.modify( dn, ModificationOperation.REPLACE_ATTRIBUTE, entry );
822         assertEquals( attribVal, lookedup.get( "sn" ).get().get() );
823     }
824     
825     
826     @Test
827     public void testModifyRemove() throws Exception
828     {
829         LdapDN dn = new LdapDN( "cn=JOhnny WAlkeR,ou=Sales,o=Good Times Co." );
830         dn.normalize( attributeRegistry.getNormalizerMapping() );
831 
832         List<Modification> mods = new ArrayList<Modification>();
833         ServerAttribute attrib = new DefaultServerAttribute( SchemaConstants.SN_AT,
834             attributeRegistry.lookup( SchemaConstants.SN_AT_OID ) );
835         
836         Modification add = new ServerModification( ModificationOperation.REMOVE_ATTRIBUTE, attrib );
837         mods.add( add );
838         
839         ServerEntry lookedup = store.lookup( store.getEntryId( dn.toNormName() ) );
840         
841         assertNotNull( lookedup.get( "sn" ).get() );
842         
843         store.modify( dn, mods );
844         assertNull( lookedup.get( "sn" ) );
845         
846         // testing the store.modify( dn, mod, entry ) API
847         ServerEntry entry = new DefaultServerEntry( registries, dn );
848         
849         // add an entry for the sake of testing the remove operation
850         entry.add( "sn", "JWalker" );
851         store.modify( dn, ModificationOperation.ADD_ATTRIBUTE, entry );
852         assertNotNull( lookedup.get( "sn" ) );
853         
854         store.modify( dn, ModificationOperation.REMOVE_ATTRIBUTE, entry );
855         assertNull( lookedup.get( "sn" ) );
856     }
857 
858     
859     @Test
860     public void testModifyReplaceNonExistingIndexAttribute() throws Exception
861     {
862         LdapDN dn = new LdapDN( "cn=Tim B,ou=Sales,o=Good Times Co." );
863         dn.normalize( attributeRegistry.getNormalizerMapping() );
864         DefaultServerEntry entry = new DefaultServerEntry( registries, dn );
865         entry.add( "objectClass", "top", "person", "organizationalPerson" );
866         entry.add( "cn", "Tim B");
867         
868         store.add( dn, entry );
869         
870         List<Modification> mods = new ArrayList<Modification>();
871         ServerAttribute attrib = new DefaultServerAttribute( SchemaConstants.OU_AT,
872             attributeRegistry.lookup( SchemaConstants.OU_AT_OID ) );
873         
874         String attribVal = "Marketing";
875         attrib.add( attribVal );
876         
877         Modification add = new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE, attrib );
878         mods.add( add );
879         
880         ServerEntry lookedup = store.lookup( store.getEntryId( dn.toNormName() ) );
881         
882         assertNull( lookedup.get( "ou" ) ); // before replacing
883         
884         store.modify( dn, mods );
885         assertEquals( attribVal, lookedup.get( "ou" ).get().get() );
886     }
887 }