...

Source file src/k8s.io/kubernetes/pkg/registry/storage/csistoragecapacity/strategy_test.go

Documentation: k8s.io/kubernetes/pkg/registry/storage/csistoragecapacity

     1  /*
     2  Copyright 2020 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 csistoragecapacity
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/google/go-cmp/cmp"
    23  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    24  	"k8s.io/apimachinery/pkg/api/resource"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
    27  	"k8s.io/kubernetes/pkg/apis/storage"
    28  )
    29  
    30  // getValidCSIStorageCapacity returns a fully-populated CSIStorageCapacity.
    31  func getValidCSIStorageCapacity(name string, capacityStr string) *storage.CSIStorageCapacity {
    32  	mib := resource.MustParse("1Mi")
    33  	c := &storage.CSIStorageCapacity{
    34  		ObjectMeta: metav1.ObjectMeta{
    35  			Name:            name,
    36  			Namespace:       metav1.NamespaceDefault,
    37  			ResourceVersion: "1",
    38  		},
    39  		StorageClassName: "bar",
    40  		NodeTopology: &metav1.LabelSelector{
    41  			MatchExpressions: []metav1.LabelSelectorRequirement{
    42  				{
    43  					Key:      "node",
    44  					Operator: metav1.LabelSelectorOpIn,
    45  					Values: []string{
    46  						"node1",
    47  					},
    48  				},
    49  			},
    50  		},
    51  		Capacity: &mib,
    52  	}
    53  	if capacityStr != "" {
    54  		capacityQuantity := resource.MustParse(capacityStr)
    55  		c.Capacity = &capacityQuantity
    56  	}
    57  	return c
    58  }
    59  
    60  func TestCSIStorageCapacityStrategy(t *testing.T) {
    61  	ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
    62  		APIGroup:   "storage.k8s.io",
    63  		APIVersion: "v1alphav1",
    64  		Resource:   "csistoragecapacities",
    65  	})
    66  	if !Strategy.NamespaceScoped() {
    67  		t.Errorf("CSIStorageCapacity must be namespace scoped")
    68  	}
    69  	if Strategy.AllowCreateOnUpdate() {
    70  		t.Errorf("CSIStorageCapacity should not allow create on update")
    71  	}
    72  
    73  	capacity := getValidCSIStorageCapacity("valid", "")
    74  	original := capacity.DeepCopy()
    75  	Strategy.PrepareForCreate(ctx, capacity)
    76  	errs := Strategy.Validate(ctx, capacity)
    77  	if len(errs) != 0 {
    78  		t.Errorf("unexpected error validating %v", errs)
    79  	}
    80  
    81  	// Create with status should have kept status and all other fields.
    82  	if !apiequality.Semantic.DeepEqual(capacity, original) {
    83  		t.Errorf("unexpected objects difference after creation: %v", cmp.Diff(original, capacity))
    84  	}
    85  
    86  	// Update of immutable fields is disallowed
    87  	fields := []struct {
    88  		name   string
    89  		update func(capacity *storage.CSIStorageCapacity)
    90  	}{
    91  		{
    92  			name: "Topology",
    93  			update: func(capacity *storage.CSIStorageCapacity) {
    94  				capacity.NodeTopology.MatchLabels = map[string]string{"some-label": "some-value"}
    95  			},
    96  		},
    97  		{
    98  			name: "StorageClass",
    99  			update: func(capacity *storage.CSIStorageCapacity) {
   100  				capacity.StorageClassName += "-suffix"
   101  			},
   102  		},
   103  	}
   104  	for _, field := range fields {
   105  		t.Run(field.name, func(t *testing.T) {
   106  			newCapacity := capacity.DeepCopy()
   107  			field.update(newCapacity)
   108  			Strategy.PrepareForUpdate(ctx, newCapacity, capacity)
   109  			errs = Strategy.ValidateUpdate(ctx, newCapacity, capacity)
   110  			if len(errs) == 0 {
   111  				t.Errorf("Expected a validation error")
   112  			}
   113  		})
   114  	}
   115  }
   116  
   117  func TestCSIStorageCapacityValidation(t *testing.T) {
   118  	ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
   119  		APIGroup:   "storage.k8s.io",
   120  		APIVersion: "v1alphav1",
   121  		Resource:   "csistoragecapacities",
   122  	})
   123  
   124  	tests := []struct {
   125  		name        string
   126  		expectError bool
   127  		old, update *storage.CSIStorageCapacity
   128  	}{
   129  		{
   130  			name:   "before: no capacity, update: 1Gi capacity",
   131  			old:    getValidCSIStorageCapacity("test", ""),
   132  			update: getValidCSIStorageCapacity("test", "1Gi"),
   133  		},
   134  		{
   135  			name:   "before: 1Gi capacity, update: no capacity",
   136  			old:    getValidCSIStorageCapacity("test", "1Gi"),
   137  			update: getValidCSIStorageCapacity("test", ""),
   138  		},
   139  		{
   140  			name:        "name change",
   141  			expectError: true,
   142  			old:         getValidCSIStorageCapacity("a", ""),
   143  			update:      getValidCSIStorageCapacity("b", ""),
   144  		},
   145  		{
   146  			name:        "storage class name change",
   147  			expectError: true,
   148  			old:         getValidCSIStorageCapacity("test", ""),
   149  			update: func() *storage.CSIStorageCapacity {
   150  				capacity := getValidCSIStorageCapacity("test", "")
   151  				capacity.StorageClassName += "-update"
   152  				return capacity
   153  			}(),
   154  		},
   155  	}
   156  
   157  	for _, test := range tests {
   158  		t.Run(test.name, func(t *testing.T) {
   159  			oldCapacity := test.old.DeepCopy()
   160  			Strategy.PrepareForCreate(ctx, oldCapacity)
   161  			errs := Strategy.Validate(ctx, oldCapacity)
   162  			if len(errs) != 0 {
   163  				t.Errorf("unexpected validating errors for create: %v", errs)
   164  			}
   165  
   166  			newCapacity := test.update.DeepCopy()
   167  			Strategy.PrepareForUpdate(ctx, newCapacity, test.old)
   168  			errs = Strategy.ValidateUpdate(ctx, newCapacity, oldCapacity)
   169  			if len(errs) > 0 && !test.expectError {
   170  				t.Errorf("unexpected validation failure: %+v", errs)
   171  			}
   172  			if len(errs) == 0 && test.expectError {
   173  				t.Errorf("validation unexpectedly succeeded")
   174  			}
   175  		})
   176  	}
   177  }
   178  

View as plain text