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  package org.apache.directory.server.core.partition.impl.btree.jdbm;
20  
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  import org.apache.directory.server.xdbm.Table;
25  import org.apache.directory.server.xdbm.Tuple;
26  import org.apache.directory.server.core.cursor.Cursor;
27  import org.apache.directory.server.core.cursor.InvalidCursorPositionException;
28  import org.apache.directory.server.schema.SerializableComparator;
29  import org.apache.directory.server.schema.registries.ComparatorRegistry;
30  import org.apache.directory.shared.ldap.schema.syntax.ComparatorDescription;
31  import org.junit.Before;
32  import org.junit.After;
33  import org.junit.Test;
34  
35  import static org.junit.Assert.*;
36  
37  import java.io.File;
38  import java.util.Comparator;
39  import java.util.Iterator;
40  
41  import jdbm.RecordManager;
42  import jdbm.recman.BaseRecordManager;
43  
44  import javax.naming.NamingException;
45  
46  
47  /**
48   * Tests the Cursor functionality of a JdbmTable when duplicate keys are not
49   * supported.
50   *
51   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52   * @version $Rev$, $Date$
53   */
54  public class NoDupsCursorTest
55  {
56      private static final Logger LOG = LoggerFactory.getLogger( NoDupsCursorTest.class.getSimpleName() );
57      private static final String TEST_OUTPUT_PATH = "test.output.path";
58  
59      transient Table<Integer,Integer> table;
60      transient File dbFile;
61      transient RecordManager recman;
62  
63  
64      @Before
65      public void createTable() throws Exception
66      {
67          File tmpDir = null;
68          if ( System.getProperty( TEST_OUTPUT_PATH, null ) != null )
69          {
70              tmpDir = new File( System.getProperty( TEST_OUTPUT_PATH ) );
71          }
72  
73          dbFile = File.createTempFile( getClass().getSimpleName(), "db", tmpDir );
74          recman = new BaseRecordManager( dbFile.getAbsolutePath() );
75  
76          // gosh this is a terrible use of a global static variable
77          SerializableComparator.setRegistry( new MockComparatorRegistry() );
78          table = new JdbmTable<Integer,Integer>( "test", recman, new SerializableComparator<Integer>( "" ), null, null );
79          LOG.debug( "Created new table and populated it with data" );
80      }
81  
82  
83      @After
84      public void destryTable() throws Exception
85      {
86          table.close();
87          table = null;
88          recman.close();
89          recman = null;
90          dbFile.deleteOnExit();
91          String fileToDelete = dbFile.getAbsolutePath();
92          new File( fileToDelete + ".db" ).delete();
93          new File( fileToDelete + ".lg" ).delete();
94          dbFile = null;
95      }
96  
97  
98      @Test( expected=InvalidCursorPositionException.class )
99      public void testEmptyTable() throws Exception
100     {
101         Cursor<Tuple<Integer,Integer>> cursor = table.cursor();
102         assertNotNull( cursor );
103         
104         assertFalse( cursor.available() );
105         assertFalse( cursor.isClosed() );
106         assertTrue( cursor.isElementReused() );
107 
108         cursor = table.cursor();
109         assertFalse( cursor.previous() );
110 
111         cursor = table.cursor();
112         assertFalse( cursor.next() );
113 
114         cursor.after( new Tuple<Integer,Integer>(7,7) );
115         cursor.get();
116     }
117 
118 
119     @Test
120     public void testOnTableWithSingleEntry() throws Exception
121     {
122         table.put( 1, 1 );
123         Cursor<Tuple<Integer,Integer>> cursor = table.cursor();
124         assertTrue( cursor.first() );
125     
126         Tuple<Integer,Integer> tuple = cursor.get();
127         assertTrue( tuple.getKey().equals( 1 ) );
128         assertTrue( tuple.getValue().equals( 1 ) );
129     
130         cursor.beforeFirst();
131         assertFalse( cursor.previous() );
132         assertTrue( cursor.next() );
133     }
134 
135     
136     @Test
137     public void testOnTableWithMultipleEntries() throws Exception
138     {
139         for( int i=1; i < 10; i++ )
140         {
141             table.put( i, i );
142         }
143     
144         Cursor<Tuple<Integer,Integer>> cursor = table.cursor();
145         
146         cursor.after( new Tuple<Integer,Integer>( 2,2 ) );
147         assertTrue( cursor.next() );
148     
149         Tuple<Integer,Integer> tuple = cursor.get();
150         assertTrue( tuple.getKey().equals( 3 ) );
151         assertTrue( tuple.getValue().equals( 3 ) );
152     
153         cursor.before( new Tuple<Integer,Integer>(7,7) );
154         cursor.next();
155         tuple = cursor.get();
156         assertTrue( tuple.getKey().equals( 7 ) );
157         assertTrue( tuple.getValue().equals( 7 ) );
158     
159         cursor.last();
160         cursor.next();
161         tuple = cursor.get();
162         assertTrue( tuple.getKey().equals( 9 ) );
163         assertTrue( tuple.getValue().equals( 9 ) );
164     
165         cursor.beforeFirst();
166         cursor.next();
167         tuple = cursor.get();
168         assertTrue( tuple.getKey().equals( 1 ) );
169         assertTrue( tuple.getValue().equals( 1 ) );
170     
171         cursor.afterLast();
172         assertFalse( cursor.next() );
173 
174         cursor.beforeFirst();
175         assertFalse( cursor.previous() );
176         
177         // just to clear the jdbmTuple value so that line 127 inside after(tuple) method
178         // can be executed as part of the below after(tuple) call
179         cursor.before(new Tuple<Integer,Integer>( 1,1 )); 
180         cursor.after( new Tuple<Integer,Integer>( 0,0 ) );
181         
182         cursor.next();
183         tuple = cursor.get();
184         assertTrue( tuple.getKey().equals( 1 ) );
185         assertTrue( tuple.getValue().equals( 1 ) );
186     }
187     
188 
189     @Test
190     public void testJdbmBrowserSwitch() throws Exception
191     {
192         for( int i=1; i < 10; i++ )
193         {
194             table.put( i, i );
195         }
196     
197         Cursor<Tuple<Integer,Integer>> cursor = table.cursor();
198         
199         // go to last and call next then previous twice then next
200         cursor.afterLast();
201         assertFalse( cursor.next() );
202         assertTrue( cursor.previous() );
203         assertEquals( 9, ( int ) cursor.get().getKey() );
204         
205         assertTrue( cursor.previous() );
206         assertEquals( 8, ( int ) cursor.get().getKey() );
207 
208         assertTrue( cursor.next() );
209          assertEquals( 9, ( int ) cursor.get().getKey() );
210  
211         
212         // go to last and call previous then next and again previous 
213         cursor.afterLast();
214         assertTrue( cursor.previous() );
215         assertEquals( 9, ( int ) cursor.get().getKey() );
216         
217         assertTrue( cursor.next() );
218         assertEquals( 9, ( int ) cursor.get().getKey() );
219         
220         assertTrue( cursor.previous() );
221         assertEquals( 8, ( int ) cursor.get().getKey() );
222         
223         
224         // go to first and call previous then next twice and again next
225         cursor.beforeFirst();
226         assertFalse( cursor.previous() );
227         assertTrue( cursor.next() );
228         assertEquals( 1, ( int ) cursor.get().getKey() );
229 
230         assertTrue( cursor.next() );
231         assertEquals( 2, ( int ) cursor.get().getKey() );
232         
233         assertTrue( cursor.previous() );
234         assertEquals( 1, ( int ) cursor.get().getKey() );
235 
236 
237         // go to first and call next twice then previous
238         cursor.beforeFirst();
239         assertTrue( cursor.next() );
240         assertEquals( 1, ( int ) cursor.get().getKey() );
241 
242         assertTrue( cursor.next() );
243         assertEquals( 2, ( int ) cursor.get().getKey() );
244         
245         assertTrue( cursor.previous() );
246         assertEquals( 1, ( int ) cursor.get().getKey() );
247 
248     }
249     
250     
251     @Test
252     public void testMiscellaneous() throws Exception
253     {
254     }
255 
256 
257     private class MockComparatorRegistry implements ComparatorRegistry
258     {
259         private Comparator<Integer> comparator = new Comparator<Integer>()
260         {
261             public int compare( Integer i1, Integer i2 )
262             {
263                 return i1.compareTo( i2 );
264             }
265         };
266 
267         public String getSchemaName( String oid ) throws NamingException
268         {
269             return null;
270         }
271 
272 
273         public void register( ComparatorDescription description, Comparator comparator ) throws NamingException
274         {
275         }
276 
277 
278         public Comparator lookup( String oid ) throws NamingException
279         {
280             return comparator;
281         }
282 
283 
284         public boolean hasComparator( String oid )
285         {
286             return true;
287         }
288 
289 
290         public Iterator<String> oidIterator()
291         {
292             return null;
293         }
294 
295 
296         public Iterator<ComparatorDescription> comparatorDescriptionIterator()
297         {
298             return null;
299         }
300 
301 
302         public void unregister( String oid ) throws NamingException
303         {
304         }
305 
306 
307         public void unregisterSchemaElements( String schemaName )
308         {
309         }
310 
311 
312         public void renameSchema( String originalSchemaName, String newSchemaName )
313         {
314         }
315     }
316 }