github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/accounting/accounting_test.go (about) 1 package accounting 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "strings" 9 "testing" 10 "unicode/utf8" 11 12 "github.com/rclone/rclone/fs" 13 "github.com/rclone/rclone/fs/asyncreader" 14 "github.com/rclone/rclone/fs/fserrors" 15 "github.com/rclone/rclone/lib/readers" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 // Check it satisfies the interfaces 21 var ( 22 _ io.ReadCloser = &Account{} 23 _ io.WriterTo = &Account{} 24 _ io.Reader = &accountStream{} 25 _ Accounter = &Account{} 26 _ Accounter = &accountStream{} 27 ) 28 29 func TestNewAccountSizeName(t *testing.T) { 30 in := ioutil.NopCloser(bytes.NewBuffer([]byte{1})) 31 stats := NewStats() 32 acc := newAccountSizeName(stats, in, 1, "test") 33 assert.Equal(t, in, acc.in) 34 assert.Equal(t, acc, stats.inProgress.get("test")) 35 err := acc.Close() 36 assert.NoError(t, err) 37 assert.Equal(t, acc, stats.inProgress.get("test")) 38 acc.Done() 39 assert.Nil(t, stats.inProgress.get("test")) 40 } 41 42 func TestAccountWithBuffer(t *testing.T) { 43 in := ioutil.NopCloser(bytes.NewBuffer([]byte{1})) 44 45 stats := NewStats() 46 acc := newAccountSizeName(stats, in, -1, "test") 47 acc.WithBuffer() 48 // should have a buffer for an unknown size 49 _, ok := acc.in.(*asyncreader.AsyncReader) 50 require.True(t, ok) 51 assert.NoError(t, acc.Close()) 52 53 acc = newAccountSizeName(stats, in, 1, "test") 54 acc.WithBuffer() 55 // should not have a buffer for a small size 56 _, ok = acc.in.(*asyncreader.AsyncReader) 57 require.False(t, ok) 58 assert.NoError(t, acc.Close()) 59 } 60 61 func TestAccountGetUpdateReader(t *testing.T) { 62 test := func(doClose bool) func(t *testing.T) { 63 return func(t *testing.T) { 64 in := ioutil.NopCloser(bytes.NewBuffer([]byte{1})) 65 stats := NewStats() 66 acc := newAccountSizeName(stats, in, 1, "test") 67 68 assert.Equal(t, in, acc.GetReader()) 69 assert.Equal(t, acc, stats.inProgress.get("test")) 70 71 if doClose { 72 // close the account before swapping it out 73 require.NoError(t, acc.Close()) 74 } 75 76 in2 := ioutil.NopCloser(bytes.NewBuffer([]byte{1})) 77 acc.UpdateReader(in2) 78 79 assert.Equal(t, in2, acc.GetReader()) 80 assert.Equal(t, acc, stats.inProgress.get("test")) 81 82 assert.NoError(t, acc.Close()) 83 } 84 } 85 t.Run("NoClose", test(false)) 86 t.Run("Close", test(true)) 87 } 88 89 func TestAccountRead(t *testing.T) { 90 in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3})) 91 stats := NewStats() 92 acc := newAccountSizeName(stats, in, 1, "test") 93 94 assert.True(t, acc.values.start.IsZero()) 95 acc.values.mu.Lock() 96 assert.Equal(t, 0, acc.values.lpBytes) 97 assert.Equal(t, int64(0), acc.values.bytes) 98 acc.values.mu.Unlock() 99 assert.Equal(t, int64(0), stats.bytes) 100 101 var buf = make([]byte, 2) 102 n, err := acc.Read(buf) 103 assert.NoError(t, err) 104 assert.Equal(t, 2, n) 105 assert.Equal(t, []byte{1, 2}, buf[:n]) 106 107 assert.False(t, acc.values.start.IsZero()) 108 acc.values.mu.Lock() 109 assert.Equal(t, 2, acc.values.lpBytes) 110 assert.Equal(t, int64(2), acc.values.bytes) 111 acc.values.mu.Unlock() 112 assert.Equal(t, int64(2), stats.bytes) 113 114 n, err = acc.Read(buf) 115 assert.NoError(t, err) 116 assert.Equal(t, 1, n) 117 assert.Equal(t, []byte{3}, buf[:n]) 118 119 n, err = acc.Read(buf) 120 assert.Equal(t, io.EOF, err) 121 assert.Equal(t, 0, n) 122 123 assert.NoError(t, acc.Close()) 124 } 125 126 func testAccountWriteTo(t *testing.T, withBuffer bool) { 127 buf := make([]byte, 2*asyncreader.BufferSize+1) 128 for i := range buf { 129 buf[i] = byte(i % 251) 130 } 131 in := ioutil.NopCloser(bytes.NewBuffer(buf)) 132 stats := NewStats() 133 acc := newAccountSizeName(stats, in, int64(len(buf)), "test") 134 if withBuffer { 135 acc = acc.WithBuffer() 136 } 137 138 assert.True(t, acc.values.start.IsZero()) 139 acc.values.mu.Lock() 140 assert.Equal(t, 0, acc.values.lpBytes) 141 assert.Equal(t, int64(0), acc.values.bytes) 142 acc.values.mu.Unlock() 143 assert.Equal(t, int64(0), stats.bytes) 144 145 var out bytes.Buffer 146 147 n, err := acc.WriteTo(&out) 148 assert.NoError(t, err) 149 assert.Equal(t, int64(len(buf)), n) 150 assert.Equal(t, buf, out.Bytes()) 151 152 assert.False(t, acc.values.start.IsZero()) 153 acc.values.mu.Lock() 154 assert.Equal(t, len(buf), acc.values.lpBytes) 155 assert.Equal(t, int64(len(buf)), acc.values.bytes) 156 acc.values.mu.Unlock() 157 assert.Equal(t, int64(len(buf)), stats.bytes) 158 159 assert.NoError(t, acc.Close()) 160 } 161 162 func TestAccountWriteTo(t *testing.T) { 163 testAccountWriteTo(t, false) 164 } 165 166 func TestAccountWriteToWithBuffer(t *testing.T) { 167 testAccountWriteTo(t, true) 168 } 169 170 func TestAccountString(t *testing.T) { 171 in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3})) 172 stats := NewStats() 173 acc := newAccountSizeName(stats, in, 3, "test") 174 175 // FIXME not an exhaustive test! 176 177 assert.Equal(t, "test: 0% /3, 0/s, -", strings.TrimSpace(acc.String())) 178 179 var buf = make([]byte, 2) 180 n, err := acc.Read(buf) 181 assert.NoError(t, err) 182 assert.Equal(t, 2, n) 183 184 assert.Equal(t, "test: 66% /3, 0/s, -", strings.TrimSpace(acc.String())) 185 186 assert.NoError(t, acc.Close()) 187 } 188 189 // Test the Accounter interface methods on Account and accountStream 190 func TestAccountAccounter(t *testing.T) { 191 in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3})) 192 stats := NewStats() 193 acc := newAccountSizeName(stats, in, 3, "test") 194 195 assert.True(t, in == acc.OldStream()) 196 197 in2 := ioutil.NopCloser(bytes.NewBuffer([]byte{2, 3, 4})) 198 199 acc.SetStream(in2) 200 assert.True(t, in2 == acc.OldStream()) 201 202 r := acc.WrapStream(in) 203 as, ok := r.(Accounter) 204 require.True(t, ok) 205 assert.True(t, in == as.OldStream()) 206 assert.True(t, in2 == acc.OldStream()) 207 accs, ok := r.(*accountStream) 208 require.True(t, ok) 209 assert.Equal(t, acc, accs.acc) 210 assert.True(t, in == accs.in) 211 212 // Check Read on the accountStream 213 var buf = make([]byte, 2) 214 n, err := r.Read(buf) 215 assert.NoError(t, err) 216 assert.Equal(t, 2, n) 217 assert.Equal(t, []byte{1, 2}, buf[:n]) 218 219 // Test that we can get another accountstream out 220 in3 := ioutil.NopCloser(bytes.NewBuffer([]byte{3, 1, 2})) 221 r2 := as.WrapStream(in3) 222 as2, ok := r2.(Accounter) 223 require.True(t, ok) 224 assert.True(t, in3 == as2.OldStream()) 225 assert.True(t, in2 == acc.OldStream()) 226 accs2, ok := r2.(*accountStream) 227 require.True(t, ok) 228 assert.Equal(t, acc, accs2.acc) 229 assert.True(t, in3 == accs2.in) 230 231 // Test we can set this new accountStream 232 as2.SetStream(in) 233 assert.True(t, in == as2.OldStream()) 234 235 // Test UnWrap on accountStream 236 unwrapped, wrap := UnWrap(r2) 237 assert.True(t, unwrapped == in) 238 r3 := wrap(in2) 239 assert.True(t, in2 == r3.(Accounter).OldStream()) 240 241 // TestUnWrap on a normal io.Reader 242 unwrapped, wrap = UnWrap(in2) 243 assert.True(t, unwrapped == in2) 244 assert.True(t, wrap(in3) == in3) 245 246 } 247 248 func TestAccountMaxTransfer(t *testing.T) { 249 old := fs.Config.MaxTransfer 250 oldMode := fs.Config.CutoffMode 251 252 fs.Config.MaxTransfer = 15 253 defer func() { 254 fs.Config.MaxTransfer = old 255 fs.Config.CutoffMode = oldMode 256 }() 257 258 in := ioutil.NopCloser(bytes.NewBuffer(make([]byte, 100))) 259 stats := NewStats() 260 acc := newAccountSizeName(stats, in, 1, "test") 261 262 var b = make([]byte, 10) 263 264 n, err := acc.Read(b) 265 assert.Equal(t, 10, n) 266 assert.NoError(t, err) 267 n, err = acc.Read(b) 268 assert.Equal(t, 5, n) 269 assert.Equal(t, ErrorMaxTransferLimitReachedFatal, err) 270 n, err = acc.Read(b) 271 assert.Equal(t, 0, n) 272 assert.Equal(t, ErrorMaxTransferLimitReachedFatal, err) 273 assert.True(t, fserrors.IsFatalError(err)) 274 275 fs.Config.CutoffMode = fs.CutoffModeSoft 276 stats = NewStats() 277 acc = newAccountSizeName(stats, in, 1, "test") 278 279 n, err = acc.Read(b) 280 assert.Equal(t, 10, n) 281 assert.NoError(t, err) 282 n, err = acc.Read(b) 283 assert.Equal(t, 10, n) 284 assert.NoError(t, err) 285 n, err = acc.Read(b) 286 assert.Equal(t, 10, n) 287 assert.NoError(t, err) 288 } 289 290 func TestAccountMaxTransferWriteTo(t *testing.T) { 291 old := fs.Config.MaxTransfer 292 oldMode := fs.Config.CutoffMode 293 294 fs.Config.MaxTransfer = 15 295 defer func() { 296 fs.Config.MaxTransfer = old 297 fs.Config.CutoffMode = oldMode 298 }() 299 300 in := ioutil.NopCloser(readers.NewPatternReader(1024)) 301 stats := NewStats() 302 acc := newAccountSizeName(stats, in, 1, "test") 303 304 var b bytes.Buffer 305 306 n, err := acc.WriteTo(&b) 307 assert.Equal(t, int64(15), n) 308 assert.Equal(t, ErrorMaxTransferLimitReachedFatal, err) 309 } 310 311 func TestShortenName(t *testing.T) { 312 for _, test := range []struct { 313 in string 314 size int 315 want string 316 }{ 317 {"", 0, ""}, 318 {"abcde", 10, "abcde"}, 319 {"abcde", 0, "abcde"}, 320 {"abcde", -1, "abcde"}, 321 {"abcde", 5, "abcde"}, 322 {"abcde", 4, "ab…e"}, 323 {"abcde", 3, "a…e"}, 324 {"abcde", 2, "a…"}, 325 {"abcde", 1, "…"}, 326 {"abcdef", 6, "abcdef"}, 327 {"abcdef", 5, "ab…ef"}, 328 {"abcdef", 4, "ab…f"}, 329 {"abcdef", 3, "a…f"}, 330 {"abcdef", 2, "a…"}, 331 {"áßcdèf", 1, "…"}, 332 {"áßcdè", 5, "áßcdè"}, 333 {"áßcdè", 4, "áß…è"}, 334 {"áßcdè", 3, "á…è"}, 335 {"áßcdè", 2, "á…"}, 336 {"áßcdè", 1, "…"}, 337 {"áßcdèł", 6, "áßcdèł"}, 338 {"áßcdèł", 5, "áß…èł"}, 339 {"áßcdèł", 4, "áß…ł"}, 340 {"áßcdèł", 3, "á…ł"}, 341 {"áßcdèł", 2, "á…"}, 342 {"áßcdèł", 1, "…"}, 343 } { 344 t.Run(fmt.Sprintf("in=%q, size=%d", test.in, test.size), func(t *testing.T) { 345 got := shortenName(test.in, test.size) 346 assert.Equal(t, test.want, got) 347 if test.size > 0 { 348 assert.True(t, utf8.RuneCountInString(got) <= test.size, "too big") 349 } 350 }) 351 } 352 }