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

     1  // Copyright (C) 2023 Storj Labs, Inc.
     2  // See LICENSE for copying information.
     3  
     4  package buffer
     5  
     6  import (
     7  	"io"
     8  	"testing"
     9  	"testing/iotest"
    10  
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestBuffer(t *testing.T) {
    15  	buf := New(NewMemoryBackend(25), 10)
    16  	r1 := buf.Reader()
    17  	r2 := buf.Reader()
    18  
    19  	requireRead := func(r io.Reader, n int, err error) {
    20  		t.Helper()
    21  		m, gerr := r.Read(make([]byte, n))
    22  		require.Equal(t, err, gerr)
    23  		require.Equal(t, n, m)
    24  	}
    25  
    26  	requireWrite := func(w io.Writer, n int) {
    27  		t.Helper()
    28  		m, err := w.Write(make([]byte, n))
    29  		require.NoError(t, err)
    30  		require.Equal(t, n, m)
    31  	}
    32  
    33  	requireWrite(buf, 10)
    34  	requireRead(r1, 5, nil)
    35  	requireWrite(buf, 5)
    36  	requireRead(r2, 15, nil)
    37  	requireWrite(buf, 10)
    38  	requireRead(r1, 20, nil)
    39  	requireRead(r2, 10, nil)
    40  
    41  	buf.DoneWriting(nil)
    42  
    43  	requireRead(r1, 0, io.EOF)
    44  	requireRead(r2, 0, io.EOF)
    45  
    46  	buf.DoneReading(nil)
    47  }
    48  
    49  func TestBufferSimpleConcurrent(t *testing.T) {
    50  	t.Run("memory", func(t *testing.T) {
    51  		const amount = 10*1024 + 10
    52  		testBufferSimpleConcurrent(t, NewMemoryBackend(amount), amount)
    53  	})
    54  
    55  	t.Run("chunked", func(t *testing.T) {
    56  		const amount = chunkSize + 1
    57  		testBufferSimpleConcurrent(t, NewChunkBackend(amount), amount)
    58  	})
    59  }
    60  
    61  func testBufferSimpleConcurrent(t *testing.T, backend Backend, amount int64) {
    62  	buf := New(backend, 2)
    63  	defer buf.DoneReading(nil)
    64  
    65  	r := buf.Reader()
    66  
    67  	go func() {
    68  		var tmp [1]byte
    69  		for i := int64(0); i < amount; i++ {
    70  			_, _ = buf.Write(tmp[:])
    71  		}
    72  		buf.DoneWriting(nil)
    73  	}()
    74  
    75  	var tmp [1]byte
    76  	for {
    77  		_, err := r.Read(tmp[:])
    78  		if err == io.EOF {
    79  			break
    80  		} else if err != nil {
    81  			t.Fatal(err)
    82  		}
    83  	}
    84  }
    85  
    86  type eternalReader struct{}
    87  
    88  func (eternalReader) Read(p []byte) (int, error) { return len(p), nil }
    89  
    90  func TestWriteBufferConcurrent(t *testing.T) {
    91  	t.Run("memory", func(t *testing.T) {
    92  		const amount = 10*1024 + 10
    93  		testWriteBufferConcurrent(t, NewMemoryBackend(amount), amount)
    94  	})
    95  
    96  	t.Run("chunked", func(t *testing.T) {
    97  		const amount = 10*1024 + 10
    98  		testWriteBufferConcurrent(t, NewChunkBackend(amount), amount)
    99  	})
   100  }
   101  
   102  func testWriteBufferConcurrent(t *testing.T, backend Backend, amount int64) {
   103  	type result struct {
   104  		n   int64
   105  		err error
   106  	}
   107  	wrap := func(n int64, err error) result { return result{n, err} }
   108  
   109  	results := make(chan result)
   110  	buf := New(backend, 1024)
   111  	defer buf.DoneReading(nil)
   112  
   113  	go func() {
   114  		results <- wrap(io.CopyN(buf, eternalReader{}, amount))
   115  		buf.DoneWriting(nil)
   116  	}()
   117  
   118  	go func() { results <- wrap(io.Copy(io.Discard, iotest.OneByteReader(buf.Reader()))) }()
   119  	go func() { results <- wrap(io.Copy(io.Discard, iotest.HalfReader(buf.Reader()))) }()
   120  	for i := 0; i < 10; i++ {
   121  		go func() { results <- wrap(io.Copy(io.Discard, buf.Reader())) }()
   122  	}
   123  
   124  	for i := 0; i < 13; i++ {
   125  		require.Equal(t, result{amount, nil}, <-results)
   126  	}
   127  }