add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / backwards / src / test / org / apache / lucene / index / TestCompoundFile.java
1 package org.apache.lucene.index;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.IOException;
21 import java.io.File;
22
23 import org.apache.lucene.util.LuceneTestCase;
24 import junit.framework.TestSuite;
25 import junit.textui.TestRunner;
26 import org.apache.lucene.store.IndexOutput;
27 import org.apache.lucene.store.Directory;
28 import org.apache.lucene.store.IndexInput;
29 import org.apache.lucene.store.SimpleFSDirectory;
30 import org.apache.lucene.store._TestHelper;
31 import org.apache.lucene.util._TestUtil;
32
33
34 public class TestCompoundFile extends LuceneTestCase
35 {
36     /** Main for running test case by itself. */
37     public static void main(String args[]) {
38         TestRunner.run (new TestSuite(TestCompoundFile.class));
39 //        TestRunner.run (new TestCompoundFile("testSingleFile"));
40 //        TestRunner.run (new TestCompoundFile("testTwoFiles"));
41 //        TestRunner.run (new TestCompoundFile("testRandomFiles"));
42 //        TestRunner.run (new TestCompoundFile("testClonedStreamsClosing"));
43 //        TestRunner.run (new TestCompoundFile("testReadAfterClose"));
44 //        TestRunner.run (new TestCompoundFile("testRandomAccess"));
45 //        TestRunner.run (new TestCompoundFile("testRandomAccessClones"));
46 //        TestRunner.run (new TestCompoundFile("testFileNotFound"));
47 //        TestRunner.run (new TestCompoundFile("testReadPastEOF"));
48
49 //        TestRunner.run (new TestCompoundFile("testIWCreate"));
50
51     }
52
53
54     private Directory dir;
55
56
57     @Override
58     public void setUp() throws Exception {
59        super.setUp();
60        File file = _TestUtil.getTempDir("testIndex");
61        // use a simple FSDir here, to be sure to have SimpleFSInputs
62        dir = new SimpleFSDirectory(file,null);
63     }
64
65     @Override
66     public void tearDown() throws Exception {
67        dir.close();
68        super.tearDown();
69     }
70
71     /** Creates a file of the specified size with random data. */
72     private void createRandomFile(Directory dir, String name, int size)
73     throws IOException
74     {
75         IndexOutput os = dir.createOutput(name);
76         for (int i=0; i<size; i++) {
77             byte b = (byte) (Math.random() * 256);
78             os.writeByte(b);
79         }
80         os.close();
81     }
82
83     /** Creates a file of the specified size with sequential data. The first
84      *  byte is written as the start byte provided. All subsequent bytes are
85      *  computed as start + offset where offset is the number of the byte.
86      */
87     private void createSequenceFile(Directory dir,
88                                     String name,
89                                     byte start,
90                                     int size)
91     throws IOException
92     {
93         IndexOutput os = dir.createOutput(name);
94         for (int i=0; i < size; i++) {
95             os.writeByte(start);
96             start ++;
97         }
98         os.close();
99     }
100
101
102     private void assertSameStreams(String msg,
103                                    IndexInput expected,
104                                    IndexInput test)
105     throws IOException
106     {
107         assertNotNull(msg + " null expected", expected);
108         assertNotNull(msg + " null test", test);
109         assertEquals(msg + " length", expected.length(), test.length());
110         assertEquals(msg + " position", expected.getFilePointer(),
111                                         test.getFilePointer());
112
113         byte expectedBuffer[] = new byte[512];
114         byte testBuffer[] = new byte[expectedBuffer.length];
115
116         long remainder = expected.length() - expected.getFilePointer();
117         while(remainder > 0) {
118             int readLen = (int) Math.min(remainder, expectedBuffer.length);
119             expected.readBytes(expectedBuffer, 0, readLen);
120             test.readBytes(testBuffer, 0, readLen);
121             assertEqualArrays(msg + ", remainder " + remainder, expectedBuffer,
122                 testBuffer, 0, readLen);
123             remainder -= readLen;
124         }
125     }
126
127
128     private void assertSameStreams(String msg,
129                                    IndexInput expected,
130                                    IndexInput actual,
131                                    long seekTo)
132     throws IOException
133     {
134         if(seekTo >= 0 && seekTo < expected.length())
135         {
136             expected.seek(seekTo);
137             actual.seek(seekTo);
138             assertSameStreams(msg + ", seek(mid)", expected, actual);
139         }
140     }
141
142
143
144     private void assertSameSeekBehavior(String msg,
145                                         IndexInput expected,
146                                         IndexInput actual)
147     throws IOException
148     {
149         // seek to 0
150         long point = 0;
151         assertSameStreams(msg + ", seek(0)", expected, actual, point);
152
153         // seek to middle
154         point = expected.length() / 2l;
155         assertSameStreams(msg + ", seek(mid)", expected, actual, point);
156
157         // seek to end - 2
158         point = expected.length() - 2;
159         assertSameStreams(msg + ", seek(end-2)", expected, actual, point);
160
161         // seek to end - 1
162         point = expected.length() - 1;
163         assertSameStreams(msg + ", seek(end-1)", expected, actual, point);
164
165         // seek to the end
166         point = expected.length();
167         assertSameStreams(msg + ", seek(end)", expected, actual, point);
168
169         // seek past end
170         point = expected.length() + 1;
171         assertSameStreams(msg + ", seek(end+1)", expected, actual, point);
172     }
173
174
175     private void assertEqualArrays(String msg,
176                                    byte[] expected,
177                                    byte[] test,
178                                    int start,
179                                    int len)
180     {
181         assertNotNull(msg + " null expected", expected);
182         assertNotNull(msg + " null test", test);
183
184         for (int i=start; i<len; i++) {
185             assertEquals(msg + " " + i, expected[i], test[i]);
186         }
187     }
188
189
190     // ===========================================================
191     //  Tests of the basic CompoundFile functionality
192     // ===========================================================
193
194
195     /** This test creates compound file based on a single file.
196      *  Files of different sizes are tested: 0, 1, 10, 100 bytes.
197      */
198     public void testSingleFile() throws IOException {
199         int data[] = new int[] { 0, 1, 10, 100 };
200         for (int i=0; i<data.length; i++) {
201             String name = "t" + data[i];
202             createSequenceFile(dir, name, (byte) 0, data[i]);
203             CompoundFileWriter csw = new CompoundFileWriter(dir, name + ".cfs");
204             csw.addFile(name);
205             csw.close();
206
207             CompoundFileReader csr = new CompoundFileReader(dir, name + ".cfs");
208             IndexInput expected = dir.openInput(name);
209             IndexInput actual = csr.openInput(name);
210             assertSameStreams(name, expected, actual);
211             assertSameSeekBehavior(name, expected, actual);
212             expected.close();
213             actual.close();
214             csr.close();
215         }
216     }
217
218
219     /** This test creates compound file based on two files.
220      *
221      */
222     public void testTwoFiles() throws IOException {
223         createSequenceFile(dir, "d1", (byte) 0, 15);
224         createSequenceFile(dir, "d2", (byte) 0, 114);
225
226         CompoundFileWriter csw = new CompoundFileWriter(dir, "d.csf");
227         csw.addFile("d1");
228         csw.addFile("d2");
229         csw.close();
230
231         CompoundFileReader csr = new CompoundFileReader(dir, "d.csf");
232         IndexInput expected = dir.openInput("d1");
233         IndexInput actual = csr.openInput("d1");
234         assertSameStreams("d1", expected, actual);
235         assertSameSeekBehavior("d1", expected, actual);
236         expected.close();
237         actual.close();
238
239         expected = dir.openInput("d2");
240         actual = csr.openInput("d2");
241         assertSameStreams("d2", expected, actual);
242         assertSameSeekBehavior("d2", expected, actual);
243         expected.close();
244         actual.close();
245         csr.close();
246     }
247
248     /** This test creates a compound file based on a large number of files of
249      *  various length. The file content is generated randomly. The sizes range
250      *  from 0 to 1Mb. Some of the sizes are selected to test the buffering
251      *  logic in the file reading code. For this the chunk variable is set to
252      *  the length of the buffer used internally by the compound file logic.
253      */
254     public void testRandomFiles() throws IOException {
255         // Setup the test segment
256         String segment = "test";
257         int chunk = 1024; // internal buffer size used by the stream
258         createRandomFile(dir, segment + ".zero", 0);
259         createRandomFile(dir, segment + ".one", 1);
260         createRandomFile(dir, segment + ".ten", 10);
261         createRandomFile(dir, segment + ".hundred", 100);
262         createRandomFile(dir, segment + ".big1", chunk);
263         createRandomFile(dir, segment + ".big2", chunk - 1);
264         createRandomFile(dir, segment + ".big3", chunk + 1);
265         createRandomFile(dir, segment + ".big4", 3 * chunk);
266         createRandomFile(dir, segment + ".big5", 3 * chunk - 1);
267         createRandomFile(dir, segment + ".big6", 3 * chunk + 1);
268         createRandomFile(dir, segment + ".big7", 1000 * chunk);
269
270         // Setup extraneous files
271         createRandomFile(dir, "onetwothree", 100);
272         createRandomFile(dir, segment + ".notIn", 50);
273         createRandomFile(dir, segment + ".notIn2", 51);
274
275         // Now test
276         CompoundFileWriter csw = new CompoundFileWriter(dir, "test.cfs");
277         final String data[] = new String[] {
278             ".zero", ".one", ".ten", ".hundred", ".big1", ".big2", ".big3",
279             ".big4", ".big5", ".big6", ".big7"
280         };
281         for (int i=0; i<data.length; i++) {
282             csw.addFile(segment + data[i]);
283         }
284         csw.close();
285
286         CompoundFileReader csr = new CompoundFileReader(dir, "test.cfs");
287         for (int i=0; i<data.length; i++) {
288             IndexInput check = dir.openInput(segment + data[i]);
289             IndexInput test = csr.openInput(segment + data[i]);
290             assertSameStreams(data[i], check, test);
291             assertSameSeekBehavior(data[i], check, test);
292             test.close();
293             check.close();
294         }
295         csr.close();
296     }
297
298
299     /** Setup a larger compound file with a number of components, each of
300      *  which is a sequential file (so that we can easily tell that we are
301      *  reading in the right byte). The methods sets up 20 files - f0 to f19,
302      *  the size of each file is 1000 bytes.
303      */
304     private void setUp_2() throws IOException {
305         CompoundFileWriter cw = new CompoundFileWriter(dir, "f.comp");
306         for (int i=0; i<20; i++) {
307             createSequenceFile(dir, "f" + i, (byte) 0, 2000);
308             cw.addFile("f" + i);
309         }
310         cw.close();
311     }
312
313
314     public void testReadAfterClose() throws IOException {
315         demo_FSIndexInputBug(dir, "test");
316     }
317
318     private void demo_FSIndexInputBug(Directory fsdir, String file)
319     throws IOException
320     {
321         // Setup the test file - we need more than 1024 bytes
322         IndexOutput os = fsdir.createOutput(file);
323         for(int i=0; i<2000; i++) {
324             os.writeByte((byte) i);
325         }
326         os.close();
327
328         IndexInput in = fsdir.openInput(file);
329
330         // This read primes the buffer in IndexInput
331         in.readByte();
332
333         // Close the file
334         in.close();
335
336         // ERROR: this call should fail, but succeeds because the buffer
337         // is still filled
338         in.readByte();
339
340         // ERROR: this call should fail, but succeeds for some reason as well
341         in.seek(1099);
342
343         try {
344             // OK: this call correctly fails. We are now past the 1024 internal
345             // buffer, so an actual IO is attempted, which fails
346             in.readByte();
347             fail("expected readByte() to throw exception");
348         } catch (IOException e) {
349           // expected exception
350         }
351     }
352
353
354     static boolean isCSIndexInput(IndexInput is) {
355         return is instanceof CompoundFileReader.CSIndexInput;
356     }
357
358     static boolean isCSIndexInputOpen(IndexInput is) throws IOException {
359         if (isCSIndexInput(is)) {
360             CompoundFileReader.CSIndexInput cis =
361             (CompoundFileReader.CSIndexInput) is;
362
363             return _TestHelper.isSimpleFSIndexInputOpen(cis.base);
364         } else {
365             return false;
366         }
367     }
368
369
370     public void testClonedStreamsClosing() throws IOException {
371         setUp_2();
372         CompoundFileReader cr = new CompoundFileReader(dir, "f.comp");
373
374         // basic clone
375         IndexInput expected = dir.openInput("f11");
376
377         // this test only works for FSIndexInput
378         assertTrue(_TestHelper.isSimpleFSIndexInput(expected));
379         assertTrue(_TestHelper.isSimpleFSIndexInputOpen(expected));
380
381         IndexInput one = cr.openInput("f11");
382         assertTrue(isCSIndexInputOpen(one));
383
384         IndexInput two = (IndexInput) one.clone();
385         assertTrue(isCSIndexInputOpen(two));
386
387         assertSameStreams("basic clone one", expected, one);
388         expected.seek(0);
389         assertSameStreams("basic clone two", expected, two);
390
391         // Now close the first stream
392         one.close();
393         assertTrue("Only close when cr is closed", isCSIndexInputOpen(one));
394
395         // The following should really fail since we couldn't expect to
396         // access a file once close has been called on it (regardless of
397         // buffering and/or clone magic)
398         expected.seek(0);
399         two.seek(0);
400         assertSameStreams("basic clone two/2", expected, two);
401
402
403         // Now close the compound reader
404         cr.close();
405         assertFalse("Now closed one", isCSIndexInputOpen(one));
406         assertFalse("Now closed two", isCSIndexInputOpen(two));
407
408         // The following may also fail since the compound stream is closed
409         expected.seek(0);
410         two.seek(0);
411         //assertSameStreams("basic clone two/3", expected, two);
412
413
414         // Now close the second clone
415         two.close();
416         expected.seek(0);
417         two.seek(0);
418         //assertSameStreams("basic clone two/4", expected, two);
419
420         expected.close();
421     }
422
423
424     /** This test opens two files from a compound stream and verifies that
425      *  their file positions are independent of each other.
426      */
427     public void testRandomAccess() throws IOException {
428         setUp_2();
429         CompoundFileReader cr = new CompoundFileReader(dir, "f.comp");
430
431         // Open two files
432         IndexInput e1 = dir.openInput("f11");
433         IndexInput e2 = dir.openInput("f3");
434
435         IndexInput a1 = cr.openInput("f11");
436         IndexInput a2 = dir.openInput("f3");
437
438         // Seek the first pair
439         e1.seek(100);
440         a1.seek(100);
441         assertEquals(100, e1.getFilePointer());
442         assertEquals(100, a1.getFilePointer());
443         byte be1 = e1.readByte();
444         byte ba1 = a1.readByte();
445         assertEquals(be1, ba1);
446
447         // Now seek the second pair
448         e2.seek(1027);
449         a2.seek(1027);
450         assertEquals(1027, e2.getFilePointer());
451         assertEquals(1027, a2.getFilePointer());
452         byte be2 = e2.readByte();
453         byte ba2 = a2.readByte();
454         assertEquals(be2, ba2);
455
456         // Now make sure the first one didn't move
457         assertEquals(101, e1.getFilePointer());
458         assertEquals(101, a1.getFilePointer());
459         be1 = e1.readByte();
460         ba1 = a1.readByte();
461         assertEquals(be1, ba1);
462
463         // Now more the first one again, past the buffer length
464         e1.seek(1910);
465         a1.seek(1910);
466         assertEquals(1910, e1.getFilePointer());
467         assertEquals(1910, a1.getFilePointer());
468         be1 = e1.readByte();
469         ba1 = a1.readByte();
470         assertEquals(be1, ba1);
471
472         // Now make sure the second set didn't move
473         assertEquals(1028, e2.getFilePointer());
474         assertEquals(1028, a2.getFilePointer());
475         be2 = e2.readByte();
476         ba2 = a2.readByte();
477         assertEquals(be2, ba2);
478
479         // Move the second set back, again cross the buffer size
480         e2.seek(17);
481         a2.seek(17);
482         assertEquals(17, e2.getFilePointer());
483         assertEquals(17, a2.getFilePointer());
484         be2 = e2.readByte();
485         ba2 = a2.readByte();
486         assertEquals(be2, ba2);
487
488         // Finally, make sure the first set didn't move
489         // Now make sure the first one didn't move
490         assertEquals(1911, e1.getFilePointer());
491         assertEquals(1911, a1.getFilePointer());
492         be1 = e1.readByte();
493         ba1 = a1.readByte();
494         assertEquals(be1, ba1);
495
496         e1.close();
497         e2.close();
498         a1.close();
499         a2.close();
500         cr.close();
501     }
502
503     /** This test opens two files from a compound stream and verifies that
504      *  their file positions are independent of each other.
505      */
506     public void testRandomAccessClones() throws IOException {
507         setUp_2();
508         CompoundFileReader cr = new CompoundFileReader(dir, "f.comp");
509
510         // Open two files
511         IndexInput e1 = cr.openInput("f11");
512         IndexInput e2 = cr.openInput("f3");
513
514         IndexInput a1 = (IndexInput) e1.clone();
515         IndexInput a2 = (IndexInput) e2.clone();
516
517         // Seek the first pair
518         e1.seek(100);
519         a1.seek(100);
520         assertEquals(100, e1.getFilePointer());
521         assertEquals(100, a1.getFilePointer());
522         byte be1 = e1.readByte();
523         byte ba1 = a1.readByte();
524         assertEquals(be1, ba1);
525
526         // Now seek the second pair
527         e2.seek(1027);
528         a2.seek(1027);
529         assertEquals(1027, e2.getFilePointer());
530         assertEquals(1027, a2.getFilePointer());
531         byte be2 = e2.readByte();
532         byte ba2 = a2.readByte();
533         assertEquals(be2, ba2);
534
535         // Now make sure the first one didn't move
536         assertEquals(101, e1.getFilePointer());
537         assertEquals(101, a1.getFilePointer());
538         be1 = e1.readByte();
539         ba1 = a1.readByte();
540         assertEquals(be1, ba1);
541
542         // Now more the first one again, past the buffer length
543         e1.seek(1910);
544         a1.seek(1910);
545         assertEquals(1910, e1.getFilePointer());
546         assertEquals(1910, a1.getFilePointer());
547         be1 = e1.readByte();
548         ba1 = a1.readByte();
549         assertEquals(be1, ba1);
550
551         // Now make sure the second set didn't move
552         assertEquals(1028, e2.getFilePointer());
553         assertEquals(1028, a2.getFilePointer());
554         be2 = e2.readByte();
555         ba2 = a2.readByte();
556         assertEquals(be2, ba2);
557
558         // Move the second set back, again cross the buffer size
559         e2.seek(17);
560         a2.seek(17);
561         assertEquals(17, e2.getFilePointer());
562         assertEquals(17, a2.getFilePointer());
563         be2 = e2.readByte();
564         ba2 = a2.readByte();
565         assertEquals(be2, ba2);
566
567         // Finally, make sure the first set didn't move
568         // Now make sure the first one didn't move
569         assertEquals(1911, e1.getFilePointer());
570         assertEquals(1911, a1.getFilePointer());
571         be1 = e1.readByte();
572         ba1 = a1.readByte();
573         assertEquals(be1, ba1);
574
575         e1.close();
576         e2.close();
577         a1.close();
578         a2.close();
579         cr.close();
580     }
581
582
583     public void testFileNotFound() throws IOException {
584         setUp_2();
585         CompoundFileReader cr = new CompoundFileReader(dir, "f.comp");
586
587         // Open two files
588         try {
589             cr.openInput("bogus");
590             fail("File not found");
591
592         } catch (IOException e) {
593             /* success */
594             //System.out.println("SUCCESS: File Not Found: " + e);
595         }
596
597         cr.close();
598     }
599
600
601     public void testReadPastEOF() throws IOException {
602         setUp_2();
603         CompoundFileReader cr = new CompoundFileReader(dir, "f.comp");
604         IndexInput is = cr.openInput("f2");
605         is.seek(is.length() - 10);
606         byte b[] = new byte[100];
607         is.readBytes(b, 0, 10);
608
609         try {
610             is.readByte();
611             fail("Single byte read past end of file");
612         } catch (IOException e) {
613             /* success */
614             //System.out.println("SUCCESS: single byte read past end of file: " + e);
615         }
616
617         is.seek(is.length() - 10);
618         try {
619             is.readBytes(b, 0, 50);
620             fail("Block read past end of file");
621         } catch (IOException e) {
622             /* success */
623             //System.out.println("SUCCESS: block read past end of file: " + e);
624         }
625
626         is.close();
627         cr.close();
628     }
629
630     /** This test that writes larger than the size of the buffer output
631      * will correctly increment the file pointer.
632      */
633     public void testLargeWrites() throws IOException {
634         IndexOutput os = dir.createOutput("testBufferStart.txt");
635
636         byte[] largeBuf = new byte[2048];
637         for (int i=0; i<largeBuf.length; i++) {
638             largeBuf[i] = (byte) (Math.random() * 256);
639         }
640
641         long currentPos = os.getFilePointer();
642         os.writeBytes(largeBuf, largeBuf.length);
643
644         try {
645             assertEquals(currentPos + largeBuf.length, os.getFilePointer());
646         } finally {
647             os.close();
648         }
649
650     }
651     
652    public void testAddExternalFile() throws IOException {
653        createSequenceFile(dir, "d1", (byte) 0, 15);
654
655        Directory newDir = newDirectory();
656        CompoundFileWriter csw = new CompoundFileWriter(newDir, "d.csf");
657        csw.addFile("d1", dir);
658        csw.close();
659
660        CompoundFileReader csr = new CompoundFileReader(newDir, "d.csf");
661        IndexInput expected = dir.openInput("d1");
662        IndexInput actual = csr.openInput("d1");
663        assertSameStreams("d1", expected, actual);
664        assertSameSeekBehavior("d1", expected, actual);
665        expected.close();
666        actual.close();
667        csr.close();
668        
669        newDir.close();
670    }
671
672 }