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.schema;
21  
22  
23  import org.apache.directory.server.constants.MetaSchemaConstants;
24  import org.apache.directory.server.core.DirectoryService;
25  import org.apache.directory.server.core.integ.CiRunner;
26  import static org.apache.directory.server.core.integ.IntegrationUtils.getSchemaContext;
27  import org.apache.directory.server.schema.registries.MatchingRuleRegistry;
28  import org.apache.directory.shared.ldap.constants.SchemaConstants;
29  import org.apache.directory.shared.ldap.exception.LdapInvalidNameException;
30  import org.apache.directory.shared.ldap.message.ResultCodeEnum;
31  import org.apache.directory.shared.ldap.name.LdapDN;
32  import org.apache.directory.shared.ldap.schema.MatchingRule;
33  import static org.junit.Assert.assertEquals;
34  import static org.junit.Assert.assertTrue;
35  import static org.junit.Assert.assertFalse;
36  import static org.junit.Assert.fail;
37  import org.junit.Test;
38  import org.junit.runner.RunWith;
39  
40  import javax.naming.NamingException;
41  import javax.naming.directory.Attribute;
42  import javax.naming.directory.Attributes;
43  import javax.naming.directory.BasicAttribute;
44  import javax.naming.directory.BasicAttributes;
45  import javax.naming.directory.DirContext;
46  import javax.naming.directory.ModificationItem;
47  
48  
49  /**
50   * A test case which tests the addition of various schema elements
51   * to the ldap server.
52   *
53   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
54   * @version $Rev$
55   */
56  @RunWith ( CiRunner.class )
57  public class MetaMatchingRuleHandlerIT
58  {
59      private static final String DESCRIPTION0 = "A test matchingRule";
60      private static final String DESCRIPTION1 = "An alternate description";
61  
62      private static final String INTEGER_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.27";
63      private static final String DIRSTR_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.15";
64      
65      private static final String OID = "1.3.6.1.4.1.18060.0.4.0.1.100000";
66      private static final String NEW_OID = "1.3.6.1.4.1.18060.0.4.0.1.100001";
67  
68  
69      public static DirectoryService service;
70  
71  
72      private static MatchingRuleRegistry getMatchingRuleRegistry()
73      {
74          return service.getRegistries().getMatchingRuleRegistry();
75      }
76      
77      
78      /**
79       * Gets relative DN to ou=schema.
80       * 
81       * @param schemaName the name of the schema
82       * @return  the dn of the container of matchingRules for a schema
83       * @throws Exception on error
84       */
85      private LdapDN getMatchingRuleContainer( String schemaName ) throws Exception
86      {
87          return new LdapDN( "ou=matchingRules,cn=" + schemaName );
88      }
89      
90      
91      // ----------------------------------------------------------------------
92      // Test all core methods with normal operational pathways
93      // ----------------------------------------------------------------------
94  
95  
96      @Test
97      public void testAddMatchingRule() throws Exception
98      {
99          Attributes attrs = new BasicAttributes( true );
100         Attribute oc = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT, "top" );
101         oc.add( MetaSchemaConstants.META_TOP_OC );
102         oc.add( MetaSchemaConstants.META_MATCHING_RULE_OC );
103         attrs.put( oc );
104         attrs.put( MetaSchemaConstants.M_OID_AT, OID );
105         attrs.put( MetaSchemaConstants.M_SYNTAX_AT, INTEGER_SYNTAX_OID );
106         attrs.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION0 );
107         
108         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
109         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
110         getSchemaContext( service ).createSubcontext( dn, attrs );
111         
112         assertTrue( getMatchingRuleRegistry().hasMatchingRule( OID ) );
113         assertEquals( getMatchingRuleRegistry().getSchemaName( OID ), "apachemeta" );
114     }
115     
116 
117     @Test
118     public void testDeleteMatchingRule() throws Exception
119     {
120         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
121         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
122         testAddMatchingRule();
123         
124         getSchemaContext( service ).destroySubcontext( dn );
125 
126         assertFalse( "matchingRule should be removed from the registry after being deleted", 
127             getMatchingRuleRegistry().hasMatchingRule( OID ) );
128         
129         try
130         {
131             getMatchingRuleRegistry().lookup( OID );
132             fail( "matchingRule lookup should fail after deleting it" );
133         }
134         catch( NamingException e )
135         {
136         }
137     }
138 
139 
140     @Test
141     public void testRenameMatchingRule() throws Exception
142     {
143         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
144         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
145         testAddMatchingRule();
146         
147         LdapDN newdn = getMatchingRuleContainer( "apachemeta" );
148         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
149         getSchemaContext( service ).rename( dn, newdn );
150 
151         assertFalse( "old matchingRule OID should be removed from the registry after being renamed", 
152             getMatchingRuleRegistry().hasMatchingRule( OID ) );
153         
154         try
155         {
156             getMatchingRuleRegistry().lookup( OID );
157             fail( "matchingRule lookup should fail after renaming the matchingRule" );
158         }
159         catch( NamingException e )
160         {
161         }
162 
163         assertTrue( getMatchingRuleRegistry().hasMatchingRule( NEW_OID ) );
164     }
165 
166 
167     @Test
168     public void testMoveMatchingRule() throws Exception
169     {
170         testAddMatchingRule();
171         
172         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
173         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
174 
175         LdapDN newdn = getMatchingRuleContainer( "apache" );
176         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
177         
178         getSchemaContext( service ).rename( dn, newdn );
179 
180         assertTrue( "matchingRule OID should still be present", 
181             getMatchingRuleRegistry().hasMatchingRule( OID ) );
182         
183         assertEquals( "matchingRule schema should be set to apache not apachemeta", 
184             getMatchingRuleRegistry().getSchemaName( OID ), "apache" );
185     }
186 
187 
188     @Test
189     public void testMoveMatchingRuleAndChangeRdn() throws Exception
190     {
191         testAddMatchingRule();
192         
193         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
194         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
195 
196         LdapDN newdn = getMatchingRuleContainer( "apache" );
197         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
198         
199         getSchemaContext( service ).rename( dn, newdn );
200 
201         assertFalse( "old matchingRule OID should NOT be present", 
202             getMatchingRuleRegistry().hasMatchingRule( OID ) );
203         
204         assertTrue( "new matchingRule OID should be present", 
205             getMatchingRuleRegistry().hasMatchingRule( NEW_OID ) );
206         
207         assertEquals( "matchingRule with new oid should have schema set to apache NOT apachemeta", 
208             getMatchingRuleRegistry().getSchemaName( NEW_OID ), "apache" );
209     }
210 
211 
212     @Test
213     public void testModifyMatchingRuleWithModificationItems() throws Exception
214     {
215         testAddMatchingRule();
216         
217         MatchingRule mr = getMatchingRuleRegistry().lookup( OID );
218         assertEquals( mr.getDescription(), DESCRIPTION0 );
219         assertEquals( mr.getSyntax().getOid(), INTEGER_SYNTAX_OID );
220 
221         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
222         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
223         
224         ModificationItem[] mods = new ModificationItem[2];
225         Attribute attr = new BasicAttribute( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION1 );
226         mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
227         attr = new BasicAttribute( MetaSchemaConstants.M_SYNTAX_AT, DIRSTR_SYNTAX_OID );
228         mods[1] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
229         getSchemaContext( service ).modifyAttributes( dn, mods );
230 
231         assertTrue( "matchingRule OID should still be present", 
232             getMatchingRuleRegistry().hasMatchingRule( OID ) );
233         
234         assertEquals( "matchingRule schema should be set to apachemeta", 
235             getMatchingRuleRegistry().getSchemaName( OID ), "apachemeta" );
236         
237         mr = getMatchingRuleRegistry().lookup( OID );
238         assertEquals( mr.getDescription(), DESCRIPTION1 );
239         assertEquals( mr.getSyntax().getOid(), DIRSTR_SYNTAX_OID );
240     }
241 
242     
243     @Test
244     public void testModifyMatchingRuleWithAttributes() throws Exception
245     {
246         testAddMatchingRule();
247         
248         MatchingRule mr = getMatchingRuleRegistry().lookup( OID );
249         assertEquals( mr.getDescription(), DESCRIPTION0 );
250         assertEquals( mr.getSyntax().getOid(), INTEGER_SYNTAX_OID );
251 
252         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
253         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
254         
255         Attributes mods = new BasicAttributes( true );
256         mods.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION1 );
257         mods.put( MetaSchemaConstants.M_SYNTAX_AT, DIRSTR_SYNTAX_OID );
258         getSchemaContext( service ).modifyAttributes( dn, DirContext.REPLACE_ATTRIBUTE, mods );
259 
260         assertTrue( "matchingRule OID should still be present", 
261             getMatchingRuleRegistry().hasMatchingRule( OID ) );
262         
263         assertEquals( "matchingRule schema should be set to apachemeta", 
264             getMatchingRuleRegistry().getSchemaName( OID ), "apachemeta" );
265 
266         mr = getMatchingRuleRegistry().lookup( OID );
267         assertEquals( mr.getDescription(), DESCRIPTION1 );
268         assertEquals( mr.getSyntax().getOid(), DIRSTR_SYNTAX_OID );
269     }
270     
271 
272     // ----------------------------------------------------------------------
273     // Test move, rename, and delete when a MR exists and uses the Normalizer
274     // ----------------------------------------------------------------------
275 
276     
277 //    public void testDeleteSyntaxWhenInUse() throws NamingException
278 //    {
279 //        LdapDN dn = getSyntaxContainer( "apachemeta" );
280 //        dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
281 //        testAddSyntax();
282 //        addDependeeMatchingRule();
283 //        
284 //        try
285 //        {
286 //            super.schemaRoot.destroySubcontext( dn );
287 //            fail( "should not be able to delete a syntax in use" );
288 //        }
289 //        catch( LdapOperationNotSupportedException e ) 
290 //        {
291 //            assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
292 //        }
293 //
294 //        assertTrue( "syntax should still be in the registry after delete failure", 
295 //            registries.getSyntaxRegistry().hasSyntax( OID ) );
296 //    }
297 //    
298 //    
299 //    public void testMoveSyntaxWhenInUse() throws NamingException
300 //    {
301 //        testAddSyntax();
302 //        addDependeeMatchingRule();
303 //        
304 //        LdapDN dn = getSyntaxContainer( "apachemeta" );
305 //        dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
306 //
307 //        LdapDN newdn = getSyntaxContainer( "apache" );
308 //        newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
309 //        
310 //        try
311 //        {
312 //            super.schemaRoot.rename( dn, newdn );
313 //            fail( "should not be able to move a syntax in use" );
314 //        }
315 //        catch( LdapOperationNotSupportedException e ) 
316 //        {
317 //            assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
318 //        }
319 //
320 //        assertTrue( "syntax should still be in the registry after move failure", 
321 //            registries.getSyntaxRegistry().hasSyntax( OID ) );
322 //    }
323 //
324 //
325 //    public void testMoveSyntaxAndChangeRdnWhenInUse() throws NamingException
326 //    {
327 //        testAddSyntax();
328 //        addDependeeMatchingRule()
329 //        
330 //        LdapDN dn = getSyntaxContainer( "apachemeta" );
331 //        dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );s
332 //
333 //        LdapDN newdn = getSyntaxContainer( "apache" );
334 //        newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
335 //        
336 //        try
337 //        {
338 //            super.schemaRoot.rename( dn, newdn );
339 //            fail( "should not be able to move a syntax in use" );
340 //        }
341 //        catch( LdapOperationNotSupportedException e ) 
342 //        {
343 //            assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
344 //        }
345 //
346 //        assertTrue( "syntax should still be in the registry after move failure", 
347 //            registries.getSyntaxRegistry().hasSyntax( OID ) );
348 //    }
349 //
350 //    
351 
352     // Need to add body to this method which creates a new matchingRule after 
353     // the matchingRule addition code has been added.
354     
355 //    private void addDependeeMatchingRule()
356 //    {
357 //        throw new NotImplementedException();
358 //    }
359 //    
360 //    public void testRenameNormalizerWhenInUse() throws NamingException
361 //    {
362 //        LdapDN dn = getSyntaxContainer( "apachemeta" );
363 //        dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
364 //        testAddSyntax();
365 //        addDependeeMatchingRule();
366 //        
367 //        LdapDN newdn = getSyntaxContainer( "apachemeta" );
368 //        newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
369 //        
370 //        try
371 //        {
372 //            super.schemaRoot.rename( dn, newdn );
373 //            fail( "should not be able to rename a syntax in use" );
374 //        }
375 //        catch( LdapOperationNotSupportedException e ) 
376 //        {
377 //            assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
378 //        }
379 //
380 //        assertTrue( "syntax should still be in the registry after rename failure", 
381 //            registries.getSyntaxRegistry().hasSyntax( OID ) );
382 //    }
383 
384 
385     // ----------------------------------------------------------------------
386     // Let's try some freaky stuff
387     // ----------------------------------------------------------------------
388 
389 
390     @Test
391     public void testMoveMatchingRuleToTop() throws Exception
392     {
393         testAddMatchingRule();
394         
395         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
396         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
397 
398         LdapDN top = new LdapDN();
399         top.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
400         
401         try
402         {
403             getSchemaContext( service ).rename( dn, top );
404             fail( "should not be able to move a matchingRule up to ou=schema" );
405         }
406         catch( LdapInvalidNameException e ) 
407         {
408             assertEquals( e.getResultCode(), ResultCodeEnum.NAMING_VIOLATION );
409         }
410 
411         assertTrue( "matchingRule should still be in the registry after move failure", 
412             getMatchingRuleRegistry().hasMatchingRule( OID ) );
413     }
414 
415 
416     @Test
417     public void testMoveMatchingRuleToComparatorContainer() throws Exception
418     {
419         testAddMatchingRule();
420         
421         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
422         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
423 
424         LdapDN newdn = new LdapDN( "ou=comparators,cn=apachemeta" );
425         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
426         
427         try
428         {
429             getSchemaContext( service ).rename( dn, newdn );
430             fail( "should not be able to move a matchingRule into comparators container" );
431         }
432         catch( LdapInvalidNameException e ) 
433         {
434             assertEquals( e.getResultCode(), ResultCodeEnum.NAMING_VIOLATION );
435         }
436 
437         assertTrue( "matchingRule should still be in the registry after move failure", 
438             getMatchingRuleRegistry().hasMatchingRule( OID ) );
439     }
440     
441     
442     @Test
443     public void testAddMatchingRuleToDisabledSchema() throws Exception
444     {
445         Attributes attrs = new BasicAttributes( true );
446         Attribute oc = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT, "top" );
447         oc.add( MetaSchemaConstants.META_TOP_OC );
448         oc.add( MetaSchemaConstants.META_MATCHING_RULE_OC );
449         attrs.put( oc );
450         attrs.put( MetaSchemaConstants.M_OID_AT, OID );
451         attrs.put( MetaSchemaConstants.M_SYNTAX_AT, INTEGER_SYNTAX_OID );
452         attrs.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION0 );
453         
454         LdapDN dn = getMatchingRuleContainer( "nis" );
455         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
456         getSchemaContext( service ).createSubcontext( dn, attrs );
457         
458         assertFalse( "adding new matchingRule to disabled schema should not register it into the registries", 
459             getMatchingRuleRegistry().hasMatchingRule( OID ) );
460     }
461 
462 
463     @Test
464     public void testMoveMatchingRuleToDisabledSchema() throws Exception
465     {
466         testAddMatchingRule();
467         
468         LdapDN dn = getMatchingRuleContainer( "apachemeta" );
469         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
470 
471         // nis is inactive by default
472         LdapDN newdn = getMatchingRuleContainer( "nis" );
473         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
474         
475         getSchemaContext( service ).rename( dn, newdn );
476 
477         assertFalse( "matchingRule OID should no longer be present", 
478             getMatchingRuleRegistry().hasMatchingRule( OID ) );
479     }
480 
481 
482     @Test
483     public void testMoveMatchingRuleToEnabledSchema() throws Exception
484     {
485         testAddMatchingRuleToDisabledSchema();
486         
487         // nis is inactive by default
488         LdapDN dn = getMatchingRuleContainer( "nis" );
489         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
490 
491         assertFalse( "matchingRule OID should NOT be present when added to disabled nis schema", 
492             getMatchingRuleRegistry().hasMatchingRule( OID ) );
493 
494         LdapDN newdn = getMatchingRuleContainer( "apachemeta" );
495         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
496         
497         getSchemaContext( service ).rename( dn, newdn );
498 
499         assertTrue( "matchingRule OID should be present when moved to enabled schema", 
500             getMatchingRuleRegistry().hasMatchingRule( OID ) );
501         
502         assertEquals( "matchingRule should be in apachemeta schema after move", 
503             getMatchingRuleRegistry().getSchemaName( OID ), "apachemeta" );
504     }
505 }