1
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
38
39
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
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
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 }
205
View as plain text