...

Source file src/k8s.io/apimachinery/pkg/util/managedfields/internal/capmanagers_test.go

Documentation: k8s.io/apimachinery/pkg/util/managedfields/internal

     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 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  // expectIdempotence does a no-op update and ensures that managedFields doesn't change by calling capUpdateManagers.
   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  // expectManagesField ensures that manager m currently manages field path p.
   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