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  }