k8s.io/kubernetes@v1.29.3/pkg/volume/csi/csi_util_test.go (about) 1 /* 2 Copyright 2019 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 csi 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "flag" 23 "fmt" 24 "os" 25 "path/filepath" 26 "testing" 27 "time" 28 29 api "k8s.io/api/core/v1" 30 storagev1 "k8s.io/api/storage/v1" 31 "k8s.io/apimachinery/pkg/api/resource" 32 meta "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "k8s.io/klog/v2" 34 "k8s.io/kubernetes/pkg/volume" 35 ) 36 37 // TestMain starting point for all tests. 38 // Surfaces klog flags by default to enable 39 // go test -v ./ --args <klog flags> 40 func TestMain(m *testing.M) { 41 klog.InitFlags(flag.CommandLine) 42 os.Exit(m.Run()) 43 } 44 45 func makeTestPVWithMountOptions(name string, sizeGig int, driverName, volID string, mountOptions []string) *api.PersistentVolume { 46 pv := makeTestPV(name, sizeGig, driverName, volID) 47 pv.Spec.MountOptions = mountOptions 48 return pv 49 } 50 51 func makeTestPV(name string, sizeGig int, driverName, volID string) *api.PersistentVolume { 52 return &api.PersistentVolume{ 53 ObjectMeta: meta.ObjectMeta{ 54 Name: name, 55 }, 56 Spec: api.PersistentVolumeSpec{ 57 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce}, 58 Capacity: api.ResourceList{ 59 api.ResourceName(api.ResourceStorage): resource.MustParse( 60 fmt.Sprintf("%dGi", sizeGig), 61 ), 62 }, 63 PersistentVolumeSource: api.PersistentVolumeSource{ 64 CSI: &api.CSIPersistentVolumeSource{ 65 Driver: driverName, 66 VolumeHandle: volID, 67 ReadOnly: false, 68 }, 69 }, 70 }, 71 } 72 } 73 74 func makeTestVol(name string, driverName string) *api.Volume { 75 ro := false 76 return &api.Volume{ 77 Name: name, 78 VolumeSource: api.VolumeSource{ 79 CSI: &api.CSIVolumeSource{ 80 Driver: driverName, 81 ReadOnly: &ro, 82 }, 83 }, 84 } 85 } 86 87 func getTestCSIDriver(name string, podInfoMount *bool, attachable *bool, volumeLifecycleModes []storagev1.VolumeLifecycleMode) *storagev1.CSIDriver { 88 defaultFSGroupPolicy := storagev1.ReadWriteOnceWithFSTypeFSGroupPolicy 89 seLinuxMountSupport := true 90 noSElinuxMountSupport := false 91 driver := &storagev1.CSIDriver{ 92 ObjectMeta: meta.ObjectMeta{ 93 Name: name, 94 }, 95 Spec: storagev1.CSIDriverSpec{ 96 PodInfoOnMount: podInfoMount, 97 AttachRequired: attachable, 98 VolumeLifecycleModes: volumeLifecycleModes, 99 FSGroupPolicy: &defaultFSGroupPolicy, 100 }, 101 } 102 switch driver.Name { 103 case "supports_selinux": 104 driver.Spec.SELinuxMount = &seLinuxMountSupport 105 case "no_selinux": 106 driver.Spec.SELinuxMount = &noSElinuxMountSupport 107 } 108 return driver 109 } 110 111 func TestSaveVolumeData(t *testing.T) { 112 plug, tmpDir := newTestPlugin(t, nil) 113 defer os.RemoveAll(tmpDir) 114 testCases := []struct { 115 name string 116 data map[string]string 117 shouldFail bool 118 }{ 119 {name: "test with data ok", data: map[string]string{"key0": "val0", "_key1": "val1", "key2": "val2"}}, 120 {name: "test with data ok 2 ", data: map[string]string{"_key0_": "val0", "&key1": "val1", "key2": "val2"}}, 121 } 122 123 for i, tc := range testCases { 124 t.Logf("test case: %s", tc.name) 125 specVolID := fmt.Sprintf("spec-volid-%d", i) 126 targetPath := getTargetPath(testPodUID, specVolID, plug.host) 127 mountDir := filepath.Join(targetPath, "mount") 128 if err := os.MkdirAll(mountDir, 0755); err != nil && !os.IsNotExist(err) { 129 t.Errorf("failed to create dir [%s]: %v", mountDir, err) 130 } 131 132 err := saveVolumeData(targetPath, volDataFileName, tc.data) 133 134 if !tc.shouldFail && err != nil { 135 t.Errorf("unexpected failure: %v", err) 136 } 137 // did file get created 138 dataDir := getTargetPath(testPodUID, specVolID, plug.host) 139 file := filepath.Join(dataDir, volDataFileName) 140 if _, err := os.Stat(file); err != nil { 141 t.Errorf("failed to create data dir: %v", err) 142 } 143 144 // validate content 145 data, err := os.ReadFile(file) 146 if !tc.shouldFail && err != nil { 147 t.Errorf("failed to read data file: %v", err) 148 } 149 150 jsonData := new(bytes.Buffer) 151 if err := json.NewEncoder(jsonData).Encode(tc.data); err != nil { 152 t.Errorf("failed to encode json: %v", err) 153 } 154 if string(data) != jsonData.String() { 155 t.Errorf("expecting encoded data %v, got %v", string(data), jsonData) 156 } 157 } 158 } 159 160 func TestCreateCSIOperationContext(t *testing.T) { 161 testCases := []struct { 162 name string 163 spec *volume.Spec 164 migrated string 165 }{ 166 { 167 name: "test volume spec nil", 168 spec: nil, 169 migrated: "false", 170 }, 171 { 172 name: "test volume normal spec with migrated true", 173 spec: &volume.Spec{ 174 Migrated: true, 175 }, 176 migrated: "true", 177 }, 178 { 179 name: "test volume normal spec with migrated false", 180 spec: &volume.Spec{ 181 Migrated: false, 182 }, 183 migrated: "false", 184 }, 185 } 186 for _, tc := range testCases { 187 t.Logf("test case: %s", tc.name) 188 timeout := time.Minute 189 ctx, _ := createCSIOperationContext(tc.spec, timeout) 190 191 additionalInfoVal := ctx.Value(additionalInfoKey) 192 if additionalInfoVal == nil { 193 t.Error("Could not load additional info from context") 194 } 195 additionalInfoV, ok := additionalInfoVal.(additionalInfo) 196 if !ok { 197 t.Errorf("Additional info type assertion fail, additionalInfo object: %v", additionalInfoVal) 198 } 199 migrated := additionalInfoV.Migrated 200 if migrated != tc.migrated { 201 t.Errorf("Expect migrated value: %v, got: %v", tc.migrated, migrated) 202 } 203 } 204 }