chore: do not use sentinel errors when unneeded

- main reason being it's a burden to always define sentinel errors at global scope, wrap them with `%w` instead of using a string directly
- only use sentinel errors when it has to be checked using `errors.Is`
- replace all usage of these sentinel errors in `fmt.Errorf` with direct strings that were in the sentinel error
- exclude the sentinel error definition requirement from .golangci.yml
- update unit tests to use ContainersError instead of ErrorIs so it stays as a "not a change detector test" without requiring a sentinel error
This commit is contained in:
Quentin McGaw
2026-05-02 00:50:16 +00:00
parent 9b6f048fe8
commit 4a78989d9d
172 changed files with 666 additions and 1433 deletions
+2 -4
View File
@@ -266,8 +266,6 @@ func makeAddressToDial(address string) (addressToDial string, err error) {
return address, nil
}
var ErrAllCheckTriesFailed = errors.New("all check tries failed")
func withRetries(ctx context.Context, tryTimeouts []time.Duration,
logger Logger, checkName string, check func(ctx context.Context, try int) error,
) error {
@@ -297,7 +295,7 @@ func withRetries(ctx context.Context, tryTimeouts []time.Duration,
for i, err := range errs {
errStrings[i] = fmt.Sprintf("attempt %d (%dms): %s", i+1, err.durationMS, err.err)
}
return fmt.Errorf("%w:\n\t%s", ErrAllCheckTriesFailed, strings.Join(errStrings, "\n\t"))
return fmt.Errorf("all check tries failed:\n\t%s", strings.Join(errStrings, "\n\t"))
}
func (c *Checker) startupCheck(ctx context.Context) error {
@@ -342,7 +340,7 @@ func (c *Checker) startupCheck(ctx context.Context) error {
for i, err := range errs {
errStrings[i] = fmt.Sprintf("parallel attempt %d/%d failed: %s", i+1, len(errs), err)
}
return fmt.Errorf("%w: %s", ErrAllCheckTriesFailed, strings.Join(errStrings, ", "))
return fmt.Errorf("all check tries failed: %s", strings.Join(errStrings, ", "))
}
const (
+5 -6
View File
@@ -2,7 +2,6 @@ package healthcheck
import (
"context"
"fmt"
"net"
"testing"
"time"
@@ -68,7 +67,7 @@ func Test_makeAddressToDial(t *testing.T) {
testCases := map[string]struct {
address string
addressToDial string
err error
errMessage string
}{
"host without port": {
address: "test.com",
@@ -79,8 +78,8 @@ func Test_makeAddressToDial(t *testing.T) {
addressToDial: "test.com:80",
},
"bad address": {
address: "test.com::",
err: fmt.Errorf("splitting host and port from address: address test.com::: too many colons in address"), //nolint:lll
address: "test.com::",
errMessage: "splitting host and port from address: address test.com::: too many colons in address",
},
}
@@ -91,8 +90,8 @@ func Test_makeAddressToDial(t *testing.T) {
addressToDial, err := makeAddressToDial(testCase.address)
assert.Equal(t, testCase.addressToDial, addressToDial)
if testCase.err != nil {
assert.EqualError(t, err, testCase.err.Error())
if testCase.errMessage != "" {
assert.EqualError(t, err, testCase.errMessage)
} else {
assert.NoError(t, err)
}
+1 -4
View File
@@ -2,15 +2,12 @@ package healthcheck
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"time"
)
var ErrHTTPStatusNotOK = errors.New("HTTP response status is not OK")
type Client struct {
httpClient *http.Client
}
@@ -41,6 +38,6 @@ func (c *Client) Check(ctx context.Context, url string) error {
if err != nil {
return err
}
return fmt.Errorf("%w: %d %s: %s", ErrHTTPStatusNotOK,
return fmt.Errorf("HTTP response status is not OK: %d %s: %s",
response.StatusCode, response.Status, string(b))
}
+1 -4
View File
@@ -2,7 +2,6 @@ package dns
import (
"context"
"errors"
"fmt"
"net"
"net/netip"
@@ -41,8 +40,6 @@ func concatAddrPorts(addrs [][]netip.AddrPort) []netip.AddrPort {
return result
}
var ErrLookupNoIPs = errors.New("no IPs found from DNS lookup")
func (c *Client) Check(ctx context.Context) error {
dnsAddr := c.serverAddrs[c.dnsIPIndex].String()
resolver := &net.Resolver{
@@ -59,7 +56,7 @@ func (c *Client) Check(ctx context.Context) error {
return fmt.Errorf("with DNS server %s: %w", dnsAddr, err)
case len(ips) == 0:
c.dnsIPIndex = (c.dnsIPIndex + 1) % len(c.serverAddrs)
return fmt.Errorf("with DNS server %s: %w", dnsAddr, ErrLookupNoIPs)
return fmt.Errorf("with DNS server %s: no IPs found from DNS lookup", dnsAddr)
default:
return nil
}
+1 -3
View File
@@ -12,11 +12,9 @@ type handler struct {
logger Logger
}
var errHealthcheckNotRunYet = errors.New("healthcheck did not run yet")
func newHandler(logger Logger) *handler {
return &handler{
healthErr: errHealthcheckNotRunYet,
healthErr: errors.New("healthcheck did not run yet"),
logger: logger,
}
}
+6 -13
View File
@@ -19,11 +19,6 @@ import (
"golang.org/x/net/ipv6"
)
var (
ErrICMPBodyUnsupported = errors.New("ICMP body type is not supported")
ErrICMPEchoDataMismatch = errors.New("ICMP data mismatch")
)
type Echoer struct {
buffer []byte
randomSource io.Reader
@@ -60,10 +55,7 @@ func (e *Echoer) Reset() {
e.seqStart = time.Now()
}
var (
ErrTimedOut = errors.New("timed out waiting for ICMP echo reply")
ErrNotPermitted = errors.New("not permitted")
)
var ErrNotPermitted = errors.New("not permitted")
func (e *Echoer) Echo(ctx context.Context, ip netip.Addr) (err error) {
var ipVersion string
@@ -114,14 +106,14 @@ func (e *Echoer) Echo(ctx context.Context, ip netip.Addr) (err error) {
receivedData, err := receiveEchoReply(conn, e.id, e.seq, e.buffer, ipVersion, e.logger)
if err != nil {
if errors.Is(err, net.ErrClosed) && ctx.Err() != nil {
return fmt.Errorf("%w from %s", ErrTimedOut, ip)
return fmt.Errorf("timed out waiting for ICMP echo reply from %s", ip)
}
return fmt.Errorf("receiving ICMP echo reply from %s: %w", ip, err)
}
sentData := message.Body.(*icmp.Echo).Data //nolint:forcetypeassert
if !bytes.Equal(receivedData, sentData) {
return fmt.Errorf("%w: sent %x to %s and received %x", ErrICMPEchoDataMismatch, sentData, ip, receivedData)
return fmt.Errorf("ICMP data mismatch: sent %x to %s and received %x", sentData, ip, receivedData)
}
return nil
@@ -216,8 +208,9 @@ func receiveEchoReply(conn net.PacketConn, id, seq int, buffer []byte, ipVersion
message.Code, returnAddr, id, seq)
continue
default:
return nil, fmt.Errorf("%w: %T (type %d, code %d, return address %s, expected id %d and seq %d)",
ErrICMPBodyUnsupported, body, message.Type, message.Code, returnAddr, id, seq)
return nil, fmt.Errorf("ICMP body type is not supported: "+
"%T (type %d, code %d, return address %s, expected id %d and seq %d)",
body, message.Type, message.Code, returnAddr, id, seq)
}
}
}