Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FR: Initial WRP Validation Framework #80

Merged
merged 26 commits into from
Jun 8, 2022

Conversation

denopink
Copy link
Contributor

@denopink denopink commented May 25, 2022

Overview

related to #25, #78, xmidt-org/scytale#88, xmidt-org/talaria#153 s.t. we want a validation mechanism that is configurable by clients & verifies the spec.

tl;dr

This pr introduces the initial validation framework, where clients supply validators (satisfying the Validator interface) to NewMsgTypeValidator and then used to verify the spec.

Explanation

Clients supply validators satisfying:

// Validator is a WRP validator that allows access to the Validate function.
type Validator interface {
	Validate(m Message) error
}

and listing which validators are used on known and unknown msg types (where unknown msg types are handled by defaultValidator):

var alwaysValid ValidatorFunc = func(msg Message) error { return nil }
msgv, err := NewTypeValidator(
	// Validates found msg types
	map[MessageType]Validators{SimpleEventMessageType: {alwaysValid}},
	// Validates unfound msg types
	AlwaysInvalid)
err = msgv.Validate(Message{Type: SimpleEventMessageType}) // Found success
err == nil // True
err = msgv.Validate(Message{Type: CreateMessageType}) // Unfound error
err == nil // False

if a default validator is not provided, all unknown msg type will fail by default

msgv, err := NewTypeValidator( // Omitted defaultValidator
	map[MessageType]Validators{SimpleEventMessageType: {alwaysValid}})
err = msgv.Validate(Message{Type: CreateMessageType}) // Unfound error
err == nil // False 
Type of Change(s)
  • Non-breaking Enhancement
  • All new and existing tests passed.

## Overview

related to xmidt-org#25, xmidt-org#78, xmidt-org/scytale#88, xmidt-org/talaria#153 s.t. we want a validation mechanism that is configurable by the application & verifies the spec.

### tl;rd
This pr introduces the initial validation framework, where applications supply validators (satisfying the `Validator interface`) to `NewMsgTypeValidator` and then used to verify the spec.

<details>
<summary> Explanation</summary>

Apps supply validators satisfying:
```go
// Validator is a WRP validator that allows access to the Validate function.
type Validator interface {
	Validate(m Message) error
}
```

and listing which validators are used on known and unknown msg types (where unknown msg types are handled by `defaultValidator`):
```go
var alwaysValidMsg ValidatorFunc = func(msg Message) error { return nil }
msgv, err := NewMsgTypeValidator(
	// Validates known msg types
	m: map[MessageType]Validators{SimpleEventMessageType: {alwaysValidMsg}},
	// Validates unknown msg types
	defaultValidator: alwaysValidMsg)
err = msgv.Validate(Message{Type: SimpleEventMessageType}) // Known msg type
err == nil // True
err = msgv.Validate(Message{Type: CreateMessageType}) // Unknown msg type, uses defaultValidator
err == nil // True
```

if a default validator is not provided, all unknown msg type will **fail** by default
```go
var alwaysValidMsg ValidatorFunc = func(msg Message) error { return nil }
msgv, err := NewMsgTypeValidator( // Omitted defaultValidator
	m: map[MessageType]Validators{SimpleEventMessageType: {alwaysInvalidMsg()}})
err = msgv.Validate(Message{Type: CreateMessageType})
err != nil // True
```
</details>

<details>
<summary>Type of Change(s)</summary>

- Non-breaking Enhancement
- All new and existing tests passed.

</details>

<details>
<summary>Module Unit Testing: [PASSING]</summary>

</details>

<details>
<summary>PR Affecting Unit Testing: validator_test.go [PASSING]</summary>

