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

feat: Support maxItems validation #40

Conversation

yongruilin
Copy link
Collaborator

@yongruilin yongruilin commented Nov 3, 2024

What type of PR is this?

/kind feature

What this PR does / why we need it:

Support maxItems validation for validation-gen

Which issue(s) this PR fixes:

Fixes

Special notes for your reviewer:

Does this PR introduce a user-facing change?


Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:


@yongruilin yongruilin marked this pull request as draft November 3, 2024 04:49
@yongruilin yongruilin force-pushed the validation-gen-plus-yongrlin-maxitem branch from 385b250 to e18cb13 Compare November 3, 2024 04:51
@yongruilin yongruilin force-pushed the validation-gen-plus-yongrlin-maxitem branch from e18cb13 to 04606a5 Compare November 4, 2024 00:07
@yongruilin yongruilin marked this pull request as ready for review November 4, 2024 17:38
@yongruilin yongruilin force-pushed the validation-gen-plus-yongrlin-maxitem branch 2 times, most recently from 99fc202 to 1345860 Compare November 4, 2024 22:15
staging/src/k8s.io/apimachinery/pkg/api/validate/schema.go Outdated Show resolved Hide resolved
M1 []T `json:"m1"`

M3 M2 `json:"m3"`
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

May want a test case that has maxItems on both the type (as in M2) and the field.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added the test cases.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So, the real trick with these tests is to have as FEW cases as possible to show that the generated code covers all sorts of cases.

I think that is:

A slice field

A slice type def with tag on the type

A slice type def with no tag, used as a field with a tag

A slice type def with tag used as a field with a tag

If using the tag on a non-slice produces a compile error, you can't really include that.

Maybe repeat once for slices of strings, again for slices of struct, pointers to strings, and pointers to struct

Maybe also for slices of slices.

I would lay those out as LS []string, LPS []*string, LT []T, LPT []*T, etc.

Then manually inspect the generated code and see that it makes sense. Then write the docs_test.go to verify success and fail.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

2 questions:

  1. Should the constraint on the type has higher priority to the constraint on field ? e.g.
type M struct {
	TypeMeta int

	// +k8s:validation:maxItems=3
	M1 LT `json:"m1"`

	// +k8s:validation:maxItems=1
	M2 LT `json:"m2"`
}

// +k8s:validation:maxItems=2
type LT []T

Which limit should apply to M1 and M2 ?

  1. Is it necessary to test string? As the validation function takes in any, shouldn't it already cover the string?

Copy link
Owner

Choose a reason for hiding this comment

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

  1. Should the constraint on the type has higher priority to the constraint on field ? e.g.

Today we do preorder traversal (unless I'm misreading the code), so I'd expect field to validate before the type. That said, for cases like this that short-circuit, I think I'd prefer we'd short circuit any validations on the (higher level) field if the (more deeply nested) type validation short circuits.

This gets into some really messing ordering considerations. It might be best to open a separate issue to start tracking those and leave this PR as-is?

Copy link
Owner

Choose a reason for hiding this comment

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

2. Is it necessary to test string? As the validation function takes in any, shouldn't it already cover the string?

I'd include it to guarantee that future changes to this code do not break our expectations.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think we need to do ordering here? If someone puts the same validation in two places, I think we should validate both and not try to be smart.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is currently ShortCircuit. We usually want to try to return as many errors as possible in a single pass, to avoid users trying again and again and again getting new errors each time, but I guess it makes sense to not try further validation if we know the list is too long - for safety against DoS?

@yongruilin yongruilin force-pushed the validation-gen-plus-yongrlin-maxitem branch from 1345860 to 966d387 Compare November 5, 2024 01:41
staging/src/k8s.io/apimachinery/pkg/api/validate/schema.go Outdated Show resolved Hide resolved
M1 []T `json:"m1"`

M3 M2 `json:"m3"`
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

So, the real trick with these tests is to have as FEW cases as possible to show that the generated code covers all sorts of cases.

I think that is:

A slice field

A slice type def with tag on the type

A slice type def with no tag, used as a field with a tag

A slice type def with tag used as a field with a tag

If using the tag on a non-slice produces a compile error, you can't really include that.

Maybe repeat once for slices of strings, again for slices of struct, pointers to strings, and pointers to struct

Maybe also for slices of slices.

I would lay those out as LS []string, LPS []*string, LT []T, LPT []*T, etc.

Then manually inspect the generated code and see that it makes sense. Then write the docs_test.go to verify success and fail.

@yongruilin yongruilin force-pushed the validation-gen-plus-yongrlin-maxitem branch from 966d387 to 76790ce Compare November 5, 2024 03:50
@yongruilin yongruilin force-pushed the validation-gen-plus-yongrlin-maxitem branch from 76790ce to 63ad000 Compare November 6, 2024 23:58
Copy link
Collaborator

@thockin thockin left a comment

Choose a reason for hiding this comment

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

This LGTM overall, sorry to nitpick on test cases, I keep thinking up new ways I might break it :)

Copy link
Collaborator

@thockin thockin left a comment

Choose a reason for hiding this comment

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

This LGTM overall, sorry to nitpick on test cases, I keep thinking up new ways I might break it :)

@yongruilin yongruilin force-pushed the validation-gen-plus-yongrlin-maxitem branch 3 times, most recently from 9b0f6b9 to c85b573 Compare December 2, 2024 22:02
@yongruilin yongruilin force-pushed the validation-gen-plus-yongrlin-maxitem branch from c85b573 to 0310624 Compare December 3, 2024 22:15
@yongruilin yongruilin merged commit c807683 into jpbetz:validation-gen Dec 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants