storj.io/uplink@v1.13.0/private/storage/streams/buffer/cursor_test.go (about)

     1  // Copyright (C) 2023 Storj Labs, Inc.
     2  // See LICENSE for copying information.
     3  
     4  package buffer
     5  
     6  import (
     7  	"runtime"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  	"github.com/zeebo/errs"
    12  )
    13  
    14  func TestCursor(t *testing.T) {
    15  	type result struct {
    16  		n   int64
    17  		ok  bool
    18  		err error
    19  	}
    20  	wrap := func(n int64, ok bool, err error) result { return result{n, ok, err} }
    21  	canceled := errs.New("canceled")
    22  
    23  	t.Run("ReadBlocksUntilFinished", func(t *testing.T) {
    24  		done := make(chan result)
    25  		cursor := NewCursor(10)
    26  		go func() { done <- wrap(cursor.WaitRead(1)) }()
    27  		runtime.Gosched() // attempt to cause the goroutine to run
    28  		cursor.DoneWriting(nil)
    29  		require.Equal(t, result{0, false, nil}, <-done)
    30  	})
    31  
    32  	t.Run("ReadBlocksUntilFinished_With_Error", func(t *testing.T) {
    33  		done := make(chan result)
    34  		cursor := NewCursor(10)
    35  		go func() { done <- wrap(cursor.WaitRead(1)) }()
    36  		runtime.Gosched() // attempt to cause the goroutine to run
    37  		cursor.DoneWriting(canceled)
    38  		require.Equal(t, result{0, false, canceled}, <-done)
    39  	})
    40  
    41  	t.Run("WriteBlocksUntilFinished_With_Error", func(t *testing.T) {
    42  		done := make(chan result)
    43  		cursor := NewCursor(10)
    44  		cursor.WroteTo(10)
    45  		go func() { done <- wrap(cursor.WaitWrite(11)) }()
    46  		runtime.Gosched() // attempt to cause the goroutine to run
    47  		cursor.DoneReading(canceled)
    48  		require.Equal(t, result{0, false, canceled}, <-done)
    49  	})
    50  
    51  	t.Run("WriteBlocksUntilFinished", func(t *testing.T) {
    52  		done := make(chan result)
    53  		cursor := NewCursor(10)
    54  		cursor.WroteTo(10)
    55  		go func() { done <- wrap(cursor.WaitWrite(11)) }()
    56  		runtime.Gosched() // attempt to cause the goroutine to run
    57  		cursor.DoneReading(nil)
    58  		require.Equal(t, result{10, false, nil}, <-done)
    59  	})
    60  
    61  	t.Run("ReadAllWritten", func(t *testing.T) {
    62  		cursor := NewCursor(10)
    63  		cursor.WroteTo(1)
    64  		cursor.DoneWriting(nil)
    65  		require.Equal(t, result{1, false, nil}, wrap(cursor.WaitRead(1)))
    66  		require.Equal(t, result{1, false, nil}, wrap(cursor.WaitRead(2)))
    67  	})
    68  
    69  	t.Run("WriteUnblocksRead", func(t *testing.T) {
    70  		done := make(chan result)
    71  		cursor := NewCursor(10)
    72  		go func() { done <- wrap(cursor.WaitRead(1)) }()
    73  		runtime.Gosched() // attempt to cause the goroutine to run
    74  		cursor.WroteTo(1)
    75  		require.Equal(t, result{1, true, nil}, <-done)
    76  	})
    77  
    78  	t.Run("ReadUnblocksWrite", func(t *testing.T) {
    79  		done := make(chan result)
    80  		cursor := NewCursor(10)
    81  		cursor.WroteTo(10)
    82  		go func() { done <- wrap(cursor.WaitWrite(11)) }()
    83  		runtime.Gosched() // attempt to cause the goroutine to run
    84  		cursor.ReadTo(1)
    85  		require.Equal(t, result{11, true, nil}, <-done)
    86  	})
    87  }
    88  
    89  func BenchmarkNewCursor(b *testing.B) {
    90  	b.ReportAllocs()
    91  
    92  	var c *Cursor
    93  	for i := 0; i < b.N; i++ {
    94  		c = NewCursor(1024)
    95  	}
    96  	runtime.KeepAlive(c)
    97  }