-
Notifications
You must be signed in to change notification settings - Fork 426
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
test(manifest): add integ test making sure all structs implement Validate #2895
Conversation
02e9895
to
45bd195
Compare
@@ -44,7 +44,26 @@ var ( | |||
) | |||
|
|||
// Validate returns nil if LoadBalancedWebService is configured correctly. | |||
func (l *LoadBalancedWebService) Validate() error { | |||
func (l LoadBalancedWebService) Validate() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why we switched the receivers from pointers to values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it won't work otherwise since Validate()
would be the method of * LoadBalancedWebService
. Also I feel it doesn't make the code much cleaner with pointer receiver.
@@ -44,7 +44,26 @@ var ( | |||
) | |||
|
|||
// Validate returns nil if LoadBalancedWebService is configured correctly. | |||
func (l *LoadBalancedWebService) Validate() error { | |||
func (l LoadBalancedWebService) Validate() error { | |||
var err error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we remove the variable with:
if err := l...Validate();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm wouldn't this avoid defining err
repetitively?
return nil | ||
} | ||
if val := int(*p); val < 0 || val > 100 { | ||
func (p Percentage) Validate() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok so by moving it to value receivers we're assuming the callers will do the nil-check from now on right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah that's right.
var val validator | ||
validatorType := reflect.TypeOf(&val).Elem() | ||
// template.Parser is not a manifest struct. | ||
var tpl template.Parser | ||
templaterType := reflect.TypeOf(&tpl).Elem() | ||
if !typ.Implements(templaterType) && !typ.Implements(validatorType) { | ||
return fmt.Errorf(`%v does not implement "Validate()"`, typ) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if instead of ignoring template.Parser
as a type we can check if the field has a "yaml"
struct tag and if so check it? https://stackoverflow.com/a/23507821/1201381
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea!
06e827a
to
e5e75ef
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two questions 🤚🏼
} | ||
for i := 0; i < typ.NumField(); i++ { | ||
// Skip if it is not a manifest yaml field. | ||
if typ.Field(i).Tag.Get("yaml") == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about fields such as HealthCheckArgs
that does not have a tag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true. I guess I'd rather revert this change @efekarakus
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😭 I'm just not a fan because it feels so fragile otherwise.
As a requirement, it makes sense to me to read "any field used during unmarshalling YAML should be validated", but now we lose that nice definition.
Isn't it good enough to have the Validate
method on HealthCheckArgsOrString
? since that already will call internally Validate
on any of its exclusive subfields. I'd rather have us keep typ.Field(i).Tag.Get("yaml") == ""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since that already will call internally Validate on any of its exclusive subfields.
Problem is this is not always guaranteed...other people could forget to do so, which is the whole point to have this test
e5e75ef
to
45bd195
Compare
} | ||
// For slice and map, validate individual member. | ||
if typ.Kind() == reflect.Array || typ.Kind() == reflect.Slice { | ||
for i := 0; i < v.Len(); i++ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought 💭 .
Since isValid
validates whether a type is implementing an interface as expected, should we use t reflect.Type
as its parameter, instead of v reflect.Vlaue
?
Then here we can use elemTyp := typ.Elem()
to retrieve the element type of the array/slice, and then call isValid(elemTyp)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we are now skipping private fields, we have to use value instead of type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but i guess you are right. we only need to check the first element since they are all the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
discussed offline now use structfield.IsExported()
to check so that we can use type as the parameter.
} | ||
if typ.Kind() == reflect.Map { | ||
for _, k := range v.MapKeys() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And also use typ.Key()
and typ.Elem()
here.
}) | ||
} | ||
} | ||
// func TestPlatformString_Validate(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this intentionally commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤦
for _, k := range basicKinds { | ||
types = append(types, k.String()) | ||
} | ||
types = append(types, reflect.TypeOf(map[string]string{}).String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this:
In isValid
, we detect the map's key and value types, and recursively call isValid
if they are of non-basic types.
Therefore, we don't need special treatment for map[string]string
- since string
and string
are basic, they won't get called on isValid
.
Same for slice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is what i was doing! i forgot to remove those
13094ba
to
4834a9e
Compare
d2675f0
to
703d597
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hooray!
…date (aws#2895) <!-- Provide summary of changes --> This PR 1. Add integ test to make sure every manifest struct or advanced type implements `Validate()`. 2. Fix a bug that `network.placement` should not be required even if `network` is not empty. <!-- Issue number, if available. E.g. "Fixes aws#31", "Addresses aws#42, 77" --> By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the Apache 2.0 License.
This PR
Validate()
.network.placement
should not be required even ifnetwork
is not empty.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the Apache 2.0 License.