github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/store/input_test.go (about) 1 package store 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "math" 7 "math/rand" 8 "os" 9 "testing" 10 "time" 11 ) 12 13 func writeBytes(aFile *os.File, size int64) (err error) { 14 buf := make([]byte, 0, 4096) 15 for i := int64(0); i < size; i++ { 16 if i%4096 == 0 && len(buf) > 0 { 17 _, err = aFile.Write(buf) 18 if err != nil { 19 return err 20 } 21 buf = make([]byte, 0, 4096) 22 } 23 buf = append(buf, byten(i)) 24 } 25 if len(buf) > 0 { 26 _, err = aFile.Write(buf) 27 } 28 return err 29 } 30 31 const TEST_FILE_LENGTH = int64(100 * 1024) 32 const TEMP_DIR = "" 33 34 // Call readByte() repeatedly, past the buffer boundary, and see that it 35 // is working as expected. 36 // Our input comes from a dynamically generated/ "file" - see 37 // MyBufferedIndexInput below. 38 func TestReadByte(t *testing.T) { 39 input := newMyBufferedIndexInput(math.MaxInt64) 40 for i := 0; i < BUFFER_SIZE; i++ { 41 b, err := input.ReadByte() 42 if err != nil { 43 t.Fatal(err) 44 } 45 assertEquals(t, b, byten(int64(i))) 46 } 47 } 48 49 func assertEquals(t *testing.T, a, b interface{}) { 50 if a != b { 51 t.Errorf("Expected '%v', but '%v'", b, a) 52 } 53 } 54 55 // Call readBytes() repeatedly, with various chunk sizes (from 1 byte to 56 // larger than the buffer size), and see that it returns the bytes we expect. 57 // Our input comes from a dynamically generated "file" - 58 // see MyBufferedIndexInput below. 59 func TestReadBytes(t *testing.T) { 60 input := newMyBufferedIndexInput(math.MaxInt64) 61 err := runReadBytes(input, BUFFER_SIZE, random(), t) 62 if err != nil { 63 t.Error(err) 64 } 65 66 // This tests the workaround code for LUCENE-1566 where readBytesInternal 67 // provides a workaround for a JVM Bug that incorrectly raises a OOM Error 68 // when a large byte buffer is passed to a file read. 69 // NOTE: this does only test the chunked reads and NOT if the Bug is triggered. 70 //final int tmpFileSize = 1024 * 1024 * 5; 71 inputBufferSize := 128 72 tmpInputFile, err := ioutil.TempFile(TEMP_DIR, "IndexInput") 73 if err != nil { 74 t.Error(err) 75 } 76 defer func() { 77 tmpInputFile.Close() 78 os.Remove(tmpInputFile.Name()) 79 }() 80 err = writeBytes(tmpInputFile, TEST_FILE_LENGTH) 81 if err != nil { 82 t.Fatal(err) 83 } 84 85 // run test with chunk size of 10 bytes 86 in, err := newSimpleFSIndexInput(fmt.Sprintf("SimpleFSIndexInput(path='%v')", tmpInputFile), tmpInputFile.Name(), 87 newTestIOContext(random())) 88 if err != nil { 89 t.Error(err) 90 } 91 err = runReadBytesAndClose(in, inputBufferSize, random(), t) 92 if err != nil { 93 t.Error(err) 94 } 95 } 96 97 func random() *rand.Rand { 98 seed := time.Now().Unix() 99 fmt.Println("Seed: ", seed) 100 return rand.New(rand.NewSource(seed)) 101 } 102 103 func runReadBytesAndClose(input IndexInput, bufferSize int, r *rand.Rand, t *testing.T) (err error) { 104 defer func() { 105 err = input.Close() 106 }() 107 108 return runReadBytes(input, bufferSize, r, t) 109 } 110 111 func runReadBytes(input IndexInput, bufferSize int, r *rand.Rand, t *testing.T) (err error) { 112 pos := 0 113 // gradually increasing size: 114 for size := 1; size < bufferSize*10; size += size/200 + 1 { 115 err = checkReadBytes(input, size, pos, t) 116 if err != nil { 117 return err 118 } 119 if pos += size; int64(pos) >= TEST_FILE_LENGTH { // wrap 120 pos = 0 121 input.Seek(0) 122 } 123 } 124 // wildly fluctuating size: 125 for i := int64(0); i < 100; i++ { 126 size := r.Intn(10000) 127 err = checkReadBytes(input, size+1, pos, t) 128 if err != nil { 129 return err 130 } 131 if pos += size + 1; int64(pos) >= TEST_FILE_LENGTH { // wrap 132 pos = 0 133 input.Seek(0) 134 } 135 } 136 // constant small size (7 bytes): 137 for i := 0; i < bufferSize; i++ { 138 err = checkReadBytes(input, 7, pos, t) 139 if err != nil { 140 return err 141 } 142 if pos += 7; int64(pos) >= TEST_FILE_LENGTH { // wrap 143 pos = 0 144 input.Seek(0) 145 } 146 } 147 return nil 148 } 149 150 var buffer []byte = make([]byte, 10) 151 152 func grow(buffer []byte, newCap int) []byte { 153 if newCap <= cap(buffer) { 154 return buffer[0:newCap] 155 } 156 ans := make([]byte, newCap) 157 copy(ans, buffer) 158 return ans 159 } 160 161 func checkReadBytes(input IndexInput, size, pos int, t *testing.T) error { 162 // Just to see that "offset" is treated properly in readBytes(), we 163 // add an arbitrary offset at the beginning of the array 164 offset := size % 10 // arbitrary 165 buffer = grow(buffer, offset+size) 166 assertEquals(t, int64(pos), input.FilePointer()) 167 left := TEST_FILE_LENGTH - input.FilePointer() 168 if left <= 0 { 169 return nil 170 } else if left < int64(size) { 171 size = int(left) 172 } 173 if err := input.ReadBytes(buffer[offset : offset+size]); err != nil { 174 return err 175 } 176 assertEquals(t, int64(pos+size), input.FilePointer()) 177 for i := 0; i < size; i++ { 178 assertEquals(t, byten(int64(pos+i)), buffer[offset+i]) 179 } 180 return nil 181 } 182 183 // This tests that attempts to readBytes() past an EOF will fail, while 184 // reads up to the EOF will succeed. The EOF is determined by the 185 // BufferedIndexInput's arbitrary length() value. 186 func testEOF(t *testing.T) { 187 input := newMyBufferedIndexInput(1024) 188 // see that we can read all the bytes at one go: 189 if err := checkReadBytes(input, int(input.Length()), 0, t); err != nil { 190 t.Error(err) 191 } 192 // go back and see that we can't read more than that, for small and 193 // large overflows: 194 pos := int(input.Length() - 10) 195 input.Seek(int64(pos)) 196 if err := checkReadBytes(input, 10, pos, t); err != nil { 197 t.Error(err) 198 } 199 input.Seek(int64(pos)) 200 if err := checkReadBytes(input, 11, pos, t); err == nil { 201 t.Error("Block read past end of file") 202 } 203 input.Seek(int64(pos)) 204 if err := checkReadBytes(input, 50, pos, t); err == nil { 205 t.Error("Block read past end of file") 206 } 207 input.Seek(int64(pos)) 208 if err := checkReadBytes(input, 100000, pos, t); err == nil { 209 t.Error("Block read past end of file") 210 } 211 } 212 213 func byten(n int64) byte { 214 return byte(n * n % 256) 215 } 216 217 type MyBufferedIndexInput struct { 218 *BufferedIndexInput 219 pos int64 220 length int64 221 } 222 223 func newMyBufferedIndexInput(length int64) *MyBufferedIndexInput { 224 ans := &MyBufferedIndexInput{pos: 0, length: length} 225 ans.BufferedIndexInput = newBufferedIndexInputBySize(ans, fmt.Sprintf( 226 "MyBufferedIndexInput(len=%v)", length), BUFFER_SIZE) 227 return ans 228 } 229 230 func (in *MyBufferedIndexInput) readInternal(buf []byte) error { 231 for i, _ := range buf { 232 buf[i] = byten(in.pos) 233 in.pos++ 234 } 235 return nil 236 } 237 238 func (in *MyBufferedIndexInput) seekInternal(pos int64) error { 239 in.pos = pos 240 return nil 241 } 242 243 func (in *MyBufferedIndexInput) Close() error { 244 return nil 245 } 246 247 func (in *MyBufferedIndexInput) Length() int64 { 248 return in.length 249 } 250 251 func (in *MyBufferedIndexInput) Slice(desc string, offset, length int64) (IndexInput, error) { 252 panic("not supported") 253 } 254 255 func (in *MyBufferedIndexInput) Clone() IndexInput { 256 return &MyBufferedIndexInput{ 257 in.BufferedIndexInput.Clone(), 258 in.pos, 259 in.length, 260 } 261 }