diff --git a/CHANGELOG.md b/CHANGELOG.md index 51bc9ab5..f17a61d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Release History +## 1.1.0 (2024-08-20) + +### Features Added + +* ConnError, SessionError and LinkError now work with errors.As(), making it easier to write generalized error handling code that wants to deal with *amqp.Error's. + ## 1.0.5 (2024-03-04) ### Bugs Fixed diff --git a/errors.go b/errors.go index c2e3b68a..3af9a022 100644 --- a/errors.go +++ b/errors.go @@ -65,6 +65,15 @@ func (e *LinkError) Error() string { return e.inner.Error() } +// Unwrap returns the RemoteErr, if any. +func (e *LinkError) Unwrap() error { + if e.RemoteErr == nil { + return nil + } + + return e.RemoteErr +} + // ConnError is returned by methods on Conn and propagated to Session and Senders/Receivers // when the connection has been closed. type ConnError struct { @@ -84,6 +93,15 @@ func (e *ConnError) Error() string { return e.inner.Error() } +// Unwrap returns the RemoteErr, if any. +func (e *ConnError) Unwrap() error { + if e.RemoteErr == nil { + return nil + } + + return e.RemoteErr +} + // SessionError is returned by methods on Session and propagated to Senders/Receivers // when the session has been closed. type SessionError struct { @@ -102,3 +120,12 @@ func (e *SessionError) Error() string { } return e.inner.Error() } + +// Unwrap returns the RemoteErr, if any. +func (e *SessionError) Unwrap() error { + if e.RemoteErr == nil { + return nil + } + + return e.RemoteErr +} diff --git a/errors_test.go b/errors_test.go new file mode 100644 index 00000000..ceffe914 --- /dev/null +++ b/errors_test.go @@ -0,0 +1,44 @@ +package amqp_test + +import ( + "errors" + "testing" + + amqp "github.com/Azure/go-amqp" + "github.com/stretchr/testify/require" +) + +func TestErrorUnwrap(t *testing.T) { + // In the majority of common use cases, the LinkError, ConnError and SessionError will contain an amqp.Error. + // It's simpler, for callers, if they can simply check errors.As(&amqp.Error) so they can write general error + // handling, rather than having to check the envelope type each time. + t.Run("LinkError", func(t *testing.T) { + var amqpErr *amqp.Error + + le := &amqp.LinkError{} + require.False(t, errors.As(le, &amqpErr)) + + le.RemoteErr = &amqp.Error{Condition: amqp.ErrCondConnectionForced} + require.ErrorAs(t, le, &amqpErr) + }) + + t.Run("ConnError", func(t *testing.T) { + var amqpErr *amqp.Error + + ce := &amqp.ConnError{} + require.False(t, errors.As(ce, &amqpErr)) + + ce.RemoteErr = &amqp.Error{Condition: amqp.ErrCondConnectionForced} + require.ErrorAs(t, ce, &amqpErr) + }) + + t.Run("SessionError", func(t *testing.T) { + var amqpErr *amqp.Error + + se := &amqp.ConnError{} + require.False(t, errors.As(se, &amqpErr)) + + se.RemoteErr = &amqp.Error{Condition: amqp.ErrCondConnectionForced} + require.ErrorAs(t, se, &amqpErr) + }) +}