1
16
17 package volumeattachment
18
19 import (
20 "context"
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 genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
28 api "k8s.io/kubernetes/pkg/apis/core"
29 "k8s.io/kubernetes/pkg/apis/storage"
30 )
31
32 func getValidVolumeAttachment(name string) *storage.VolumeAttachment {
33 return &storage.VolumeAttachment{
34 ObjectMeta: metav1.ObjectMeta{
35 Name: name,
36 },
37 Spec: storage.VolumeAttachmentSpec{
38 Attacher: "valid-attacher",
39 Source: storage.VolumeAttachmentSource{
40 PersistentVolumeName: &name,
41 },
42 NodeName: "valid-node",
43 },
44 }
45 }
46
47 func getValidVolumeAttachmentWithInlineSpec(name string) *storage.VolumeAttachment {
48 volumeAttachment := getValidVolumeAttachment(name)
49 volumeAttachment.Spec.Source.PersistentVolumeName = nil
50 volumeAttachment.Spec.Source.InlineVolumeSpec = &api.PersistentVolumeSpec{
51 Capacity: api.ResourceList{
52 api.ResourceName(api.ResourceStorage): resource.MustParse("10"),
53 },
54 AccessModes: []api.PersistentVolumeAccessMode{api.ReadWriteOnce},
55 PersistentVolumeSource: api.PersistentVolumeSource{
56 CSI: &api.CSIPersistentVolumeSource{
57 Driver: "com.test.foo",
58 VolumeHandle: name,
59 },
60 },
61 MountOptions: []string{"soft"},
62 }
63 return volumeAttachment
64 }
65
66 func TestVolumeAttachmentStrategy(t *testing.T) {
67 ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
68 APIGroup: "storage.k8s.io",
69 APIVersion: "v1",
70 Resource: "volumeattachments",
71 })
72 if Strategy.NamespaceScoped() {
73 t.Errorf("VolumeAttachment must not be namespace scoped")
74 }
75 if Strategy.AllowCreateOnUpdate() {
76 t.Errorf("VolumeAttachment should not allow create on update")
77 }
78
79 volumeAttachment := getValidVolumeAttachment("valid-attachment")
80
81 Strategy.PrepareForCreate(ctx, volumeAttachment)
82
83 errs := Strategy.Validate(ctx, volumeAttachment)
84 if len(errs) != 0 {
85 t.Errorf("unexpected error validating %v", errs)
86 }
87
88
89 statusVolumeAttachment := volumeAttachment.DeepCopy()
90 statusVolumeAttachment.Status = storage.VolumeAttachmentStatus{Attached: true}
91 Strategy.PrepareForCreate(ctx, statusVolumeAttachment)
92 if !apiequality.Semantic.DeepEqual(statusVolumeAttachment, volumeAttachment) {
93 t.Errorf("unexpected objects difference after creating with status: %v", cmp.Diff(statusVolumeAttachment, volumeAttachment))
94 }
95
96
97 newVolumeAttachment := volumeAttachment.DeepCopy()
98 newVolumeAttachment.Spec.NodeName = "valid-node-2"
99
100 Strategy.PrepareForUpdate(ctx, newVolumeAttachment, volumeAttachment)
101
102 errs = Strategy.ValidateUpdate(ctx, newVolumeAttachment, volumeAttachment)
103 if len(errs) == 0 {
104 t.Errorf("Expected a validation error")
105 }
106
107
108 statusVolumeAttachment = volumeAttachment.DeepCopy()
109 statusVolumeAttachment.Status = storage.VolumeAttachmentStatus{Attached: true}
110
111 Strategy.PrepareForUpdate(ctx, statusVolumeAttachment, volumeAttachment)
112
113 if !apiequality.Semantic.DeepEqual(statusVolumeAttachment, volumeAttachment) {
114 t.Errorf("unexpected objects difference after modifying status: %v", cmp.Diff(statusVolumeAttachment, volumeAttachment))
115 }
116 }
117
118 func TestVolumeAttachmentStrategySourceInlineSpec(t *testing.T) {
119 ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
120 APIGroup: "storage.k8s.io",
121 APIVersion: "v1",
122 Resource: "volumeattachments",
123 })
124
125 volumeAttachment := getValidVolumeAttachmentWithInlineSpec("valid-attachment")
126 volumeAttachmentSaved := volumeAttachment.DeepCopy()
127 Strategy.PrepareForCreate(ctx, volumeAttachment)
128 if volumeAttachment.Spec.Source.InlineVolumeSpec == nil {
129 t.Errorf("InlineVolumeSpec unexpectedly set to nil during PrepareForCreate")
130 }
131 if !apiequality.Semantic.DeepEqual(volumeAttachmentSaved, volumeAttachment) {
132 t.Errorf("unexpected difference in object after creation: %v", cmp.Diff(volumeAttachment, volumeAttachmentSaved))
133 }
134 Strategy.PrepareForUpdate(ctx, volumeAttachmentSaved, volumeAttachment)
135 if volumeAttachmentSaved.Spec.Source.InlineVolumeSpec == nil {
136 t.Errorf("InlineVolumeSpec unexpectedly set to nil during PrepareForUpdate")
137 }
138 Strategy.PrepareForUpdate(ctx, volumeAttachmentSaved, volumeAttachment)
139 if volumeAttachmentSaved.Spec.Source.InlineVolumeSpec == nil {
140 t.Errorf("InlineVolumeSpec unexpectedly set to nil during PrepareForUpdate")
141 }
142 }
143
144 func TestVolumeAttachmentStatusStrategy(t *testing.T) {
145 ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
146 APIGroup: "storage.k8s.io",
147 APIVersion: "v1",
148 Resource: "volumeattachments",
149 })
150
151 volumeAttachment := getValidVolumeAttachment("valid-attachment")
152
153
154 statusVolumeAttachment := volumeAttachment.DeepCopy()
155 statusVolumeAttachment.Status = storage.VolumeAttachmentStatus{Attached: true}
156
157 expectedVolumeAttachment := statusVolumeAttachment.DeepCopy()
158 StatusStrategy.PrepareForUpdate(ctx, statusVolumeAttachment, volumeAttachment)
159 if !apiequality.Semantic.DeepEqual(statusVolumeAttachment, expectedVolumeAttachment) {
160 t.Errorf("unexpected objects difference after modifying status: %v", cmp.Diff(statusVolumeAttachment, expectedVolumeAttachment))
161 }
162
163
164 newVolumeAttachment := volumeAttachment.DeepCopy()
165 newVolumeAttachment.Spec.NodeName = "valid-node-2"
166 newVolumeAttachment.Labels = map[string]string{"foo": "bar"}
167 newVolumeAttachment.Annotations = map[string]string{"foo": "baz"}
168 newVolumeAttachment.OwnerReferences = []metav1.OwnerReference{
169 {
170 APIVersion: "v1",
171 Kind: "Pod",
172 Name: "Foo",
173 },
174 }
175
176 StatusStrategy.PrepareForUpdate(ctx, newVolumeAttachment, volumeAttachment)
177 if !apiequality.Semantic.DeepEqual(newVolumeAttachment, volumeAttachment) {
178 t.Errorf("unexpected objects difference after modifying spec: %v", cmp.Diff(newVolumeAttachment, volumeAttachment))
179 }
180 }
181
182 func TestUpdatePreventsStatusWrite(t *testing.T) {
183 va := getValidVolumeAttachment("valid-attachment")
184 newAttachment := va.DeepCopy()
185 newAttachment.Status.Attached = true
186 Strategy.PrepareForUpdate(context.TODO(), newAttachment, va)
187 if newAttachment.Status.Attached {
188 t.Errorf("expected status to be %v got %v", false, newAttachment.Status.Attached)
189 }
190 }
191
192 func TestCreatePreventsStatusWrite(t *testing.T) {
193 va := getValidVolumeAttachment("valid-attachment")
194 va.Status.Attached = true
195 Strategy.PrepareForCreate(context.TODO(), va)
196 if va.Status.Attached {
197 t.Errorf("expected status to be false got %v", va.Status.Attached)
198 }
199 }
200
201 func TestVolumeAttachmentValidation(t *testing.T) {
202 invalidPVName := "invalid-!@#$%^&*()"
203 validPVName := "valid-volume-name"
204 tests := []struct {
205 name string
206 volumeAttachment *storage.VolumeAttachment
207 expectError bool
208 }{
209 {
210 "valid attachment",
211 getValidVolumeAttachment("foo"),
212 false,
213 },
214 {
215 "invalid PV name",
216 &storage.VolumeAttachment{
217 ObjectMeta: metav1.ObjectMeta{
218 Name: "foo",
219 },
220 Spec: storage.VolumeAttachmentSpec{
221 Attacher: "valid-attacher",
222 Source: storage.VolumeAttachmentSource{
223 PersistentVolumeName: &invalidPVName,
224 },
225 NodeName: "valid-node",
226 },
227 },
228 true,
229 },
230 {
231 "invalid attacher name",
232 &storage.VolumeAttachment{
233 ObjectMeta: metav1.ObjectMeta{
234 Name: "foo",
235 },
236 Spec: storage.VolumeAttachmentSpec{
237 Attacher: "invalid!@#$%^&*()",
238 Source: storage.VolumeAttachmentSource{
239 PersistentVolumeName: &validPVName,
240 },
241 NodeName: "valid-node",
242 },
243 },
244 true,
245 },
246 {
247 "invalid volume attachment",
248 &storage.VolumeAttachment{
249 ObjectMeta: metav1.ObjectMeta{
250 Name: "foo",
251 },
252 Spec: storage.VolumeAttachmentSpec{
253 Attacher: "invalid!@#$%^&*()",
254 Source: storage.VolumeAttachmentSource{
255 PersistentVolumeName: nil,
256 },
257 NodeName: "valid-node",
258 },
259 },
260 true,
261 },
262 }
263
264 for _, test := range tests {
265 t.Run(test.name, func(t *testing.T) {
266 err := Strategy.Validate(context.TODO(), test.volumeAttachment)
267 if len(err) > 0 && !test.expectError {
268 t.Errorf("Validation of object failed: %+v", err)
269 }
270 if len(err) == 0 && test.expectError {
271 t.Errorf("Validation of object unexpectedly succeeded")
272 }
273 })
274 }
275 }
276
View as plain text