overdue
This commit is contained in:
1032
.rclone_repo/backend/sftp/sftp.go
Executable file
1032
.rclone_repo/backend/sftp/sftp.go
Executable file
File diff suppressed because it is too large
Load Diff
37
.rclone_repo/backend/sftp/sftp_internal_test.go
Executable file
37
.rclone_repo/backend/sftp/sftp_internal_test.go
Executable file
@@ -0,0 +1,37 @@
|
||||
// +build !plan9,go1.9
|
||||
|
||||
package sftp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestShellEscape(t *testing.T) {
|
||||
for i, test := range []struct {
|
||||
unescaped, escaped string
|
||||
}{
|
||||
{"", ""},
|
||||
{"/this/is/harmless", "/this/is/harmless"},
|
||||
{"$(rm -rf /)", "\\$\\(rm\\ -rf\\ /\\)"},
|
||||
{"/test/\n", "/test/'\n'"},
|
||||
{":\"'", ":\\\"\\'"},
|
||||
} {
|
||||
got := shellEscape(test.unescaped)
|
||||
assert.Equal(t, test.escaped, got, fmt.Sprintf("Test %d unescaped = %q", i, test.unescaped))
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseHash(t *testing.T) {
|
||||
for i, test := range []struct {
|
||||
sshOutput, checksum string
|
||||
}{
|
||||
{"8dbc7733dbd10d2efc5c0a0d8dad90f958581821 RELEASE.md\n", "8dbc7733dbd10d2efc5c0a0d8dad90f958581821"},
|
||||
{"03cfd743661f07975fa2f1220c5194cbaff48451 -\n", "03cfd743661f07975fa2f1220c5194cbaff48451"},
|
||||
} {
|
||||
got := parseHash([]byte(test.sshOutput))
|
||||
assert.Equal(t, test.checksum, got, fmt.Sprintf("Test %d sshOutput = %q", i, test.sshOutput))
|
||||
}
|
||||
}
|
||||
20
.rclone_repo/backend/sftp/sftp_test.go
Executable file
20
.rclone_repo/backend/sftp/sftp_test.go
Executable file
@@ -0,0 +1,20 @@
|
||||
// Test Sftp filesystem interface
|
||||
|
||||
// +build !plan9,go1.9
|
||||
|
||||
package sftp_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ncw/rclone/backend/sftp"
|
||||
"github.com/ncw/rclone/fstest/fstests"
|
||||
)
|
||||
|
||||
// TestIntegration runs integration tests against the remote
|
||||
func TestIntegration(t *testing.T) {
|
||||
fstests.Run(t, &fstests.Opt{
|
||||
RemoteName: "TestSftp:",
|
||||
NilObject: (*sftp.Object)(nil),
|
||||
})
|
||||
}
|
||||
6
.rclone_repo/backend/sftp/sftp_unsupported.go
Executable file
6
.rclone_repo/backend/sftp/sftp_unsupported.go
Executable file
@@ -0,0 +1,6 @@
|
||||
// Build for sftp for unsupported platforms to stop go complaining
|
||||
// about "no buildable Go source files "
|
||||
|
||||
// +build plan9 !go1.9
|
||||
|
||||
package sftp
|
||||
49
.rclone_repo/backend/sftp/stringlock.go
Executable file
49
.rclone_repo/backend/sftp/stringlock.go
Executable file
@@ -0,0 +1,49 @@
|
||||
// +build !plan9,go1.9
|
||||
|
||||
package sftp
|
||||
|
||||
import "sync"
|
||||
|
||||
// stringLock locks for string IDs passed in
|
||||
type stringLock struct {
|
||||
mu sync.Mutex // mutex to protect below
|
||||
locks map[string]chan struct{} // map of locks
|
||||
}
|
||||
|
||||
// newStringLock creates a stringLock
|
||||
func newStringLock() *stringLock {
|
||||
return &stringLock{
|
||||
locks: make(map[string]chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Lock locks on the id passed in
|
||||
func (l *stringLock) Lock(ID string) {
|
||||
l.mu.Lock()
|
||||
for {
|
||||
ch, ok := l.locks[ID]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
// Wait for the channel to be closed
|
||||
l.mu.Unlock()
|
||||
// fs.Logf(nil, "Waiting for stringLock on %q", ID)
|
||||
<-ch
|
||||
l.mu.Lock()
|
||||
}
|
||||
l.locks[ID] = make(chan struct{})
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
// Unlock unlocks on the id passed in. Will panic if Lock with the
|
||||
// given id wasn't called first.
|
||||
func (l *stringLock) Unlock(ID string) {
|
||||
l.mu.Lock()
|
||||
ch, ok := l.locks[ID]
|
||||
if !ok {
|
||||
panic("stringLock: Unlock before Lock")
|
||||
}
|
||||
close(ch)
|
||||
delete(l.locks, ID)
|
||||
l.mu.Unlock()
|
||||
}
|
||||
42
.rclone_repo/backend/sftp/stringlock_test.go
Executable file
42
.rclone_repo/backend/sftp/stringlock_test.go
Executable file
@@ -0,0 +1,42 @@
|
||||
// +build !plan9,go1.9
|
||||
|
||||
package sftp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStringLock(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
counter := [3]int{}
|
||||
lock := newStringLock()
|
||||
const (
|
||||
outer = 10
|
||||
inner = 100
|
||||
total = outer * inner
|
||||
)
|
||||
for k := 0; k < outer; k++ {
|
||||
for j := range counter {
|
||||
wg.Add(1)
|
||||
go func(j int) {
|
||||
defer wg.Done()
|
||||
ID := fmt.Sprintf("%d", j)
|
||||
for i := 0; i < inner; i++ {
|
||||
lock.Lock(ID)
|
||||
n := counter[j]
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
counter[j] = n + 1
|
||||
lock.Unlock(ID)
|
||||
}
|
||||
|
||||
}(j)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
assert.Equal(t, [3]int{total, total, total}, counter)
|
||||
}
|
||||
Reference in New Issue
Block a user