Skip to content

Commit

Permalink
Return NotFounder error, if ID attribute is not present on plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
breml committed Feb 15, 2021
1 parent 04f44c3 commit 6f663bf
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 1 deletion.
4 changes: 3 additions & 1 deletion ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ func (p Plugin) String() string {
// The id attribute is one of the common options, that is optionally available
// on every Logstash plugin. In generall, it is highly recommended for a Logstash
// plugin to have an id.
// If the ID attribute is not present, an error is returned, who implements
// the NotFounder interface.
func (p Plugin) ID() (string, error) {
for _, attr := range p.Attributes {
if attr != nil && attr.Name() == "id" {
Expand All @@ -176,7 +178,7 @@ func (p Plugin) ID() (string, error) {
}
}
}
return "", fmt.Errorf("plugin %s does not contain an id attribute", p.name)
return "", NotFoundErrorf("plugin %s does not contain an id attribute", p.name)
}

// Attribute interface combines Logstash plugin attribute types.
Expand Down
66 changes: 66 additions & 0 deletions ast/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package ast

import (
"errors"
"fmt"
)

// NotFounder interface is implemented by errors, that indicate that a record
// is not found.
type NotFounder interface {
Error() string
NotFound()
}

type notFoundError struct {
err error
}

// NewNotFoundError wraps an error as a not found error.
func NewNotFoundError(err error) error {
if err == nil {
return nil
}

return notFoundError{
err: err,
}
}

// NotFoundErrorf formats according to a format specifier and returns the string
// as a value that satisfies NotFounder.
func NotFoundErrorf(format string, a ...interface{}) error {
return NewNotFoundError(fmt.Errorf(format, a...))
}

// NotFound implements the NotFounder interface to indicate, that the error is
// of type not found.
func (e notFoundError) NotFound() {}

func (e notFoundError) Error() string {
return "not found: " + e.err.Error()
}

// Format implements the fmt.Formatter interface to print the error differently
// depending on the format verb.
func (e notFoundError) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "not found: %+v", e.err)
return
}
fallthrough
case 's':
fmt.Fprint(s, e.Error())
case 'q':
fmt.Fprintf(s, "%q", e.Error())
}
}

// IsNotFoundError returns true, if the provided error implements the NotFound
// interface.
func IsNotFoundError(e error) bool {
var notFoundErr NotFounder
return errors.As(e, &notFoundErr)
}
91 changes: 91 additions & 0 deletions ast/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package ast_test

import (
"errors"
"fmt"
"testing"

"github.com/breml/logstash-config/ast"
)

func TestNotFoundError(t *testing.T) {
cases := []struct {
formatVerb string

wantErrorString string
}{
{
formatVerb: "%s",

wantErrorString: "not found: error",
},
{
formatVerb: "%v",

wantErrorString: "not found: error",
},
{
formatVerb: "%+v",

wantErrorString: "not found: error",
},
{
formatVerb: "%q",

wantErrorString: `"not found: error"`,
},
}

for _, test := range cases {
t.Run(test.formatVerb, func(t *testing.T) {
err := ast.NotFoundErrorf("%s", "error")

if err == nil {
t.Fatal("Expect an error, but got none.")
}

if test.wantErrorString != fmt.Sprintf(test.formatVerb, err) {
t.Errorf("Expect error to print %q with verb %q, but got: %q", test.wantErrorString, test.formatVerb, fmt.Sprintf(test.formatVerb, err))
}

if !ast.IsNotFoundError(err) {
t.Fatalf("Expect err %v to implement NotFounder interface, but it does not.", err)
}
})
}
}

func TestNotFoundErrorNotFound(t *testing.T) {
ast.NewNotFoundError(errors.New("error")).(ast.NotFounder).NotFound()
}

func TestIsNotFoundError(t *testing.T) {
cases := []struct {
name string
err error

want bool
}{
{
name: "nil",
},
{
name: "nil not founder",
err: ast.NewNotFoundError(nil),
},
{
name: "error",
err: ast.NewNotFoundError(errors.New("error")),
want: true,
},
}

for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
got := ast.IsNotFoundError(test.err)
if test.want != got {
t.Fatalf("Expectation (%v) not met: %v", test.want, got)
}
})
}
}

0 comments on commit 6f663bf

Please sign in to comment.