mirror of
https://github.com/rclone/rclone.git
synced 2025-03-10 20:45:14 +08:00

Before this change, bucket.Join would tidy up object keys by removing repeated / in them. This means we can't access objects with // in them which is valid for object keys (but not for file system paths). This could have consequences for users who are relying on rclone to fix improper paths for them.
188 lines
4.6 KiB
Go
188 lines
4.6 KiB
Go
package bucket
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestSplit(t *testing.T) {
|
|
for _, test := range []struct {
|
|
in string
|
|
wantBucket string
|
|
wantPath string
|
|
}{
|
|
{in: "", wantBucket: "", wantPath: ""},
|
|
{in: "bucket", wantBucket: "bucket", wantPath: ""},
|
|
{in: "bucket/path", wantBucket: "bucket", wantPath: "path"},
|
|
{in: "bucket/path/subdir", wantBucket: "bucket", wantPath: "path/subdir"},
|
|
} {
|
|
gotBucket, gotPath := Split(test.in)
|
|
assert.Equal(t, test.wantBucket, gotBucket, test.in)
|
|
assert.Equal(t, test.wantPath, gotPath, test.in)
|
|
}
|
|
}
|
|
|
|
func TestJoin(t *testing.T) {
|
|
for _, test := range []struct {
|
|
in1, in2 string
|
|
want string
|
|
}{
|
|
{in1: "", in2: "", want: ""},
|
|
{in1: "in1", in2: "", want: "in1"},
|
|
{in1: "", in2: "in2", want: "in2"},
|
|
{in1: "in1", in2: "in2", want: "in1/in2"},
|
|
{in1: "in1/", in2: "in2", want: "in1//in2"},
|
|
{in1: "in1", in2: "/in2", want: "in1//in2"},
|
|
{in1: "in1", in2: "in2/", want: "in1/in2/"},
|
|
{in1: "/in1", in2: "/in2", want: "/in1//in2"},
|
|
{in1: "/in1", in2: "../in2", want: "/in1/../in2"},
|
|
} {
|
|
got := Join(test.in1, test.in2)
|
|
assert.Equal(t, test.want, got, fmt.Sprintf("in1=%q, in2=%q", test.in1, test.in2))
|
|
}
|
|
}
|
|
|
|
func TestIsAllSlashes(t *testing.T) {
|
|
for _, test := range []struct {
|
|
in string
|
|
want bool
|
|
}{
|
|
{in: "", want: false},
|
|
{in: "/", want: true},
|
|
{in: "x/", want: false},
|
|
{in: "/x", want: false},
|
|
{in: "//", want: true},
|
|
{in: "/x/", want: false},
|
|
{in: "///", want: true},
|
|
} {
|
|
got := IsAllSlashes(test.in)
|
|
assert.Equal(t, test.want, got, test.in)
|
|
}
|
|
}
|
|
|
|
func TestCache(t *testing.T) {
|
|
c := NewCache()
|
|
errBoom := errors.New("boom")
|
|
|
|
assert.Equal(t, 0, len(c.status))
|
|
|
|
// IsDeleted before creation
|
|
assert.False(t, c.IsDeleted("bucket"))
|
|
|
|
// MarkOK
|
|
|
|
c.MarkOK("")
|
|
assert.Equal(t, 0, len(c.status))
|
|
|
|
// MarkOK again
|
|
|
|
c.MarkOK("bucket")
|
|
assert.Equal(t, map[string]bool{"bucket": true}, c.status)
|
|
|
|
// MarkDeleted
|
|
|
|
c.MarkDeleted("bucket")
|
|
assert.Equal(t, map[string]bool{"bucket": false}, c.status)
|
|
|
|
// MarkOK again
|
|
|
|
c.MarkOK("bucket")
|
|
assert.Equal(t, map[string]bool{"bucket": true}, c.status)
|
|
|
|
// IsDeleted after creation
|
|
assert.False(t, c.IsDeleted("bucket"))
|
|
|
|
// Create from root
|
|
|
|
err := c.Create("", nil, nil)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true}, c.status)
|
|
|
|
// Create bucket that is already OK
|
|
|
|
err = c.Create("bucket", nil, nil)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true}, c.status)
|
|
|
|
// Create new bucket
|
|
|
|
err = c.Create("bucket2", func() error {
|
|
return nil
|
|
}, func() (bool, error) {
|
|
return true, nil
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": true}, c.status)
|
|
|
|
// Create bucket that has been deleted with error
|
|
|
|
c.status["bucket2"] = false // mark bucket deleted
|
|
err = c.Create("bucket2", nil, func() (bool, error) {
|
|
return false, errBoom
|
|
})
|
|
assert.Equal(t, errBoom, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": false}, c.status)
|
|
|
|
// Create bucket that has been deleted with no error
|
|
|
|
err = c.Create("bucket2", nil, func() (bool, error) {
|
|
return true, nil
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": true}, c.status)
|
|
|
|
// Create a new bucket with no exists function
|
|
|
|
err = c.Create("bucket3", func() error {
|
|
return nil
|
|
}, nil)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": true, "bucket3": true}, c.status)
|
|
|
|
// Create a new bucket with no exists function with an error
|
|
|
|
err = c.Create("bucket4", func() error {
|
|
return errBoom
|
|
}, nil)
|
|
assert.Equal(t, errBoom, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": true, "bucket3": true}, c.status)
|
|
|
|
// Remove root
|
|
|
|
err = c.Remove("", func() error {
|
|
return nil
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": true, "bucket3": true}, c.status)
|
|
|
|
// Remove existing bucket
|
|
|
|
err = c.Remove("bucket3", func() error {
|
|
return nil
|
|
})
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": true, "bucket3": false}, c.status)
|
|
|
|
// IsDeleted after removal
|
|
assert.True(t, c.IsDeleted("bucket3"))
|
|
|
|
// Remove it again
|
|
|
|
err = c.Remove("bucket3", func() error {
|
|
return errBoom
|
|
})
|
|
assert.Equal(t, ErrAlreadyDeleted, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": true, "bucket3": false}, c.status)
|
|
|
|
// Remove bucket with error
|
|
|
|
err = c.Remove("bucket2", func() error {
|
|
return errBoom
|
|
})
|
|
assert.Equal(t, errBoom, err)
|
|
assert.Equal(t, map[string]bool{"bucket": true, "bucket2": true, "bucket3": false}, c.status)
|
|
}
|