-
Notifications
You must be signed in to change notification settings - Fork 210
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
Add direct conversion from Gnostic v2 types to spec.Swagger #283
Add direct conversion from Gnostic v2 types to spec.Swagger #283
Conversation
numbers look really promising, thanks is this ready for review? I see a lot of question marks and commented out code |
8d2f9d0
to
0e8d80a
Compare
@liggitt It is ready for review as of my latest force push. You looked too quickly! |
f98efd5
to
f9d96bf
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.
Minor nits, the conversion code seems good to me, especially as it round-trips properly.
pkg/validation/spec/gnostic_test.go
Outdated
func TestGnosticConversionSmallDeterministic2(t *testing.T) { | ||
// A failed case of TestGnosticConversionSmallRandom | ||
// which failed during development/testing loop | ||
gnosticCommonTest( | ||
t, | ||
fuzz. | ||
NewWithSeed(1646770841). | ||
NilChance(0.8). | ||
MaxDepth(10). | ||
NumElements(1, 2), | ||
) | ||
} | ||
|
||
func TestGnosticConversionSmallDeterministic3(t *testing.T) { | ||
// A failed case of TestGnosticConversionSmallRandom | ||
// which failed during development/testing loop | ||
gnosticCommonTest( | ||
t, | ||
fuzz. | ||
NewWithSeed(1646772024). | ||
NilChance(0.8). | ||
MaxDepth(10). | ||
NumElements(1, 2), | ||
) | ||
} | ||
|
||
func TestGnosticConversionSmallDeterministic4(t *testing.T) { | ||
// A failed case of TestGnosticConversionSmallRandom | ||
// which failed during development/testing loop | ||
gnosticCommonTest( | ||
t, | ||
fuzz. | ||
NewWithSeed(1646791953). | ||
NilChance(0.8). | ||
MaxDepth(10). | ||
NumElements(1, 2), | ||
) | ||
} | ||
|
||
|
||
func TestGnosticConversionSmallRandom(t *testing.T) { | ||
seed := time.Now().Unix() | ||
t.Log("Using seed: ", seed) | ||
|
||
gnosticCommonTest( | ||
t, | ||
fuzz. | ||
NewWithSeed(seed). | ||
NilChance(0.8). | ||
MaxDepth(10). |
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 don't know if we need all these variants of the test. If it were me, I'd have kept it in a single test, and ran a loop a few times (100? depending on how much each invocation takes), re-fuzzing every-time rather than sticking to either pre-determined seed or even changing parameters like this. I don't think the "size" really has an impact for these.
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 disagree that the "deterministic" tests add no value. The SmallRandom
test case does as you described to fuzz for new failing test cases (though it maybe should be modified to fuzz more than once). Once a failing case is discovered by the random fuzzer it is easy to take the seed used to reproduce the failure, fix it, and add a regression test. Do this enough times and you have a corpus of tricky test cases the code is known to have failed in the past against to guard against regression.
To fuzz in a loop 100 times without printing the random seed or fuzzed object used for each case offers no value to a developer other than to say "it's broken", since the exact case can't be reproduced.
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.
even changing parameters like this. I don't think the "size" really has an impact for these.
I was forced to change the parameters since the fuzz to generate the object would take too long otherwise. The different "sizes" was useful for me during development to work on smaller cases and then larger and larger. The distinction may not be useful as part of the test sweet but I see no need to remove them.
Had a few comments:
I didn't review the specific gnostic structs carefully to check all the fields were caught... I'm assuming fuzzing will catch simple field copies. For the interface types we're doing type switches on, do you have the unit test coverage handy to see how well the tests are exercising all the cases? |
a37ac22
to
a9971bd
Compare
@liggitt With my latest updates I think I have addressed most of your comments:
I gathered test coverage info for the gnostic tests. |
huh, that's a pretty sharp edge. I can easily imagine someone using
👍
👍
👍
👍 |
Yeah, I think that's our only option right now. That's a little unfortunate but hopefully that'll be limited to OpenAPI v2. |
29f061e
to
5989484
Compare
With my latest commit all supported gnostic types and significant LOC are now being exercised within the tests. |
/retest |
@alexzielenski: Cannot trigger testing until a trusted user reviews the PR and leaves an In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
331eb4d
to
0f7b134
Compare
looking really solid, thanks. noted a few places we want to make sure we exercise plumbing with tests |
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.
one way to improve coverage of tested code paths is to remove unused ones... I noted several places where we have no use of the ok
data loss return indicator... trimming that to only places that are propagating errors from License/ContactInfo/ExternalDocumentation will help clarify where we could actually exercise those branches in tests
ee5c5ea
to
53e58cf
Compare
/lgtm |
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.
a couple last nits, then lgtm
53e58cf
to
5995b80
Compare
also add benchmark for gnostic conversion with swagger
5995b80
to
c715a76
Compare
/lgtm |
/approve Thanks, that's awesome! Can't wait to see the opposite direction 😂 |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: alexzielenski, apelisse, liggitt The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
This PR continues conversation from #279 and privately with @liggitt wherein we decided the best path to convert gnostic to kube-openapi was to write a direct conversion.
This PR adds a direct conversion from gnostic openapiv2 types to kube-openapi's spec.Swagger. Below are benchmark results from the same benchmark used in #279:
pb->gnostic->swagger using this method takes ~39ms
this compares favorably to pb->gnostic->yaml->swagger from the last PR in ~97ms
which compared favorably to pb->gnostic->yaml->json->swagger, today's existing solution, which clocked this benchmark at ~628ms
Caveats:
Maximum
,Minimum
,MaxItems
, etc in gnostic are not implemented as pointers. This means the conversion has no way to differentiate between one of these being0
vs being unusedkube->json->gnostic->kube
, those fields would be missing, sincejson->gnostic
would ignore them.VendorExtensible
embedded even when OpenAPI spec permits "x-" extensions. This means any extensions used in gnostic for a few types are not carried over. This can be corrected in another PRFor the use case of kubernetes' swagger.json, most of these caveats do not apply:
prefixItems
is used as the array version of oldItems
): http://json-schema.org/draft/2020-12/json-schema-core.html#items@natasha41575
/cc @apelisse