Refactoring #3
@@ -0,0 +1,51 @@
|
|||||||
|
package source
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorKind uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrorKindUnknown ErrorKind = iota
|
||||||
|
ErrorKindTemporary // timeout or temporarily early/late data i.e. wait or resync
|
||||||
|
ErrorKindUnavailable // producer/flow disappeared
|
||||||
|
ErrorKindInvalidConfig // wrong media type, invalid rate, etc.
|
||||||
|
)
|
||||||
|
|
||||||
|
type SourceError struct {
|
||||||
|
Op string
|
||||||
|
Kind ErrorKind
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SourceError) Error() string {
|
||||||
|
if e.Op == "" {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s: %v", e.Op, e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SourceError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func errorKind(err error) ErrorKind {
|
||||||
|
var sourceErr *SourceError
|
||||||
|
if errors.As(err, &sourceErr) {
|
||||||
|
return sourceErr.Kind
|
||||||
|
}
|
||||||
|
return ErrorKindUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapError(op string, kind ErrorKind, err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &SourceError{
|
||||||
|
Op: op,
|
||||||
|
Kind: kind,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package source
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestErrorKindThroughWrapping(t *testing.T) {
|
||||||
|
base := errors.New("producer disappeared")
|
||||||
|
wrapped := wrapError("read video", ErrorKindUnavailable, base)
|
||||||
|
outer := fmt.Errorf("worker failed: %w", wrapped)
|
||||||
|
|
||||||
|
if got := errorKind(outer); got != ErrorKindUnavailable {
|
||||||
|
t.Fatalf("errorKind() = %v, want %v", got, ErrorKindUnavailable)
|
||||||
|
}
|
||||||
|
if !errors.Is(outer, base) {
|
||||||
|
t.Fatal("wrapped error does not preserve its cause")
|
||||||
|
}
|
||||||
|
if wrapError("nil", 0, nil) != nil {
|
||||||
|
t.Fatal("nil error is not wrapped as nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorKindUnknown(t *testing.T) {
|
||||||
|
if got := errorKind(errors.New("ordinary error")); got != ErrorKindUnknown {
|
||||||
|
t.Fatalf("errorKind() = %v, want %v", got, ErrorKindUnknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSourceErrorWithOperation(t *testing.T) {
|
||||||
|
err := &SourceError{
|
||||||
|
Op: "read video",
|
||||||
|
Kind: ErrorKindTemporary,
|
||||||
|
Err: errors.New("timeout"),
|
||||||
|
}
|
||||||
|
|
||||||
|
const want = "read video: timeout"
|
||||||
|
if got := err.Error(); got != want {
|
||||||
|
t.Fatalf("Error() = %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSourceErrorWithoutOperation(t *testing.T) {
|
||||||
|
err := &SourceError{
|
||||||
|
Kind: ErrorKindTemporary,
|
||||||
|
Err: errors.New("timeout"),
|
||||||
|
}
|
||||||
|
|
||||||
|
const want = "timeout"
|
||||||
|
if got := err.Error(); got != want {
|
||||||
|
t.Fatalf("Error() = %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user