github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/fs/operations/reopen_test.go (about) 1 package operations 2 3 import ( 4 "context" 5 "io" 6 "io/ioutil" 7 "testing" 8 9 "github.com/pkg/errors" 10 "github.com/rclone/rclone/fs" 11 "github.com/rclone/rclone/fs/hash" 12 "github.com/rclone/rclone/fstest/mockobject" 13 "github.com/stretchr/testify/assert" 14 ) 15 16 // check interface 17 var _ io.ReadCloser = (*reOpen)(nil) 18 19 var errorTestError = errors.New("test error") 20 21 // this is a wrapper for an mockobject with a custom Open function 22 // 23 // breaks indicate the number of bytes to read before returning an 24 // error 25 type reOpenTestObject struct { 26 fs.Object 27 breaks []int64 28 } 29 30 // Open opens the file for read. Call Close() on the returned io.ReadCloser 31 // 32 // This will break after reading the number of bytes in breaks 33 func (o *reOpenTestObject) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) { 34 rc, err := o.Object.Open(ctx, options...) 35 if err != nil { 36 return nil, err 37 } 38 if len(o.breaks) > 0 { 39 // Pop a breakpoint off 40 N := o.breaks[0] 41 o.breaks = o.breaks[1:] 42 // If 0 then return an error immediately 43 if N == 0 { 44 return nil, errorTestError 45 } 46 // Read N bytes then an error 47 r := io.MultiReader(&io.LimitedReader{R: rc, N: N}, errorReader{errorTestError}) 48 // Wrap with Close in a new readCloser 49 rc = readCloser{Reader: r, Closer: rc} 50 } 51 return rc, nil 52 } 53 54 // Return an error only 55 type errorReader struct { 56 err error 57 } 58 59 // Read returning an error 60 func (er errorReader) Read(p []byte) (n int, err error) { 61 return 0, er.err 62 } 63 64 func TestReOpen(t *testing.T) { 65 for testIndex, testName := range []string{"Seek", "Range"} { 66 t.Run(testName, func(t *testing.T) { 67 // Contents for the mock object 68 var ( 69 reOpenTestcontents = []byte("0123456789") 70 expectedRead = reOpenTestcontents 71 rangeOption *fs.RangeOption 72 ) 73 if testIndex > 0 { 74 rangeOption = &fs.RangeOption{Start: 1, End: 7} 75 expectedRead = reOpenTestcontents[1:8] 76 } 77 78 // Start the test with the given breaks 79 testReOpen := func(breaks []int64, maxRetries int) (io.ReadCloser, error) { 80 srcOrig := mockobject.New("potato").WithContent(reOpenTestcontents, mockobject.SeekModeNone) 81 src := &reOpenTestObject{ 82 Object: srcOrig, 83 breaks: breaks, 84 } 85 hashOption := &fs.HashesOption{Hashes: hash.NewHashSet(hash.MD5)} 86 return newReOpen(context.Background(), src, hashOption, rangeOption, maxRetries) 87 } 88 89 t.Run("Basics", func(t *testing.T) { 90 // open 91 h, err := testReOpen(nil, 10) 92 assert.NoError(t, err) 93 94 // Check contents read correctly 95 got, err := ioutil.ReadAll(h) 96 assert.NoError(t, err) 97 assert.Equal(t, expectedRead, got) 98 99 // Check read after end 100 var buf = make([]byte, 1) 101 n, err := h.Read(buf) 102 assert.Equal(t, 0, n) 103 assert.Equal(t, io.EOF, err) 104 105 // Check close 106 assert.NoError(t, h.Close()) 107 108 // Check double close 109 assert.Equal(t, errorFileClosed, h.Close()) 110 111 // Check read after close 112 n, err = h.Read(buf) 113 assert.Equal(t, 0, n) 114 assert.Equal(t, errorFileClosed, err) 115 }) 116 117 t.Run("ErrorAtStart", func(t *testing.T) { 118 // open with immediate breaking 119 h, err := testReOpen([]int64{0}, 10) 120 assert.Equal(t, errorTestError, err) 121 assert.Nil(t, h) 122 }) 123 124 t.Run("WithErrors", func(t *testing.T) { 125 // open with a few break points but less than the max 126 h, err := testReOpen([]int64{2, 1, 3}, 10) 127 assert.NoError(t, err) 128 129 // check contents 130 got, err := ioutil.ReadAll(h) 131 assert.NoError(t, err) 132 assert.Equal(t, expectedRead, got) 133 134 // check close 135 assert.NoError(t, h.Close()) 136 }) 137 138 t.Run("TooManyErrors", func(t *testing.T) { 139 // open with a few break points but >= the max 140 h, err := testReOpen([]int64{2, 1, 3}, 3) 141 assert.NoError(t, err) 142 143 // check contents 144 got, err := ioutil.ReadAll(h) 145 assert.Equal(t, errorTestError, err) 146 assert.Equal(t, expectedRead[:6], got) 147 148 // check old error is returned 149 var buf = make([]byte, 1) 150 n, err := h.Read(buf) 151 assert.Equal(t, 0, n) 152 assert.Equal(t, errorTooManyTries, err) 153 154 // Check close 155 assert.Equal(t, errorFileClosed, h.Close()) 156 }) 157 }) 158 } 159 }