fix: enable errorlint in api, client and pkg

Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
This commit is contained in:
Matthieu MOREL 2024-10-13 19:39:18 +02:00
parent d6412f468e
commit b281a3c4fa
22 changed files with 69 additions and 52 deletions

View File

@ -15,6 +15,7 @@
package rpctypes
import (
"errors"
"testing"
"google.golang.org/grpc/codes"
@ -24,19 +25,20 @@ import (
func TestConvert(t *testing.T) {
e1 := status.Error(codes.InvalidArgument, "etcdserver: key is not provided")
e2 := ErrGRPCEmptyKey
e3 := ErrEmptyKey
var e3 EtcdError
errors.As(ErrEmptyKey, &e3)
if e1.Error() != e2.Error() {
t.Fatalf("expected %q == %q", e1.Error(), e2.Error())
}
if ev1, ok := status.FromError(e1); ok && ev1.Code() != e3.(EtcdError).Code() {
t.Fatalf("expected them to be equal, got %v / %v", ev1.Code(), e3.(EtcdError).Code())
if ev1, ok := status.FromError(e1); ok && ev1.Code() != e3.Code() {
t.Fatalf("expected them to be equal, got %v / %v", ev1.Code(), e3.Code())
}
if e1.Error() == e3.Error() {
t.Fatalf("expected %q != %q", e1.Error(), e3.Error())
}
if ev2, ok := status.FromError(e2); ok && ev2.Code() != e3.(EtcdError).Code() {
t.Fatalf("expected them to be equal, got %v / %v", ev2.Code(), e3.(EtcdError).Code())
if ev2, ok := status.FromError(e2); ok && ev2.Code() != e3.Code() {
t.Fatalf("expected them to be equal, got %v / %v", ev2.Code(), e3.Code())
}
}

View File

@ -17,6 +17,7 @@
package fileutil
import (
"errors"
"fmt"
"io"
"os"
@ -58,13 +59,13 @@ func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
func ofdTryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
f, err := os.OpenFile(path, flag, perm)
if err != nil {
return nil, fmt.Errorf("ofdTryLockFile failed to open %q (%v)", path, err)
return nil, fmt.Errorf("ofdTryLockFile failed to open %q (%w)", path, err)
}
flock := wrlck
if err = syscall.FcntlFlock(f.Fd(), unix.F_OFD_SETLK, &flock); err != nil {
f.Close()
if err == syscall.EWOULDBLOCK {
if errors.Is(err, syscall.EWOULDBLOCK) {
err = ErrLocked
}
return nil, err
@ -79,7 +80,7 @@ func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
func ofdLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
f, err := os.OpenFile(path, flag, perm)
if err != nil {
return nil, fmt.Errorf("ofdLockFile failed to open %q (%v)", path, err)
return nil, fmt.Errorf("ofdLockFile failed to open %q (%w)", path, err)
}
flock := wrlck

View File

@ -17,6 +17,7 @@
package fileutil
import (
"errors"
"os"
"syscall"
)
@ -25,10 +26,10 @@ func preallocExtend(f *os.File, sizeInBytes int64) error {
// use mode = 0 to change size
err := syscall.Fallocate(int(f.Fd()), 0, 0, sizeInBytes)
if err != nil {
errno, ok := err.(syscall.Errno)
var errno syscall.Errno
// not supported; fallback
// fallocate EINTRs frequently in some environments; fallback
if ok && (errno == syscall.ENOTSUP || errno == syscall.EINTR) {
if errors.As(err, &errno) && (errno == syscall.ENOTSUP || errno == syscall.EINTR) {
return preallocExtendTrunc(f, sizeInBytes)
}
}
@ -39,9 +40,9 @@ func preallocFixed(f *os.File, sizeInBytes int64) error {
// use mode = 1 to keep size; see FALLOC_FL_KEEP_SIZE
err := syscall.Fallocate(int(f.Fd()), 1, 0, sizeInBytes)
if err != nil {
errno, ok := err.(syscall.Errno)
var errno syscall.Errno
// treat not supported as nil error
if ok && errno == syscall.ENOTSUP {
if errors.As(err, &errno) && errno == syscall.ENOTSUP {
return nil
}
}

View File

@ -87,7 +87,7 @@ func GetCluster(serviceScheme, service, name, dns string, apurls types.URLs) ([]
err := updateNodeMap(service, serviceScheme)
if err != nil {
return nil, fmt.Errorf("error querying DNS SRV records for _%s %s", service, err)
return nil, fmt.Errorf("error querying DNS SRV records for _%s %w", service, err)
}
return stringParts, nil
}
@ -123,7 +123,7 @@ func GetClient(service, domain string, serviceName string) (*SRVClients, error)
errHTTP := updateURLs(GetSRVService(service, serviceName, "http"), "http")
if errHTTPS != nil && errHTTP != nil {
return nil, fmt.Errorf("dns lookup errors: %s and %s", errHTTPS, errHTTP)
return nil, fmt.Errorf("dns lookup errors: %w and %w", errHTTPS, errHTTP)
}
endpoints := make([]string, len(urls))

View File

@ -15,6 +15,7 @@
package transport
import (
"errors"
"net"
"testing"
"time"
@ -57,7 +58,8 @@ func TestReadWriteTimeoutDialer(t *testing.T) {
t.Fatal("wait timeout")
}
if operr, ok := err.(*net.OpError); !ok || operr.Op != "write" || !operr.Timeout() {
var operr *net.OpError
if !errors.As(err, &operr) || operr.Op != "write" || !operr.Timeout() {
t.Errorf("err = %v, want write i/o timeout error", err)
}
@ -77,7 +79,7 @@ func TestReadWriteTimeoutDialer(t *testing.T) {
t.Fatal("wait timeout")
}
if operr, ok := err.(*net.OpError); !ok || operr.Op != "read" || !operr.Timeout() {
if !errors.As(err, &operr) || operr.Op != "read" || !operr.Timeout() {
t.Errorf("err = %v, want read i/o timeout error", err)
}
}

View File

@ -15,6 +15,7 @@
package transport
import (
"errors"
"net"
"testing"
"time"
@ -82,7 +83,8 @@ func TestWriteReadTimeoutListener(t *testing.T) {
t.Fatal("wait timeout")
}
if operr, ok := err.(*net.OpError); !ok || operr.Op != "write" || !operr.Timeout() {
var operr *net.OpError
if !errors.As(err, &operr) || operr.Op != "write" || !operr.Timeout() {
t.Errorf("err = %v, want write i/o timeout error", err)
}
writerStopCh <- struct{}{}
@ -109,7 +111,7 @@ func TestWriteReadTimeoutListener(t *testing.T) {
t.Fatal("wait timeout")
}
if operr, ok := err.(*net.OpError); !ok || operr.Op != "read" || !operr.Timeout() {
if !errors.As(err, &operr) || operr.Op != "read" || !operr.Timeout() {
t.Errorf("err = %v, want read i/o timeout error", err)
}
readerStopCh <- struct{}{}

View File

@ -294,7 +294,7 @@ func (c *Client) getToken(ctx context.Context) error {
resp, err := c.Auth.Authenticate(ctx, c.Username, c.Password)
if err != nil {
if err == rpctypes.ErrAuthNotEnabled {
if errors.Is(err, rpctypes.ErrAuthNotEnabled) {
c.authTokenBundle.UpdateAuthToken("")
return nil
}
@ -605,7 +605,8 @@ func ContextError(ctx context.Context, err error) error {
return nil
}
err = rpctypes.Error(err)
if _, ok := err.(rpctypes.EtcdError); ok {
var serverErr rpctypes.EtcdError
if errors.As(err, &serverErr) {
return err
}
if ev, ok := status.FromError(err); ok {
@ -627,7 +628,7 @@ func canceledByCaller(stopCtx context.Context, err error) bool {
return false
}
return err == context.Canceled || err == context.DeadlineExceeded
return errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)
}
// IsConnCanceled returns true, if error is from a closed gRPC connection.
@ -645,7 +646,7 @@ func IsConnCanceled(err error) bool {
}
// >= gRPC v1.10.x
if err == context.Canceled {
if errors.Is(err, context.Canceled) {
return true
}

View File

@ -430,8 +430,8 @@ func TestClientRejectOldCluster(t *testing.T) {
},
}
if err := c.checkVersion(); err != tt.expectedError {
t.Errorf("heckVersion err:%v", err)
if err := c.checkVersion(); !errors.Is(err, tt.expectedError) {
t.Errorf("checkVersion err:%v", err)
}
})
}

View File

@ -16,6 +16,7 @@ package recipe
import (
"context"
"errors"
"fmt"
"strings"
"time"
@ -51,7 +52,7 @@ func newUniqueKV(kv v3.KV, prefix string, val string) (*RemoteKV, error) {
if err == nil {
return &RemoteKV{kv, newKey, rev, val}, nil
}
if err != ErrKeyExists {
if !errors.Is(err, ErrKeyExists) {
return nil, err
}
}
@ -155,7 +156,7 @@ func newUniqueEphemeralKV(s *concurrency.Session, prefix, val string) (ek *Ephem
for {
newKey := fmt.Sprintf("%s/%v", prefix, time.Now().UnixNano())
ek, err = newEphemeralKV(s, newKey, val)
if err == nil || err != ErrKeyExists {
if err == nil || !errors.Is(err, ErrKeyExists) {
break
}
}

View File

@ -16,6 +16,7 @@ package clientv3
import (
"context"
"errors"
"sync"
"time"
@ -464,7 +465,7 @@ func (l *lessor) recvKeepAliveLoop() (gerr error) {
return err
}
if ContextError(l.stopCtx, err) == rpctypes.ErrNoLeader {
if errors.Is(ContextError(l.stopCtx, err), rpctypes.ErrNoLeader) {
l.closeRequireLeader()
}
break

View File

@ -16,6 +16,7 @@ package leasing
import (
"context"
"errors"
"strings"
"sync"
"time"
@ -282,7 +283,8 @@ func (lkv *leasingKV) acquire(ctx context.Context, key string, op v3.Op) (*v3.Tx
return resp, nil
}
// retry if transient error
if _, ok := err.(rpctypes.EtcdError); ok {
var serverErr rpctypes.EtcdError
if errors.As(err, &serverErr) {
return nil, err
}
if ev, ok := status.FromError(err); ok && ev.Code() != codes.Unavailable {

View File

@ -117,7 +117,7 @@ func NewMaintenance(c *Client) Maintenance {
dial: func(endpoint string) (pb.MaintenanceClient, func(), error) {
conn, err := c.Dial(endpoint)
if err != nil {
return nil, nil, fmt.Errorf("failed to dial endpoint %s with maintenance client: %v", endpoint, err)
return nil, nil, fmt.Errorf("failed to dial endpoint %s with maintenance client: %w", endpoint, err)
}
cancel := func() { conn.Close() }
@ -297,8 +297,8 @@ func (m *maintenance) Snapshot(ctx context.Context) (io.ReadCloser, error) {
}
func (m *maintenance) logAndCloseWithError(err error, pw *io.PipeWriter) {
switch err {
case io.EOF:
switch {
case errors.Is(err, io.EOF):
m.lg.Info("completed snapshot read; closing")
default:
m.lg.Warn("failed to receive from snapshot stream; closing", zap.Error(err))

View File

@ -85,12 +85,12 @@ func startMockServersUnix(count int) (ms *MockServers, err error) {
for i := 0; i < count; i++ {
f, err := os.CreateTemp(dir, "etcd-unix-so-")
if err != nil {
return nil, fmt.Errorf("failed to allocate temp file for unix socket: %v", err)
return nil, fmt.Errorf("failed to allocate temp file for unix socket: %w", err)
}
fn := f.Name()
err = os.Remove(fn)
if err != nil {
return nil, fmt.Errorf("failed to remove temp file before creating unix socket: %v", err)
return nil, fmt.Errorf("failed to remove temp file before creating unix socket: %w", err)
}
addrs = append(addrs, fn)
}
@ -110,7 +110,7 @@ func startMockServers(network string, addrs []string) (ms *MockServers, err erro
for idx, addr := range addrs {
ln, err := net.Listen(network, addr)
if err != nil {
return nil, fmt.Errorf("failed to listen %v", err)
return nil, fmt.Errorf("failed to listen %w", err)
}
ms.Servers[idx] = &MockServer{ln: ln, Network: network, Address: ln.Addr().String()}
ms.StartAt(idx)
@ -126,7 +126,7 @@ func (ms *MockServers) StartAt(idx int) (err error) {
if ms.Servers[idx].ln == nil {
ms.Servers[idx].ln, err = net.Listen(ms.Servers[idx].Network, ms.Servers[idx].Address)
if err != nil {
return fmt.Errorf("failed to listen %v", err)
return fmt.Errorf("failed to listen %w", err)
}
}

View File

@ -16,6 +16,7 @@ package clientv3
import (
"context"
"errors"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
@ -52,7 +53,8 @@ func (rp retryPolicy) String() string {
// handle itself even with retries.
func isSafeRetryImmutableRPC(err error) bool {
eErr := rpctypes.Error(err)
if serverErr, ok := eErr.(rpctypes.EtcdError); ok && serverErr.Code() != codes.Unavailable {
var serverErr rpctypes.EtcdError
if errors.As(eErr, &serverErr) && serverErr.Code() != codes.Unavailable {
// interrupted by non-transient server-side or gRPC-side error
// client cannot handle itself (e.g. rpctypes.ErrCompacted)
return false

View File

@ -349,10 +349,10 @@ func isContextError(err error) bool {
}
func contextErrToGRPCErr(err error) error {
switch err {
case context.DeadlineExceeded:
switch {
case errors.Is(err, context.DeadlineExceeded):
return status.Errorf(codes.DeadlineExceeded, err.Error())
case context.Canceled:
case errors.Is(err, context.Canceled):
return status.Errorf(codes.Canceled, err.Error())
default:
return status.Errorf(codes.Unknown, err.Error())

View File

@ -62,7 +62,7 @@ func SaveWithVersion(ctx context.Context, lg *zap.Logger, cfg clientv3.Config, d
var f *os.File
f, err = os.OpenFile(partpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileutil.PrivateFileMode)
if err != nil {
return "", fmt.Errorf("could not open %s (%v)", partpath, err)
return "", fmt.Errorf("could not open %s (%w)", partpath, err)
}
lg.Info("created temporary db file", zap.String("path", partpath))
@ -95,7 +95,7 @@ func SaveWithVersion(ctx context.Context, lg *zap.Logger, cfg clientv3.Config, d
)
if err = os.Rename(partpath, dbPath); err != nil {
return resp.Version, fmt.Errorf("could not rename %s to %s (%v)", partpath, dbPath, err)
return resp.Version, fmt.Errorf("could not rename %s to %s (%w)", partpath, dbPath, err)
}
lg.Info("saved", zap.String("path", dbPath))
return resp.Version, nil

View File

@ -395,7 +395,7 @@ func (w *watcher) Close() (err error) {
}
}
// Consider context.Canceled as a successful close
if err == context.Canceled {
if errors.Is(err, context.Canceled) {
err = nil
}
return err
@ -653,7 +653,7 @@ func (w *watchGRPCStream) run() {
// watch client failed on Recv; spawn another if possible
case err := <-w.errc:
if isHaltErr(w.ctx, err) || ContextError(w.ctx, err) == v3rpc.ErrNoLeader {
if isHaltErr(w.ctx, err) || errors.Is(ContextError(w.ctx, err), v3rpc.ErrNoLeader) {
closeErr = err
return
}

View File

@ -201,7 +201,7 @@ func (f *featureGate) Set(value string) error {
v := strings.TrimSpace(arr[1])
boolValue, err := strconv.ParseBool(v)
if err != nil {
return fmt.Errorf("invalid value of %s=%s, err: %v", k, v, err)
return fmt.Errorf("invalid value of %s=%s, err: %w", k, v, err)
}
m[k] = boolValue
}

View File

@ -108,7 +108,7 @@ func setFlagFromEnv(lg *zap.Logger, fs flagSetter, prefix, fname string, usedEnv
if val != "" {
usedEnvKey[key] = true
if serr := fs.Set(fname, val); serr != nil {
return fmt.Errorf("invalid value %q for %s: %v", val, key, serr)
return fmt.Errorf("invalid value %q for %s: %w", val, key, serr)
}
if log && lg != nil {
lg.Info(

View File

@ -63,7 +63,7 @@ func (ss *StubServer) Start(sopts []grpc.ServerOption, dopts ...grpc.DialOption)
lis, err := net.Listen(ss.Network, ss.Address)
if err != nil {
return fmt.Errorf("net.Listen(%q, %q) = %v", ss.Network, ss.Address, err)
return fmt.Errorf("net.Listen(%q, %q) = %w", ss.Network, ss.Address, err)
}
ss.Address = lis.Addr().String()
ss.cleanups = append(ss.cleanups, func() { lis.Close() })

View File

@ -16,6 +16,7 @@ package ioutil
import (
"bytes"
"errors"
"io"
"testing"
)
@ -28,7 +29,7 @@ func (rc *readerNilCloser) Close() error { return nil }
func TestExactReadCloserExpectEOF(t *testing.T) {
buf := bytes.NewBuffer(make([]byte, 10))
rc := NewExactReadCloser(&readerNilCloser{buf}, 1)
if _, err := rc.Read(make([]byte, 10)); err != ErrExpectEOF {
if _, err := rc.Read(make([]byte, 10)); !errors.Is(err, ErrExpectEOF) {
t.Fatalf("expected %v, got %v", ErrExpectEOF, err)
}
}
@ -40,7 +41,7 @@ func TestExactReadCloserShort(t *testing.T) {
if _, err := rc.Read(make([]byte, 10)); err != nil {
t.Fatalf("Read expected nil err, got %v", err)
}
if err := rc.Close(); err != ErrShortRead {
if err := rc.Close(); !errors.Is(err, ErrShortRead) {
t.Fatalf("Close expected %v, got %v", ErrShortRead, err)
}
}

View File

@ -16,6 +16,7 @@ package netutil
import (
"context"
"errors"
"fmt"
"net"
"net/url"
@ -70,14 +71,14 @@ func resolveTCPAddrs(ctx context.Context, lg *zap.Logger, urls [][]url.URL) ([][
for i, u := range us {
nu, err := url.Parse(u.String())
if err != nil {
return nil, fmt.Errorf("failed to parse %q (%v)", u.String(), err)
return nil, fmt.Errorf("failed to parse %q (%w)", u.String(), err)
}
nus[i] = *nu
}
for i, u := range nus {
h, err := resolveURL(ctx, lg, u)
if err != nil {
return nil, fmt.Errorf("failed to resolve %q (%v)", u.String(), err)
return nil, fmt.Errorf("failed to resolve %q (%w)", u.String(), err)
}
if h != "" {
nus[i].Host = h
@ -217,6 +218,6 @@ func stringsToURLs(us []string) ([]url.URL, error) {
}
func IsNetworkTimeoutError(err error) bool {
nerr, ok := err.(net.Error)
return ok && nerr.Timeout()
var nerr net.Error
return errors.As(err, &nerr) && nerr.Timeout()
}