errors_paths_test.mx raw

   1  package errors
   2  
   3  import (
   4  	"fmt"
   5  	"testing"
   6  )
   7  
   8  // The constructors and the helpers' non-domain paths. The suite above covers
   9  // the common errors; these are the builder methods and the plain-error answers
  10  // a caller gets when the error in hand is not a DomainError.
  11  
  12  func TestBaseStringAndWithMessage(t *testing.T) {
  13  	e := ErrInvalidJSON
  14  	if e.String() == "" || e.String() != e.Error() {
  15  		t.Fatal("String must mirror Error")
  16  	}
  17  	m := e.WithMessage([]byte("custom"))
  18  	if string(m.message) != "custom" {
  19  		t.Fatal("WithMessage")
  20  	}
  21  	if string(m.Code()) != "INVALID_JSON" || string(m.Category()) != "validation" {
  22  		t.Fatal("WithMessage must keep the code and category")
  23  	}
  24  	if m.IsRetryable() {
  25  		t.Fatal("WithMessage must keep the retryable flag")
  26  	}
  27  	if string(e.message) != "malformed JSON" {
  28  		t.Fatal("WithMessage must not mutate the original")
  29  	}
  30  	// No cause: the message stands alone.
  31  	if e.Error() != "malformed JSON" {
  32  		t.Fatalf("Error without a cause = %s", e.Error())
  33  	}
  34  }
  35  
  36  func TestWithFieldAndConstructors(t *testing.T) {
  37  	v := ErrInvalidEventID.WithField([]byte("other"))
  38  	if string(v.Field) != "other" || string(v.Code()) != "INVALID_ID" {
  39  		t.Fatal("WithField")
  40  	}
  41  	if string(v.Category()) != "validation" {
  42  		t.Fatal("WithField must keep the category")
  43  	}
  44  
  45  	a := NewAccessDenied([]byte("write"), []byte("nope"))
  46  	if string(a.Code()) != "ACCESS_DENIED" || string(a.AccessLevel) != "write" || a.NeedsAuth() {
  47  		t.Fatal("NewAccessDenied")
  48  	}
  49  	if a.Category()[0] != 'a' {
  50  		t.Fatal("NewAccessDenied category")
  51  	}
  52  
  53  	p := NewProcessingError([]byte("X"), []byte("x"), true).WithEventID([]byte("abc"))
  54  	if string(p.EventID) != "abc" || !p.IsRetryable() {
  55  		t.Fatal("WithEventID")
  56  	}
  57  	p2 := p.WithKind(7)
  58  	if p2.Kind != 7 || string(p2.EventID) != "abc" {
  59  		t.Fatal("WithKind")
  60  	}
  61  
  62  	pb := NewPolicyBlocked([]byte("rule"), []byte("no"))
  63  	if string(pb.RuleName) != "rule" || string(pb.Action) != "block" {
  64  		t.Fatal("NewPolicyBlocked")
  65  	}
  66  	pr := NewPolicyRejected([]byte("rule"), []byte("no"))
  67  	if string(pr.Action) != "reject" || string(pr.Code()) != "POLICY_REJECTED" {
  68  		t.Fatal("NewPolicyRejected")
  69  	}
  70  	if !NeedsAuth(NewAuthRequired([]byte("because"))) {
  71  		t.Fatal("NewAuthRequired")
  72  	}
  73  
  74  	ap := ErrBanned.WithPubkey([]byte("pk"))
  75  	if string(ap.Pubkey) != "pk" || string(ap.Code()) != "BANNED" {
  76  		t.Fatal("WithPubkey")
  77  	}
  78  }
  79  
  80  func TestCodeCategoryAndIsOnPlainErrors(t *testing.T) {
  81  	plain := fmt.Errorf("plain")
  82  	if Code(plain) != nil {
  83  		t.Fatal("a plain error has no code")
  84  	}
  85  	if string(Category(plain)) != "unknown" {
  86  		t.Fatal("a plain error's category is unknown")
  87  	}
  88  	if Is(plain, ErrDuplicate) {
  89  		t.Fatal("Is on a plain error is false")
  90  	}
  91  	if IsRetryable(plain) {
  92  		t.Fatal("a plain error is not retryable")
  93  	}
  94  	if NeedsAuth(plain) {
  95  		t.Fatal("a plain error does not need auth")
  96  	}
  97  
  98  	if string(Code(ErrAuthRequired)) != "AUTH_REQUIRED" {
  99  		t.Fatal("code")
 100  	}
 101  	if string(Category(ErrRateLimited)) != "processing" {
 102  		t.Fatal("rate limit category")
 103  	}
 104  	if string(Category(ErrKindBlocked)) != "policy" {
 105  		t.Fatal("policy category")
 106  	}
 107  	if string(Category(ErrServiceUnavailable)) != "service" || !IsRetryable(ErrServiceUnavailable) {
 108  		t.Fatal("service error")
 109  	}
 110  	if string(Category(ErrStorageFull)) != "storage" {
 111  		t.Fatal("storage category")
 112  	}
 113  	if !Is(ErrAuthRequired, ErrAuthRequired) {
 114  		t.Fatal("Is matches on the code, not the pointer")
 115  	}
 116  }
 117