1
16
17 package internal_test
18
19 import (
20 "fmt"
21 "reflect"
22 "testing"
23 "time"
24
25 v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/util/managedfields/managedfieldstest"
27
28 "k8s.io/apimachinery/pkg/api/meta"
29 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
30 "k8s.io/apimachinery/pkg/runtime"
31 "k8s.io/apimachinery/pkg/runtime/schema"
32 "k8s.io/apimachinery/pkg/util/managedfields/internal"
33 "sigs.k8s.io/yaml"
34 )
35
36 func TestManagedFieldsUpdateDoesModifyTime(t *testing.T) {
37 var err error
38 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
39
40 err = updateObject(f, "fieldmanager_test", []byte(`{
41 "apiVersion": "v1",
42 "kind": "ConfigMap",
43 "metadata": {
44 "name": "configmap"
45 },
46 "data": {
47 "key": "value"
48 }
49 }`))
50 if err != nil {
51 t.Fatal(err)
52 }
53 previousManagedFields := f.ManagedFields()
54
55 time.Sleep(time.Second)
56
57 err = updateObject(f, "fieldmanager_test", []byte(`{
58 "apiVersion": "v1",
59 "kind": "ConfigMap",
60 "metadata": {
61 "name": "configmap"
62 },
63 "data": {
64 "key": "new-value"
65 }
66 }`))
67 if err != nil {
68 t.Fatal(err)
69 }
70 newManagedFields := f.ManagedFields()
71
72 if previousManagedFields[0].Time.Equal(newManagedFields[0].Time) {
73 t.Errorf("ManagedFields time has not been updated:\n%v", newManagedFields)
74 }
75 }
76
77 func TestManagedFieldsApplyDoesModifyTime(t *testing.T) {
78 var err error
79 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
80
81 err = applyObject(f, "fieldmanager_test", []byte(`{
82 "apiVersion": "v1",
83 "kind": "ConfigMap",
84 "metadata": {
85 "name": "configmap"
86 },
87 "data": {
88 "key": "value"
89 }
90 }`))
91 if err != nil {
92 t.Fatal(err)
93 }
94 previousManagedFields := f.ManagedFields()
95
96 time.Sleep(time.Second)
97
98 err = applyObject(f, "fieldmanager_test", []byte(`{
99 "apiVersion": "v1",
100 "kind": "ConfigMap",
101 "metadata": {
102 "name": "configmap"
103 },
104 "data": {
105 "key": "new-value"
106 }
107 }`))
108 if err != nil {
109 t.Fatal(err)
110 }
111 newManagedFields := f.ManagedFields()
112
113 if previousManagedFields[0].Time.Equal(newManagedFields[0].Time) {
114 t.Errorf("ManagedFields time has not been updated:\n%v", newManagedFields)
115 }
116 }
117
118 func TestManagedFieldsUpdateWithoutChangesDoesNotModifyTime(t *testing.T) {
119 var err error
120 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
121
122 err = updateObject(f, "fieldmanager_test", []byte(`{
123 "apiVersion": "v1",
124 "kind": "ConfigMap",
125 "metadata": {
126 "name": "configmap"
127 },
128 "data": {
129 "key": "value"
130 }
131 }`))
132 if err != nil {
133 t.Fatal(err)
134 }
135 previousManagedFields := f.ManagedFields()
136
137 time.Sleep(time.Second)
138
139 err = updateObject(f, "fieldmanager_test", []byte(`{
140 "apiVersion": "v1",
141 "kind": "ConfigMap",
142 "metadata": {
143 "name": "configmap"
144 },
145 "data": {
146 "key": "value"
147 }
148 }`))
149 if err != nil {
150 t.Fatal(err)
151 }
152 newManagedFields := f.ManagedFields()
153
154 if !previousManagedFields[0].Time.Equal(newManagedFields[0].Time) {
155 t.Errorf("ManagedFields time has changed:\nBefore:\n%v\nAfter:\n%v", previousManagedFields, newManagedFields)
156 }
157 }
158
159 func TestManagedFieldsApplyWithoutChangesDoesNotModifyTime(t *testing.T) {
160 var err error
161 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
162
163 err = applyObject(f, "fieldmanager_test", []byte(`{
164 "apiVersion": "v1",
165 "kind": "ConfigMap",
166 "metadata": {
167 "name": "configmap"
168 },
169 "data": {
170 "key": "value"
171 }
172 }`))
173 if err != nil {
174 t.Fatal(err)
175 }
176 previousManagedFields := f.ManagedFields()
177
178 time.Sleep(time.Second)
179
180 err = applyObject(f, "fieldmanager_test", []byte(`{
181 "apiVersion": "v1",
182 "kind": "ConfigMap",
183 "metadata": {
184 "name": "configmap"
185 },
186 "data": {
187 "key": "value"
188 }
189 }`))
190 if err != nil {
191 t.Fatal(err)
192 }
193 newManagedFields := f.ManagedFields()
194
195 if !previousManagedFields[0].Time.Equal(newManagedFields[0].Time) {
196 t.Errorf("ManagedFields time has changed:\nBefore:\n%v\nAfter:\n%v", previousManagedFields, newManagedFields)
197 }
198 }
199
200 func TestNonManagedFieldsUpdateDoesNotModifyTime(t *testing.T) {
201 var err error
202 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
203
204 err = updateObject(f, "fieldmanager_a_test", []byte(`{
205 "apiVersion": "v1",
206 "kind": "ConfigMap",
207 "metadata": {
208 "name": "configmap"
209 },
210 "data": {
211 "key_a": "value"
212 }
213 }`))
214 if err != nil {
215 t.Fatal(err)
216 }
217 err = updateObject(f, "fieldmanager_b_test", []byte(`{
218 "apiVersion": "v1",
219 "kind": "ConfigMap",
220 "metadata": {
221 "name": "configmap"
222 },
223 "data": {
224 "key_b": "value"
225 }
226 }`))
227 if err != nil {
228 t.Fatal(err)
229 }
230 previousManagedFields := f.ManagedFields()
231 previousEntries := map[string]v1.ManagedFieldsEntry{}
232 for _, entry := range previousManagedFields {
233 previousEntries[entry.Manager] = entry
234 }
235
236 time.Sleep(time.Second)
237
238 err = updateObject(f, "fieldmanager_a_test", []byte(`{
239 "apiVersion": "v1",
240 "kind": "ConfigMap",
241 "metadata": {
242 "name": "configmap"
243 },
244 "data": {
245 "key_a": "value",
246 "key_b": "new-value"
247 }
248 }`))
249 if err != nil {
250 t.Fatal(err)
251 }
252 newManagedFields := f.ManagedFields()
253 newEntries := map[string]v1.ManagedFieldsEntry{}
254 for _, entry := range newManagedFields {
255 newEntries[entry.Manager] = entry
256 }
257
258 if _, ok := newEntries["fieldmanager_b_test"]; ok {
259 t.Errorf("FieldManager B ManagedFields has changed:\n%v", newEntries["fieldmanager_b_test"])
260 }
261 }
262
263 func TestNonManagedFieldsApplyDoesNotModifyTime(t *testing.T) {
264 var err error
265 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
266
267 err = applyObject(f, "fieldmanager_a_test", []byte(`{
268 "apiVersion": "v1",
269 "kind": "ConfigMap",
270 "metadata": {
271 "name": "configmap"
272 },
273 "data": {
274 "key_a": "value"
275 }
276 }`))
277 if err != nil {
278 t.Fatal(err)
279 }
280 err = applyObject(f, "fieldmanager_b_test", []byte(`{
281 "apiVersion": "v1",
282 "kind": "ConfigMap",
283 "metadata": {
284 "name": "configmap"
285 },
286 "data": {
287 "key_b": "value"
288 }
289 }`))
290 if err != nil {
291 t.Fatal(err)
292 }
293 previousManagedFields := f.ManagedFields()
294 previousEntries := map[string]v1.ManagedFieldsEntry{}
295 for _, entry := range previousManagedFields {
296 previousEntries[entry.Manager] = entry
297 }
298
299 time.Sleep(time.Second)
300
301 err = applyObject(f, "fieldmanager_a_test", []byte(`{
302 "apiVersion": "v1",
303 "kind": "ConfigMap",
304 "metadata": {
305 "name": "configmap"
306 },
307 "data": {
308 "key_a": "new-value"
309 }
310 }`))
311 if err != nil {
312 t.Fatal(err)
313 }
314 newManagedFields := f.ManagedFields()
315 newEntries := map[string]v1.ManagedFieldsEntry{}
316 for _, entry := range newManagedFields {
317 newEntries[entry.Manager] = entry
318 }
319
320 if !previousEntries["fieldmanager_b_test"].Time.Equal(newEntries["fieldmanager_b_test"].Time) {
321 t.Errorf("FieldManager B ManagedFields time changed:\nBefore:\n%v\nAfter:\n%v",
322 previousEntries["fieldmanager_b_test"], newEntries["fieldmanager_b_test"])
323 }
324 }
325
326 func TestTakingOverManagedFieldsDuringUpdateDoesNotModifyPreviousManagerTime(t *testing.T) {
327 var err error
328 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
329
330 err = updateObject(f, "fieldmanager_a_test", []byte(`{
331 "apiVersion": "v1",
332 "kind": "ConfigMap",
333 "metadata": {
334 "name": "configmap"
335 },
336 "data": {
337 "key_a": "value",
338 "key_b": value"
339 }
340 }`))
341 if err != nil {
342 t.Fatal(err)
343 }
344 previousManagedFields := f.ManagedFields()
345 previousEntries := map[string]v1.ManagedFieldsEntry{}
346 for _, entry := range previousManagedFields {
347 previousEntries[entry.Manager] = entry
348 }
349
350 time.Sleep(time.Second)
351
352 err = updateObject(f, "fieldmanager_b_test", []byte(`{
353 "apiVersion": "v1",
354 "kind": "ConfigMap",
355 "metadata": {
356 "name": "configmap"
357 },
358 "data": {
359 "key_b": "new-value"
360 }
361 }`))
362 if err != nil {
363 t.Fatal(err)
364 }
365 newManagedFields := f.ManagedFields()
366 newEntries := map[string]v1.ManagedFieldsEntry{}
367 for _, entry := range newManagedFields {
368 newEntries[entry.Manager] = entry
369 }
370
371 if !previousEntries["fieldmanager_a_test"].Time.Equal(newEntries["fieldmanager_a_test"].Time) {
372 t.Errorf("FieldManager A ManagedFields time has been updated:\nBefore:\n%v\nAfter:\n%v",
373 previousEntries["fieldmanager_a_test"], newEntries["fieldmanager_a_test"])
374 }
375 }
376
377 func TestTakingOverManagedFieldsDuringApplyDoesNotModifyPreviousManagerTime(t *testing.T) {
378 var err error
379 f := managedfieldstest.NewTestFieldManager(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "ConfigMap"))
380
381 err = applyObject(f, "fieldmanager_a_test", []byte(`{
382 "apiVersion": "v1",
383 "kind": "ConfigMap",
384 "metadata": {
385 "name": "configmap"
386 },
387 "data": {
388 "key_a": "value",
389 "key_b": value"
390 }
391 }`))
392 if err != nil {
393 t.Fatal(err)
394 }
395 previousManagedFields := f.ManagedFields()
396 previousEntries := map[string]v1.ManagedFieldsEntry{}
397 for _, entry := range previousManagedFields {
398 previousEntries[entry.Manager] = entry
399 }
400
401 time.Sleep(time.Second)
402
403 err = applyObject(f, "fieldmanager_b_test", []byte(`{
404 "apiVersion": "v1",
405 "kind": "ConfigMap",
406 "metadata": {
407 "name": "configmap"
408 },
409 "data": {
410 "key_b": "new-value"
411 }
412 }`))
413 if err != nil {
414 t.Fatal(err)
415 }
416 newManagedFields := f.ManagedFields()
417 newEntries := map[string]v1.ManagedFieldsEntry{}
418 for _, entry := range newManagedFields {
419 newEntries[entry.Manager] = entry
420 }
421
422 if !previousEntries["fieldmanager_a_test"].Time.Equal(newEntries["fieldmanager_a_test"].Time) {
423 t.Errorf("FieldManager A ManagedFields time has been updated:\nBefore:\n%v\nAfter:\n%v",
424 previousEntries["fieldmanager_a_test"], newEntries["fieldmanager_a_test"])
425 }
426 }
427
428 type NoopManager struct{}
429
430 func (NoopManager) Apply(liveObj, appliedObj runtime.Object, managed internal.Managed, fieldManager string, force bool) (runtime.Object, internal.Managed, error) {
431 return nil, managed, nil
432 }
433
434 func (NoopManager) Update(liveObj, newObj runtime.Object, managed internal.Managed, manager string) (runtime.Object, internal.Managed, error) {
435 return nil, nil, nil
436 }
437
438 func updateObject(f managedfieldstest.TestFieldManager, fieldManagerName string, object []byte) error {
439 obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
440 if err := yaml.Unmarshal(object, &obj.Object); err != nil {
441 return fmt.Errorf("error decoding YAML: %v", err)
442 }
443 if err := f.Update(obj, fieldManagerName); err != nil {
444 return fmt.Errorf("failed to update object: %v", err)
445 }
446 return nil
447 }
448
449 func applyObject(f managedfieldstest.TestFieldManager, fieldManagerName string, object []byte) error {
450 obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
451 if err := yaml.Unmarshal(object, &obj.Object); err != nil {
452 return fmt.Errorf("error decoding YAML: %v", err)
453 }
454 if err := f.Apply(obj, fieldManagerName, true); err != nil {
455 return fmt.Errorf("failed to apply object: %v", err)
456 }
457 return nil
458 }
459
460
461
462
463
464 func TestNilNewObjectReplacedWithDeepCopyExcludingManagedFields(t *testing.T) {
465
466 obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
467 if err := yaml.Unmarshal([]byte(`{
468 "apiVersion": "v1",
469 "kind": "Pod",
470 "metadata": {
471 "name": "pod",
472 "labels": {"app": "nginx"},
473 "managedFields": [
474 {
475 "apiVersion": "v1",
476 "fieldsType": "FieldsV1",
477 "fieldsV1": {
478 "f:metadata": {
479 "f:labels": {
480 "f:app": {}
481 }
482 }
483 },
484 "manager": "fieldmanager_test",
485 "operation": "Apply",
486 "time": "2021-11-11T18:41:17Z"
487 }
488 ]
489 }
490 }`), &obj.Object); err != nil {
491 t.Fatalf("error decoding YAML: %v", err)
492 }
493
494 accessor, err := meta.Accessor(obj)
495 if err != nil {
496 t.Fatalf("couldn't get accessor: %v", err)
497 }
498
499
500 managed, err := internal.DecodeManagedFields(accessor.GetManagedFields())
501 if err != nil {
502 t.Fatalf("failed to decode managed fields: %v", err)
503 }
504
505 updater := internal.NewManagedFieldsUpdater(NoopManager{})
506
507 newObject, _, err := updater.Apply(obj, obj.DeepCopyObject(), managed, "some_manager", false)
508 if err != nil {
509 t.Fatalf("failed to apply configuration %v", err)
510 }
511
512 if newObject == obj {
513 t.Fatalf("returned newObject must not be the same instance as the passed in liveObj")
514 }
515
516
517
518 liveWithoutManaged := obj.DeepCopyObject()
519 internal.RemoveObjectManagedFields(liveWithoutManaged)
520
521 if !reflect.DeepEqual(liveWithoutManaged, newObject) {
522 t.Fatalf("returned newObject must be deeply equal to the input live object, without managed fields")
523 }
524 }
525
View as plain text