github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/fs/sync/pipe_test.go (about) 1 package sync 2 3 import ( 4 "context" 5 "sync" 6 "sync/atomic" 7 "testing" 8 9 "github.com/ncw/rclone/fs" 10 "github.com/ncw/rclone/fstest/mockobject" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 func TestPipe(t *testing.T) { 15 var queueLength int 16 var queueSize int64 17 stats := func(n int, size int64) { 18 queueLength, queueSize = n, size 19 } 20 21 // Make a new pipe 22 p := newPipe(stats, 10) 23 24 checkStats := func(expectedN int, expectedSize int64) { 25 n, size := p.Stats() 26 assert.Equal(t, expectedN, n) 27 assert.Equal(t, expectedSize, size) 28 assert.Equal(t, expectedN, queueLength) 29 assert.Equal(t, expectedSize, queueSize) 30 } 31 32 checkStats(0, 0) 33 34 ctx := context.Background() 35 36 obj1 := mockobject.New("potato").WithContent([]byte("hello"), mockobject.SeekModeNone) 37 38 pair1 := fs.ObjectPair{Src: obj1, Dst: nil} 39 40 // Put an object 41 ok := p.Put(ctx, pair1) 42 assert.Equal(t, true, ok) 43 checkStats(1, 5) 44 45 // Close the pipe showing reading on closed pipe is OK 46 p.Close() 47 48 // Read from pipe 49 pair2, ok := p.Get(ctx) 50 assert.Equal(t, pair1, pair2) 51 assert.Equal(t, true, ok) 52 checkStats(0, 0) 53 54 // Check read on closed pipe 55 pair2, ok = p.Get(ctx) 56 assert.Equal(t, fs.ObjectPair{}, pair2) 57 assert.Equal(t, false, ok) 58 59 // Check panic on write to closed pipe 60 assert.Panics(t, func() { p.Put(ctx, pair1) }) 61 62 // Make a new pipe 63 p = newPipe(stats, 10) 64 ctx2, cancel := context.WithCancel(ctx) 65 66 // cancel it in the background - check read ceases 67 go cancel() 68 pair2, ok = p.Get(ctx2) 69 assert.Equal(t, fs.ObjectPair{}, pair2) 70 assert.Equal(t, false, ok) 71 72 // check we can't write 73 ok = p.Put(ctx2, pair1) 74 assert.Equal(t, false, ok) 75 76 } 77 78 // TestPipeConcurrent runs concurrent Get and Put to flush out any 79 // race conditions and concurrency problems. 80 func TestPipeConcurrent(t *testing.T) { 81 const ( 82 N = 1000 83 readWriters = 10 84 ) 85 86 stats := func(n int, size int64) {} 87 88 // Make a new pipe 89 p := newPipe(stats, 10) 90 91 var wg sync.WaitGroup 92 obj1 := mockobject.New("potato").WithContent([]byte("hello"), mockobject.SeekModeNone) 93 pair1 := fs.ObjectPair{Src: obj1, Dst: nil} 94 ctx := context.Background() 95 var count int64 96 97 for j := 0; j < readWriters; j++ { 98 wg.Add(2) 99 go func() { 100 defer wg.Done() 101 for i := 0; i < N; i++ { 102 // Read from pipe 103 pair2, ok := p.Get(ctx) 104 assert.Equal(t, pair1, pair2) 105 assert.Equal(t, true, ok) 106 atomic.AddInt64(&count, -1) 107 } 108 }() 109 go func() { 110 defer wg.Done() 111 for i := 0; i < N; i++ { 112 // Put an object 113 ok := p.Put(ctx, pair1) 114 assert.Equal(t, true, ok) 115 atomic.AddInt64(&count, 1) 116 } 117 }() 118 } 119 wg.Wait() 120 121 assert.Equal(t, int64(0), count) 122 }