From 793d6f40c94aed96b06b382e46dd83f69145e566 Mon Sep 17 00:00:00 2001 From: Owen Cabalceta Date: Thu, 26 May 2022 13:32:47 -0400 Subject: [PATCH] Squash: examples, docs, multierr updates 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 --- go.mod | 1 + go.sum | 4 ++ validator.go | 63 ++++++++++++++-------- validator_test.go | 133 ++++++++++++++++++++++------------------------ 4 files changed, 110 insertions(+), 91 deletions(-) diff --git a/go.mod b/go.mod index 1fd3bdd..393c95c 100644 --- a/go.mod +++ b/go.mod @@ -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 ) diff --git a/go.sum b/go.sum index a1d9119..8370579 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/validator.go b/validator.go index 6736faf..f909660 100644 --- a/validator.go +++ b/validator.go @@ -19,6 +19,8 @@ package wrp import ( "errors" + + "go.uber.org/multierr" ) var ( @@ -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 { @@ -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 @@ -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 { @@ -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 } } @@ -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 } } @@ -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 +} diff --git a/validator_test.go b/validator_test.go index 11a41a9..64cf8c7 100644 --- a/validator_test.go +++ b/validator_test.go @@ -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 @@ -42,19 +41,19 @@ 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}, }, }, @@ -62,19 +61,19 @@ func testTypeValidatorValidate(t *testing.T) { { 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}, }, @@ -102,11 +101,10 @@ 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 @@ -114,69 +112,83 @@ func testNewTypeValidator(t *testing.T) { }{ // 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) @@ -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) { @@ -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 }