@@ -19,18 +19,42 @@ package deviceclass
1919import (
2020 "testing"
2121
22+ "github.com/stretchr/testify/assert"
23+
2224 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2325 genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
26+ utilfeature "k8s.io/apiserver/pkg/util/feature"
27+ featuregatetesting "k8s.io/component-base/featuregate/testing"
28+ "k8s.io/kubernetes/pkg/apis/core"
2429 "k8s.io/kubernetes/pkg/apis/resource"
30+ "k8s.io/kubernetes/pkg/features"
2531)
2632
27- var deviceClass = & resource.DeviceClass {
33+ var obj = & resource.DeviceClass {
34+ ObjectMeta : metav1.ObjectMeta {
35+ Name : "valid-class" ,
36+ Generation : 1 ,
37+ },
38+ }
39+
40+ var objWithGatedFields = & resource.DeviceClass {
2841 ObjectMeta : metav1.ObjectMeta {
29- Name : "valid-class" ,
42+ Name : "valid-class" ,
43+ Generation : 1 ,
44+ },
45+ Spec : resource.DeviceClassSpec {
46+ SuitableNodes : & core.NodeSelector {
47+ NodeSelectorTerms : []core.NodeSelectorTerm {{
48+ MatchExpressions : []core.NodeSelectorRequirement {{
49+ Key : "foo" ,
50+ Operator : core .NodeSelectorOpExists ,
51+ }},
52+ }},
53+ },
3054 },
3155}
3256
33- func TestClassStrategy (t * testing.T ) {
57+ func TestStrategy (t * testing.T ) {
3458 if Strategy .NamespaceScoped () {
3559 t .Errorf ("DeviceClass must not be namespace scoped" )
3660 }
@@ -39,42 +63,135 @@ func TestClassStrategy(t *testing.T) {
3963 }
4064}
4165
42- func TestClassStrategyCreate (t * testing.T ) {
66+ func TestStrategyCreate (t * testing.T ) {
4367 ctx := genericapirequest .NewDefaultContext ()
44- deviceClass := deviceClass .DeepCopy ()
4568
46- Strategy .PrepareForCreate (ctx , deviceClass )
47- errs := Strategy .Validate (ctx , deviceClass )
48- if len (errs ) != 0 {
49- t .Errorf ("unexpected error validating for create %v" , errs )
69+ testcases := map [string ]struct {
70+ obj * resource.DeviceClass
71+ controlPlaneController bool
72+ expectValidationError bool
73+ expectObj * resource.DeviceClass
74+ }{
75+ "simple" : {
76+ obj : obj ,
77+ expectObj : obj ,
78+ },
79+ "validation-error" : {
80+ obj : func () * resource.DeviceClass {
81+ obj := obj .DeepCopy ()
82+ obj .Name = "%#@$%$"
83+ return obj
84+ }(),
85+ expectValidationError : true ,
86+ },
87+ "drop-fields" : {
88+ obj : objWithGatedFields ,
89+ controlPlaneController : false ,
90+ expectObj : obj ,
91+ },
92+ "keep-fields" : {
93+ obj : objWithGatedFields ,
94+ controlPlaneController : true ,
95+ expectObj : objWithGatedFields ,
96+ },
97+ }
98+
99+ for name , tc := range testcases {
100+ t .Run (name , func (t * testing.T ) {
101+ featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .DRAControlPlaneController , tc .controlPlaneController )
102+
103+ obj := tc .obj .DeepCopy ()
104+ Strategy .PrepareForCreate (ctx , obj )
105+ if errs := Strategy .Validate (ctx , obj ); len (errs ) != 0 {
106+ if ! tc .expectValidationError {
107+ t .Fatalf ("unexpected validation errors: %q" , errs )
108+ }
109+ return
110+ } else if tc .expectValidationError {
111+ t .Fatal ("expected validation error(s), got none" )
112+ }
113+ if warnings := Strategy .WarningsOnCreate (ctx , obj ); len (warnings ) != 0 {
114+ t .Fatalf ("unexpected warnings: %q" , warnings )
115+ }
116+ Strategy .Canonicalize (obj )
117+ assert .Equal (t , tc .expectObj , obj )
118+ })
50119 }
51120}
52121
53- func TestClassStrategyUpdate (t * testing.T ) {
54- t .Run ("no-changes-okay" , func (t * testing.T ) {
55- ctx := genericapirequest .NewDefaultContext ()
56- deviceClass := deviceClass .DeepCopy ()
57- newClass := deviceClass .DeepCopy ()
58- newClass .ResourceVersion = "4"
59-
60- Strategy .PrepareForUpdate (ctx , newClass , deviceClass )
61- errs := Strategy .ValidateUpdate (ctx , newClass , deviceClass )
62- if len (errs ) != 0 {
63- t .Errorf ("unexpected validation errors: %v" , errs )
64- }
65- })
66-
67- t .Run ("name-change-not-allowed" , func (t * testing.T ) {
68- ctx := genericapirequest .NewDefaultContext ()
69- deviceClass := deviceClass .DeepCopy ()
70- newClass := deviceClass .DeepCopy ()
71- newClass .Name = "valid-class-2"
72- newClass .ResourceVersion = "4"
73-
74- Strategy .PrepareForUpdate (ctx , newClass , deviceClass )
75- errs := Strategy .ValidateUpdate (ctx , newClass , deviceClass )
76- if len (errs ) == 0 {
77- t .Errorf ("expected a validation error" )
78- }
79- })
122+ func TestStrategyUpdate (t * testing.T ) {
123+ ctx := genericapirequest .NewDefaultContext ()
124+
125+ testcases := map [string ]struct {
126+ oldObj * resource.DeviceClass
127+ newObj * resource.DeviceClass
128+ controlPlaneController bool
129+ expectValidationError bool
130+ expectObj * resource.DeviceClass
131+ }{
132+ "no-changes-okay" : {
133+ oldObj : obj ,
134+ newObj : obj ,
135+ expectObj : obj ,
136+ },
137+ "name-change-not-allowed" : {
138+ oldObj : obj ,
139+ newObj : func () * resource.DeviceClass {
140+ obj := obj .DeepCopy ()
141+ obj .Name += "-2"
142+ return obj
143+ }(),
144+ expectValidationError : true ,
145+ },
146+ "drop-fields" : {
147+ oldObj : obj ,
148+ newObj : objWithGatedFields ,
149+ controlPlaneController : false ,
150+ expectObj : obj ,
151+ },
152+ "keep-fields" : {
153+ oldObj : obj ,
154+ newObj : objWithGatedFields ,
155+ controlPlaneController : true ,
156+ expectObj : func () * resource.DeviceClass {
157+ obj := objWithGatedFields .DeepCopy ()
158+ // Spec changes -> generation gets bumped.
159+ obj .Generation ++
160+ return obj
161+ }(),
162+ },
163+ "keep-existing-fields" : {
164+ oldObj : objWithGatedFields ,
165+ newObj : objWithGatedFields ,
166+ controlPlaneController : false ,
167+ expectObj : objWithGatedFields ,
168+ },
169+ }
170+
171+ for name , tc := range testcases {
172+ t .Run (name , func (t * testing.T ) {
173+ featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .DRAControlPlaneController , tc .controlPlaneController )
174+ oldObj := tc .oldObj .DeepCopy ()
175+ newObj := tc .newObj .DeepCopy ()
176+ newObj .ResourceVersion = "4"
177+
178+ Strategy .PrepareForUpdate (ctx , newObj , oldObj )
179+ if errs := Strategy .ValidateUpdate (ctx , newObj , oldObj ); len (errs ) != 0 {
180+ if ! tc .expectValidationError {
181+ t .Fatalf ("unexpected validation errors: %q" , errs )
182+ }
183+ return
184+ } else if tc .expectValidationError {
185+ t .Fatal ("expected validation error(s), got none" )
186+ }
187+ if warnings := Strategy .WarningsOnUpdate (ctx , newObj , oldObj ); len (warnings ) != 0 {
188+ t .Fatalf ("unexpected warnings: %q" , warnings )
189+ }
190+ Strategy .Canonicalize (newObj )
191+
192+ expectObj := tc .expectObj .DeepCopy ()
193+ expectObj .ResourceVersion = "4"
194+ assert .Equal (t , expectObj , newObj )
195+ })
196+ }
80197}
0 commit comments