k8s.io/kubernetes@v1.29.3/pkg/registry/core/persistentvolumeclaim/strategy_test.go (about) 1 /* 2 Copyright 2015 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 persistentvolumeclaim 18 19 import ( 20 "fmt" 21 "reflect" 22 "testing" 23 24 "github.com/google/go-cmp/cmp" 25 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 26 utilfeature "k8s.io/apiserver/pkg/util/feature" 27 featuregatetesting "k8s.io/component-base/featuregate/testing" 28 apitesting "k8s.io/kubernetes/pkg/api/testing" 29 api "k8s.io/kubernetes/pkg/apis/core" 30 "k8s.io/kubernetes/pkg/features" 31 32 // ensure types are installed 33 _ "k8s.io/kubernetes/pkg/apis/core/install" 34 ) 35 36 func TestSelectableFieldLabelConversions(t *testing.T) { 37 apitesting.TestSelectableFieldLabelConversionsOfKind(t, 38 "v1", 39 "PersistentVolumeClaim", 40 PersistentVolumeClaimToSelectableFields(&api.PersistentVolumeClaim{}), 41 map[string]string{"name": "metadata.name"}, 42 ) 43 } 44 45 func TestDropConditions(t *testing.T) { 46 ctx := genericapirequest.NewDefaultContext() 47 pvcWithConditions := func() *api.PersistentVolumeClaim { 48 return &api.PersistentVolumeClaim{ 49 Status: api.PersistentVolumeClaimStatus{ 50 Conditions: []api.PersistentVolumeClaimCondition{ 51 {Type: api.PersistentVolumeClaimResizing, Status: api.ConditionTrue}, 52 }, 53 }, 54 } 55 } 56 pvcWithoutConditions := func() *api.PersistentVolumeClaim { 57 return &api.PersistentVolumeClaim{ 58 Status: api.PersistentVolumeClaimStatus{}, 59 } 60 } 61 62 pvcInfo := []struct { 63 description string 64 hasConditions bool 65 pvc func() *api.PersistentVolumeClaim 66 }{ 67 { 68 description: "has Conditions", 69 hasConditions: true, 70 pvc: pvcWithConditions, 71 }, 72 { 73 description: "does not have Conditions", 74 hasConditions: false, 75 pvc: pvcWithoutConditions, 76 }, 77 } 78 79 for _, oldPvcInfo := range pvcInfo { 80 for _, newPvcInfo := range pvcInfo { 81 oldPvcHasConditins, oldPvc := oldPvcInfo.hasConditions, oldPvcInfo.pvc() 82 newPvcHasConditions, newPvc := newPvcInfo.hasConditions, newPvcInfo.pvc() 83 84 t.Run(fmt.Sprintf("old pvc %s, new pvc %s", oldPvcInfo.description, newPvcInfo.description), func(t *testing.T) { 85 StatusStrategy.PrepareForUpdate(ctx, newPvc, oldPvc) 86 87 // old pvc should never be changed 88 if !reflect.DeepEqual(oldPvc, oldPvcInfo.pvc()) { 89 t.Errorf("old pvc changed: %v", cmp.Diff(oldPvc, oldPvcInfo.pvc())) 90 } 91 92 switch { 93 case oldPvcHasConditins || newPvcHasConditions: 94 // new pvc should not be changed if the feature is enabled, or if the old pvc had Conditions 95 if !reflect.DeepEqual(newPvc, newPvcInfo.pvc()) { 96 t.Errorf("new pvc changed: %v", cmp.Diff(newPvc, newPvcInfo.pvc())) 97 } 98 default: 99 // new pvc should not need to be changed 100 if !reflect.DeepEqual(newPvc, newPvcInfo.pvc()) { 101 t.Errorf("new pvc changed: %v", cmp.Diff(newPvc, newPvcInfo.pvc())) 102 } 103 } 104 }) 105 } 106 } 107 108 } 109 110 var ( 111 coreGroup = "" 112 snapGroup = "snapshot.storage.k8s.io" 113 genericGroup = "generic.storage.k8s.io" 114 pvcKind = "PersistentVolumeClaim" 115 snapKind = "VolumeSnapshot" 116 genericKind = "Generic" 117 podKind = "Pod" 118 ) 119 120 func makeDataSource(apiGroup, kind, name string) *api.TypedLocalObjectReference { 121 return &api.TypedLocalObjectReference{ 122 APIGroup: &apiGroup, 123 Kind: kind, 124 Name: name, 125 } 126 127 } 128 129 func makeDataSourceRef(apiGroup, kind, name string, namespace *string) *api.TypedObjectReference { 130 return &api.TypedObjectReference{ 131 APIGroup: &apiGroup, 132 Kind: kind, 133 Name: name, 134 Namespace: namespace, 135 } 136 } 137 138 func TestPrepareForCreate(t *testing.T) { 139 ctx := genericapirequest.NewDefaultContext() 140 141 ns := "ns1" 142 volumeDataSource := makeDataSource(coreGroup, pvcKind, "my-vol") 143 volumeDataSourceRef := makeDataSourceRef(coreGroup, pvcKind, "my-vol", nil) 144 xnsVolumeDataSourceRef := makeDataSourceRef(coreGroup, pvcKind, "my-vol", &ns) 145 snapshotDataSource := makeDataSource(snapGroup, snapKind, "my-snap") 146 snapshotDataSourceRef := makeDataSourceRef(snapGroup, snapKind, "my-snap", nil) 147 xnsSnapshotDataSourceRef := makeDataSourceRef(snapGroup, snapKind, "my-snap", &ns) 148 genericDataSource := makeDataSource(genericGroup, genericKind, "my-foo") 149 genericDataSourceRef := makeDataSourceRef(genericGroup, genericKind, "my-foo", nil) 150 xnsGenericDataSourceRef := makeDataSourceRef(genericGroup, genericKind, "my-foo", &ns) 151 coreDataSource := makeDataSource(coreGroup, podKind, "my-pod") 152 coreDataSourceRef := makeDataSourceRef(coreGroup, podKind, "my-pod", nil) 153 xnsCoreDataSourceRef := makeDataSourceRef(coreGroup, podKind, "my-pod", &ns) 154 155 var tests = map[string]struct { 156 anyEnabled bool 157 xnsEnabled bool 158 dataSource *api.TypedLocalObjectReference 159 dataSourceRef *api.TypedObjectReference 160 want *api.TypedLocalObjectReference 161 wantRef *api.TypedObjectReference 162 }{ 163 "any disabled with empty ds": { 164 want: nil, 165 }, 166 "any disabled with volume ds": { 167 dataSource: volumeDataSource, 168 want: volumeDataSource, 169 }, 170 "any disabled with snapshot ds": { 171 dataSource: snapshotDataSource, 172 want: snapshotDataSource, 173 }, 174 "any disabled with generic ds": { 175 dataSource: genericDataSource, 176 want: nil, 177 }, 178 "any disabled with invalid ds": { 179 dataSource: coreDataSource, 180 want: nil, 181 }, 182 "any disabled with volume ds ref": { 183 dataSourceRef: volumeDataSourceRef, 184 }, 185 "any disabled with snapshot ds ref": { 186 dataSourceRef: snapshotDataSourceRef, 187 }, 188 "any disabled with generic ds ref": { 189 dataSourceRef: genericDataSourceRef, 190 }, 191 "any disabled with invalid ds ref": { 192 dataSourceRef: coreDataSourceRef, 193 }, 194 "any enabled with empty ds": { 195 anyEnabled: true, 196 want: nil, 197 }, 198 "any enabled with volume ds": { 199 dataSource: volumeDataSource, 200 anyEnabled: true, 201 want: volumeDataSource, 202 wantRef: volumeDataSourceRef, 203 }, 204 "any enabled with snapshot ds": { 205 dataSource: snapshotDataSource, 206 anyEnabled: true, 207 want: snapshotDataSource, 208 wantRef: snapshotDataSourceRef, 209 }, 210 "any enabled with generic ds": { 211 dataSource: genericDataSource, 212 anyEnabled: true, 213 }, 214 "any enabled with invalid ds": { 215 dataSource: coreDataSource, 216 anyEnabled: true, 217 }, 218 "any enabled with volume ds ref": { 219 dataSourceRef: volumeDataSourceRef, 220 anyEnabled: true, 221 want: volumeDataSource, 222 wantRef: volumeDataSourceRef, 223 }, 224 "any enabled with snapshot ds ref": { 225 dataSourceRef: snapshotDataSourceRef, 226 anyEnabled: true, 227 want: snapshotDataSource, 228 wantRef: snapshotDataSourceRef, 229 }, 230 "any enabled with generic ds ref": { 231 dataSourceRef: genericDataSourceRef, 232 anyEnabled: true, 233 want: genericDataSource, 234 wantRef: genericDataSourceRef, 235 }, 236 "any enabled with invalid ds ref": { 237 dataSourceRef: coreDataSourceRef, 238 anyEnabled: true, 239 want: coreDataSource, 240 wantRef: coreDataSourceRef, 241 }, 242 "any enabled with mismatched data sources": { 243 dataSource: volumeDataSource, 244 dataSourceRef: snapshotDataSourceRef, 245 anyEnabled: true, 246 want: volumeDataSource, 247 wantRef: snapshotDataSourceRef, 248 }, 249 "both any and xns enabled with empty ds": { 250 anyEnabled: true, 251 xnsEnabled: true, 252 want: nil, 253 }, 254 "both any and xns enabled with volume ds": { 255 dataSource: volumeDataSource, 256 anyEnabled: true, 257 xnsEnabled: true, 258 want: volumeDataSource, 259 wantRef: volumeDataSourceRef, 260 }, 261 "both any and xns enabled with snapshot ds": { 262 dataSource: snapshotDataSource, 263 anyEnabled: true, 264 xnsEnabled: true, 265 want: snapshotDataSource, 266 wantRef: snapshotDataSourceRef, 267 }, 268 "both any and xns enabled with generic ds": { 269 dataSource: genericDataSource, 270 anyEnabled: true, 271 xnsEnabled: true, 272 }, 273 "both any and xns enabled with invalid ds": { 274 dataSource: coreDataSource, 275 anyEnabled: true, 276 xnsEnabled: true, 277 }, 278 "both any and xns enabled with volume ds ref": { 279 dataSourceRef: volumeDataSourceRef, 280 anyEnabled: true, 281 xnsEnabled: true, 282 want: volumeDataSource, 283 wantRef: volumeDataSourceRef, 284 }, 285 "both any and xns enabled with snapshot ds ref": { 286 dataSourceRef: snapshotDataSourceRef, 287 anyEnabled: true, 288 xnsEnabled: true, 289 want: snapshotDataSource, 290 wantRef: snapshotDataSourceRef, 291 }, 292 "both any and xns enabled with generic ds ref": { 293 dataSourceRef: genericDataSourceRef, 294 anyEnabled: true, 295 xnsEnabled: true, 296 want: genericDataSource, 297 wantRef: genericDataSourceRef, 298 }, 299 "both any and xns enabled with invalid ds ref": { 300 dataSourceRef: coreDataSourceRef, 301 anyEnabled: true, 302 xnsEnabled: true, 303 want: coreDataSource, 304 wantRef: coreDataSourceRef, 305 }, 306 "both any and xns enabled with mismatched data sources": { 307 dataSource: volumeDataSource, 308 dataSourceRef: snapshotDataSourceRef, 309 anyEnabled: true, 310 xnsEnabled: true, 311 want: volumeDataSource, 312 wantRef: snapshotDataSourceRef, 313 }, 314 "both any and xns enabled with volume xns ds ref": { 315 dataSourceRef: xnsVolumeDataSourceRef, 316 anyEnabled: true, 317 xnsEnabled: true, 318 wantRef: xnsVolumeDataSourceRef, 319 }, 320 "both any and xns enabled with snapshot xns ds ref": { 321 dataSourceRef: xnsSnapshotDataSourceRef, 322 anyEnabled: true, 323 xnsEnabled: true, 324 wantRef: xnsSnapshotDataSourceRef, 325 }, 326 "both any and xns enabled with generic xns ds ref": { 327 dataSourceRef: xnsGenericDataSourceRef, 328 anyEnabled: true, 329 xnsEnabled: true, 330 wantRef: xnsGenericDataSourceRef, 331 }, 332 "both any and xns enabled with invalid xns ds ref": { 333 dataSourceRef: xnsCoreDataSourceRef, 334 anyEnabled: true, 335 xnsEnabled: true, 336 wantRef: xnsCoreDataSourceRef, 337 }, 338 "only xns enabled with snapshot xns ds ref": { 339 dataSourceRef: xnsSnapshotDataSourceRef, 340 xnsEnabled: true, 341 }, 342 } 343 344 for testName, test := range tests { 345 t.Run(testName, func(t *testing.T) { 346 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnyVolumeDataSource, test.anyEnabled)() 347 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CrossNamespaceVolumeDataSource, test.xnsEnabled)() 348 pvc := api.PersistentVolumeClaim{ 349 Spec: api.PersistentVolumeClaimSpec{ 350 DataSource: test.dataSource, 351 DataSourceRef: test.dataSourceRef, 352 }, 353 } 354 355 // Method under test 356 Strategy.PrepareForCreate(ctx, &pvc) 357 358 if !reflect.DeepEqual(pvc.Spec.DataSource, test.want) { 359 t.Errorf("data source does not match, test: %s, anyEnabled: %v, dataSource: %v, expected: %v", 360 testName, test.anyEnabled, test.dataSource, test.want) 361 } 362 if !reflect.DeepEqual(pvc.Spec.DataSourceRef, test.wantRef) { 363 t.Errorf("data source ref does not match, test: %s, anyEnabled: %v, dataSourceRef: %v, expected: %v", 364 testName, test.anyEnabled, test.dataSourceRef, test.wantRef) 365 } 366 }) 367 } 368 }