Skip to content

Commit

Permalink
js: leverage more errors package internals
Browse files Browse the repository at this point in the history
Signed-off-by: Waldemar Quevedo <wally@nats.io>
  • Loading branch information
wallyqs committed Aug 22, 2022
1 parent e3147fa commit aad6326
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 11 deletions.
37 changes: 30 additions & 7 deletions jsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,19 +161,36 @@ type APIError struct {
Description string `json:"description,omitempty"`
}

// Error prints the JetStream API error code and description
func (e *APIError) Error() string {
return fmt.Sprintf("nats: API error %d: %s", e.ErrorCode, e.Description)
}

// Is matches against an APIError.
func (e *APIError) Is(err error) bool {
// Extract internal APIError to match against.
var aerr *APIError
ok := errors.As(err, &aerr)
if !ok {
return ok
}
return e.ErrorCode == aerr.ErrorCode
}

// JetStreamAPIError is an error result from making a request to the
// JetStream API.
type JetStreamAPIError interface {
Code() int
ErrorCode() ErrorCode
Description() string
Error() string
error
}

type jsAPIError struct {
code int
errorCode ErrorCode
description string
message string
}

func (err *jsAPIError) Code() int {
Expand All @@ -185,11 +202,22 @@ func (err *jsAPIError) ErrorCode() ErrorCode {
}

func (err *jsAPIError) Description() string {
if err.description == "" {
return err.message
}
return err.description
}

func (err *jsAPIError) Error() string {
return err.description
return fmt.Sprintf("nats: %v", err.message)
}

func (err *jsAPIError) Unwrap() error {
return &APIError{
Code: err.Code(),
ErrorCode: err.ErrorCode(),
Description: err.Description(),
}
}

// apiResponse is a standard response from the JetStream JSON API
Expand Down Expand Up @@ -266,11 +294,6 @@ const (
JSErrCodeMessageNotFound ErrorCode = 10037
)

// Error prints the JetStream API error code and description
func (e *APIError) Error() string {
return fmt.Sprintf("nats: API error %d: %s", e.ErrorCode, e.Description)
}

var (
// ErrJetStreamNotEnabled is an error returned when JetStream is not enabled.
ErrJetStreamNotEnabledForAccount JetStreamAPIError = &jsAPIError{errorCode: JSErrCodeJetStreamNotEnabledForAccount, description: "nats: jetstream not enabled for account"}
Expand Down
4 changes: 0 additions & 4 deletions nats.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,6 @@ var (
ErrMaxConnectionsExceeded = errors.New("nats: server maximum connections exceeded")
ErrBadRequest = errors.New("nats: bad request")
ErrConnectionNotTLS = errors.New("nats: connection is not tls")

// DEPRECATED: ErrInvalidDurableName is no longer returned and will be removed in future releases
// Use ErrInvalidConsumerName instead
ErrInvalidDurableName = errors.New("nats: invalid durable name")
)

func init() {
Expand Down
52 changes: 52 additions & 0 deletions test/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,23 @@ func TestJetStreamNotAccountEnabled(t *testing.T) {
defer nc.Close()

_, err := js.AccountInfo()
// check directly to var (backwards compatible)
if err != nats.ErrJetStreamNotEnabledForAccount {
t.Fatalf("Did not get the proper error, got %v", err)
}

// matching via errors.Is
if ok := errors.Is(err, nats.ErrJetStreamNotEnabled); !ok {
t.Fatal("Expected ErrJetStreamNotEnabled")
}

// matching wrapped via error.Is
err2 := fmt.Errorf("custom error: %w", nats.ErrJetStreamNotEnabled)
if ok := errors.Is(err2, nats.ErrJetStreamNotEnabled); !ok {
t.Fatal("Expected wrapped ErrJetStreamNotEnabled")
}

// via classic type assertion.
jserr, ok := err.(nats.JetStreamAPIError)
if !ok {
t.Fatal("Expected a JetStreamAPIError")
Expand All @@ -99,6 +113,44 @@ func TestJetStreamNotAccountEnabled(t *testing.T) {
if jserr.ErrorCode() != nats.ErrorCode(expected) {
t.Fatalf("Expected: %v, got: %v", expected, jserr.ErrorCode())
}

// matching to interface via errors.As(...)
var apierr nats.JetStreamAPIError
ok = errors.As(err, &apierr)
if !ok {
t.Fatal("Expected a JetStreamAPIError")
}
if apierr.ErrorCode() != expected {
t.Fatalf("Expected: %v, got: %v", expected, apierr.ErrorCode())
}
expectedMessage := "nats: jetstream not enabled"
if apierr.Error() != expectedMessage {
t.Fatalf("Expected: %v, got: %v", expectedMessage, apierr.Error())
}

// matching arbitrary custom error via errors.Is(...)
customErr := &nats.APIError{ErrorCode: expected}
if ok := errors.Is(customErr, nats.ErrJetStreamNotEnabled); !ok {
t.Fatal("Expected wrapped ErrJetStreamNotEnabled")
}
customErr = &nats.APIError{ErrorCode: 1}
if ok := errors.Is(customErr, nats.ErrJetStreamNotEnabled); ok {
t.Fatal("Expected to not match ErrJetStreamNotEnabled")
}

// matching to concrete type via errors.As(...)
var aerr *nats.APIError
ok = errors.As(err, &aerr)
if !ok {
t.Fatal("Expected an APIError")
}
if aerr.ErrorCode != expected {
t.Fatalf("Expected: %v, got: %v", expected, aerr.ErrorCode)
}
expectedMessage = "nats: API error 10039: jetstream not enabled"
if aerr.Error() != expectedMessage {
t.Fatalf("Expected: %v, got: %v", expectedMessage, apierr.Error())
}
}

func TestJetStreamPublish(t *testing.T) {
Expand Down

0 comments on commit aad6326

Please sign in to comment.