```console
Running tool: /usr/local/bin/go test -timeout 30s -run ^(TestHelperValidators|TestMsgTypeValidator)$ github.com/xmidt-org/wrp-go/v3

=== RUN   TestHelperValidators
=== RUN   TestHelperValidators/alwaysInvalidMsg
--- PASS: TestHelperValidators (0.00s)
    --- PASS: TestHelperValidators/alwaysInvalidMsg (0.00s)
=== RUN   TestMsgTypeValidator
=== RUN   TestMsgTypeValidator/MsgTypeValidator_validate
=== RUN   TestMsgTypeValidator/MsgTypeValidator_validate/known_message_type
=== RUN   TestMsgTypeValidator/MsgTypeValidator_validate/unknown_message_type_with_provided_default_Validator
=== RUN   TestMsgTypeValidator/MsgTypeValidator_validate/known_message_type_with_a_failing_Validator
=== RUN   TestMsgTypeValidator/MsgTypeValidator_validate/unknown_message_type_without_provided_default_Validator
=== RUN   TestMsgTypeValidator/MsgTypeValidator_factory
=== RUN   TestMsgTypeValidator/MsgTypeValidator_factory/with_provided_default_Validator
=== RUN   TestMsgTypeValidator/MsgTypeValidator_factory/without_provided_default_Validator
=== RUN   TestMsgTypeValidator/MsgTypeValidator_factory/empty_list_of_message_type_Validators
=== RUN   TestMsgTypeValidator/MsgTypeValidator_factory/empty_value_'m'_map[MessageType]Validators
--- PASS: TestMsgTypeValidator (0.00s)
    --- PASS: TestMsgTypeValidator/MsgTypeValidator_validate (0.00s)
        --- PASS: TestMsgTypeValidator/MsgTypeValidator_validate/known_message_type (0.00s)
        --- PASS: TestMsgTypeValidator/MsgTypeValidator_validate/unknown_message_type_with_provided_default_Validator (0.00s)
        --- PASS: TestMsgTypeValidator/MsgTypeValidator_validate/known_message_type_with_a_failing_Validator (0.00s)
        --- PASS: TestMsgTypeValidator/MsgTypeValidator_validate/unknown_message_type_without_provided_default_Validator (0.00s)
    --- PASS: TestMsgTypeValidator/MsgTypeValidator_factory (0.00s)
        --- PASS: TestMsgTypeValidator/MsgTypeValidator_factory/with_provided_default_Validator (0.00s)
        --- PASS: TestMsgTypeValidator/MsgTypeValidator_factory/without_provided_default_Validator (0.00s)
        --- PASS: TestMsgTypeValidator/MsgTypeValidator_factory/empty_list_of_message_type_Validators (0.00s)
        --- PASS: TestMsgTypeValidator/MsgTypeValidator_factory/empty_value_'m'_map[MessageType]Validators (0.00s)
PASS
ok      github.com/xmidt-org/wrp-go/v3  0.303s

> Test run finished at 5/25/2022, 11:39:22 AM <
```

</details>
@denopink denopink added the enhancement New feature or request label May 25, 2022
@denopink denopink self-assigned this May 25, 2022
@codecov
Copy link

codecov bot commented May 25, 2022

Codecov Report

Merging #80 (0218fb9) into main (840a19e) will increase coverage by 0.37%.
The diff coverage is 100.00%.

❗ Current head 0218fb9 differs from pull request most recent head fc099bf. Consider uploading reports for the commit fc099bf to get more accurate results

@@            Coverage Diff             @@
##             main      #80      +/-   ##
==========================================
+ Coverage   49.30%   49.67%   +0.37%     
==========================================
  Files          19       20       +1     
  Lines        3235     3259      +24     
==========================================
+ Hits         1595     1619      +24     
  Misses       1469     1469              
  Partials      171      171              
Impacted Files Coverage Δ
validator.go 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 840a19e...fc099bf. Read the comment docs.

simplifies the usage of alwaysInvalidMsg
Return `ErrInvalidMsgTypeValidator` and `ErrInvalidMsgType` without additional details. We can add those error details downstream later
Copy link
Contributor

@kristinapathak kristinapathak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good start, left some small suggestions.

header_wrp.go Outdated Show resolved Hide resolved
validator.go Outdated Show resolved Hide resolved
validator.go Show resolved Hide resolved
validator.go Outdated Show resolved Hide resolved
validator.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
@denopink
Copy link
Contributor Author

denopink commented May 26, 2022

@kristinapathak I added some testable examples just to try them out. it's pretty neat

image

I can take them out if it's too early for doc examples.

@kristinapathak
Copy link
Contributor

@denopink, example looks good! 👍

validator.go Show resolved Hide resolved
validator.go Outdated Show resolved Hide resolved
validator.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
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
@denopink denopink force-pushed the denopink/FR-WRPValidationFramework branch from d943b60 to 793d6f4 Compare June 1, 2022 20:32
Copy link
Contributor

@kristinapathak kristinapathak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally the functions are looking good - I think I only focused on that last time, so have more unit tests comments now. 👍

validator.go Outdated Show resolved Hide resolved
validator.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Outdated Show resolved Hide resolved
validator_test.go Show resolved Hide resolved
* converted remaining `Validators` to `Validator`
* remove func `validateValidator`
* move nil checks to `Validate` func
* remove Test struct
* add new unexported field to check if `TypeValidato` is valid
* add func `IsBad` to TypeValidato to say whether `TypeValidato` is valid
* update tests for testAlwaysInvalid and testAlwaysValid
* update tests names for `TestTypeValidator`
* add tests for `Validators`
@denopink denopink requested review from kristinapathak and renaz6 and removed request for renaz6 June 7, 2022 20:40
* [misunderstanding] Remove unexported field `isbad` from `TypeValidator` and its references
* [misunderstanding] Remove `IsBad` func from `TypeValidator`
* Use `assert.Zero/NotZero` funcs to test `TypeValidator`'s state
Copy link
Contributor

@kristinapathak kristinapathak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests look great! Realized I missed these two small suggestions earlier.

validator.go Outdated Show resolved Hide resolved
validator.go Outdated Show resolved Hide resolved
* rename `defaultValidators` to `defaultValidator`
* replace `defaultValidators` variadic to `defaultValidator Validator` in `NewTypeValidator` func
Copy link
Contributor

@kristinapathak kristinapathak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants