From e760fac1c6f287bc822d460c75021ca539850211 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Wed, 7 Oct 2020 17:27:53 +0300 Subject: [PATCH 1/6] Try to stdlib errors.Unwrap errors as well --- lib/netext/httpext/error_codes.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/netext/httpext/error_codes.go b/lib/netext/httpext/error_codes.go index 1d771629d34..54ae4b5a6d0 100644 --- a/lib/netext/httpext/error_codes.go +++ b/lib/netext/httpext/error_codes.go @@ -23,6 +23,7 @@ package httpext import ( "crypto/tls" "crypto/x509" + stderrors "errors" "fmt" "net" "net/url" @@ -79,7 +80,7 @@ const ( // errors till 1651 + 13 are other HTTP2 Connection errors with a specific errCode // Custom k6 content errors, i.e. when the magic fails - //defaultContentError errCode = 1700 // reserved for future use + // defaultContentError errCode = 1700 // reserved for future use responseDecompressionErrorCode errCode = 1701 ) @@ -107,7 +108,25 @@ func http2ErrCodeOffset(code http2.ErrCode) errCode { // errorCodeForError returns the errorCode and a specific error message for given error. func errorCodeForError(err error) (errCode, string) { - switch e := errors.Cause(err).(type) { + inner := stderrors.Unwrap(err) + if inner != nil && inner != err { + code, resultErr := errorCodeForError(inner) + if code != defaultErrorCode { + return code, resultErr + } + } + + causeErr := errors.Cause(err) + + inner = stderrors.Unwrap(causeErr) + if inner != nil && inner != causeErr { + code, resultErr := errorCodeForError(inner) + if code != defaultErrorCode { + return code, resultErr + } + } + + switch e := errors.Cause(causeErr).(type) { case K6Error: return e.Code, e.Message case *net.DNSError: From c26e54e5242ca68c108cd88c2058ce7f329dd1d7 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Thu, 8 Oct 2020 12:04:46 +0300 Subject: [PATCH 2/6] Add test for connReset errorCode and a fix --- lib/netext/httpext/error_codes.go | 28 ++++------- lib/netext/httpext/error_codes_test.go | 64 +++++++++++++++++++++----- 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/lib/netext/httpext/error_codes.go b/lib/netext/httpext/error_codes.go index 54ae4b5a6d0..4663c95943a 100644 --- a/lib/netext/httpext/error_codes.go +++ b/lib/netext/httpext/error_codes.go @@ -85,10 +85,10 @@ const ( ) const ( - tcpResetByPeerErrorCodeMsg = "write: connection reset by peer" + tcpResetByPeerErrorCodeMsg = "%s: connection reset by peer" tcpDialTimeoutErrorCodeMsg = "dial: i/o timeout" tcpDialRefusedErrorCodeMsg = "dial: connection refused" - tcpBrokenPipeErrorCodeMsg = "write: broken pipe" + tcpBrokenPipeErrorCodeMsg = "%s: broken pipe" netUnknownErrnoErrorCodeMsg = "%s: unknown errno `%d` on %s with message `%s`" dnsNoSuchHostErrorCodeMsg = "lookup: no such host" blackListedIPErrorCodeMsg = "ip is blacklisted" @@ -108,17 +108,9 @@ func http2ErrCodeOffset(code http2.ErrCode) errCode { // errorCodeForError returns the errorCode and a specific error message for given error. func errorCodeForError(err error) (errCode, string) { - inner := stderrors.Unwrap(err) - if inner != nil && inner != err { - code, resultErr := errorCodeForError(inner) - if code != defaultErrorCode { - return code, resultErr - } - } - causeErr := errors.Cause(err) - inner = stderrors.Unwrap(causeErr) + inner := stderrors.Unwrap(causeErr) if inner != nil && inner != causeErr { code, resultErr := errorCodeForError(inner) if code != defaultErrorCode { @@ -152,14 +144,12 @@ func errorCodeForError(err error) (errCode, string) { // TODO: figure out how this happens return defaultNetNonTCPErrorCode, err.Error() } - if e.Op == "write" { - if sErr, ok := e.Err.(*os.SyscallError); ok { - switch sErr.Err { - case syscall.ECONNRESET: - return tcpResetByPeerErrorCode, tcpResetByPeerErrorCodeMsg - case syscall.EPIPE: - return tcpBrokenPipeErrorCode, tcpBrokenPipeErrorCodeMsg - } + if sErr, ok := e.Err.(*os.SyscallError); ok { + switch sErr.Err { + case syscall.ECONNRESET: + return tcpResetByPeerErrorCode, fmt.Sprintf(tcpResetByPeerErrorCodeMsg, e.Op) + case syscall.EPIPE: + return tcpBrokenPipeErrorCode, fmt.Sprintf(tcpBrokenPipeErrorCodeMsg, e.Op) } } if e.Op == "dial" { diff --git a/lib/netext/httpext/error_codes_test.go b/lib/netext/httpext/error_codes_test.go index 50c3d76e99d..dacf77de118 100644 --- a/lib/netext/httpext/error_codes_test.go +++ b/lib/netext/httpext/error_codes_test.go @@ -25,13 +25,16 @@ import ( "crypto/x509" "fmt" "net" + "net/http" "net/url" "os" "runtime" "syscall" "testing" + "time" "github.com/pkg/errors" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/net/http2" @@ -43,9 +46,9 @@ func TestDefaultError(t *testing.T) { } func TestHTTP2Errors(t *testing.T) { - var unknownErrorCode = 220 - var connectionError = http2.ConnectionError(unknownErrorCode) - var testTable = map[errCode]error{ + unknownErrorCode := 220 + connectionError := http2.ConnectionError(unknownErrorCode) + testTable := map[errCode]error{ unknownHTTP2ConnectionErrorCode + 1: new(http2.ConnectionError), unknownHTTP2StreamErrorCode + 1: new(http2.StreamError), unknownHTTP2GoAwayErrorCode + 1: new(http2.GoAwayError), @@ -58,7 +61,7 @@ func TestHTTP2Errors(t *testing.T) { } func TestTLSErrors(t *testing.T) { - var testTable = map[errCode]error{ + testTable := map[errCode]error{ x509UnknownAuthorityErrorCode: new(x509.UnknownAuthorityError), x509HostnameErrorCode: new(x509.HostnameError), defaultTLSErrorCode: new(tls.RecordHeaderError), @@ -73,7 +76,7 @@ func TestDNSErrors(t *testing.T) { ) noSuchHostError.Err = "no such host" // defined as private in go stdlib - var testTable = map[errCode]error{ + testTable := map[errCode]error{ defaultDNSErrorCode: defaultDNSError, dnsNoSuchHostErrorCode: noSuchHostError, } @@ -81,9 +84,9 @@ func TestDNSErrors(t *testing.T) { } func TestBlackListedIPError(t *testing.T) { - var err = netext.BlackListedIPError{} + err := netext.BlackListedIPError{} testErrorCode(t, blackListedIPErrorCode, err) - var errorCode, errorMsg = errorCodeForError(err) + errorCode, errorMsg := errorCodeForError(err) require.NotEqual(t, err.Error(), errorMsg) require.Equal(t, blackListedIPErrorCode, errorCode) } @@ -99,14 +102,14 @@ func (t timeoutError) Error() string { } func TestUnknownNetErrno(t *testing.T) { - var err = new(net.OpError) + err := new(net.OpError) err.Op = "write" err.Net = "tcp" err.Err = syscall.ENOTRECOVERABLE // Highly unlikely to actually need to do anything with this error - var expectedError = fmt.Sprintf( + expectedError := fmt.Sprintf( "write: unknown errno `%d` on %s with message `%s`", syscall.ENOTRECOVERABLE, runtime.GOOS, err.Err) - var errorCode, errorMsg = errorCodeForError(err) + errorCode, errorMsg := errorCodeForError(err) require.Equal(t, expectedError, errorMsg) require.Equal(t, netUnknownErrnoErrorCode, errorCode) } @@ -123,7 +126,7 @@ func TestTCPErrors(t *testing.T) { notTimeoutedError = &net.OpError{Net: "tcp", Op: "dial", Err: timeoutError(false)} ) - var testTable = map[errCode]error{ + testTable := map[errCode]error{ defaultNetNonTCPErrorCode: nonTCPError, tcpResetByPeerErrorCode: econnreset, tcpBrokenPipeErrorCode: epipeerror, @@ -155,3 +158,42 @@ func testMapOfErrorCodes(t *testing.T, testTable map[errCode]error) { testErrorCode(t, code, err) } } + +func TestConnReset(t *testing.T) { + // based on https://gist.github.com/jpittis/4357d817dc425ae99fbf719828ab1800 + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatal(err) + } + addr := ln.Addr() + ch := make(chan error, 10) + + go func() { + defer close(ch) + // Accept one connection. + conn, innerErr := ln.Accept() + if innerErr != nil { + ch <- innerErr + return + } + + // Force an RST + tcpConn := conn.(*net.TCPConn) + innerErr = tcpConn.SetLinger(0) + if innerErr != nil { + ch <- innerErr + } + time.Sleep(time.Second) // Give time for the http request to start + _ = conn.Close() + }() + + res, err := http.Get("http://" + addr.String()) //nolint:bodyclose,noctx + require.Nil(t, res) + + code, msg := errorCodeForError(err) + assert.Equal(t, tcpResetByPeerErrorCode, code) + assert.Contains(t, msg, fmt.Sprintf(tcpResetByPeerErrorCodeMsg, "")) + for err := range ch { + assert.Nil(t, err) + } +} From d1def0f05222b92ee9af0e90b85bb88c04c25e9c Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Thu, 8 Oct 2020 12:23:35 +0300 Subject: [PATCH 3/6] Add test for the Unwrap error codes path --- lib/netext/httpext/error_codes_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/netext/httpext/error_codes_test.go b/lib/netext/httpext/error_codes_test.go index dacf77de118..9ffb4f18160 100644 --- a/lib/netext/httpext/error_codes_test.go +++ b/lib/netext/httpext/error_codes_test.go @@ -197,3 +197,14 @@ func TestConnReset(t *testing.T) { assert.Nil(t, err) } } + +func TestDnsResolve(t *testing.T) { + // this uses the Unwrap path + // this is not happening in our current codebase as the resolution in our code + // happens earlier so it doesn't get wrapped, but possibly happens in other cases as well + _, err := http.Get("http://s.com") //nolint:bodyclose,noctx + code, msg := errorCodeForError(err) + + assert.Equal(t, dnsNoSuchHostErrorCode, code) + assert.Equal(t, dnsNoSuchHostErrorCodeMsg, msg) +} From 36837c1da29974547316a2735e617f342b22ca2a Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Thu, 8 Oct 2020 14:39:30 +0300 Subject: [PATCH 4/6] Try to fix test on windows --- lib/netext/httpext/error_codes.go | 6 +++++- lib/netext/httpext/error_codes_syscall_posix.go | 12 ++++++++++++ .../httpext/error_codes_syscall_windows.go | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 lib/netext/httpext/error_codes_syscall_posix.go create mode 100644 lib/netext/httpext/error_codes_syscall_windows.go diff --git a/lib/netext/httpext/error_codes.go b/lib/netext/httpext/error_codes.go index 4663c95943a..f55cfb60d8a 100644 --- a/lib/netext/httpext/error_codes.go +++ b/lib/netext/httpext/error_codes.go @@ -145,12 +145,16 @@ func errorCodeForError(err error) (errCode, string) { return defaultNetNonTCPErrorCode, err.Error() } if sErr, ok := e.Err.(*os.SyscallError); ok { - switch sErr.Err { + switch sErr.Unwrap() { case syscall.ECONNRESET: return tcpResetByPeerErrorCode, fmt.Sprintf(tcpResetByPeerErrorCodeMsg, e.Op) case syscall.EPIPE: return tcpBrokenPipeErrorCode, fmt.Sprintf(tcpBrokenPipeErrorCodeMsg, e.Op) } + code, msg := getOSSyscallErrorCode(e, sErr) + if code != 0 { + return code, msg + } } if e.Op == "dial" { if e.Timeout() { diff --git a/lib/netext/httpext/error_codes_syscall_posix.go b/lib/netext/httpext/error_codes_syscall_posix.go new file mode 100644 index 00000000000..65a61a924c6 --- /dev/null +++ b/lib/netext/httpext/error_codes_syscall_posix.go @@ -0,0 +1,12 @@ +// +build !windows + +package httpext + +import ( + "net" + "os" +) + +func getOSSyscallErrorCode(e *net.OpError, se *os.SyscallError) (errCode, string) { + return 0, "" +} diff --git a/lib/netext/httpext/error_codes_syscall_windows.go b/lib/netext/httpext/error_codes_syscall_windows.go new file mode 100644 index 00000000000..27e82e342f1 --- /dev/null +++ b/lib/netext/httpext/error_codes_syscall_windows.go @@ -0,0 +1,16 @@ +package httpext + +import ( + "fmt" + "net" + "os" + "syscall" +) + +func getOSSyscallErrorCode(e *net.OpError, se *os.SyscallError) (errCode, string) { + switch se.Unwrap() { + case syscall.WSAECONNRESET: + return tcpResetByPeerErrorCode, fmt.Sprintf(tcpResetByPeerErrorCodeMsg, e.Op) + } + return 0, "" +} From 19fe91d0d7593532ed4ff0a2460cd8d423089325 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Thu, 8 Oct 2020 16:42:05 +0300 Subject: [PATCH 5/6] Update github.com/pkg/errors to v0.9.1 --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/pkg/errors/README.md | 15 +++- vendor/github.com/pkg/errors/errors.go | 51 ++++++++---- vendor/github.com/pkg/errors/go113.go | 38 +++++++++ vendor/github.com/pkg/errors/stack.go | 109 ++++++++++++------------- vendor/modules.txt | 2 +- 7 files changed, 142 insertions(+), 79 deletions(-) create mode 100644 vendor/github.com/pkg/errors/go113.go diff --git a/go.mod b/go.mod index 418b973a189..eb92f531dd1 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 github.com/pierrec/lz4 v1.0.2-0.20171218195038-2fcda4cb7018 // indirect github.com/pierrec/xxHash v0.1.1 // indirect - github.com/pkg/errors v0.8.0 + github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.0 github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 // indirect github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516 diff --git a/go.sum b/go.sum index d306dab29e5..2deeccb0fcb 100644 --- a/go.sum +++ b/go.sum @@ -115,8 +115,8 @@ github.com/pierrec/lz4 v1.0.2-0.20171218195038-2fcda4cb7018 h1:z+gewaCBdXQRy5LXN github.com/pierrec/lz4 v1.0.2-0.20171218195038-2fcda4cb7018/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/xxHash v0.1.1 h1:KP4NrV9023xp3M4FkTYfcXqWigsOCImL1ANJ7sh5vg4= github.com/pierrec/xxHash v0.1.1/go.mod h1:w2waW5Zoa/Wc4Yqe0wgrIYAGKqRMf7czn2HNKXmuL+I= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= diff --git a/vendor/github.com/pkg/errors/README.md b/vendor/github.com/pkg/errors/README.md index 273db3c98ae..54dfdcb12ea 100644 --- a/vendor/github.com/pkg/errors/README.md +++ b/vendor/github.com/pkg/errors/README.md @@ -1,4 +1,4 @@ -# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) +# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) Package errors provides simple error handling primitives. @@ -41,12 +41,19 @@ default: [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). +## Roadmap + +With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows: + +- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible) +- 1.0. Final release. + ## Contributing -We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. +Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports. -Before proposing a change, please discuss your change by raising an issue. +Before sending a PR, please discuss your change by raising an issue. -## Licence +## License BSD-2-Clause diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go index 842ee80456d..161aea25829 100644 --- a/vendor/github.com/pkg/errors/errors.go +++ b/vendor/github.com/pkg/errors/errors.go @@ -6,7 +6,7 @@ // return err // } // -// which applied recursively up the call stack results in error reports +// which when applied recursively up the call stack results in error reports // without context or debugging information. The errors package allows // programmers to add context to the failure path in their code in a way // that does not destroy the original value of the error. @@ -15,16 +15,17 @@ // // The errors.Wrap function returns a new error that adds context to the // original error by recording a stack trace at the point Wrap is called, -// and the supplied message. For example +// together with the supplied message. For example // // _, err := ioutil.ReadAll(r) // if err != nil { // return errors.Wrap(err, "read failed") // } // -// If additional control is required the errors.WithStack and errors.WithMessage -// functions destructure errors.Wrap into its component operations of annotating -// an error with a stack trace and an a message, respectively. +// If additional control is required, the errors.WithStack and +// errors.WithMessage functions destructure errors.Wrap into its component +// operations: annotating an error with a stack trace and with a message, +// respectively. // // Retrieving the cause of an error // @@ -38,7 +39,7 @@ // } // // can be inspected by errors.Cause. errors.Cause will recursively retrieve -// the topmost error which does not implement causer, which is assumed to be +// the topmost error that does not implement causer, which is assumed to be // the original cause. For example: // // switch err := errors.Cause(err).(type) { @@ -48,16 +49,16 @@ // // unknown error // } // -// causer interface is not exported by this package, but is considered a part -// of stable public API. +// Although the causer interface is not exported by this package, it is +// considered a part of its stable public interface. // // Formatted printing of errors // // All error values returned from this package implement fmt.Formatter and can -// be formatted by the fmt package. The following verbs are supported +// be formatted by the fmt package. The following verbs are supported: // // %s print the error. If the error has a Cause it will be -// printed recursively +// printed recursively. // %v see %s // %+v extended format. Each Frame of the error's StackTrace will // be printed in detail. @@ -65,13 +66,13 @@ // Retrieving the stack trace of an error or wrapper // // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are -// invoked. This information can be retrieved with the following interface. +// invoked. This information can be retrieved with the following interface: // // type stackTracer interface { // StackTrace() errors.StackTrace // } // -// Where errors.StackTrace is defined as +// The returned errors.StackTrace type is defined as // // type StackTrace []Frame // @@ -81,12 +82,12 @@ // // if err, ok := err.(stackTracer); ok { // for _, f := range err.StackTrace() { -// fmt.Printf("%+s:%d", f) +// fmt.Printf("%+s:%d\n", f, f) // } // } // -// stackTracer interface is not exported by this package, but is considered a part -// of stable public API. +// Although the stackTracer interface is not exported by this package, it is +// considered a part of its stable public interface. // // See the documentation for Frame.Format for more details. package errors @@ -158,6 +159,9 @@ type withStack struct { func (w *withStack) Cause() error { return w.error } +// Unwrap provides compatibility for Go 1.13 error chains. +func (w *withStack) Unwrap() error { return w.error } + func (w *withStack) Format(s fmt.State, verb rune) { switch verb { case 'v': @@ -192,7 +196,7 @@ func Wrap(err error, message string) error { } // Wrapf returns an error annotating err with a stack trace -// at the point Wrapf is call, and the format specifier. +// at the point Wrapf is called, and the format specifier. // If err is nil, Wrapf returns nil. func Wrapf(err error, format string, args ...interface{}) error { if err == nil { @@ -220,6 +224,18 @@ func WithMessage(err error, message string) error { } } +// WithMessagef annotates err with the format specifier. +// If err is nil, WithMessagef returns nil. +func WithMessagef(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } +} + type withMessage struct { cause error msg string @@ -228,6 +244,9 @@ type withMessage struct { func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } func (w *withMessage) Cause() error { return w.cause } +// Unwrap provides compatibility for Go 1.13 error chains. +func (w *withMessage) Unwrap() error { return w.cause } + func (w *withMessage) Format(s fmt.State, verb rune) { switch verb { case 'v': diff --git a/vendor/github.com/pkg/errors/go113.go b/vendor/github.com/pkg/errors/go113.go new file mode 100644 index 00000000000..be0d10d0c79 --- /dev/null +++ b/vendor/github.com/pkg/errors/go113.go @@ -0,0 +1,38 @@ +// +build go1.13 + +package errors + +import ( + stderrors "errors" +) + +// Is reports whether any error in err's chain matches target. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +func Is(err, target error) bool { return stderrors.Is(err, target) } + +// As finds the first error in err's chain that matches target, and if so, sets +// target to that error value and returns true. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error matches target if the error's concrete value is assignable to the value +// pointed to by target, or if the error has a method As(interface{}) bool such that +// As(target) returns true. In the latter case, the As method is responsible for +// setting target. +// +// As will panic if target is not a non-nil pointer to either a type that implements +// error, or to any interface type. As returns false if err is nil. +func As(err error, target interface{}) bool { return stderrors.As(err, target) } + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +func Unwrap(err error) error { + return stderrors.Unwrap(err) +} diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go index 6b1f2891a5a..779a8348fb9 100644 --- a/vendor/github.com/pkg/errors/stack.go +++ b/vendor/github.com/pkg/errors/stack.go @@ -5,10 +5,13 @@ import ( "io" "path" "runtime" + "strconv" "strings" ) // Frame represents a program counter inside a stack frame. +// For historical reasons if Frame is interpreted as a uintptr +// its value represents the program counter + 1. type Frame uintptr // pc returns the program counter for this frame; @@ -37,6 +40,15 @@ func (f Frame) line() int { return line } +// name returns the name of this function, if known. +func (f Frame) name() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + return fn.Name() +} + // Format formats the frame according to the fmt.Formatter interface. // // %s source file @@ -46,29 +58,24 @@ func (f Frame) line() int { // // Format accepts flags that alter the printing of some verbs, as follows: // -// %+s path of source file relative to the compile time GOPATH +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) // %+v equivalent to %+s:%d func (f Frame) Format(s fmt.State, verb rune) { switch verb { case 's': switch { case s.Flag('+'): - pc := f.pc() - fn := runtime.FuncForPC(pc) - if fn == nil { - io.WriteString(s, "unknown") - } else { - file, _ := fn.FileLine(pc) - fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) - } + io.WriteString(s, f.name()) + io.WriteString(s, "\n\t") + io.WriteString(s, f.file()) default: io.WriteString(s, path.Base(f.file())) } case 'd': - fmt.Fprintf(s, "%d", f.line()) + io.WriteString(s, strconv.Itoa(f.line())) case 'n': - name := runtime.FuncForPC(f.pc()).Name() - io.WriteString(s, funcname(name)) + io.WriteString(s, funcname(f.name())) case 'v': f.Format(s, 's') io.WriteString(s, ":") @@ -76,25 +83,57 @@ func (f Frame) Format(s fmt.State, verb rune) { } } +// MarshalText formats a stacktrace Frame as a text string. The output is the +// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs. +func (f Frame) MarshalText() ([]byte, error) { + name := f.name() + if name == "unknown" { + return []byte(name), nil + } + return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil +} + // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). type StackTrace []Frame +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. func (st StackTrace) Format(s fmt.State, verb rune) { switch verb { case 'v': switch { case s.Flag('+'): for _, f := range st { - fmt.Fprintf(s, "\n%+v", f) + io.WriteString(s, "\n") + f.Format(s, verb) } case s.Flag('#'): fmt.Fprintf(s, "%#v", []Frame(st)) default: - fmt.Fprintf(s, "%v", []Frame(st)) + st.formatSlice(s, verb) } case 's': - fmt.Fprintf(s, "%s", []Frame(st)) + st.formatSlice(s, verb) + } +} + +// formatSlice will format this StackTrace into the given buffer as a slice of +// Frame, only valid when called with '%s' or '%v'. +func (st StackTrace) formatSlice(s fmt.State, verb rune) { + io.WriteString(s, "[") + for i, f := range st { + if i > 0 { + io.WriteString(s, " ") + } + f.Format(s, verb) } + io.WriteString(s, "]") } // stack represents a stack of program counters. @@ -136,43 +175,3 @@ func funcname(name string) string { i = strings.Index(name, ".") return name[i+1:] } - -func trimGOPATH(name, file string) string { - // Here we want to get the source file path relative to the compile time - // GOPATH. As of Go 1.6.x there is no direct way to know the compiled - // GOPATH at runtime, but we can infer the number of path segments in the - // GOPATH. We note that fn.Name() returns the function name qualified by - // the import path, which does not include the GOPATH. Thus we can trim - // segments from the beginning of the file path until the number of path - // separators remaining is one more than the number of path separators in - // the function name. For example, given: - // - // GOPATH /home/user - // file /home/user/src/pkg/sub/file.go - // fn.Name() pkg/sub.Type.Method - // - // We want to produce: - // - // pkg/sub/file.go - // - // From this we can easily see that fn.Name() has one less path separator - // than our desired output. We count separators from the end of the file - // path until it finds two more than in the function name and then move - // one character forward to preserve the initial path segment without a - // leading separator. - const sep = "/" - goal := strings.Count(name, sep) + 2 - i := len(file) - for n := 0; n < goal; n++ { - i = strings.LastIndex(file[:i], sep) - if i == -1 { - // not enough separators found, set i so that the slice expression - // below leaves file unmodified - i = -len(sep) - break - } - } - // get back to 0 or trim the leading separator - file = file[i+len(sep):] - return file -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 6c0270bcca6..93cd9d2f356 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -175,7 +175,7 @@ github.com/pierrec/lz4 # github.com/pierrec/xxHash v0.1.1 ## explicit github.com/pierrec/xxHash/xxHash32 -# github.com/pkg/errors v0.8.0 +# github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 From 9fda18e416da077370c19fe33a0442abc798484c Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Thu, 8 Oct 2020 16:50:33 +0300 Subject: [PATCH 6/6] Drop the usage of pkg/errors in error codes --- lib/netext/httpext/error_codes.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/netext/httpext/error_codes.go b/lib/netext/httpext/error_codes.go index f55cfb60d8a..bd82df6dae5 100644 --- a/lib/netext/httpext/error_codes.go +++ b/lib/netext/httpext/error_codes.go @@ -23,7 +23,7 @@ package httpext import ( "crypto/tls" "crypto/x509" - stderrors "errors" + "errors" "fmt" "net" "net/url" @@ -31,7 +31,6 @@ import ( "runtime" "syscall" - "github.com/pkg/errors" "golang.org/x/net/http2" "github.com/loadimpact/k6/lib/netext" @@ -108,17 +107,15 @@ func http2ErrCodeOffset(code http2.ErrCode) errCode { // errorCodeForError returns the errorCode and a specific error message for given error. func errorCodeForError(err error) (errCode, string) { - causeErr := errors.Cause(err) - - inner := stderrors.Unwrap(causeErr) - if inner != nil && inner != causeErr { + inner := errors.Unwrap(err) + if inner != nil && inner != err { code, resultErr := errorCodeForError(inner) if code != defaultErrorCode { return code, resultErr } } - switch e := errors.Cause(causeErr).(type) { + switch e := err.(type) { case K6Error: return e.Code, e.Message case *net.DNSError: