1
16
17 package internal_test
18
19 import (
20 "bytes"
21 "encoding/json"
22 "fmt"
23 "testing"
24 "time"
25
26 apiequality "k8s.io/apimachinery/pkg/api/equality"
27 "k8s.io/apimachinery/pkg/api/meta"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
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 internaltesting "k8s.io/apimachinery/pkg/util/managedfields/internal/testing"
34 "k8s.io/apimachinery/pkg/util/managedfields/managedfieldstest"
35 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
36 )
37
38 type fakeManager struct{}
39
40 var _ internal.Manager = &fakeManager{}
41
42 func (*fakeManager) Update(_, newObj runtime.Object, managed internal.Managed, _ string) (runtime.Object, internal.Managed, error) {
43 return newObj, managed, nil
44 }
45
46 func (*fakeManager) Apply(_, _ runtime.Object, _ internal.Managed, _ string, _ bool) (runtime.Object, internal.Managed, error) {
47 panic("not implemented")
48 }
49
50 func TestCapManagersManagerMergesEntries(t *testing.T) {
51 f := internaltesting.NewTestFieldManagerImpl(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"),
52 "",
53 func(m internal.Manager) internal.Manager {
54 return internal.NewCapManagersManager(m, 3)
55 })
56
57 podWithLabels := func(labels ...string) runtime.Object {
58 labelMap := map[string]interface{}{}
59 for _, key := range labels {
60 labelMap[key] = "true"
61 }
62 obj := &unstructured.Unstructured{
63 Object: map[string]interface{}{
64 "metadata": map[string]interface{}{
65 "labels": labelMap,
66 },
67 },
68 }
69 obj.SetKind("Pod")
70 obj.SetAPIVersion("v1")
71 return obj
72 }
73
74 if err := f.Update(podWithLabels("one"), "fieldmanager_test_update_1"); err != nil {
75 t.Fatalf("failed to update object: %v", err)
76 }
77 expectIdempotence(t, f)
78
79 if err := f.Update(podWithLabels("one", "two"), "fieldmanager_test_update_2"); err != nil {
80 t.Fatalf("failed to update object: %v", err)
81 }
82 expectIdempotence(t, f)
83
84 if err := f.Update(podWithLabels("one", "two", "three"), "fieldmanager_test_update_3"); err != nil {
85 t.Fatalf("failed to update object: %v", err)
86 }
87 expectIdempotence(t, f)
88
89 if err := f.Update(podWithLabels("one", "two", "three", "four"), "fieldmanager_test_update_4"); err != nil {
90 t.Fatalf("failed to update object: %v", err)
91 }
92 expectIdempotence(t, f)
93
94 if e, a := 3, len(f.ManagedFields()); e != a {
95 t.Fatalf("exected %v entries in managedFields, but got %v: %#v", e, a, f.ManagedFields())
96 }
97
98 if e, a := "ancient-changes", f.ManagedFields()[0].Manager; e != a {
99 t.Fatalf("exected first manager name to be %v, but got %v: %#v", e, a, f.ManagedFields())
100 }
101
102 if e, a := "fieldmanager_test_update_3", f.ManagedFields()[1].Manager; e != a {
103 t.Fatalf("exected second manager name to be %v, but got %v: %#v", e, a, f.ManagedFields())
104 }
105
106 if e, a := "fieldmanager_test_update_4", f.ManagedFields()[2].Manager; e != a {
107 t.Fatalf("exected third manager name to be %v, but got %v: %#v", e, a, f.ManagedFields())
108 }
109
110 expectManagesField(t, f, "ancient-changes", fieldpath.MakePathOrDie("metadata", "labels", "one"))
111 expectManagesField(t, f, "ancient-changes", fieldpath.MakePathOrDie("metadata", "labels", "two"))
112 expectManagesField(t, f, "fieldmanager_test_update_3", fieldpath.MakePathOrDie("metadata", "labels", "three"))
113 expectManagesField(t, f, "fieldmanager_test_update_4", fieldpath.MakePathOrDie("metadata", "labels", "four"))
114 }
115
116 func TestCapUpdateManagers(t *testing.T) {
117 f := internaltesting.NewTestFieldManagerImpl(fakeTypeConverter, schema.FromAPIVersionAndKind("v1", "Pod"),
118 "",
119 func(m internal.Manager) internal.Manager {
120 return internal.NewCapManagersManager(m, 3)
121 })
122
123 set := func(fields ...string) *metav1.FieldsV1 {
124 s := fieldpath.NewSet()
125 for _, f := range fields {
126 s.Insert(fieldpath.MakePathOrDie(f))
127 }
128 b, err := s.ToJSON()
129 if err != nil {
130 panic(fmt.Sprintf("error building ManagedFieldsEntry for test: %v", err))
131 }
132 return &metav1.FieldsV1{Raw: b}
133 }
134
135 entry := func(name string, version string, order int, fields *metav1.FieldsV1) metav1.ManagedFieldsEntry {
136 return metav1.ManagedFieldsEntry{
137 Manager: name,
138 APIVersion: version,
139 Operation: "Update",
140 FieldsType: "FieldsV1",
141 FieldsV1: fields,
142 Time: &metav1.Time{Time: time.Time{}.Add(time.Hour * time.Duration(order))},
143 }
144 }
145
146 testCases := []struct {
147 name string
148 input []metav1.ManagedFieldsEntry
149 expected []metav1.ManagedFieldsEntry
150 }{
151 {
152 name: "one version, no ancient changes",
153 input: []metav1.ManagedFieldsEntry{
154 entry("update-manager1", "v1", 1, set("a")),
155 entry("update-manager2", "v1", 2, set("b")),
156 entry("update-manager3", "v1", 3, set("c")),
157 entry("update-manager4", "v1", 4, set("d")),
158 },
159 expected: []metav1.ManagedFieldsEntry{
160 entry("ancient-changes", "v1", 2, set("a", "b")),
161 entry("update-manager3", "v1", 3, set("c")),
162 entry("update-manager4", "v1", 4, set("d")),
163 },
164 }, {
165 name: "one version, one ancient changes",
166 input: []metav1.ManagedFieldsEntry{
167 entry("ancient-changes", "v1", 2, set("a", "b")),
168 entry("update-manager3", "v1", 3, set("c")),
169 entry("update-manager4", "v1", 4, set("d")),
170 entry("update-manager5", "v1", 5, set("e")),
171 },
172 expected: []metav1.ManagedFieldsEntry{
173 entry("ancient-changes", "v1", 3, set("a", "b", "c")),
174 entry("update-manager4", "v1", 4, set("d")),
175 entry("update-manager5", "v1", 5, set("e")),
176 },
177 }, {
178 name: "two versions, no ancient changes",
179 input: []metav1.ManagedFieldsEntry{
180 entry("update-manager1", "v1", 1, set("a")),
181 entry("update-manager2", "v2", 2, set("b")),
182 entry("update-manager3", "v1", 3, set("c")),
183 entry("update-manager4", "v1", 4, set("d")),
184 entry("update-manager5", "v1", 5, set("e")),
185 },
186 expected: []metav1.ManagedFieldsEntry{
187 entry("update-manager2", "v2", 2, set("b")),
188 entry("ancient-changes", "v1", 4, set("a", "c", "d")),
189 entry("update-manager5", "v1", 5, set("e")),
190 },
191 }, {
192 name: "three versions, one ancient changes",
193 input: []metav1.ManagedFieldsEntry{
194 entry("update-manager2", "v2", 2, set("b")),
195 entry("ancient-changes", "v1", 4, set("a", "c", "d")),
196 entry("update-manager5", "v1", 5, set("e")),
197 entry("update-manager6", "v3", 6, set("f")),
198 entry("update-manager7", "v2", 7, set("g")),
199 },
200 expected: []metav1.ManagedFieldsEntry{
201 entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")),
202 entry("update-manager6", "v3", 6, set("f")),
203 entry("ancient-changes", "v2", 7, set("b", "g")),
204 },
205 }, {
206 name: "three versions, two ancient changes",
207 input: []metav1.ManagedFieldsEntry{
208 entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")),
209 entry("update-manager6", "v3", 6, set("f")),
210 entry("ancient-changes", "v2", 7, set("b", "g")),
211 entry("update-manager8", "v3", 8, set("h")),
212 },
213 expected: []metav1.ManagedFieldsEntry{
214 entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")),
215 entry("ancient-changes", "v2", 7, set("b", "g")),
216 entry("ancient-changes", "v3", 8, set("f", "h")),
217 },
218 }, {
219 name: "four versions, two ancient changes",
220 input: []metav1.ManagedFieldsEntry{
221 entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")),
222 entry("update-manager6", "v3", 6, set("f")),
223 entry("ancient-changes", "v2", 7, set("b", "g")),
224 entry("update-manager8", "v4", 8, set("h")),
225 },
226 expected: []metav1.ManagedFieldsEntry{
227 entry("ancient-changes", "v1", 5, set("a", "c", "d", "e")),
228 entry("update-manager6", "v3", 6, set("f")),
229 entry("ancient-changes", "v2", 7, set("b", "g")),
230 entry("update-manager8", "v4", 8, set("h")),
231 },
232 },
233 }
234
235 for _, tc := range testCases {
236 f.Reset()
237 live := f.Live()
238 accessor, err := meta.Accessor(live)
239 if err != nil {
240 t.Fatalf("%v: couldn't get accessor: %v", tc.name, err)
241 }
242 accessor.SetManagedFields(tc.input)
243 if err := f.Update(live, "no-op-update"); err != nil {
244 t.Fatalf("%v: failed to do no-op update to object: %v", tc.name, err)
245 }
246
247 if e, a := tc.expected, f.ManagedFields(); !apiequality.Semantic.DeepEqual(e, a) {
248 t.Errorf("%v: unexpected value for managedFields:\nexpected: %v\n but got: %v", tc.name, mustMarshal(e), mustMarshal(a))
249 }
250 expectIdempotence(t, f)
251 }
252 }
253
254
255 func expectIdempotence(t *testing.T, f managedfieldstest.TestFieldManager) {
256 before := []metav1.ManagedFieldsEntry{}
257 for _, m := range f.ManagedFields() {
258 before = append(before, *m.DeepCopy())
259 }
260
261 if err := f.Update(f.Live(), "no-op-update"); err != nil {
262 t.Fatalf("failed to do no-op update to object: %v", err)
263 }
264
265 if after := f.ManagedFields(); !apiequality.Semantic.DeepEqual(before, after) {
266 t.Fatalf("exected idempotence, but managedFields changed:\nbefore: %v\n after: %v", mustMarshal(before), mustMarshal(after))
267 }
268 }
269
270
271 func expectManagesField(t *testing.T, f managedfieldstest.TestFieldManager, m string, p fieldpath.Path) {
272 for _, e := range f.ManagedFields() {
273 if e.Manager == m {
274 var s fieldpath.Set
275 err := s.FromJSON(bytes.NewReader(e.FieldsV1.Raw))
276 if err != nil {
277 t.Fatalf("error parsing managedFields for %v: %v: %#v", m, err, f.ManagedFields())
278 }
279 if !s.Has(p) {
280 t.Fatalf("expected managedFields for %v to contain %v, but got:\n%v", m, p.String(), s.String())
281 }
282 return
283 }
284 }
285 t.Fatalf("exected to find manager name %v, but got: %#v", m, f.ManagedFields())
286 }
287
288 func mustMarshal(i interface{}) string {
289 b, err := json.MarshalIndent(i, "", " ")
290 if err != nil {
291 panic(fmt.Sprintf("error marshalling %v to json: %v", i, err))
292 }
293 return string(b)
294 }
295
View as plain text