Files
rclone/fs/fserrors/error_syscall_test.go
T
nielash 6676f2673e fs: retry "network is unreachable" and "network is down" errors
ENETUNREACH and ENETDOWN were not in the list of retriable errors on
non-Windows platforms, so a single failed connection aborted the
transfer instead of being retried as a low level retry. The Windows
list already includes the equivalent WSAENETUNREACH and WSAENETDOWN.

This is easy to hit on a host with IPv6 enabled but no IPv6 route: if
the A lookup fails transiently while the AAAA lookup succeeds, the only
address to dial is IPv6 and the connect fails with ENETUNREACH. A retry
resolves again and normally succeeds.

(cherry picked from commit 94e319d2fa)
2026-10-08 17:17:11 +01:00

76 lines
1.7 KiB
Go

//go:build !plan9
package fserrors
import (
"fmt"
"net"
"net/url"
"os"
"syscall"
"testing"
"github.com/stretchr/testify/assert"
)
// make a plausible network error with the underlying errno
func makeNetErr(errno syscall.Errno) error {
return &net.OpError{
Op: "write",
Net: "tcp",
Source: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 123},
Addr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8080},
Err: &os.SyscallError{
Syscall: "write",
Err: errno,
},
}
}
func TestWithSyscallCause(t *testing.T) {
for i, test := range []struct {
err error
wantRetriable bool
wantErr error
}{
{makeNetErr(syscall.EAGAIN), true, syscall.EAGAIN},
{makeNetErr(syscall.Errno(123123123)), false, syscall.Errno(123123123)},
} {
gotRetriable, gotErr := Cause(test.err)
what := fmt.Sprintf("test #%d: %v", i, test.err)
assert.Equal(t, test.wantErr, gotErr, what)
assert.Equal(t, test.wantRetriable, gotRetriable, what)
}
}
func TestWithSyscallShouldRetry(t *testing.T) {
for i, test := range []struct {
err error
want bool
}{
{makeNetErr(syscall.EAGAIN), true},
{makeNetErr(syscall.ENETDOWN), true},
{makeNetErr(syscall.ENETUNREACH), true},
{makeNetErr(syscall.Errno(123123123)), false},
{
wrap(&url.Error{
Op: "post",
URL: "http://localhost/",
Err: makeNetErr(syscall.EPIPE),
}, "potato error"),
true,
},
{
wrap(&url.Error{
Op: "post",
URL: "http://localhost/",
Err: makeNetErr(syscall.Errno(123123123)),
}, "listing error"),
false,
},
} {
got := ShouldRetry(test.err)
assert.Equal(t, test.want, got, fmt.Sprintf("test #%d: %v", i, test.err))
}
}