Skip to content

Commit

Permalink
refactored errors to better allow generic error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
johnabass committed Mar 6, 2024
1 parent 117ea76 commit a1d4530
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 77 deletions.
2 changes: 1 addition & 1 deletion basculehttp/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var defaultCredentialsParser bascule.CredentialsParser = bascule.CredentialsPars
Value: value,
}
} else {
err = &bascule.InvalidCredentialsError{
err = &bascule.BadCredentialsError{
Raw: raw,
}
}
Expand Down
2 changes: 1 addition & 1 deletion basculehttp/credentials_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (suite *CredentialsTestSuite) testDefaultCredentialsParserFailure() {
suite.Require().Error(err)
suite.Equal(bascule.Credentials{}, creds)

var ice *bascule.InvalidCredentialsError
var ice *bascule.BadCredentialsError
if suite.ErrorAs(err, &ice) {
suite.Equal(testCase, ice.Raw)
}
Expand Down
43 changes: 0 additions & 43 deletions credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,6 @@

package bascule

import "strings"

// InvalidCredentialsError is returned typically by CredentialsParser.Parse
// to indicate that a raw, serialized credentials were badly formatted.
type InvalidCredentialsError struct {
// Cause represents any lower-level error that occurred, if any.
Cause error

// Raw represents the raw credentials that couldn't be parsed.
Raw string
}

func (err *InvalidCredentialsError) Unwrap() error { return err.Cause }

func (err *InvalidCredentialsError) Error() string {
var o strings.Builder
o.WriteString(`Invalid credentials "`)
o.WriteString(err.Raw)
o.WriteString(`"`)

if err.Cause != nil {
o.WriteString(": ")
o.WriteString(err.Cause.Error())
}

return o.String()
}

// UnsupportedSchemeError indicates that a credential scheme was not
// supported via the particular way bascule was configured.
type UnsupportedSchemeError struct {
// Scheme is the authorization scheme that wasn't supported.
Scheme Scheme
}

func (err *UnsupportedSchemeError) Error() string {
var o strings.Builder
o.WriteString(`Unsupported credential scheme: "`)
o.WriteString(string(err.Scheme))
o.WriteString(`"`)
return o.String()
}

// Scheme represents how a security token should be parsed. For HTTP, examples
// of a scheme are "Bearer" and "Basic".
type Scheme string
Expand Down
31 changes: 0 additions & 31 deletions credentials_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,6 @@ type CredentialsTestSuite struct {
suite.Suite
}

func (suite *CredentialsTestSuite) TestInvalidCredentialsError() {
suite.Run("WithCause", func() {
cause := errors.New("cause")
err := InvalidCredentialsError{
Cause: cause,
Raw: "raw",
}

suite.Same(err.Unwrap(), cause)
suite.Contains(err.Error(), "cause")
suite.Contains(err.Error(), "raw")
})

suite.Run("NoCause", func() {
err := InvalidCredentialsError{
Raw: "raw",
}

suite.Nil(err.Unwrap())
suite.Contains(err.Error(), "raw")
})
}

func (suite *CredentialsTestSuite) TestUnsupportedSchemeError() {
err := UnsupportedSchemeError{
Scheme: Scheme("scheme"),
}

suite.Contains(err.Error(), "scheme")
}

func (suite *CredentialsTestSuite) TestCredentialsParserFunc() {
const expectedRaw = "expected raw credentials"
expectedErr := errors.New("expected error")
Expand Down
44 changes: 43 additions & 1 deletion error.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@

package bascule

import (
"errors"
"strings"
)

// ErrorType is an enumeration type for various types of security errors.
// This type can be used to determine more detail about the context of an error.
type ErrorType int
Expand Down Expand Up @@ -40,9 +45,46 @@ type Error interface {
// GetErrorType examines err to determine its associated metadata type. If err
// does not implement Error, this function returns ErrorTypeUnknown.
func GetErrorType(err error) ErrorType {
if e, ok := err.(Error); ok {
var e Error
if errors.As(err, &e) {
return e.Type()
}

return ErrorTypeUnknown
}

// UnsupportedSchemeError indicates that a credentials scheme was not supported
// by a TokenParser.
type UnsupportedSchemeError struct {
// Scheme is the unsupported credential scheme.
Scheme Scheme
}

// Type tags errors of this type as ErrorTypeBadCredentials.
func (err *UnsupportedSchemeError) Type() ErrorType { return ErrorTypeBadCredentials }

func (err *UnsupportedSchemeError) Error() string {
var o strings.Builder
o.WriteString(`Unsupported scheme: "`)
o.WriteString(string(err.Scheme))
o.WriteRune('"')
return o.String()
}

// BadCredentialsError is a general-purpose error indicating that credentials
// could not be parsed.
type BadCredentialsError struct {
// Raw is the raw value of the credentials that could not be parsed.
Raw string
}

// Type tags errors of this type as ErrorTypeBadCredentials.
func (err *BadCredentialsError) Type() ErrorType { return ErrorTypeBadCredentials }

func (err *BadCredentialsError) Error() string {
var o strings.Builder
o.WriteString(`Bad credentials: "`)
o.WriteString(err.Raw)
o.WriteRune('"')
return o.String()
}
50 changes: 50 additions & 0 deletions error_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package bascule

import (
"errors"
"testing"

"github.com/stretchr/testify/suite"
)

type ErrorSuite struct {
suite.Suite
}

func (suite *ErrorSuite) TestUnsupportedSchemeError() {
err := UnsupportedSchemeError{
Scheme: Scheme("scheme"),
}

suite.Contains(err.Error(), "scheme")
suite.Equal(ErrorTypeBadCredentials, err.Type())
}

func (suite *ErrorSuite) TestBadCredentialsError() {
err := BadCredentialsError{
Raw: "these are an unparseable, raw credentials",
}

suite.Contains(err.Error(), "these are an unparseable, raw credentials")
suite.Equal(ErrorTypeBadCredentials, err.Type())
}

func (suite *ErrorSuite) TestGetErrorType() {
suite.Run("Unknown", func() {
suite.Equal(
ErrorTypeUnknown,
GetErrorType(errors.New("this is an error that is unknown to bascule")),
)
})

suite.Run("ImplementsError", func() {
suite.Equal(
ErrorTypeBadCredentials,
GetErrorType(new(BadCredentialsError)),
)
})
}

func TestError(t *testing.T) {
suite.Run(t, new(ErrorSuite))
}

0 comments on commit a1d4530

Please sign in to comment.