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  }