From e5a63483ffff36a9ef0e4bedb1184ebf4bfd633e Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Thu, 31 Oct 2024 18:54:59 +0100 Subject: [PATCH] fix: enable errorlint linter Signed-off-by: Matthieu MOREL --- contrib/raftexample/kvstore.go | 3 ++- contrib/raftexample/raft.go | 5 ++-- tests/e2e/ctl_v3_auth_test.go | 6 ++--- tests/e2e/utils.go | 2 +- tests/e2e/v3_curl_election_test.go | 2 +- tests/e2e/v3_curl_maxstream_test.go | 10 ++++---- tests/framework/e2e/cluster.go | 14 +++++------ tests/framework/e2e/etcdctl.go | 3 ++- tests/framework/e2e/util.go | 2 +- tests/framework/integration/cluster.go | 10 ++++---- tests/framework/integration/integration.go | 2 +- tests/integration/clientv3/kv_test.go | 5 ++-- .../integration/clientv3/lease/lease_test.go | 3 ++- tests/integration/clientv3/user_test.go | 6 ++--- tests/integration/clientv3/watch_test.go | 6 ++--- tests/integration/v2store/store_test.go | 24 ++++++++++++------- tests/integration/v3_grpc_test.go | 3 ++- tests/integration/v3_lease_test.go | 2 +- tests/robustness/failpoint/failpoint.go | 10 ++++---- tests/robustness/failpoint/gofail.go | 2 +- tests/robustness/report/wal.go | 6 ++--- tests/robustness/validate/operations.go | 2 +- tools/.golangci.yaml | 1 + tools/etcd-dump-db/backend.go | 4 ++-- tools/etcd-dump-logs/main.go | 9 +++---- 25 files changed, 79 insertions(+), 63 deletions(-) diff --git a/contrib/raftexample/kvstore.go b/contrib/raftexample/kvstore.go index b319677cada..11bbf1fc6e7 100644 --- a/contrib/raftexample/kvstore.go +++ b/contrib/raftexample/kvstore.go @@ -18,6 +18,7 @@ import ( "bytes" "encoding/gob" "encoding/json" + "errors" "log" "strings" "sync" @@ -113,7 +114,7 @@ func (s *kvstore) getSnapshot() ([]byte, error) { func (s *kvstore) loadSnapshot() (*raftpb.Snapshot, error) { snapshot, err := s.snapshotter.Load() - if err == snap.ErrNoSnapshot { + if errors.Is(err, snap.ErrNoSnapshot) { return nil, nil } if err != nil { diff --git a/contrib/raftexample/raft.go b/contrib/raftexample/raft.go index 2c4ae9cf4b5..2ed8c27eab6 100644 --- a/contrib/raftexample/raft.go +++ b/contrib/raftexample/raft.go @@ -16,6 +16,7 @@ package main import ( "context" + "errors" "fmt" "log" "net/http" @@ -206,7 +207,7 @@ func (rc *raftNode) loadSnapshot() *raftpb.Snapshot { log.Fatalf("raftexample: error listing snapshots (%v)", err) } snapshot, err := rc.snapshotter.LoadNewestAvailable(walSnaps) - if err != nil && err != snap.ErrNoSnapshot { + if err != nil && !errors.Is(err, snap.ErrNoSnapshot) { log.Fatalf("raftexample: error loading snapshot (%v)", err) } return snapshot @@ -391,7 +392,7 @@ func (rc *raftNode) maybeTriggerSnapshot(applyDoneC <-chan struct{}) { compactIndex = rc.appliedIndex - snapshotCatchUpEntriesN } if err := rc.raftStorage.Compact(compactIndex); err != nil { - if err != raft.ErrCompacted { + if !errors.Is(err, raft.ErrCompacted) { panic(err) } } else { diff --git a/tests/e2e/ctl_v3_auth_test.go b/tests/e2e/ctl_v3_auth_test.go index 6c252e9c202..c221c9e047d 100644 --- a/tests/e2e/ctl_v3_auth_test.go +++ b/tests/e2e/ctl_v3_auth_test.go @@ -46,13 +46,13 @@ func TestCtlV3AuthSnapshotJWT(t *testing.T) { func authEnable(cx ctlCtx) error { // create root user with root role if err := ctlV3User(cx, []string{"add", "root", "--interactive=false"}, "User root created", []string{"root"}); err != nil { - return fmt.Errorf("failed to create root user %v", err) + return fmt.Errorf("failed to create root user %w", err) } if err := ctlV3User(cx, []string{"grant-role", "root", "root"}, "Role root is granted to user root", nil); err != nil { - return fmt.Errorf("failed to grant root user root role %v", err) + return fmt.Errorf("failed to grant root user root role %w", err) } if err := ctlV3AuthEnable(cx); err != nil { - return fmt.Errorf("authEnableTest ctlV3AuthEnable error (%v)", err) + return fmt.Errorf("authEnableTest ctlV3AuthEnable error (%w)", err) } return nil } diff --git a/tests/e2e/utils.go b/tests/e2e/utils.go index c8ccf9c1990..8917bd8072a 100644 --- a/tests/e2e/utils.go +++ b/tests/e2e/utils.go @@ -77,7 +77,7 @@ func tlsInfo(t testing.TB, cfg e2e.ClientConfig) (*transport.TLSInfo, error) { if cfg.AutoTLS { tls, err := transport.SelfCert(zap.NewNop(), t.TempDir(), []string{"localhost"}, 1) if err != nil { - return nil, fmt.Errorf("failed to generate cert: %s", err) + return nil, fmt.Errorf("failed to generate cert: %w", err) } return &tls, nil } diff --git a/tests/e2e/v3_curl_election_test.go b/tests/e2e/v3_curl_election_test.go index 01c7194ed3b..149bf057c2d 100644 --- a/tests/e2e/v3_curl_election_test.go +++ b/tests/e2e/v3_curl_election_test.go @@ -173,7 +173,7 @@ func CURLWithExpected(cx ctlCtx, tests []v3cURLTest) error { for _, t := range tests { value := fmt.Sprintf("%v", t.value) if err := e2e.CURLPost(cx.epc, e2e.CURLReq{Endpoint: t.endpoint, Value: value, Expected: expect.ExpectedResponse{Value: t.expected}}); err != nil { - return fmt.Errorf("endpoint (%s): error (%v), wanted %v", t.endpoint, err, t.expected) + return fmt.Errorf("endpoint (%s): error (%w), wanted %v", t.endpoint, err, t.expected) } } return nil diff --git a/tests/e2e/v3_curl_maxstream_test.go b/tests/e2e/v3_curl_maxstream_test.go index bdf5a2712e7..f1cf5a77c15 100644 --- a/tests/e2e/v3_curl_maxstream_test.go +++ b/tests/e2e/v3_curl_maxstream_test.go @@ -169,7 +169,7 @@ func submitConcurrentWatch(cx ctlCtx, number int, wgDone *sync.WaitGroup, closeC expectedLine := `"created":true}}` _, lerr := proc.ExpectWithContext(context.TODO(), expect.ExpectedResponse{Value: expectedLine}) if lerr != nil { - return fmt.Errorf("%v %v (expected %q). Try EXPECT_DEBUG=TRUE", args, lerr, expectedLine) + return fmt.Errorf("%v %w (expected %q). Try EXPECT_DEBUG=TRUE", args, lerr, expectedLine) } wgSchedule.Done() @@ -182,7 +182,7 @@ func submitConcurrentWatch(cx ctlCtx, number int, wgDone *sync.WaitGroup, closeC case <-closeCh: default: // perr could be nil. - return fmt.Errorf("unexpected connection close before server closes: %v", perr) + return fmt.Errorf("unexpected connection close before server closes: %w", perr) } return nil } @@ -225,19 +225,19 @@ func submitRangeAfterConcurrentWatch(cx ctlCtx, expectedValue string) { func setRLimit(nofile uint64) (func() error, error) { var rLimit syscall.Rlimit if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { - return nil, fmt.Errorf("failed to get open file limit, error: %v", err) + return nil, fmt.Errorf("failed to get open file limit, error: %w", err) } var wLimit syscall.Rlimit wLimit.Max = nofile wLimit.Cur = nofile if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &wLimit); err != nil { - return nil, fmt.Errorf("failed to set max open file limit, %v", err) + return nil, fmt.Errorf("failed to set max open file limit, %w", err) } return func() error { if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { - return fmt.Errorf("failed reset max open file limit, %v", err) + return fmt.Errorf("failed reset max open file limit, %w", err) } return nil }, nil diff --git a/tests/framework/e2e/cluster.go b/tests/framework/e2e/cluster.go index 23d422aa313..4aff11b9d6f 100644 --- a/tests/framework/e2e/cluster.go +++ b/tests/framework/e2e/cluster.go @@ -437,7 +437,7 @@ func InitEtcdProcessCluster(t testing.TB, cfg *EtcdProcessClusterConfig) (*EtcdP proc, err := NewEtcdProcess(t, etcdCfgs[i]) if err != nil { epc.Close() - return nil, fmt.Errorf("cannot configure: %v", err) + return nil, fmt.Errorf("cannot configure: %w", err) } epc.Procs[i] = proc } @@ -449,11 +449,11 @@ func InitEtcdProcessCluster(t testing.TB, cfg *EtcdProcessClusterConfig) (*EtcdP func StartEtcdProcessCluster(ctx context.Context, t testing.TB, epc *EtcdProcessCluster, cfg *EtcdProcessClusterConfig) (*EtcdProcessCluster, error) { if cfg.RollingStart { if err := epc.RollingStart(ctx); err != nil { - return nil, fmt.Errorf("cannot rolling-start: %v", err) + return nil, fmt.Errorf("cannot rolling-start: %w", err) } } else { if err := epc.Start(ctx); err != nil { - return nil, fmt.Errorf("cannot start: %v", err) + return nil, fmt.Errorf("cannot start: %w", err) } } @@ -465,7 +465,7 @@ func StartEtcdProcessCluster(ctx context.Context, t testing.TB, epc *EtcdProcess } if cfg.InitialLeaderIndex >= 0 { if err := epc.MoveLeader(ctx, t, cfg.InitialLeaderIndex); err != nil { - return nil, fmt.Errorf("failed to move leader: %v", err) + return nil, fmt.Errorf("failed to move leader: %w", err) } } return epc, nil @@ -864,7 +864,7 @@ func (epc *EtcdProcessCluster) StartNewProcFromConfig(ctx context.Context, tb te proc, err := NewEtcdProcess(tb, serverCfg) if err != nil { epc.Close() - return fmt.Errorf("cannot configure: %v", err) + return fmt.Errorf("cannot configure: %w", err) } epc.Procs = append(epc.Procs, proc) @@ -947,7 +947,7 @@ func (epc *EtcdProcessCluster) Stop() (err error) { } if curErr := p.Stop(); curErr != nil { if err != nil { - err = fmt.Errorf("%v; %v", err, curErr) + err = fmt.Errorf("%w; %w", err, curErr) } else { err = curErr } @@ -969,7 +969,7 @@ func (epc *EtcdProcessCluster) ConcurrentStop() (err error) { for range epc.Procs { if curErr := <-errCh; curErr != nil { if err != nil { - err = fmt.Errorf("%v; %v", err, curErr) + err = fmt.Errorf("%w; %w", err, curErr) } else { err = curErr } diff --git a/tests/framework/e2e/etcdctl.go b/tests/framework/e2e/etcdctl.go index 81d57c088d5..d0c8dc14c72 100644 --- a/tests/framework/e2e/etcdctl.go +++ b/tests/framework/e2e/etcdctl.go @@ -17,6 +17,7 @@ package e2e import ( "context" "encoding/json" + "errors" "fmt" "io" "strconv" @@ -252,7 +253,7 @@ func AddTxnResponse(resp *clientv3.TxnResponse, jsonData string) { jd := json.NewDecoder(strings.NewReader(jsonData)) for { t, e := jd.Token() - if e == io.EOF { + if errors.Is(e, io.EOF) { break } if t == "response_range" { diff --git a/tests/framework/e2e/util.go b/tests/framework/e2e/util.go index dcb73874786..d72f2d4939d 100644 --- a/tests/framework/e2e/util.go +++ b/tests/framework/e2e/util.go @@ -73,7 +73,7 @@ func SpawnWithExpectLines(ctx context.Context, args []string, envVars map[string l, lerr := proc.ExpectWithContext(ctx, txt) if lerr != nil { proc.Close() - return nil, fmt.Errorf("%v %v (expected %q, got %q). Try EXPECT_DEBUG=TRUE", args, lerr, txt.Value, lines) + return nil, fmt.Errorf("%v %w (expected %q, got %q). Try EXPECT_DEBUG=TRUE", args, lerr, txt.Value, lines) } lines = append(lines, l) } diff --git a/tests/framework/integration/cluster.go b/tests/framework/integration/cluster.go index 95b5c88d9f8..a71e8146907 100644 --- a/tests/framework/integration/cluster.go +++ b/tests/framework/integration/cluster.go @@ -780,13 +780,13 @@ func (m *Member) listenGRPC() error { m.Logger.Info("LISTEN GRPC", zap.String("grpcAddr", grpcAddr), zap.String("m.Name", m.Name), zap.String("workdir", wd)) grpcListener, err := net.Listen(network, grpcAddr) if err != nil { - return fmt.Errorf("listen failed on grpc socket %s (%v)", grpcAddr, err) + return fmt.Errorf("listen failed on grpc socket %s (%w)", grpcAddr, err) } addr := grpcListener.Addr().String() _, port, err = net.SplitHostPort(addr) if err != nil { - return fmt.Errorf("failed to parse grpc listen port from address %s (%v)", addr, err) + return fmt.Errorf("failed to parse grpc listen port from address %s (%w)", addr, err) } m.Port = port m.GRPCURL = fmt.Sprintf("%s://%s", m.clientScheme(), addr) @@ -830,7 +830,7 @@ func (m *Member) addBridge() (*bridge, error) { m.Logger.Info("LISTEN BRIDGE", zap.String("grpc-address", bridgeAddr), zap.String("member", m.Name)) bridgeListener, err := transport.NewUnixListener(bridgeAddr) if err != nil { - return nil, fmt.Errorf("listen failed on bridge socket %s (%v)", bridgeAddr, err) + return nil, fmt.Errorf("listen failed on bridge socket %s (%w)", bridgeAddr, err) } m.GRPCBridge = newBridge(dialer{network: network, addr: grpcAddr}, bridgeListener) @@ -962,7 +962,7 @@ func (m *Member) Launch() error { ) var err error if m.Server, err = etcdserver.NewServer(m.ServerConfig); err != nil { - return fmt.Errorf("failed to initialize the etcd server: %v", err) + return fmt.Errorf("failed to initialize the etcd server: %w", err) } m.Server.SyncTicker = time.NewTicker(500 * time.Millisecond) m.Server.Start() @@ -1568,7 +1568,7 @@ func (c *Cluster) GetLearnerMembers() ([]*pb.Member, error) { cli := c.Client(0) resp, err := cli.MemberList(context.Background()) if err != nil { - return nil, fmt.Errorf("failed to list member %v", err) + return nil, fmt.Errorf("failed to list member %w", err) } var learners []*pb.Member for _, m := range resp.Members { diff --git a/tests/framework/integration/integration.go b/tests/framework/integration/integration.go index 41fd78a8655..6e5de0cd528 100644 --- a/tests/framework/integration/integration.go +++ b/tests/framework/integration/integration.go @@ -77,7 +77,7 @@ func tlsInfo(t testing.TB, cfg config.TLSConfig) (*transport.TLSInfo, error) { case config.AutoTLS: tls, err := transport.SelfCert(zap.NewNop(), t.TempDir(), []string{"localhost"}, 1) if err != nil { - return nil, fmt.Errorf("failed to generate cert: %s", err) + return nil, fmt.Errorf("failed to generate cert: %w", err) } return &tls, nil case config.ManualTLS: diff --git a/tests/integration/clientv3/kv_test.go b/tests/integration/clientv3/kv_test.go index 5f66b4f9034..66a9bce59d5 100644 --- a/tests/integration/clientv3/kv_test.go +++ b/tests/integration/clientv3/kv_test.go @@ -461,7 +461,7 @@ func TestKVCompact(t *testing.T) { if !wr.Canceled { t.Fatalf("expected canceled watcher on compacted revision, got %v", wr.Canceled) } - if wr.Err() != rpctypes.ErrCompacted { + if !errors.Is(wr.Err(), rpctypes.ErrCompacted) { t.Fatalf("watch response error expected %v, got %v", rpctypes.ErrCompacted, wr.Err()) } wr, ok := <-wchan @@ -750,7 +750,8 @@ func TestKVLargeRequests(t *testing.T) { cli := clus.Client(0) _, err := cli.Put(context.TODO(), "foo", strings.Repeat("a", test.valueSize)) - if _, ok := err.(rpctypes.EtcdError); ok { + var etcdErr rpctypes.EtcdError + if errors.As(err, &etcdErr) { if !errors.Is(err, test.expectError) { t.Errorf("#%d: expected %v, got %v", i, test.expectError, err) } diff --git a/tests/integration/clientv3/lease/lease_test.go b/tests/integration/clientv3/lease/lease_test.go index 3f09ffbcf39..66b4f92ae4d 100644 --- a/tests/integration/clientv3/lease/lease_test.go +++ b/tests/integration/clientv3/lease/lease_test.go @@ -721,7 +721,8 @@ func TestLeaseKeepAliveLoopExit(t *testing.T) { cli.Close() _, err = cli.KeepAlive(ctx, resp.ID) - if _, ok := err.(clientv3.ErrKeepAliveHalted); !ok { + var keepAliveHaltedErr clientv3.ErrKeepAliveHalted + if !errors.As(err, &keepAliveHaltedErr) { t.Fatalf("expected %T, got %v(%T)", clientv3.ErrKeepAliveHalted{}, err, err) } } diff --git a/tests/integration/clientv3/user_test.go b/tests/integration/clientv3/user_test.go index 7ed13e7ed44..e1f20fe1986 100644 --- a/tests/integration/clientv3/user_test.go +++ b/tests/integration/clientv3/user_test.go @@ -194,10 +194,10 @@ func TestGetTokenWithoutAuth(t *testing.T) { defer client.Close() } - switch err { - case nil: + switch { + case err == nil: t.Log("passes as expected") - case context.DeadlineExceeded: + case errors.Is(err, context.DeadlineExceeded): t.Errorf("not expected result:%v with endpoint:%s", err, authapi.Endpoints()) default: t.Errorf("other errors:%v", err) diff --git a/tests/integration/clientv3/watch_test.go b/tests/integration/clientv3/watch_test.go index 090e473d065..5f229c554ea 100644 --- a/tests/integration/clientv3/watch_test.go +++ b/tests/integration/clientv3/watch_test.go @@ -472,7 +472,7 @@ func TestWatchResumeCompacted(t *testing.T) { if wresp.Err() == nil { continue } - if wresp.Err() != rpctypes.ErrCompacted { + if !errors.Is(wresp.Err(), rpctypes.ErrCompacted) { t.Fatalf("wresp.Err() expected %v, got %+v", rpctypes.ErrCompacted, wresp.Err()) } break @@ -519,7 +519,7 @@ func TestWatchCompactRevision(t *testing.T) { if !ok { t.Fatalf("expected wresp, but got closed channel") } - if wresp.Err() != rpctypes.ErrCompacted { + if !errors.Is(wresp.Err(), rpctypes.ErrCompacted) { t.Fatalf("wresp.Err() expected %v, but got %v", rpctypes.ErrCompacted, wresp.Err()) } if !wresp.Canceled { @@ -858,7 +858,7 @@ func TestWatchWithRequireLeader(t *testing.T) { if !ok { t.Fatalf("expected %v watch channel, got closed channel", rpctypes.ErrNoLeader) } - if resp.Err() != rpctypes.ErrNoLeader { + if !errors.Is(resp.Err(), rpctypes.ErrNoLeader) { t.Fatalf("expected %v watch response error, got %+v", rpctypes.ErrNoLeader, resp) } case <-time.After(integration2.RequestWaitTimeout): diff --git a/tests/integration/v2store/store_test.go b/tests/integration/v2store/store_test.go index e6db02ec8c5..37eb9748ea6 100644 --- a/tests/integration/v2store/store_test.go +++ b/tests/integration/v2store/store_test.go @@ -227,7 +227,8 @@ func TestStoreCreateFailsIfExists(t *testing.T) { // create /foo as dir again e, _err := s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) - err := _err.(*v2error.Error) + var err *v2error.Error + require.ErrorAs(t, _err, &err) assert.Equal(t, v2error.EcodeNodeExist, err.ErrorCode) assert.Equal(t, "Key already exists", err.Message) assert.Equal(t, "/foo", err.Cause) @@ -290,7 +291,8 @@ func TestStoreUpdateFailsIfDirectory(t *testing.T) { s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) e, _err := s.Update("/foo", "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) - err := _err.(*v2error.Error) + var err *v2error.Error + require.ErrorAs(t, _err, &err) assert.Equal(t, v2error.EcodeNotFile, err.ErrorCode) assert.Equal(t, "Not a file", err.Message) assert.Equal(t, "/foo", err.Cause) @@ -355,7 +357,8 @@ func TestStoreDeleteDirectoryFailsIfNonRecursiveAndDir(t *testing.T) { s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) e, _err := s.Delete("/foo", false, false) - err := _err.(*v2error.Error) + var err *v2error.Error + require.ErrorAs(t, _err, &err) assert.Equal(t, v2error.EcodeNotFile, err.ErrorCode) assert.Equal(t, "Not a file", err.Message) assert.Nil(t, e) @@ -407,7 +410,8 @@ func TestStoreCompareAndDeletePrevValueFailsIfNotMatch(t *testing.T) { var eidx uint64 = 1 s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) e, _err := s.CompareAndDelete("/foo", "baz", 0) - err := _err.(*v2error.Error) + var err *v2error.Error + require.ErrorAs(t, _err, &err) assert.Equal(t, v2error.EcodeTestFailed, err.ErrorCode) assert.Equal(t, "Compare failed", err.Message) assert.Nil(t, e) @@ -440,7 +444,8 @@ func TestStoreCompareAndDeletePrevIndexFailsIfNotMatch(t *testing.T) { s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) e, _err := s.CompareAndDelete("/foo", "", 100) require.Error(t, _err) - err := _err.(*v2error.Error) + var err *v2error.Error + require.ErrorAs(t, _err, &err) assert.Equal(t, v2error.EcodeTestFailed, err.ErrorCode) assert.Equal(t, "Compare failed", err.Message) assert.Nil(t, e) @@ -456,7 +461,8 @@ func TestStoreCompareAndDeleteDirectoryFail(t *testing.T) { s.Create("/foo", true, "", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) _, _err := s.CompareAndDelete("/foo", "", 0) require.Error(t, _err) - err := _err.(*v2error.Error) + var err *v2error.Error + require.ErrorAs(t, _err, &err) assert.Equal(t, v2error.EcodeNotFile, err.ErrorCode) } @@ -490,7 +496,8 @@ func TestStoreCompareAndSwapPrevValueFailsIfNotMatch(t *testing.T) { var eidx uint64 = 1 s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) e, _err := s.CompareAndSwap("/foo", "wrong_value", 0, "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) - err := _err.(*v2error.Error) + var err *v2error.Error + require.ErrorAs(t, _err, &err) assert.Equal(t, v2error.EcodeTestFailed, err.ErrorCode) assert.Equal(t, "Compare failed", err.Message) assert.Nil(t, e) @@ -529,7 +536,8 @@ func TestStoreCompareAndSwapPrevIndexFailsIfNotMatch(t *testing.T) { var eidx uint64 = 1 s.Create("/foo", false, "bar", false, v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) e, _err := s.CompareAndSwap("/foo", "", 100, "baz", v2store.TTLOptionSet{ExpireTime: v2store.Permanent}) - err := _err.(*v2error.Error) + var err *v2error.Error + require.ErrorAs(t, _err, &err) assert.Equal(t, v2error.EcodeTestFailed, err.ErrorCode) assert.Equal(t, "Compare failed", err.Message) assert.Nil(t, e) diff --git a/tests/integration/v3_grpc_test.go b/tests/integration/v3_grpc_test.go index 61fef15d8cd..e93f30e3b13 100644 --- a/tests/integration/v3_grpc_test.go +++ b/tests/integration/v3_grpc_test.go @@ -1961,7 +1961,8 @@ func TestV3AdditionalGRPCOptions(t *testing.T) { kvcli := integration.ToGRPC(clus.Client(0)).KV reqput := &pb.PutRequest{Key: []byte("foo"), Value: make([]byte, test.valueSize)} if _, err := kvcli.Put(context.TODO(), reqput); err != nil { - if _, ok := err.(rpctypes.EtcdError); ok { + var etcdErr rpctypes.EtcdError + if errors.As(err, &etcdErr) { if err.Error() != status.Convert(test.expectError).Message() { t.Errorf("expected %v, got %v", status.Convert(test.expectError).Message(), err.Error()) } diff --git a/tests/integration/v3_lease_test.go b/tests/integration/v3_lease_test.go index 2ec93a3ac84..339b05a526d 100644 --- a/tests/integration/v3_lease_test.go +++ b/tests/integration/v3_lease_test.go @@ -590,7 +590,7 @@ func stressLeaseTimeToLive(tctx context.Context, lc pb.LeaseClient) (reterr erro continue } _, kerr := lc.LeaseTimeToLive(tctx, &pb.LeaseTimeToLiveRequest{ID: resp.ID}) - if rpctypes.Error(kerr) == rpctypes.ErrLeaseNotFound { + if errors.Is(rpctypes.Error(kerr), rpctypes.ErrLeaseNotFound) { return kerr } } diff --git a/tests/robustness/failpoint/failpoint.go b/tests/robustness/failpoint/failpoint.go index 235f13debb2..252fb3e6314 100644 --- a/tests/robustness/failpoint/failpoint.go +++ b/tests/robustness/failpoint/failpoint.go @@ -85,17 +85,17 @@ func Inject(ctx context.Context, t *testing.T, lg *zap.Logger, clus *e2e.EtcdPro var err error if err = verifyClusterHealth(ctx, t, clus); err != nil { - return nil, fmt.Errorf("failed to verify cluster health before failpoint injection, err: %v", err) + return nil, fmt.Errorf("failed to verify cluster health before failpoint injection, err: %w", err) } lg.Info("Triggering failpoint", zap.String("failpoint", failpoint.Name())) start := time.Since(baseTime) clientReport, err := failpoint.Inject(ctx, t, lg, clus, baseTime, ids) if err != nil { lg.Error("Failed to trigger failpoint", zap.String("failpoint", failpoint.Name()), zap.Error(err)) - return nil, fmt.Errorf("failed triggering failpoint, err: %v", err) + return nil, fmt.Errorf("failed triggering failpoint, err: %w", err) } if err = verifyClusterHealth(ctx, t, clus); err != nil { - return nil, fmt.Errorf("failed to verify cluster health after failpoint injection, err: %v", err) + return nil, fmt.Errorf("failed to verify cluster health after failpoint injection, err: %w", err) } lg.Info("Finished triggering failpoint", zap.String("failpoint", failpoint.Name())) end := time.Since(baseTime) @@ -119,14 +119,14 @@ func verifyClusterHealth(ctx context.Context, _ *testing.T, clus *e2e.EtcdProces DialKeepAliveTimeout: 100 * time.Millisecond, }) if err != nil { - return fmt.Errorf("Error creating client for cluster %s: %v", clus.Procs[i].Config().Name, err) + return fmt.Errorf("Error creating client for cluster %s: %w", clus.Procs[i].Config().Name, err) } defer clusterClient.Close() cli := healthpb.NewHealthClient(clusterClient.ActiveConnection()) resp, err := cli.Check(ctx, &healthpb.HealthCheckRequest{}) if err != nil { - return fmt.Errorf("Error checking member %s health: %v", clus.Procs[i].Config().Name, err) + return fmt.Errorf("Error checking member %s health: %w", clus.Procs[i].Config().Name, err) } if resp.Status != healthpb.HealthCheckResponse_SERVING { return fmt.Errorf("Member %s health status expected %s, got %s", diff --git a/tests/robustness/failpoint/gofail.go b/tests/robustness/failpoint/gofail.go index 55486404783..2253fc79a36 100644 --- a/tests/robustness/failpoint/gofail.go +++ b/tests/robustness/failpoint/gofail.go @@ -120,7 +120,7 @@ func (f goPanicFailpoint) Inject(ctx context.Context, t *testing.T, lg *zap.Logg err = member.Wait(ctx) if err != nil && !strings.Contains(err.Error(), "unexpected exit code") { lg.Info("Member didn't exit as expected", zap.String("member", member.Config().Name), zap.Error(err)) - return reports, fmt.Errorf("member didn't exit as expected: %v", err) + return reports, fmt.Errorf("member didn't exit as expected: %w", err) } lg.Info("Member exited as expected", zap.String("member", member.Config().Name)) diff --git a/tests/robustness/report/wal.go b/tests/robustness/report/wal.go index 5ba0cb37059..e152be5450b 100644 --- a/tests/robustness/report/wal.go +++ b/tests/robustness/report/wal.go @@ -109,7 +109,7 @@ func ReadWAL(lg *zap.Logger, dataDir string) (state raftpb.HardState, ents []raf for { w, err := wal.OpenForRead(lg, walDir, walpb.Snapshot{Index: 0}) if err != nil { - return state, nil, fmt.Errorf("failed to open WAL, err: %s", err) + return state, nil, fmt.Errorf("failed to open WAL, err: %w", err) } _, state, ents, err = w.ReadAll() w.Close() @@ -119,10 +119,10 @@ func ReadWAL(lg *zap.Logger, dataDir string) (state raftpb.HardState, ents []raf } // we can only repair ErrUnexpectedEOF and we never repair twice. if repaired || !errors.Is(err, io.ErrUnexpectedEOF) { - return state, nil, fmt.Errorf("failed to read WAL, cannot be repaired, err: %s", err) + return state, nil, fmt.Errorf("failed to read WAL, cannot be repaired, err: %w", err) } if !wal.Repair(lg, walDir) { - return state, nil, fmt.Errorf("failed to repair WAL, err: %s", err) + return state, nil, fmt.Errorf("failed to repair WAL, err: %w", err) } lg.Info("repaired WAL", zap.Error(err)) repaired = true diff --git a/tests/robustness/validate/operations.go b/tests/robustness/validate/operations.go index efb36408044..9f39407ad81 100644 --- a/tests/robustness/validate/operations.go +++ b/tests/robustness/validate/operations.go @@ -50,7 +50,7 @@ func validateLinearizableOperationsAndVisualize(lg *zap.Logger, operations []por lg.Info("Saving visualization", zap.String("path", path)) err := porcupine.VisualizePath(model.NonDeterministicModel, info, path) if err != nil { - return fmt.Errorf("failed to visualize, err: %v", err) + return fmt.Errorf("failed to visualize, err: %w", err) } return nil } diff --git a/tools/.golangci.yaml b/tools/.golangci.yaml index 39358b0d83d..db4ea5cc395 100644 --- a/tools/.golangci.yaml +++ b/tools/.golangci.yaml @@ -18,6 +18,7 @@ linters: # - deadcode # - structcheck # - varcheck + - errorlint - gofmt - goimports - ineffassign diff --git a/tools/etcd-dump-db/backend.go b/tools/etcd-dump-db/backend.go index 6d64c005b75..9c41787acb8 100644 --- a/tools/etcd-dump-db/backend.go +++ b/tools/etcd-dump-db/backend.go @@ -37,7 +37,7 @@ func snapDir(dataDir string) string { func getBuckets(dbPath string) (buckets []string, err error) { db, derr := bolt.Open(dbPath, 0600, &bolt.Options{Timeout: flockTimeout}) if derr != nil { - return nil, fmt.Errorf("failed to open bolt DB %v", derr) + return nil, fmt.Errorf("failed to open bolt DB %w", derr) } defer db.Close() @@ -134,7 +134,7 @@ func metaDecoder(k, v []byte) { func iterateBucket(dbPath, bucket string, limit uint64, decode bool) (err error) { db, err := bolt.Open(dbPath, 0600, &bolt.Options{Timeout: flockTimeout}) if err != nil { - return fmt.Errorf("failed to open bolt DB %v", err) + return fmt.Errorf("failed to open bolt DB %w", err) } defer db.Close() diff --git a/tools/etcd-dump-logs/main.go b/tools/etcd-dump-logs/main.go index a13669ccc2e..4355997177c 100644 --- a/tools/etcd-dump-logs/main.go +++ b/tools/etcd-dump-logs/main.go @@ -18,6 +18,7 @@ import ( "bufio" "encoding/hex" "encoding/json" + "errors" "flag" "fmt" "io" @@ -119,8 +120,8 @@ func readUsingReadAll(lg *zap.Logger, index *uint64, snapfile *string, dataDir s snapshot, err = snap.Read(lg, filepath.Join(snapDir(dataDir), *snapfile)) } - switch err { - case nil: + switch { + case err == nil: walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term nodes := genIDSlice(snapshot.Metadata.ConfState.Voters) @@ -130,7 +131,7 @@ func readUsingReadAll(lg *zap.Logger, index *uint64, snapfile *string, dataDir s } fmt.Printf("Snapshot:\nterm=%d index=%d nodes=%s confstate=%s\n", walsnap.Term, walsnap.Index, nodes, confStateJSON) - case snap.ErrNoSnapshot: + case errors.Is(err, snap.ErrNoSnapshot): fmt.Print("Snapshot:\nempty\n") default: log.Fatalf("Failed loading snapshot: %v", err) @@ -149,7 +150,7 @@ func readUsingReadAll(lg *zap.Logger, index *uint64, snapfile *string, dataDir s } wmetadata, state, ents, err := w.ReadAll() w.Close() - if err != nil && (!isIndex || err != wal.ErrSnapshotNotFound) { + if err != nil && (!isIndex || !errors.Is(err, wal.ErrSnapshotNotFound)) { log.Fatalf("Failed reading WAL: %v", err) } id, cid := parseWALMetadata(wmetadata)