1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server;
18  
19  import java.util.Hashtable;
20  
21  import javax.naming.NameNotFoundException;
22  import javax.naming.NamingException;
23  import javax.naming.directory.Attribute;
24  import javax.naming.directory.Attributes;
25  import javax.naming.directory.BasicAttribute;
26  import javax.naming.directory.BasicAttributes;
27  import javax.naming.directory.DirContext;
28  import javax.naming.ldap.InitialLdapContext;
29  import javax.naming.ldap.LdapContext;
30  
31  import junit.framework.TestCase;
32  
33  /***
34   * Testcase with different modify DN operations on a person entry.
35   * Originally created to demonstrate DIREVE-173.
36   * 
37   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
38   * @version $Rev$
39   */
40  public class ModifyRdnTest extends AbstractServerTest
41  {
42  
43      private LdapContext ctx = null;
44  
45      /***
46       * Create attributes for a person entry.
47       */
48      protected Attributes getPersonAttributes(String sn, String cn)
49      {
50          Attributes attributes = new BasicAttributes();
51          Attribute attribute = new BasicAttribute("objectClass");
52          attribute.add("top");
53          attribute.add("person");
54          attributes.put(attribute);
55          attributes.put("cn", cn);
56          attributes.put("sn", sn);
57          attributes.put("description", cn + " is a person.");
58  
59          return attributes;
60      }
61  
62      /***
63       * Create context
64       */
65      public void setUp() throws Exception
66      {
67          super.setUp();
68  
69          Hashtable env = new Hashtable();
70          env.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
71          env.put("java.naming.provider.url", "ldap://localhost:" + port + "/ou=system" ); 
72          env.put("java.naming.security.principal", "uid=admin,ou=system" ); 
73          env.put("java.naming.security.credentials", "secret" );
74          env.put("java.naming.security.authentication", "simple");
75  
76          ctx = new InitialLdapContext(env, null);
77  
78          assertNotNull(ctx);
79      }
80  
81      /***
82       * Close context
83       */
84      public void tearDown() throws Exception
85      {
86          ctx.close();
87          ctx = null;
88  
89          super.tearDown();
90      }
91  
92      /***
93       * Just a little test to check wether opening the connection succeeds.
94       */
95      public void testSetUpTearDown() throws NamingException
96      {
97          assertNotNull(ctx);
98      }
99  
100     /***
101      * Modify Rdn of an entry, delete its old rdn value.
102      * 
103      * @throws NamingException
104      */
105     public void testModifyRdnAndDeleteOld() throws NamingException
106     {
107         // Create a person, cn value is rdn
108         String oldCn = "Myra Ellen Amos";
109         String oldRdn = "cn=" + oldCn;
110         Attributes attributes = this.getPersonAttributes("Amos", oldCn);
111         ctx.createSubcontext(oldRdn, attributes);
112 
113         // modify Rdn
114         String newCn = "Tori Amos";
115         String newRdn = "cn=" + newCn;
116         ctx.addToEnvironment("java.naming.ldap.deleteRDN", "true");
117         ctx.rename(oldRdn, newRdn);
118 
119         // Check, whether old Entry does not exists
120         try {
121             ctx.lookup(oldRdn);
122             fail("Entry must not exist");
123         } catch (NameNotFoundException ignored) {
124             // expected behaviour
125             assertTrue(true);
126         }
127 
128         // Check, whether new Entry exists
129         DirContext tori = (DirContext) ctx.lookup(newRdn);
130         assertNotNull(tori);
131 
132         // Check values of cn
133         Attribute cn = tori.getAttributes("").get("cn");
134         assertTrue(cn.contains(newCn));
135         assertTrue(!cn.contains(oldCn)); // old value is gone
136         assertEquals(1, cn.size());
137 
138         // Remove entry (use new rdn)
139         ctx.unbind(newRdn);
140     }
141 
142     /***
143      * Modify Rdn of an entry, keep its old rdn value.
144      * 
145      * @throws NamingException
146      */
147     public void testModifyRdnAndKeepOld() throws NamingException
148     {
149         // Create a person, cn value is rdn
150         String oldCn = "Myra Ellen Amos";
151         String oldRdn = "cn=" + oldCn;
152         Attributes attributes = this.getPersonAttributes("Amos", oldCn);
153         ctx.createSubcontext(oldRdn, attributes);
154 
155         // modify Rdn
156         String newCn = "Tori Amos";
157         String newRdn = "cn=" + newCn;
158         ctx.addToEnvironment("java.naming.ldap.deleteRDN", "false");
159         ctx.rename(oldRdn, newRdn);
160 
161         // Check, whether old entry does not exist
162         try {
163             ctx.lookup(oldRdn);
164             fail("Entry must not exist");
165         } catch (NameNotFoundException ignored) {
166             // expected behaviour
167             assertTrue(true);
168         }
169 
170         // Check, whether new entry exists
171         DirContext tori = (DirContext) ctx.lookup(newRdn);
172         assertNotNull(tori);
173 
174         // Check values of cn
175         Attribute cn = tori.getAttributes("").get("cn");
176         assertTrue(cn.contains(newCn));
177         assertTrue(cn.contains(oldCn)); // old value is still there
178         assertEquals(2, cn.size());
179 
180         // Remove entry (use new rdn)
181         ctx.unbind(newRdn);
182     }
183 
184     /***
185      * Modify Rdn of an entry, delete its old rdn value. Here, the rdn attribute
186      * cn has another value as well.
187      * 
188      * @throws NamingException
189      */
190     public void testModifyRdnAndDeleteOldVariant() throws NamingException
191     {
192         // Create a person, cn value is rdn
193         String oldCn = "Myra Ellen Amos";
194         String oldRdn = "cn=" + oldCn;
195         Attributes attributes = this.getPersonAttributes("Amos", oldCn);
196 
197         // add a second cn value
198         String alternateCn = "Myra E. Amos";
199         Attribute cn = attributes.get("cn");
200         cn.add(alternateCn);
201         assertEquals(2, cn.size());
202 
203         ctx.createSubcontext(oldRdn, attributes);
204 
205         // modify Rdn
206         String newCn = "Tori Amos";
207         String newRdn = "cn=" + newCn;
208         ctx.addToEnvironment("java.naming.ldap.deleteRDN", "true");
209         ctx.rename(oldRdn, newRdn);
210 
211         // Check, whether old Entry does not exist anymore
212         try {
213             ctx.lookup(oldRdn);
214             fail("Entry must not exist");
215         } catch (NameNotFoundException ignored) {
216             // expected behaviour
217             assertTrue(true);
218         }
219 
220         // Check, whether new Entry exists
221         DirContext tori = (DirContext) ctx.lookup(newRdn);
222         assertNotNull(tori);
223 
224         // Check values of cn
225         cn = tori.getAttributes("").get("cn");
226         assertTrue(cn.contains(newCn));
227         assertTrue(!cn.contains(oldCn)); // old value is gone
228         assertTrue(cn.contains(alternateCn)); // alternate value is still available
229         assertEquals(2, cn.size());
230 
231         // Remove entry (use new rdn)
232         ctx.unbind(newRdn);
233     }
234     
235     /***
236      * Modify DN of an entry, changing RDN from cn to sn.
237      * 
238      * @throws NamingException
239      */
240     public void testModifyRdnDifferentAttribute() throws NamingException {
241 
242         // Create a person, cn value is rdn
243         String cnVal = "Tori Amos";
244         String snVal = "Amos";
245         String oldRdn = "cn=" + cnVal;
246         Attributes attributes = this.getPersonAttributes(snVal, cnVal);
247         ctx.createSubcontext(oldRdn, attributes);
248 
249         // modify Rdn from cn=... to sn=...
250         String newRdn = "sn=" + snVal;
251         ctx.addToEnvironment("java.naming.ldap.deleteRDN", "false");
252         ctx.rename(oldRdn, newRdn);
253 
254         // Check, whether old Entry does not exists
255         try {
256             ctx.lookup(oldRdn);
257             fail("Entry must not exist");
258         } catch (NameNotFoundException ignored) {
259             // expected behaviour
260         }
261 
262         // Check, whether new Entry exists
263         DirContext tori = (DirContext) ctx.lookup(newRdn);
264         assertNotNull(tori);
265 
266         // Check values of cn and sn
267         // especially the number of cn and sn occurences
268         Attribute cn = tori.getAttributes("").get("cn");
269         assertTrue(cn.contains(cnVal));
270         assertEquals("Number of cn occurences", 1, cn.size());
271         Attribute sn = tori.getAttributes("").get("sn");
272         assertTrue(sn.contains(snVal));
273         assertEquals("Number of sn occurences", 1, sn.size());
274         
275         // Remove entry (use new rdn)
276         ctx.unbind(newRdn);
277     }
278 }