k8s.io/kubernetes@v1.29.3/pkg/registry/core/persistentvolumeclaim/storage/storage_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 storage 18 19 import ( 20 "reflect" 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 apiequality "k8s.io/apimachinery/pkg/api/equality" 25 "k8s.io/apimachinery/pkg/api/resource" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/fields" 28 "k8s.io/apimachinery/pkg/labels" 29 "k8s.io/apimachinery/pkg/runtime" 30 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 31 "k8s.io/apiserver/pkg/registry/generic" 32 genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" 33 "k8s.io/apiserver/pkg/registry/rest" 34 etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" 35 utilfeature "k8s.io/apiserver/pkg/util/feature" 36 featuregatetesting "k8s.io/component-base/featuregate/testing" 37 api "k8s.io/kubernetes/pkg/apis/core" 38 "k8s.io/kubernetes/pkg/features" 39 "k8s.io/kubernetes/pkg/registry/registrytest" 40 ) 41 42 func newStorage(t *testing.T) (*REST, *StatusREST, *etcd3testing.EtcdTestServer) { 43 etcdStorage, server := registrytest.NewEtcdStorage(t, "") 44 restOptions := generic.RESTOptions{ 45 StorageConfig: etcdStorage, 46 Decorator: generic.UndecoratedStorage, 47 DeleteCollectionWorkers: 1, 48 ResourcePrefix: "persistentvolumeclaims", 49 } 50 persistentVolumeClaimStorage, statusStorage, err := NewREST(restOptions) 51 if err != nil { 52 t.Fatalf("unexpected error from REST storage: %v", err) 53 } 54 return persistentVolumeClaimStorage, statusStorage, server 55 } 56 57 func validNewPersistentVolumeClaim(name, ns string) *api.PersistentVolumeClaim { 58 pv := &api.PersistentVolumeClaim{ 59 ObjectMeta: metav1.ObjectMeta{ 60 Name: name, 61 Namespace: ns, 62 }, 63 Spec: api.PersistentVolumeClaimSpec{ 64 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, 65 Resources: api.VolumeResourceRequirements{ 66 Requests: api.ResourceList{ 67 api.ResourceName(api.ResourceStorage): resource.MustParse("10G"), 68 }, 69 }, 70 }, 71 Status: api.PersistentVolumeClaimStatus{ 72 Phase: api.ClaimPending, 73 }, 74 } 75 return pv 76 } 77 78 func TestCreate(t *testing.T) { 79 storage, _, server := newStorage(t) 80 defer server.Terminate(t) 81 defer storage.Store.DestroyFunc() 82 test := genericregistrytest.New(t, storage.Store) 83 pv := validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault) 84 pv.ObjectMeta = metav1.ObjectMeta{} 85 test.TestCreate( 86 // valid 87 pv, 88 // invalid 89 &api.PersistentVolumeClaim{ 90 ObjectMeta: metav1.ObjectMeta{Name: "*BadName!"}, 91 }, 92 ) 93 } 94 95 func TestUpdate(t *testing.T) { 96 storage, _, server := newStorage(t) 97 defer server.Terminate(t) 98 defer storage.Store.DestroyFunc() 99 test := genericregistrytest.New(t, storage.Store) 100 test.TestUpdate( 101 // valid 102 validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault), 103 // updateFunc 104 func(obj runtime.Object) runtime.Object { 105 object := obj.(*api.PersistentVolumeClaim) 106 object.Spec.VolumeName = "onlyVolumeNameUpdateAllowed" 107 return object 108 }, 109 ) 110 } 111 112 func TestDelete(t *testing.T) { 113 storage, _, server := newStorage(t) 114 defer server.Terminate(t) 115 defer storage.Store.DestroyFunc() 116 test := genericregistrytest.New(t, storage.Store).ReturnDeletedObject() 117 test.TestDelete(validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault)) 118 } 119 120 func TestGet(t *testing.T) { 121 storage, _, server := newStorage(t) 122 defer server.Terminate(t) 123 defer storage.Store.DestroyFunc() 124 test := genericregistrytest.New(t, storage.Store) 125 test.TestGet(validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault)) 126 } 127 128 func TestList(t *testing.T) { 129 storage, _, server := newStorage(t) 130 defer server.Terminate(t) 131 defer storage.Store.DestroyFunc() 132 test := genericregistrytest.New(t, storage.Store) 133 test.TestList(validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault)) 134 } 135 136 func TestWatch(t *testing.T) { 137 storage, _, server := newStorage(t) 138 defer server.Terminate(t) 139 defer storage.Store.DestroyFunc() 140 test := genericregistrytest.New(t, storage.Store) 141 test.TestWatch( 142 validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault), 143 // matching labels 144 []labels.Set{}, 145 // not matching labels 146 []labels.Set{ 147 {"foo": "bar"}, 148 }, 149 // matching fields 150 []fields.Set{ 151 {"metadata.name": "foo"}, 152 {"name": "foo"}, 153 }, 154 // not matching fields 155 []fields.Set{ 156 {"metadata.name": "bar"}, 157 }, 158 ) 159 } 160 161 func TestUpdateStatus(t *testing.T) { 162 storage, statusStorage, server := newStorage(t) 163 defer server.Terminate(t) 164 defer storage.Store.DestroyFunc() 165 ctx := genericapirequest.NewDefaultContext() 166 167 key, _ := storage.KeyFunc(ctx, "foo") 168 pvcStart := validNewPersistentVolumeClaim("foo", metav1.NamespaceDefault) 169 err := storage.Storage.Create(ctx, key, pvcStart, nil, 0, false) 170 if err != nil { 171 t.Fatalf("Unexpected error: %v", err) 172 } 173 174 pvc := &api.PersistentVolumeClaim{ 175 ObjectMeta: metav1.ObjectMeta{ 176 Name: "foo", 177 Namespace: metav1.NamespaceDefault, 178 }, 179 Spec: api.PersistentVolumeClaimSpec{ 180 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, 181 Resources: api.VolumeResourceRequirements{ 182 Requests: api.ResourceList{ 183 api.ResourceName(api.ResourceStorage): resource.MustParse("3Gi"), 184 }, 185 }, 186 }, 187 Status: api.PersistentVolumeClaimStatus{ 188 Phase: api.ClaimBound, 189 }, 190 } 191 192 _, _, err = statusStorage.Update(ctx, pvc.Name, rest.DefaultUpdatedObjectInfo(pvc), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) 193 if err != nil { 194 t.Fatalf("Unexpected error: %v", err) 195 } 196 obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) 197 if err != nil { 198 t.Errorf("unexpected error: %v", err) 199 } 200 pvcOut := obj.(*api.PersistentVolumeClaim) 201 // only compare relevant changes b/c of difference in metadata 202 if !apiequality.Semantic.DeepEqual(pvc.Status, pvcOut.Status) { 203 t.Errorf("unexpected object: %s", cmp.Diff(pvc.Status, pvcOut.Status)) 204 } 205 } 206 207 func TestShortNames(t *testing.T) { 208 storage, _, server := newStorage(t) 209 defer server.Terminate(t) 210 defer storage.Store.DestroyFunc() 211 expected := []string{"pvc"} 212 registrytest.AssertShortNames(t, storage, expected) 213 } 214 215 func TestDefaultOnReadPvc(t *testing.T) { 216 storage, _, server := newStorage(t) 217 defer server.Terminate(t) 218 defer storage.Store.DestroyFunc() 219 dataSource := api.TypedLocalObjectReference{ 220 Kind: "PersistentVolumeClaim", 221 Name: "my-pvc", 222 } 223 dataSourceRef := api.TypedObjectReference{ 224 Kind: "PersistentVolumeClaim", 225 Name: "my-pvc", 226 } 227 228 var tests = map[string]struct { 229 anyEnabled bool 230 dataSource bool 231 dataSourceRef bool 232 want bool 233 wantRef bool 234 }{ 235 "any disabled with empty ds": { 236 anyEnabled: false, 237 }, 238 "any disabled with volume ds": { 239 dataSource: true, 240 want: true, 241 }, 242 "any disabled with volume ds ref": { 243 dataSourceRef: true, 244 wantRef: true, 245 }, 246 "any disabled with both data sources": { 247 dataSource: true, 248 dataSourceRef: true, 249 want: true, 250 wantRef: true, 251 }, 252 "any enabled with empty ds": { 253 anyEnabled: true, 254 }, 255 "any enabled with volume ds": { 256 anyEnabled: true, 257 dataSource: true, 258 want: true, 259 wantRef: true, 260 }, 261 "any enabled with volume ds ref": { 262 anyEnabled: true, 263 dataSourceRef: true, 264 want: true, 265 wantRef: true, 266 }, 267 "any enabled with both data sources": { 268 anyEnabled: true, 269 dataSource: true, 270 dataSourceRef: true, 271 want: true, 272 wantRef: true, 273 }, 274 } 275 276 for testName, test := range tests { 277 t.Run(testName, func(t *testing.T) { 278 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnyVolumeDataSource, test.anyEnabled)() 279 pvc := new(api.PersistentVolumeClaim) 280 if test.dataSource { 281 pvc.Spec.DataSource = dataSource.DeepCopy() 282 } 283 if test.dataSourceRef { 284 pvc.Spec.DataSourceRef = dataSourceRef.DeepCopy() 285 } 286 var expectDataSource *api.TypedLocalObjectReference 287 if test.want { 288 expectDataSource = &dataSource 289 } 290 var expectDataSourceRef *api.TypedObjectReference 291 if test.wantRef { 292 expectDataSourceRef = &dataSourceRef 293 } 294 295 // Method under test 296 storage.defaultOnReadPvc(pvc) 297 298 if !reflect.DeepEqual(pvc.Spec.DataSource, expectDataSource) { 299 t.Errorf("data source does not match, test: %s, anyEnabled: %v, dataSource: %v, expected: %v", 300 testName, test.anyEnabled, test.dataSource, test.want) 301 } 302 if !reflect.DeepEqual(pvc.Spec.DataSourceRef, expectDataSourceRef) { 303 t.Errorf("data source ref does not match, test: %s, anyEnabled: %v, dataSourceRef: %v, expected: %v", 304 testName, test.anyEnabled, test.dataSourceRef, test.wantRef) 305 } 306 }) 307 } 308 }