func TestNewLog(t *testing.T) { mockfile := tests.NewMockFile() seeklen := int64(16 * 4096) mockfile.MockSeek = func(offset int64, whence int) (int64, error) { return seeklen, nil } // Mock openFile defer tests.Patch(&openFile, func(name string, flag int, perm os.FileMode) (Filer, error) { return mockfile, nil }).Restore() // Simple log l, blocks, err := NewLog("file", 4096, 4, 4096*2, false) tests.Assert(t, err == nil) tests.Assert(t, l != nil) tests.Assert(t, blocks == 16) l.Close() // Check the log correctly return maximum number of // blocks that are aligned to the segments. // 17 blocks are not aligned to a segment with 4 blocks // per segment seeklen = 17 * 4096 l, blocks, err = NewLog("file", 4096, 4, 4096*2, false) tests.Assert(t, err == nil) tests.Assert(t, l != nil) tests.Assert(t, blocks == 16) l.Close() }
func TestAsuOpenFile(t *testing.T) { usedirectio := true asu := NewAsu(usedirectio) mockfile := tests.NewMockFile() mockerror := errors.New("Test Error") directio_set := false // Mock openFile defer tests.Patch(&openFile, func(name string, flag int, perm os.FileMode) (Filer, error) { directio_set = false if (flag & cache.OSSYNC) == cache.OSSYNC { directio_set = true } return mockfile, mockerror }).Restore() // Call err := asu.Open("filename") // Check results tests.Assert(t, directio_set == true) tests.Assert(t, err == mockerror) // Now try without directio set usedirectio = false asu = NewAsu(usedirectio) // Check results err = asu.Open("filename") tests.Assert(t, directio_set == false) tests.Assert(t, err == mockerror) }
func TestAsuOpenSeek(t *testing.T) { usedirectio := true asu := NewAsu(usedirectio) mockfile := tests.NewMockFile() seeklen := int64(0) mockerror := errors.New("Test Error") seekerror := error(nil) mockfile.MockSeek = func(offset int64, whence int) (int64, error) { return seeklen, seekerror } // Mock openFile defer tests.Patch(&openFile, func(name string, flag int, perm os.FileMode) (Filer, error) { return mockfile, nil }).Restore() // Seek will return len of 0 err := asu.Open("filename") tests.Assert(t, err != nil) tests.Assert(t, len(asu.fps) == 0) // Seek will return error seekerror = mockerror err = asu.Open("filename") tests.Assert(t, err != nil) tests.Assert(t, err == mockerror) tests.Assert(t, len(asu.fps) == 0) // Seek will return correct data seeklen = int64(4 * KB * 100) asublocks := uint32(seeklen / (4 * KB)) seekerror = nil err = asu.Open("filename") tests.Assert(t, err == nil) tests.Assert(t, len(asu.fps) == 1) tests.Assert(t, asu.len == asublocks) // Now add a larger file, but it should // only add the min() size of the files opened seeklen = int64(4 * KB * 110) asublocks += asublocks err = asu.Open("filename") tests.Assert(t, err == nil) tests.Assert(t, len(asu.fps) == 2) tests.Assert(t, asu.len == asublocks) // Now add a smaller file, but it should // only add the min() size of the files opened seeklen = int64(4 * KB * 50) asublocks = 50 * 3 err = asu.Open("filename") tests.Assert(t, err == nil) tests.Assert(t, len(asu.fps) == 3) tests.Assert(t, asu.len == asublocks) }
func TestLogMultiBlock(t *testing.T) { // 256 blocks available in the log seeklen := int64(256 * 4096) // Setup Mockfile mockfile := tests.NewMockFile() mockfile.MockSeek = func(offset int64, whence int) (int64, error) { return seeklen, nil } mock_byteswritten := 0 mock_written := 0 mock_off_written := int64(0) continue_test := make(chan bool, 1) mockfile.MockWriteAt = func(p []byte, off int64) (n int, err error) { mock_written++ mock_off_written = off mock_byteswritten += len(p) continue_test <- true return len(p), nil } mock_bytesread := 0 mock_read := 0 mock_off_read := int64(0) mockfile.MockReadAt = func(p []byte, off int64) (n int, err error) { mock_read++ mock_off_read = off mock_bytesread += len(p) continue_test <- true return len(p), nil } // Mock openFile defer tests.Patch(&openFile, func(name string, flag int, perm os.FileMode) (Filer, error) { return mockfile, nil }).Restore() // Simple log l, blocks, err := NewLog("file", 4096, 4, 0, false) tests.Assert(t, err == nil) tests.Assert(t, l != nil) tests.Assert(t, blocks == 256) l.Start() // Send 8 blocks here := make(chan *message.Message) m := message.NewMsgPut() iopkt := m.IoPkt() m.RetChan = here iopkt.Buffer = make([]byte, 8*4096) iopkt.Blocks = 8 for block := uint32(0); block < iopkt.Blocks; block++ { child := message.NewMsgPut() m.Add(child) child_io := child.IoPkt() child_io.Address = iopkt.Address + uint64(block) child_io.Buffer = SubBlockBuffer(iopkt.Buffer, 4096, block, 1) child_io.LogBlock = block child_io.Blocks = 1 l.Msgchan <- child } m.Done() <-here <-continue_test tests.Assert(t, mock_byteswritten == 4*4096) tests.Assert(t, mock_written == 1) tests.Assert(t, mock_off_written == 0) tests.Assert(t, mock_read == 0) tests.Assert(t, len(continue_test) == 0) // At this point we have 4 blocks written to the log storage // and 4 blocks in the current segment. // Read log blocks 0-3 m = message.NewMsgGet() iopkt = m.IoPkt() m.RetChan = here iopkt.Blocks = 4 iopkt.Buffer = make([]byte, 4*4096) iopkt.LogBlock = 0 mock_written = 0 mock_byteswritten = 0 l.Msgchan <- m <-here <-continue_test tests.Assert(t, mock_byteswritten == 0) tests.Assert(t, mock_written == 0) tests.Assert(t, mock_read == 1) tests.Assert(t, mock_bytesread == 4*4096) tests.Assert(t, mock_off_read == 0) tests.Assert(t, len(continue_test) == 0) // Now read log blocks 1,2,3,4,5. Blocks 1,2,3 will be on the storage // device, and blocks 4,5 will be in ram m = message.NewMsgGet() iopkt = m.IoPkt() m.RetChan = here iopkt.Blocks = 5 iopkt.Buffer = make([]byte, 5*4096) iopkt.LogBlock = 1 mock_written = 0 mock_byteswritten = 0 mock_bytesread = 0 mock_read = 0 l.Msgchan <- m <-here <-continue_test tests.Assert(t, mock_byteswritten == 0) tests.Assert(t, mock_written == 0) tests.Assert(t, mock_read == 1) tests.Assert(t, mock_bytesread == 3*4096) tests.Assert(t, mock_off_read == 1*4096) tests.Assert(t, len(continue_test) == 0) // Cleanup l.Close() }
func TestAsuIoAt(t *testing.T) { usedirectio := true asu := NewAsu(usedirectio) // Setup Head - 10 4k blocks head := tests.NewMockFile() head.MockSeek = func(offset int64, whence int) (int64, error) { return 10 * 4 * KB, nil } var ( head_check_p_len int head_check_offset int64 head_called bool ) head.MockReadAt = func(p []byte, off int64) (n int, err error) { tests.Assert(t, len(p) == head_check_p_len) tests.Assert(t, head_check_offset == off) head_called = true return len(p), nil } head.MockWriteAt = func(p []byte, off int64) (n int, err error) { tests.Assert(t, len(p) == head_check_p_len) tests.Assert(t, head_check_offset == off) head_called = true return len(p), nil } // Setup Tail - 12 4K blocks tail := tests.NewMockFile() tail.MockSeek = func(offset int64, whence int) (int64, error) { return 12 * 4 * KB, nil } var ( tail_check_p_len int tail_check_offset int64 tail_called bool ) tail.MockReadAt = func(p []byte, off int64) (n int, err error) { tests.Assert(t, len(p) == tail_check_p_len) tests.Assert(t, tail_check_offset == off) tail_called = true return len(p), nil } tail.MockWriteAt = func(p []byte, off int64) (n int, err error) { tests.Assert(t, len(p) == tail_check_p_len) tests.Assert(t, tail_check_offset == off) tail_called = true return len(p), nil } // Mock openFile defer tests.Patch(&openFile, func(name string, flag int, perm os.FileMode) (Filer, error) { if name == "head" { return head, nil } else { return tail, nil } }).Restore() // Open files err := asu.Open("head") tests.Assert(t, err == nil) err = asu.Open("tail") tests.Assert(t, err == nil) // Write small, it should not over flow into file2 small := make([]byte, 4*KB) head_check_offset = 4 * KB head_check_p_len = len(small) tail_called = false head_called = false n, err := asu.WriteAt(small, 4*KB) tests.Assert(t, n == len(small)) tests.Assert(t, err == nil) tests.Assert(t, head_called == true) tests.Assert(t, tail_called == false) // Write large buffer. It should only write // to the first file since it the buffer is exactly // the same size as the size of the file. large := make([]byte, 10*4*KB) head_check_offset = 0 head_check_p_len = 10 * 4 * KB tail_check_offset = 0 tail_check_p_len = 0 tail_called = false head_called = true n, err = asu.WriteAt(large, 0) tests.Assert(t, n == len(large)) tests.Assert(t, err == nil) tests.Assert(t, head_called == true) tests.Assert(t, tail_called == false) // Write large, should go across files head_check_offset = 1 * 4 * KB head_check_p_len = 9 * 4 * KB tail_check_offset = 0 tail_check_p_len = 1 * 4 * KB tail_called = false head_called = false n, err = asu.WriteAt(large, 4*KB) tests.Assert(t, n == len(large)) tests.Assert(t, err == nil) tests.Assert(t, head_called == true) tests.Assert(t, tail_called == true) // Repeat with ReadAt // Read small, it should not over flow into file2 head_check_offset = 4 * KB head_check_p_len = len(small) tail_called = false head_called = false n, err = asu.ReadAt(small, 4*KB) tests.Assert(t, n == len(small)) tests.Assert(t, err == nil) tests.Assert(t, head_called == true) tests.Assert(t, tail_called == false) // Write large, should go across files head_check_offset = 9 * 4 * KB head_check_p_len = 1 * 4 * KB tail_check_offset = 0 tail_check_p_len = 9 * 4 * KB tail_called = false head_called = false n, err = asu.ReadAt(large, 9*4*KB) tests.Assert(t, n == len(large)) tests.Assert(t, err == nil) tests.Assert(t, head_called == true) tests.Assert(t, tail_called == true) }
func TestSpcContextQuit(t *testing.T) { // initialize var cache *cache.CacheMap usedirectio := false blocksize := 4 * KB s := NewSpcInfo(cache, usedirectio, blocksize) // Setup Mockfile mockfile := tests.NewMockFile() seeklen := int64(4 * 1024 * 1024 * 1024) mockfile.MockSeek = func(offset int64, whence int) (int64, error) { return seeklen, nil } // Mock openfile defer tests.Patch(&openFile, func(name string, flag int, perm os.FileMode) (Filer, error) { return mockfile, nil }).Restore() // Open files err := s.Open(1, "asu1file") tests.Assert(t, err == nil) err = s.Open(2, "asu2file") tests.Assert(t, err == nil) err = s.Open(3, "asu3file") tests.Assert(t, err == nil) // Initialize bsu := 50 contexts := 1 err = s.Spc1Init(bsu, contexts) tests.Assert(t, err == nil) // Setup channel for Context() subroutines // to send stats back iotime := make(chan *IoStats) // 60 secs, but we will send a quit signal runlen := 60 teststart := time.Now() // Create context goroutine var wg sync.WaitGroup wg.Add(1) quit := make(chan struct{}) go s.Context(&wg, iotime, quit, runlen, contexts) // Create a go routine to get stats // from channel var iostatwg sync.WaitGroup iostatwg.Add(1) go func() { defer iostatwg.Done() for iostat := range iotime { if iostat == nil { t.Error("iostat is nil") } if iostat.Io == nil { t.Errorf("iostat return nil Io") } if iostat.Start.Before(teststart) { t.Errorf("iostat returned a time in the past") } } }() // Wait a bit time.Sleep(time.Second) // Send the quit signal close(quit) // Wait here for Context() to finish wg.Wait() end := time.Now() // Shutdown iotime channel reader close(iotime) iostatwg.Wait() // These are quite big, but just in case a test framework // is very busy tests.Assert(t, end.Sub(teststart).Seconds() < 5) tests.Assert(t, end.Sub(teststart).Seconds() > 1) // Cleanup s.Close() }