mirror of
https://github.com/nats-io/nats.go.git
synced 2025-10-28 02:42:14 +08:00
211 lines
6.0 KiB
Go
211 lines
6.0 KiB
Go
// Copyright 2020-2023 The NATS Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package jetstream
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nats-io/nats.go"
|
|
)
|
|
|
|
func TestJetStreamErrors(t *testing.T) {
|
|
t.Run("API error", func(t *testing.T) {
|
|
conf := createConfFile(t, []byte(`
|
|
listen: 127.0.0.1:-1
|
|
no_auth_user: rip
|
|
jetstream: {max_mem_store: 64GB, max_file_store: 10TB}
|
|
accounts: {
|
|
JS: {
|
|
jetstream: enabled
|
|
users: [ {user: dlc, password: foo} ]
|
|
},
|
|
IU: {
|
|
users: [ {user: rip, password: bar} ]
|
|
},
|
|
}
|
|
`))
|
|
defer os.Remove(conf)
|
|
|
|
s, _ := RunServerWithConfig(conf)
|
|
defer shutdownJSServerAndRemoveStorage(t, s)
|
|
|
|
nc, err := nats.Connect(s.ClientURL())
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
js, err := New(nc)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
defer nc.Close()
|
|
|
|
_, err = js.AccountInfo(ctx)
|
|
// check directly to var (backwards compatible)
|
|
if err != ErrJetStreamNotEnabledForAccount {
|
|
t.Fatalf("Did not get the proper error, got %v", err)
|
|
}
|
|
|
|
// matching via errors.Is
|
|
if ok := errors.Is(err, ErrJetStreamNotEnabledForAccount); !ok {
|
|
t.Fatal("Expected ErrJetStreamNotEnabledForAccount")
|
|
}
|
|
|
|
// matching wrapped via error.Is
|
|
err2 := fmt.Errorf("custom error: %w", ErrJetStreamNotEnabledForAccount)
|
|
if ok := errors.Is(err2, ErrJetStreamNotEnabledForAccount); !ok {
|
|
t.Fatal("Expected wrapped ErrJetStreamNotEnabled")
|
|
}
|
|
|
|
// via classic type assertion.
|
|
jserr, ok := err.(JetStreamError)
|
|
if !ok {
|
|
t.Fatal("Expected a JetStreamError")
|
|
}
|
|
expected := JSErrCodeJetStreamNotEnabledForAccount
|
|
if jserr.APIError().ErrorCode != expected {
|
|
t.Fatalf("Expected: %v, got: %v", expected, jserr.APIError().ErrorCode)
|
|
}
|
|
if jserr.APIError() == nil {
|
|
t.Fatal("Expected APIError")
|
|
}
|
|
|
|
// matching to interface via errors.As(...)
|
|
var apierr JetStreamError
|
|
ok = errors.As(err, &apierr)
|
|
if !ok {
|
|
t.Fatal("Expected a JetStreamError")
|
|
}
|
|
if apierr.APIError() == nil {
|
|
t.Fatal("Expected APIError")
|
|
}
|
|
if apierr.APIError().ErrorCode != expected {
|
|
t.Fatalf("Expected: %v, got: %v", expected, apierr.APIError().ErrorCode)
|
|
}
|
|
expectedMessage := "nats: API error: code=503 err_code=10039 description=jetstream not enabled for account"
|
|
if apierr.Error() != expectedMessage {
|
|
t.Fatalf("Expected: %v, got: %v", expectedMessage, apierr.Error())
|
|
}
|
|
|
|
// an APIError also implements the JetStreamError interface.
|
|
var _ JetStreamError = &APIError{}
|
|
|
|
// matching arbitrary custom error via errors.Is(...)
|
|
customErr := &APIError{ErrorCode: expected}
|
|
if ok := errors.Is(customErr, ErrJetStreamNotEnabledForAccount); !ok {
|
|
t.Fatal("Expected wrapped ErrJetStreamNotEnabledForAccount")
|
|
}
|
|
customErr = &APIError{ErrorCode: 1}
|
|
if ok := errors.Is(customErr, ErrJetStreamNotEnabledForAccount); ok {
|
|
t.Fatal("Expected to not match ErrJetStreamNotEnabled")
|
|
}
|
|
var cerr JetStreamError
|
|
if ok := errors.As(customErr, &cerr); !ok {
|
|
t.Fatal("Expected custom error to be a JetStreamError")
|
|
}
|
|
|
|
// matching to concrete type via errors.As(...)
|
|
var aerr *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: code=503 err_code=10039 description=jetstream not enabled for account"
|
|
if aerr.Error() != expectedMessage {
|
|
t.Fatalf("Expected: %v, got: %v", expectedMessage, apierr.Error())
|
|
}
|
|
})
|
|
|
|
t.Run("test non-api error", func(t *testing.T) {
|
|
s := RunBasicJetStreamServer()
|
|
defer shutdownJSServerAndRemoveStorage(t, s)
|
|
|
|
nc, err := nats.Connect(s.ClientURL())
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
js, err := New(nc)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
defer nc.Close()
|
|
|
|
// stream with empty name
|
|
_, err = js.CreateStream(ctx, StreamConfig{})
|
|
if err == nil {
|
|
t.Fatalf("Expected error, got nil")
|
|
}
|
|
|
|
// check directly to var (backwards compatible)
|
|
if err != ErrStreamNameRequired {
|
|
t.Fatalf("Expected: %v; got: %v", ErrInvalidStreamName, err)
|
|
}
|
|
|
|
// matching via errors.Is
|
|
if ok := errors.Is(err, ErrStreamNameRequired); !ok {
|
|
t.Fatalf("Expected: %v; got: %v", ErrStreamNameRequired, err)
|
|
}
|
|
|
|
// matching wrapped via error.Is
|
|
err2 := fmt.Errorf("custom error: %w", ErrStreamNameRequired)
|
|
if ok := errors.Is(err2, ErrStreamNameRequired); !ok {
|
|
t.Fatal("Expected wrapped ErrStreamNameRequired")
|
|
}
|
|
|
|
// via classic type assertion.
|
|
jserr, ok := err.(JetStreamError)
|
|
if !ok {
|
|
t.Fatal("Expected a JetStreamError")
|
|
}
|
|
if jserr.APIError() != nil {
|
|
t.Fatalf("Expected: empty APIError; got: %v", jserr.APIError())
|
|
}
|
|
|
|
// matching to interface via errors.As(...)
|
|
var jserr2 JetStreamError
|
|
ok = errors.As(err, &jserr2)
|
|
if !ok {
|
|
t.Fatal("Expected a JetStreamError")
|
|
}
|
|
if jserr2.APIError() != nil {
|
|
t.Fatalf("Expected: empty APIError; got: %v", jserr2.APIError())
|
|
}
|
|
expectedMessage := "nats: stream name is required"
|
|
if jserr2.Error() != expectedMessage {
|
|
t.Fatalf("Expected: %v, got: %v", expectedMessage, jserr2.Error())
|
|
}
|
|
|
|
// matching to concrete type via errors.As(...)
|
|
var aerr *APIError
|
|
ok = errors.As(err, &aerr)
|
|
if ok {
|
|
t.Fatal("Expected ErrStreamNameRequired not to map to APIError")
|
|
}
|
|
})
|
|
|
|
}
|