forked from TrueCloudLab/rclone
5990573ccd
This fixes several things wrong with the layout of the stats. Transfers which haven't started are printed in the same format as those which have so the stats with `--progress` don't show horrible artifacts. Checkers and transfers now get a ": checkers" and ": transfers" label on the end of the stats line. Transfers will have the transfer stats when the transfer has started instead of this. There was a bug in the routine which shortened the file names (it always produces strings 1 too long). This is now fixed with a test. The formatting string was wrong with a fixed width of 45 - this is now replaces with the value of `--stats-file-name-length`. This also meant that there were unecessary leading spaces in the file names. So the default `--stats-file-name-length` was raised to 45 from 40.
255 lines
6.4 KiB
Go
255 lines
6.4 KiB
Go
package accounting
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"strings"
|
|
"testing"
|
|
"unicode/utf8"
|
|
|
|
"github.com/ncw/rclone/fs"
|
|
"github.com/ncw/rclone/fs/asyncreader"
|
|
"github.com/ncw/rclone/fs/fserrors"
|
|
"github.com/ncw/rclone/fstest/mockobject"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// Check it satisfies the interfaces
|
|
var (
|
|
_ io.ReadCloser = &Account{}
|
|
_ io.Reader = &accountStream{}
|
|
_ Accounter = &Account{}
|
|
_ Accounter = &accountStream{}
|
|
)
|
|
|
|
func TestNewAccountSizeName(t *testing.T) {
|
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
|
acc := NewAccountSizeName(in, 1, "test")
|
|
assert.Equal(t, in, acc.in)
|
|
assert.Equal(t, acc, Stats.inProgress.get("test"))
|
|
err := acc.Close()
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, Stats.inProgress.get("test"))
|
|
}
|
|
|
|
func TestNewAccount(t *testing.T) {
|
|
obj := mockobject.Object("test")
|
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
|
acc := NewAccount(in, obj)
|
|
assert.Equal(t, in, acc.in)
|
|
assert.Equal(t, acc, Stats.inProgress.get("test"))
|
|
err := acc.Close()
|
|
assert.NoError(t, err)
|
|
assert.Nil(t, Stats.inProgress.get("test"))
|
|
}
|
|
|
|
func TestAccountWithBuffer(t *testing.T) {
|
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
|
|
|
acc := NewAccountSizeName(in, -1, "test")
|
|
acc.WithBuffer()
|
|
// should have a buffer for an unknown size
|
|
_, ok := acc.in.(*asyncreader.AsyncReader)
|
|
require.True(t, ok)
|
|
assert.NoError(t, acc.Close())
|
|
|
|
acc = NewAccountSizeName(in, 1, "test")
|
|
acc.WithBuffer()
|
|
// should not have a buffer for a small size
|
|
_, ok = acc.in.(*asyncreader.AsyncReader)
|
|
require.False(t, ok)
|
|
assert.NoError(t, acc.Close())
|
|
}
|
|
|
|
func TestAccountGetUpdateReader(t *testing.T) {
|
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
|
acc := NewAccountSizeName(in, 1, "test")
|
|
|
|
assert.Equal(t, in, acc.GetReader())
|
|
|
|
in2 := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
|
acc.UpdateReader(in2)
|
|
|
|
assert.Equal(t, in2, acc.GetReader())
|
|
|
|
assert.NoError(t, acc.Close())
|
|
}
|
|
|
|
func TestAccountRead(t *testing.T) {
|
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
|
acc := NewAccountSizeName(in, 1, "test")
|
|
|
|
assert.True(t, acc.start.IsZero())
|
|
assert.Equal(t, 0, acc.lpBytes)
|
|
assert.Equal(t, int64(0), acc.bytes)
|
|
assert.Equal(t, int64(0), Stats.bytes)
|
|
|
|
var buf = make([]byte, 2)
|
|
n, err := acc.Read(buf)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, n)
|
|
assert.Equal(t, []byte{1, 2}, buf[:n])
|
|
|
|
assert.False(t, acc.start.IsZero())
|
|
assert.Equal(t, 2, acc.lpBytes)
|
|
assert.Equal(t, int64(2), acc.bytes)
|
|
assert.Equal(t, int64(2), Stats.bytes)
|
|
|
|
n, err = acc.Read(buf)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, n)
|
|
assert.Equal(t, []byte{3}, buf[:n])
|
|
|
|
n, err = acc.Read(buf)
|
|
assert.Equal(t, io.EOF, err)
|
|
assert.Equal(t, 0, n)
|
|
|
|
assert.NoError(t, acc.Close())
|
|
}
|
|
|
|
func TestAccountString(t *testing.T) {
|
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
|
acc := NewAccountSizeName(in, 3, "test")
|
|
|
|
// FIXME not an exhaustive test!
|
|
|
|
assert.Equal(t, "test: 0% /3, 0/s, -", strings.TrimSpace(acc.String()))
|
|
|
|
var buf = make([]byte, 2)
|
|
n, err := acc.Read(buf)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, n)
|
|
|
|
assert.Equal(t, "test: 66% /3, 0/s, -", strings.TrimSpace(acc.String()))
|
|
|
|
assert.NoError(t, acc.Close())
|
|
}
|
|
|
|
// Test the Accounter interface methods on Account and accountStream
|
|
func TestAccountAccounter(t *testing.T) {
|
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
|
acc := NewAccountSizeName(in, 3, "test")
|
|
|
|
assert.True(t, in == acc.OldStream())
|
|
|
|
in2 := ioutil.NopCloser(bytes.NewBuffer([]byte{2, 3, 4}))
|
|
|
|
acc.SetStream(in2)
|
|
assert.True(t, in2 == acc.OldStream())
|
|
|
|
r := acc.WrapStream(in)
|
|
as, ok := r.(Accounter)
|
|
require.True(t, ok)
|
|
assert.True(t, in == as.OldStream())
|
|
assert.True(t, in2 == acc.OldStream())
|
|
accs, ok := r.(*accountStream)
|
|
require.True(t, ok)
|
|
assert.Equal(t, acc, accs.acc)
|
|
assert.True(t, in == accs.in)
|
|
|
|
// Check Read on the accountStream
|
|
var buf = make([]byte, 2)
|
|
n, err := r.Read(buf)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, n)
|
|
assert.Equal(t, []byte{1, 2}, buf[:n])
|
|
|
|
// Test that we can get another accountstream out
|
|
in3 := ioutil.NopCloser(bytes.NewBuffer([]byte{3, 1, 2}))
|
|
r2 := as.WrapStream(in3)
|
|
as2, ok := r2.(Accounter)
|
|
require.True(t, ok)
|
|
assert.True(t, in3 == as2.OldStream())
|
|
assert.True(t, in2 == acc.OldStream())
|
|
accs2, ok := r2.(*accountStream)
|
|
require.True(t, ok)
|
|
assert.Equal(t, acc, accs2.acc)
|
|
assert.True(t, in3 == accs2.in)
|
|
|
|
// Test we can set this new accountStream
|
|
as2.SetStream(in)
|
|
assert.True(t, in == as2.OldStream())
|
|
|
|
// Test UnWrap on accountStream
|
|
unwrapped, wrap := UnWrap(r2)
|
|
assert.True(t, unwrapped == in)
|
|
r3 := wrap(in2)
|
|
assert.True(t, in2 == r3.(Accounter).OldStream())
|
|
|
|
// TestUnWrap on a normal io.Reader
|
|
unwrapped, wrap = UnWrap(in2)
|
|
assert.True(t, unwrapped == in2)
|
|
assert.True(t, wrap(in3) == in3)
|
|
|
|
}
|
|
|
|
func TestAccountMaxTransfer(t *testing.T) {
|
|
old := fs.Config.MaxTransfer
|
|
fs.Config.MaxTransfer = 15
|
|
defer func() {
|
|
fs.Config.MaxTransfer = old
|
|
}()
|
|
Stats.ResetCounters()
|
|
|
|
in := ioutil.NopCloser(bytes.NewBuffer(make([]byte, 100)))
|
|
acc := NewAccountSizeName(in, 1, "test")
|
|
|
|
var b = make([]byte, 10)
|
|
|
|
n, err := acc.Read(b)
|
|
assert.Equal(t, 10, n)
|
|
assert.NoError(t, err)
|
|
n, err = acc.Read(b)
|
|
assert.Equal(t, 10, n)
|
|
assert.NoError(t, err)
|
|
n, err = acc.Read(b)
|
|
assert.Equal(t, 0, n)
|
|
assert.Equal(t, ErrorMaxTransferLimitReached, err)
|
|
assert.True(t, fserrors.IsFatalError(err))
|
|
}
|
|
|
|
func TestShortenName(t *testing.T) {
|
|
for _, test := range []struct {
|
|
in string
|
|
size int
|
|
want string
|
|
}{
|
|
{"", 0, ""},
|
|
{"abcde", 10, "abcde"},
|
|
{"abcde", 0, "abcde"},
|
|
{"abcde", -1, "abcde"},
|
|
{"abcde", 5, "abcde"},
|
|
{"abcde", 4, "ab…e"},
|
|
{"abcde", 3, "a…e"},
|
|
{"abcde", 2, "a…"},
|
|
{"abcde", 1, "…"},
|
|
{"abcdef", 6, "abcdef"},
|
|
{"abcdef", 5, "ab…ef"},
|
|
{"abcdef", 4, "ab…f"},
|
|
{"abcdef", 3, "a…f"},
|
|
{"abcdef", 2, "a…"},
|
|
{"áßcdèf", 1, "…"},
|
|
{"áßcdè", 5, "áßcdè"},
|
|
{"áßcdè", 4, "áß…è"},
|
|
{"áßcdè", 3, "á…è"},
|
|
{"áßcdè", 2, "á…"},
|
|
{"áßcdè", 1, "…"},
|
|
{"áßcdèł", 6, "áßcdèł"},
|
|
{"áßcdèł", 5, "áß…èł"},
|
|
{"áßcdèł", 4, "áß…ł"},
|
|
{"áßcdèł", 3, "á…ł"},
|
|
{"áßcdèł", 2, "á…"},
|
|
{"áßcdèł", 1, "…"},
|
|
} {
|
|
t.Run(fmt.Sprintf("in=%q, size=%d", test.in, test.size), func(t *testing.T) {
|
|
got := shortenName(test.in, test.size)
|
|
assert.Equal(t, test.want, got)
|
|
if test.size > 0 {
|
|
assert.True(t, utf8.RuneCountInString(got) <= test.size, "too big")
|
|
}
|
|
})
|
|
}
|
|
}
|