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.operations.search;
21  
22  
23  import java.util.HashSet;
24  import java.util.Set;
25  
26  import javax.naming.NamingEnumeration;
27  import javax.naming.directory.SearchControls;
28  import javax.naming.directory.SearchResult;
29  
30  import org.apache.directory.server.core.integ.Level;
31  import org.apache.directory.server.core.integ.annotations.ApplyLdifs;
32  import org.apache.directory.server.core.integ.annotations.CleanupLevel;
33  import org.apache.directory.server.core.integ.annotations.Factory;
34  import org.apache.directory.server.integ.SiRunner;
35  import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
36  
37  import org.apache.directory.server.ldap.LdapService;
38  import org.junit.Test;
39  import org.junit.runner.RunWith;
40  
41  import javax.naming.directory.DirContext;
42  
43  import static org.junit.Assert.assertTrue;
44  import static org.junit.Assert.assertEquals;
45  import static org.junit.Assert.assertFalse;
46  
47  
48  /**
49   * A set of tests to make sure the negation operator is working 
50   * properly when included in search filters. Created in response
51   * to JIRA issue 
52   * <a href="https://issues.apache.org/jira/browse/DIRSERVER-951">DIRSERVER-951</a>.
53   * 
54   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
55   * @version $Rev: 519077 $
56   */
57  @RunWith ( SiRunner.class ) 
58  @CleanupLevel ( Level.SUITE )
59  @Factory ( IndexedNegationSearchIT.Factory.class )
60  @ApplyLdifs( {
61      "dn: ou=actors,ou=system\n" +
62      "objectClass: top\n" +
63      "objectClass: organizationalUnit\n" +
64      "ou: actors\n\n" +
65  
66      "dn: uid=jblack,ou=actors,ou=system\n" +
67      "objectClass: top\n" +
68      "objectClass: person\n" +
69      "objectClass: organizationalPerson\n" +
70      "objectClass: uidObject\n" +
71      "uid: jblack\n" +
72      "ou: comedy\n" +
73      "ou: adventure\n" +
74      "cn: Jack Black\n" +
75      "sn: Black\n\n" +
76  
77      "dn: uid=bpitt,ou=actors,ou=system\n" +
78      "objectClass: top\n" +
79      "objectClass: person\n" +
80      "objectClass: organizationalPerson\n" +
81      "objectClass: uidObject\n" +
82      "uid: bpitt\n" +
83      "ou: drama\n" +
84      "ou: adventure\n" +
85      "cn: Brad Pitt\n" +
86      "sn: Pitt\n\n" +
87  
88      "dn: uid=gcloony,ou=actors,ou=system\n" +
89      "objectClass: top\n" +
90      "objectClass: person\n" +
91      "objectClass: organizationalPerson\n" +
92      "objectClass: uidObject\n" +
93      "uid: gcloony\n" +
94      "ou: drama\n" +
95      "cn: Goerge Cloony\n" +
96      "sn: Cloony\n\n" +
97  
98      "dn: uid=jnewbie,ou=actors,ou=system\n" +
99      "objectClass: top\n" +
100     "objectClass: person\n" +
101     "objectClass: organizationalPerson\n" +
102     "objectClass: uidObject\n" +
103     "uid: jnewbie\n" +
104     "cn: Joe Newbie\n" +
105     "sn: Newbie\n\n" 
106 
107     }
108 )
109 public class NegationSearchIT 
110 {
111     public static LdapService ldapService;
112 
113     
114     /**
115      * Tests to make sure a negated search for actors without ou
116      * with value 'drama' returns those that do not have the attribute
117      * and do not have a 'drama' value for ou if the attribute still
118      * exists.  This test does not build an index on ou for the system
119      * partition.
120      */
121     @Test
122     public void testSearchNotDrama() throws Exception
123     {
124         // jack black has ou but not drama, and joe newbie has no ou what so ever
125         Set<SearchResult> results = getResults( "(!(ou=drama))" );
126         assertTrue( contains( "uid=jblack,ou=actors,ou=system", results ) );
127         assertTrue( contains( "uid=jnewbie,ou=actors,ou=system", results ) );
128         assertEquals( 2, results.size() );
129     }
130 
131     
132     /**
133      * Tests to make sure a negated search for actors without ou
134      * with value 'drama' returns those that do not have the attribute
135      * and do not have a 'drama' value for ou if the attribute still
136      * exists.  This test does not build an index on ou for the system
137      * partition.
138      */
139     @Test
140     public void testSearchNotDramaNotNewbie() throws Exception
141     {
142         // jack black has ou but not drama, and joe newbie has no ou what so ever
143         Set<SearchResult> results = getResults( "(& (!(uid=jnewbie)) (!(ou=drama)) )" );
144         assertTrue( contains( "uid=jblack,ou=actors,ou=system", results ) );
145         assertFalse( contains( "uid=jnewbie,ou=actors,ou=system", results ) );
146         assertEquals( 1, results.size() );
147     }
148 
149     
150     boolean contains( String dn, Set<SearchResult> results )
151     {
152         for ( SearchResult result : results )
153         {
154             if ( result.getNameInNamespace().equals( dn ) )
155             {
156                 return true;
157             }
158         }
159         
160         return false;
161     }
162     
163     
164     Set<SearchResult> getResults( String filter ) throws Exception
165     {
166         DirContext ctx = getWiredContext( ldapService );
167         Set<SearchResult> results = new HashSet<SearchResult>();
168         SearchControls controls = new SearchControls();
169         controls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
170         NamingEnumeration<SearchResult> namingEnumeration = ctx.search( "ou=actors,ou=system", filter, controls );
171         while( namingEnumeration.hasMore() )
172         {
173             results.add( namingEnumeration.next() );
174         }
175         
176         return results;
177     }
178 }