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 }