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  }