...

Source file src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/validation_test.go

Documentation: k8s.io/apiextensions-apiserver/pkg/apiserver/schema

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package schema
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  
    25  	fuzz "github.com/google/gofuzz"
    26  )
    27  
    28  func TestValidateStructuralMetadataInvariants(t *testing.T) {
    29  	fuzzer := fuzz.New()
    30  	fuzzer.Funcs(
    31  		func(s *JSON, c fuzz.Continue) {
    32  			if c.RandBool() {
    33  				s.Object = float64(42.0)
    34  			}
    35  		},
    36  		func(s **StructuralOrBool, c fuzz.Continue) {
    37  			if c.RandBool() {
    38  				*s = &StructuralOrBool{}
    39  			}
    40  		},
    41  		func(s **Structural, c fuzz.Continue) {
    42  			if c.RandBool() {
    43  				*s = &Structural{}
    44  			}
    45  		},
    46  		func(s *Structural, c fuzz.Continue) {
    47  			if c.RandBool() {
    48  				*s = Structural{}
    49  			}
    50  		},
    51  		func(vv **NestedValueValidation, c fuzz.Continue) {
    52  			if c.RandBool() {
    53  				*vv = &NestedValueValidation{}
    54  			}
    55  		},
    56  		func(vv *NestedValueValidation, c fuzz.Continue) {
    57  			if c.RandBool() {
    58  				*vv = NestedValueValidation{}
    59  			}
    60  		},
    61  	)
    62  	fuzzer.NilChance(0)
    63  
    64  	// check that type must be object
    65  	typeNames := []string{"object", "array", "number", "integer", "boolean", "string"}
    66  	for _, typeName := range typeNames {
    67  		s := Structural{
    68  			Generic: Generic{
    69  				Type: typeName,
    70  			},
    71  		}
    72  
    73  		errs := validateStructuralMetadataInvariants(&s, true, rootLevel, nil)
    74  		if len(errs) != 0 {
    75  			t.Logf("errors returned: %v", errs)
    76  		}
    77  		if len(errs) != 0 && typeName == "object" {
    78  			t.Errorf("unexpected forbidden field validation errors for: %#v", s)
    79  		}
    80  		if len(errs) == 0 && typeName != "object" {
    81  			t.Errorf("expected forbidden field validation errors for: %#v", s)
    82  		}
    83  	}
    84  
    85  	// check that anything other than name and generateName of ObjectMeta in metadata properties is forbidden
    86  	tt := reflect.TypeOf(metav1.ObjectMeta{})
    87  	for i := 0; i < tt.NumField(); i++ {
    88  		property := tt.Field(i).Name
    89  		s := &Structural{
    90  			Generic: Generic{
    91  				Type: "object",
    92  			},
    93  			Properties: map[string]Structural{
    94  				property: {},
    95  			},
    96  		}
    97  
    98  		errs := validateStructuralMetadataInvariants(s, true, rootLevel, nil)
    99  		if len(errs) != 0 {
   100  			t.Logf("errors returned: %v", errs)
   101  		}
   102  		if len(errs) != 0 && (property == "name" || property == "generateName") {
   103  			t.Errorf("unexpected forbidden field validation errors for: %#v", s)
   104  		}
   105  		if len(errs) == 0 && property != "name" && property != "generateName" {
   106  			t.Errorf("expected forbidden field validation errors for: %#v", s)
   107  		}
   108  	}
   109  
   110  	// check that anything other than type and properties in metadata is forbidden
   111  	tt = reflect.TypeOf(Structural{})
   112  	for i := 0; i < tt.NumField(); i++ {
   113  		s := Structural{}
   114  		x := reflect.ValueOf(&s).Elem()
   115  		fuzzer.Fuzz(x.Field(i).Addr().Interface())
   116  		s.Type = "object"
   117  		s.Properties = map[string]Structural{
   118  			"name":         {},
   119  			"generateName": {},
   120  		}
   121  		s.Default.Object = nil // this is checked in API validation, we don't need to test it here
   122  
   123  		valid := reflect.DeepEqual(s, Structural{
   124  			Generic: Generic{
   125  				Type: "object",
   126  				Default: JSON{
   127  					Object: nil,
   128  				},
   129  			},
   130  			Properties: map[string]Structural{
   131  				"name":         {},
   132  				"generateName": {},
   133  			},
   134  		})
   135  
   136  		errs := validateStructuralMetadataInvariants(s.DeepCopy(), true, rootLevel, nil)
   137  		if len(errs) != 0 {
   138  			t.Logf("errors returned: %v", errs)
   139  		}
   140  		if len(errs) != 0 && valid {
   141  			t.Errorf("unexpected forbidden field validation errors for: %#v", s)
   142  		}
   143  		if len(errs) == 0 && !valid {
   144  			t.Errorf("expected forbidden field validation errors for: %#v", s)
   145  		}
   146  	}
   147  }
   148  
   149  func TestValidateNestedValueValidationComplete(t *testing.T) {
   150  	fuzzer := fuzz.New()
   151  	fuzzer.Funcs(
   152  		func(s *JSON, c fuzz.Continue) {
   153  			if c.RandBool() {
   154  				s.Object = float64(42.0)
   155  			}
   156  		},
   157  		func(s **StructuralOrBool, c fuzz.Continue) {
   158  			if c.RandBool() {
   159  				*s = &StructuralOrBool{}
   160  			}
   161  		},
   162  	)
   163  	fuzzer.NilChance(0)
   164  
   165  	// check that we didn't forget to check any forbidden generic field
   166  	tt := reflect.TypeOf(Generic{})
   167  	for i := 0; i < tt.NumField(); i++ {
   168  		vv := &NestedValueValidation{}
   169  		x := reflect.ValueOf(&vv.ForbiddenGenerics).Elem()
   170  		fuzzer.Fuzz(x.Field(i).Addr().Interface())
   171  
   172  		errs := validateNestedValueValidation(vv, false, false, fieldLevel, nil)
   173  		if len(errs) == 0 && !reflect.DeepEqual(vv.ForbiddenGenerics, Generic{}) {
   174  			t.Errorf("expected ForbiddenGenerics validation errors for: %#v", vv)
   175  		}
   176  	}
   177  
   178  	// check that we didn't forget to check any forbidden extension field
   179  	tt = reflect.TypeOf(Extensions{})
   180  	for i := 0; i < tt.NumField(); i++ {
   181  		vv := &NestedValueValidation{}
   182  		x := reflect.ValueOf(&vv.ForbiddenExtensions).Elem()
   183  		fuzzer.Fuzz(x.Field(i).Addr().Interface())
   184  
   185  		errs := validateNestedValueValidation(vv, false, false, fieldLevel, nil)
   186  		if len(errs) == 0 && !reflect.DeepEqual(vv.ForbiddenExtensions, Extensions{}) {
   187  			t.Errorf("expected ForbiddenExtensions validation errors for: %#v", vv)
   188  		}
   189  	}
   190  }
   191  

View as plain text