Skip to content

Commit

Permalink
Squash: examples, docs, multierr updates
Browse files Browse the repository at this point in the history
update examples

Doc/var update

Add test for `Nil default Validators` edge case

update examples output

doc update

Updates based on PR review

* exported alwaysValid
* decoupled data structures leveraging `Validators` to `Validator`
* added validateValidator

Add multierr to Validator
  • Loading branch information
denopink committed Jun 1, 2022
1 parent 1ee6c2e commit 793d6f4
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 91 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ require (
github.com/ugorji/go/codec v1.2.6
github.com/xmidt-org/httpaux v0.3.0
github.com/xmidt-org/webpa-common v1.3.2
go.uber.org/multierr v1.8.0
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ github.com/xmidt-org/httpaux v0.3.0 h1:JdV4QceiE8EMA1Qf5rnJzHdkIPzQV12ddARHLU8hr
github.com/xmidt-org/httpaux v0.3.0/go.mod h1:mviIlg5fHGb3lAv3l0sbiwVG/q9rqvXaudEYxVrzXdE=
github.com/xmidt-org/webpa-common v1.3.2 h1:dE1Fi+XVnkt3tMGMjH7/hN/UGcaQ/ukKriXuMDyCWnM=
github.com/xmidt-org/webpa-common v1.3.2/go.mod h1:oCpKzOC+9h2vYHVzAU/06tDTQuBN4RZz+rhgIXptpOI=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
63 changes: 40 additions & 23 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package wrp

import (
"errors"

"go.uber.org/multierr"
)

var (
Expand All @@ -27,9 +29,10 @@ var (
)

// AlwaysInvalid doesn't validate anything about the message and always returns an error.
var AlwaysInvalid ValidatorFunc = func(m Message) error {
return ErrInvalidMsgType
}
var AlwaysInvalid ValidatorFunc = func(m Message) error { return ErrInvalidMsgType }

// AlwaysValid doesn't validate anything about the message and always returns nil.
var AlwaysValid ValidatorFunc = func(msg Message) error { return nil }

// Validator is a WRP validator that allows access to the Validate function.
type Validator interface {
Expand All @@ -43,14 +46,12 @@ type Validators []Validator
// Validate runs messages through each validator in the validators list.
// It returns as soon as the message is considered invalid, otherwise returns nil if valid.
func (vs Validators) Validate(m Message) error {
var err error
for _, v := range vs {
err := v.Validate(m)
if err != nil {
return err
}
err = multierr.Append(err, v.Validate(m))
}

return nil
return err
}

// ValidatorFunc is a WRP validator that takes messages and validates them
Expand All @@ -63,14 +64,14 @@ func (vf ValidatorFunc) Validate(m Message) error {
}

// TypeValidator is a WRP validator that validates based on message type
// or using the defaultValidators if message type is unknown.
// or using the defaultValidators if message type is unfound.
type TypeValidator struct {
m map[MessageType]Validators
m map[MessageType]Validator
defaultValidators Validators
}

// Validate validates messages based on message type or using the defaultValidators
// if message type is unknown.
// if message type is unfound.
func (m TypeValidator) Validate(msg Message) error {
vs := m.m[msg.MessageType()]
if vs == nil {
Expand All @@ -81,20 +82,14 @@ func (m TypeValidator) Validate(msg Message) error {
}

// NewTypeValidator is a TypeValidator factory.
func NewTypeValidator(m map[MessageType]Validators, defaultValidators ...Validator) (TypeValidator, error) {
func NewTypeValidator(m map[MessageType]Validator, defaultValidators ...Validator) (TypeValidator, error) {
if m == nil {
return TypeValidator{}, ErrInvalidTypeValidator
}

for _, vs := range m {
if vs == nil || len(vs) == 0 {
return TypeValidator{}, ErrInvalidTypeValidator
}

for _, v := range vs {
if v == nil {
return TypeValidator{}, ErrInvalidTypeValidator
}
for _, v := range m {
if err := validateValidator(v); err != nil {
return TypeValidator{}, err
}
}

Expand All @@ -103,8 +98,8 @@ func NewTypeValidator(m map[MessageType]Validators, defaultValidators ...Validat
}

for _, v := range defaultValidators {
if v == nil {
return TypeValidator{}, ErrInvalidTypeValidator
if err := validateValidator(v); err != nil {
return TypeValidator{}, err
}
}

Expand All @@ -113,3 +108,25 @@ func NewTypeValidator(m map[MessageType]Validators, defaultValidators ...Validat
defaultValidators: defaultValidators,
}, nil
}

// validateValidator validates a given Validator.
func validateValidator(v Validator) error {
switch vs := v.(type) {
case Validators:
if vs == nil || len(vs) == 0 {
return ErrInvalidTypeValidator
}

for _, v := range vs {
if v == nil {
return ErrInvalidTypeValidator
}
}
case Validator, ValidatorFunc:
// catch nil Validator
default:
return ErrInvalidTypeValidator
}

return nil
}
133 changes: 65 additions & 68 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,11 @@ import (

func testTypeValidatorValidate(t *testing.T) {
type Test struct {
m map[MessageType]Validators
m map[MessageType]Validator
defaultValidators Validators
msg Message
}

var alwaysValid ValidatorFunc = func(msg Message) error { return nil }
tests := []struct {
description string
value Test
Expand All @@ -42,39 +41,39 @@ func testTypeValidatorValidate(t *testing.T) {
{
description: "Found success",
value: Test{
m: map[MessageType]Validators{
SimpleEventMessageType: {alwaysValid},
m: map[MessageType]Validator{
SimpleEventMessageType: Validators{AlwaysValid},
},
msg: Message{Type: SimpleEventMessageType},
},
},
{
description: "Not found success",
description: "Unfound success",
value: Test{
m: map[MessageType]Validators{
SimpleEventMessageType: {AlwaysInvalid},
m: map[MessageType]Validator{
SimpleEventMessageType: Validators{AlwaysInvalid},
},
defaultValidators: Validators{alwaysValid},
defaultValidators: Validators{AlwaysValid},
msg: Message{Type: CreateMessageType},
},
},
// Failure case
{
description: "Found error",
value: Test{
m: map[MessageType]Validators{
SimpleEventMessageType: {AlwaysInvalid},
m: map[MessageType]Validator{
SimpleEventMessageType: Validators{AlwaysInvalid},
},
defaultValidators: Validators{alwaysValid},
defaultValidators: Validators{AlwaysValid},
msg: Message{Type: SimpleEventMessageType},
},
expectedErr: ErrInvalidMsgType,
},
{
description: "Not Found error",
description: "Unfound error",
value: Test{
m: map[MessageType]Validators{
SimpleEventMessageType: {alwaysValid},
m: map[MessageType]Validator{
SimpleEventMessageType: Validators{AlwaysValid},
},
msg: Message{Type: CreateMessageType},
},
Expand Down Expand Up @@ -102,81 +101,94 @@ func testTypeValidatorValidate(t *testing.T) {

func testNewTypeValidator(t *testing.T) {
type Test struct {
m map[MessageType]Validators
m map[MessageType]Validator
defaultValidators Validators
}

var alwaysValid ValidatorFunc = func(msg Message) error { return nil }
tests := []struct {
description string
value Test
expectedErr error
}{
// Success case
{
description: "Default Validator success",
description: "Default Validators success",
value: Test{
m: map[MessageType]Validators{
SimpleEventMessageType: {alwaysValid},
m: map[MessageType]Validator{
SimpleEventMessageType: AlwaysValid,
},
defaultValidators: Validators{alwaysValid},
defaultValidators: Validators{AlwaysValid},
},
expectedErr: nil,
},
{
description: "Empty map of Validators success",
value: Test{
m: map[MessageType]Validators{},
defaultValidators: Validators{alwaysValid},
m: map[MessageType]Validator{},
defaultValidators: Validators{AlwaysValid},
},
expectedErr: nil,
},
{
description: "Omit default Validator success",
description: "Omit default Validators success",
value: Test{
m: map[MessageType]Validators{
SimpleEventMessageType: {alwaysValid},
m: map[MessageType]Validator{
SimpleEventMessageType: Validators{AlwaysValid},
},
},
expectedErr: nil,
},
// Failure case
{
description: "Nil list of default Validators error ",
value: Test{
m: map[MessageType]Validator{
SimpleEventMessageType: AlwaysValid,
},
defaultValidators: Validators{nil},
},
expectedErr: ErrInvalidTypeValidator,
},
{
description: "Empty list of Validators error",
value: Test{
m: map[MessageType]Validators{
SimpleEventMessageType: {},
m: map[MessageType]Validator{
SimpleEventMessageType: Validators{},
},
defaultValidators: Validators{alwaysValid},
defaultValidators: Validators{AlwaysValid},
},
expectedErr: ErrInvalidTypeValidator,
},
{
description: "Nil Validators error",
description: "Nil Validator error",
value: Test{
m: map[MessageType]Validators{
m: map[MessageType]Validator{
SimpleEventMessageType: nil,
},
defaultValidators: Validators{alwaysValid},
defaultValidators: Validators{AlwaysValid},
},
expectedErr: ErrInvalidTypeValidator,
},
{
description: "Nil list of Validators error",
value: Test{
m: map[MessageType]Validators{
SimpleEventMessageType: {nil},
m: map[MessageType]Validator{
SimpleEventMessageType: Validators{nil},
},
defaultValidators: Validators{alwaysValid},
defaultValidators: Validators{AlwaysValid},
},
expectedErr: ErrInvalidTypeValidator,
},
{
description: "Empty map of Validators error",
value: Test{},
description: "Nil map of Validators error",
value: Test{
m: nil,
defaultValidators: Validators{AlwaysValid},
},
expectedErr: ErrInvalidTypeValidator,
},
}

for _, tc := range tests {
t.Run(tc.description, func(t *testing.T) {
assert := assert.New(t)
Expand All @@ -196,9 +208,7 @@ func testAlwaysInvalid(t *testing.T) {
assert := assert.New(t)
msg := Message{}
err := AlwaysInvalid(msg)

assert.ErrorIs(err, ErrInvalidMsgType)

}

func TestHelperValidators(t *testing.T) {
Expand Down Expand Up @@ -229,40 +239,27 @@ func TestTypeValidator(t *testing.T) {
}

func ExampleNewTypeValidator() {
var alwaysValid ValidatorFunc = func(msg Message) error { return nil }
msgv, err := NewTypeValidator(
// Validates known msg types
map[MessageType]Validators{SimpleEventMessageType: {alwaysValid}},
// Validates unknown msg types
// Validates found msg types
map[MessageType]Validator{SimpleEventMessageType: Validators{AlwaysValid}},
// Validates unfound msg types
AlwaysInvalid)
if err != nil {
return
}
err = msgv.Validate(Message{Type: SimpleEventMessageType}) // Found success
fmt.Println(err == nil)
// Output: true

fmt.Printf("%v %T", err == nil, msgv)
// Output: true wrp.TypeValidator
}

func ExampleTypeValidator_Validate_found() {
var alwaysValid ValidatorFunc = func(msg Message) error { return nil }
func ExampleTypeValidator_Validate() {
msgv, err := NewTypeValidator(
// Validates known msg types
map[MessageType]Validators{SimpleEventMessageType: {alwaysValid}},
// Validates unknown msg types
// Validates found msg types
map[MessageType]Validator{SimpleEventMessageType: Validators{AlwaysValid}},
// Validates unfound msg types
AlwaysInvalid)
err = msgv.Validate(Message{Type: SimpleEventMessageType}) // Found success
fmt.Println(err == nil)
// Output: true
}
func ExampleTypeValidator_Validate_notFound() {
var alwaysValid ValidatorFunc = func(msg Message) error { return nil }
msgv, err := NewTypeValidator(
// Validates known msg types
map[MessageType]Validators{SimpleEventMessageType: {alwaysValid}},
// Validates unknown msg types
AlwaysInvalid)
err = msgv.Validate(Message{Type: CreateMessageType}) // Not Found error
fmt.Println(err == nil)
// Output: false
if err != nil {
return
}

foundErr := msgv.Validate(Message{Type: SimpleEventMessageType}) // Found success
unfoundErr := msgv.Validate(Message{Type: CreateMessageType}) // Unfound error
fmt.Println(foundErr == nil, unfoundErr == nil)
// Output: true false
}

0 comments on commit 793d6f4

Please sign in to comment.