Merge pull request #85722 from sttts/sttts-apiextensions-nullable-required

apiextensions: filter required nullable to workaround kubectl validation
This commit is contained in:
Kubernetes Prow Robot 2019-11-28 06:09:27 -08:00 committed by GitHub
commit 1d343c8a0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 115 additions and 0 deletions

View File

@ -73,6 +73,15 @@ func ToStructuralOpenAPIV2(in *structuralschema.Structural) *structuralschema.St
changed = true
}
for f, fs := range s.Properties {
if fs.Nullable {
s.ValueValidation.Required, changed = filterOut(s.ValueValidation.Required, f)
}
}
if s.AdditionalProperties != nil && s.AdditionalProperties.Structural != nil && s.AdditionalProperties.Structural.Nullable {
s.ValueValidation.Required, changed = nil, true
}
return changed
},
// we drop all junctors above, and hence, never reach nested value validations
@ -82,3 +91,24 @@ func ToStructuralOpenAPIV2(in *structuralschema.Structural) *structuralschema.St
return out
}
func filterOut(ss []string, x string) ([]string, bool) {
var filtered []string
for i, s := range ss {
if s == x {
if filtered == nil {
filtered = make([]string, i, len(ss))
copy(filtered, ss[:i])
}
} else if filtered != nil {
filtered = append(filtered, s)
}
}
if filtered != nil {
if len(filtered) == 0 {
return nil, true
}
return filtered, true
}
return ss, false
}

View File

@ -172,6 +172,63 @@ func Test_ConvertJSONSchemaPropsToOpenAPIv2SchemaByType(t *testing.T) {
},
expected: new(spec.Schema),
},
{
name: "nullable required",
in: &apiextensions.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensions.JSONSchemaProps{
"a": {
Nullable: true,
Type: "string",
},
"b": {
Nullable: true,
Type: "string",
},
"c": {
Type: "string",
},
},
Required: []string{"a", "c"},
},
expected: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"a": {},
"b": {},
"c": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
},
},
},
Required: []string{"c"},
},
},
},
{
name: "nullable required additionalProperties",
in: &apiextensions.JSONSchemaProps{
Type: "object",
AdditionalProperties: &apiextensions.JSONSchemaPropsOrBool{
Schema: &apiextensions.JSONSchemaProps{
Nullable: true,
Type: "string",
},
},
Required: []string{"a", "c"},
},
expected: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Allows: true,
Schema: &spec.Schema{},
},
},
},
},
{
name: "title",
in: &apiextensions.JSONSchemaProps{
@ -829,6 +886,34 @@ func fuzzFuncs(f *fuzz.Fuzzer, refFunc func(ref *spec.Ref, c fuzz.Continue, visi
)
}
func TestFilterOut(t *testing.T) {
type Test struct {
name string
input []string
x string
expected []string
expectedChanged bool
}
for _, tt := range []Test{
{"nil", nil, "foo", nil, false},
{"empty", []string{}, "foo", []string{}, false},
{"foo", []string{"foo"}, "foo", nil, true},
{"aaa", []string{"a", "a", "a"}, "a", nil, true},
{"abc", []string{"a", "b", "c"}, "c", []string{"a", "b"}, true},
{"abbbcc", []string{"a", "b", "b", "b", "c", "c"}, "b", []string{"a", "c", "c"}, true},
} {
t.Run(tt.name, func(t *testing.T) {
got, gotChanged := filterOut(tt.input, tt.x)
if !reflect.DeepEqual(tt.expected, got) {
t.Errorf("expected slice %v, got %v", tt.expected, got)
}
if tt.expectedChanged != gotChanged {
t.Errorf("expected changed %v, got %v", tt.expected, got)
}
})
}
}
func max(i, j int) int {
if i > j {
return i