...

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

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

     1  /*
     2  Copyright 2018 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
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"testing"
    23  	"time"
    24  
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  
    27  	"sigs.k8s.io/yaml"
    28  )
    29  
    30  // TestHasFieldsType makes sure that we fail if we don't have a
    31  // FieldsType set properly.
    32  func TestHasFieldsType(t *testing.T) {
    33  	var unmarshaled []metav1.ManagedFieldsEntry
    34  	if err := yaml.Unmarshal([]byte(`- apiVersion: v1
    35    fieldsType: FieldsV1
    36    fieldsV1:
    37      f:field: {}
    38    manager: foo
    39    operation: Apply
    40  `), &unmarshaled); err != nil {
    41  		t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
    42  	}
    43  	if _, err := DecodeManagedFields(unmarshaled); err != nil {
    44  		t.Fatalf("did not expect decoding error but got: %v", err)
    45  	}
    46  
    47  	// Invalid fieldsType V2.
    48  	if err := yaml.Unmarshal([]byte(`- apiVersion: v1
    49    fieldsType: FieldsV2
    50    fieldsV1:
    51      f:field: {}
    52    manager: foo
    53    operation: Apply
    54  `), &unmarshaled); err != nil {
    55  		t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
    56  	}
    57  	if _, err := DecodeManagedFields(unmarshaled); err == nil {
    58  		t.Fatal("Expect decoding error but got none")
    59  	}
    60  
    61  	// Missing fieldsType.
    62  	if err := yaml.Unmarshal([]byte(`- apiVersion: v1
    63    fieldsV1:
    64      f:field: {}
    65    manager: foo
    66    operation: Apply
    67  `), &unmarshaled); err != nil {
    68  		t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
    69  	}
    70  	if _, err := DecodeManagedFields(unmarshaled); err == nil {
    71  		t.Fatal("Expect decoding error but got none")
    72  	}
    73  }
    74  
    75  // TestHasAPIVersion makes sure that we fail if we don't have an
    76  // APIVersion set.
    77  func TestHasAPIVersion(t *testing.T) {
    78  	var unmarshaled []metav1.ManagedFieldsEntry
    79  	if err := yaml.Unmarshal([]byte(`- apiVersion: v1
    80    fieldsType: FieldsV1
    81    fieldsV1:
    82      f:field: {}
    83    manager: foo
    84    operation: Apply
    85  `), &unmarshaled); err != nil {
    86  		t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
    87  	}
    88  	if _, err := DecodeManagedFields(unmarshaled); err != nil {
    89  		t.Fatalf("did not expect decoding error but got: %v", err)
    90  	}
    91  
    92  	// Missing apiVersion.
    93  	unmarshaled = nil
    94  	if err := yaml.Unmarshal([]byte(`- fieldsType: FieldsV1
    95    fieldsV1:
    96      f:field: {}
    97    manager: foo
    98    operation: Apply
    99  `), &unmarshaled); err != nil {
   100  		t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
   101  	}
   102  	if _, err := DecodeManagedFields(unmarshaled); err == nil {
   103  		t.Fatal("Expect decoding error but got none")
   104  	}
   105  }
   106  
   107  // TestHasOperation makes sure that we fail if we don't have an
   108  // Operation set properly.
   109  func TestHasOperation(t *testing.T) {
   110  	var unmarshaled []metav1.ManagedFieldsEntry
   111  	if err := yaml.Unmarshal([]byte(`- apiVersion: v1
   112    fieldsType: FieldsV1
   113    fieldsV1:
   114      f:field: {}
   115    manager: foo
   116    operation: Apply
   117  `), &unmarshaled); err != nil {
   118  		t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
   119  	}
   120  	if _, err := DecodeManagedFields(unmarshaled); err != nil {
   121  		t.Fatalf("did not expect decoding error but got: %v", err)
   122  	}
   123  
   124  	// Invalid operation.
   125  	if err := yaml.Unmarshal([]byte(`- apiVersion: v1
   126    fieldsType: FieldsV1
   127    fieldsV1:
   128      f:field: {}
   129    manager: foo
   130    operation: Invalid
   131  `), &unmarshaled); err != nil {
   132  		t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
   133  	}
   134  	if _, err := DecodeManagedFields(unmarshaled); err == nil {
   135  		t.Fatal("Expect decoding error but got none")
   136  	}
   137  
   138  	// Missing operation.
   139  	unmarshaled = nil
   140  	if err := yaml.Unmarshal([]byte(`- apiVersion: v1
   141    fieldsType: FieldsV1
   142    fieldsV1:
   143      f:field: {}
   144    manager: foo
   145  `), &unmarshaled); err != nil {
   146  		t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
   147  	}
   148  	if _, err := DecodeManagedFields(unmarshaled); err == nil {
   149  		t.Fatal("Expect decoding error but got none")
   150  	}
   151  }
   152  
   153  // TestRoundTripManagedFields will roundtrip ManagedFields from the wire format
   154  // (api format) to the format used by sigs.k8s.io/structured-merge-diff and back
   155  func TestRoundTripManagedFields(t *testing.T) {
   156  	tests := []string{
   157  		`null
   158  `,
   159  		`- apiVersion: v1
   160    fieldsType: FieldsV1
   161    fieldsV1:
   162      v:3:
   163        f:alsoPi: {}
   164      v:3.1415:
   165        f:pi: {}
   166      v:false:
   167        f:notTrue: {}
   168    manager: foo
   169    operation: Update
   170    time: "2001-02-03T04:05:06Z"
   171  - apiVersion: v1beta1
   172    fieldsType: FieldsV1
   173    fieldsV1:
   174      i:5:
   175        f:i: {}
   176    manager: foo
   177    operation: Update
   178    time: "2011-12-13T14:15:16Z"
   179  `,
   180  		`- apiVersion: v1
   181    fieldsType: FieldsV1
   182    fieldsV1:
   183      f:spec:
   184        f:containers:
   185          k:{"name":"c"}:
   186            f:image: {}
   187            f:name: {}
   188    manager: foo
   189    operation: Apply
   190  `,
   191  		`- apiVersion: v1
   192    fieldsType: FieldsV1
   193    fieldsV1:
   194      f:apiVersion: {}
   195      f:kind: {}
   196      f:metadata:
   197        f:labels:
   198          f:app: {}
   199        f:name: {}
   200      f:spec:
   201        f:replicas: {}
   202        f:selector:
   203          f:matchLabels:
   204            f:app: {}
   205        f:template:
   206          f:medatada:
   207            f:labels:
   208              f:app: {}
   209          f:spec:
   210            f:containers:
   211              k:{"name":"nginx"}:
   212                .: {}
   213                f:image: {}
   214                f:name: {}
   215                f:ports:
   216                  i:0:
   217                    f:containerPort: {}
   218    manager: foo
   219    operation: Update
   220  `,
   221  		`- apiVersion: v1
   222    fieldsType: FieldsV1
   223    fieldsV1:
   224      f:allowVolumeExpansion: {}
   225      f:apiVersion: {}
   226      f:kind: {}
   227      f:metadata:
   228        f:name: {}
   229        f:parameters:
   230          f:resturl: {}
   231          f:restuser: {}
   232          f:secretName: {}
   233          f:secretNamespace: {}
   234      f:provisioner: {}
   235    manager: foo
   236    operation: Apply
   237  `,
   238  		`- apiVersion: v1
   239    fieldsType: FieldsV1
   240    fieldsV1:
   241      f:apiVersion: {}
   242      f:kind: {}
   243      f:metadata:
   244        f:name: {}
   245      f:spec:
   246        f:group: {}
   247        f:names:
   248          f:kind: {}
   249          f:plural: {}
   250          f:shortNames:
   251            i:0: {}
   252          f:singular: {}
   253        f:scope: {}
   254        f:versions:
   255          k:{"name":"v1"}:
   256            f:name: {}
   257            f:served: {}
   258            f:storage: {}
   259    manager: foo
   260    operation: Update
   261  `,
   262  		`- apiVersion: v1
   263    fieldsType: FieldsV1
   264    fieldsV1:
   265      f:spec:
   266        f:replicas: {}
   267    manager: foo
   268    operation: Update
   269    subresource: scale
   270  `,
   271  	}
   272  
   273  	for _, test := range tests {
   274  		t.Run(test, func(t *testing.T) {
   275  			var unmarshaled []metav1.ManagedFieldsEntry
   276  			if err := yaml.Unmarshal([]byte(test), &unmarshaled); err != nil {
   277  				t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
   278  			}
   279  			decoded, err := DecodeManagedFields(unmarshaled)
   280  			if err != nil {
   281  				t.Fatalf("did not expect decoding error but got: %v", err)
   282  			}
   283  			encoded, err := encodeManagedFields(decoded)
   284  			if err != nil {
   285  				t.Fatalf("did not expect encoding error but got: %v", err)
   286  			}
   287  			marshaled, err := yaml.Marshal(&encoded)
   288  			if err != nil {
   289  				t.Fatalf("did not expect yaml marshalling error but got: %v", err)
   290  			}
   291  			if !reflect.DeepEqual(string(marshaled), test) {
   292  				t.Fatalf("expected:\n%v\nbut got:\n%v", test, string(marshaled))
   293  			}
   294  		})
   295  	}
   296  }
   297  
   298  func TestBuildManagerIdentifier(t *testing.T) {
   299  	tests := []struct {
   300  		managedFieldsEntry string
   301  		expected           string
   302  	}{
   303  		{
   304  			managedFieldsEntry: `
   305  apiVersion: v1
   306  fieldsV1:
   307    f:apiVersion: {}
   308  manager: foo
   309  operation: Update
   310  time: "2001-02-03T04:05:06Z"
   311  `,
   312  			expected: "{\"manager\":\"foo\",\"operation\":\"Update\",\"apiVersion\":\"v1\"}",
   313  		},
   314  		{
   315  			managedFieldsEntry: `
   316  apiVersion: v1
   317  fieldsV1:
   318    f:apiVersion: {}
   319  manager: foo
   320  operation: Apply
   321  time: "2001-02-03T04:05:06Z"
   322  `,
   323  			expected: "{\"manager\":\"foo\",\"operation\":\"Apply\"}",
   324  		},
   325  		{
   326  			managedFieldsEntry: `
   327  apiVersion: v1
   328  fieldsV1:
   329    f:apiVersion: {}
   330  manager: foo
   331  operation: Apply
   332  subresource: scale
   333  time: "2001-02-03T04:05:06Z"
   334  `,
   335  			expected: "{\"manager\":\"foo\",\"operation\":\"Apply\",\"subresource\":\"scale\"}",
   336  		},
   337  	}
   338  
   339  	for _, test := range tests {
   340  		t.Run(test.managedFieldsEntry, func(t *testing.T) {
   341  			var unmarshaled metav1.ManagedFieldsEntry
   342  			if err := yaml.Unmarshal([]byte(test.managedFieldsEntry), &unmarshaled); err != nil {
   343  				t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
   344  			}
   345  			decoded, err := BuildManagerIdentifier(&unmarshaled)
   346  			if err != nil {
   347  				t.Fatalf("did not expect decoding error but got: %v", err)
   348  			}
   349  			if !reflect.DeepEqual(decoded, test.expected) {
   350  				t.Fatalf("expected:\n%v\nbut got:\n%v", test.expected, decoded)
   351  			}
   352  		})
   353  	}
   354  }
   355  
   356  func TestSortEncodedManagedFields(t *testing.T) {
   357  	tests := []struct {
   358  		name          string
   359  		managedFields []metav1.ManagedFieldsEntry
   360  		expected      []metav1.ManagedFieldsEntry
   361  	}{
   362  		{
   363  			name:          "empty",
   364  			managedFields: []metav1.ManagedFieldsEntry{},
   365  			expected:      []metav1.ManagedFieldsEntry{},
   366  		},
   367  		{
   368  			name:          "nil",
   369  			managedFields: nil,
   370  			expected:      nil,
   371  		},
   372  		{
   373  			name: "remains untouched",
   374  			managedFields: []metav1.ManagedFieldsEntry{
   375  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   376  				{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   377  			},
   378  			expected: []metav1.ManagedFieldsEntry{
   379  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   380  				{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   381  			},
   382  		},
   383  		{
   384  			name: "manager without time first",
   385  			managedFields: []metav1.ManagedFieldsEntry{
   386  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   387  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   388  			},
   389  			expected: []metav1.ManagedFieldsEntry{
   390  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   391  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   392  			},
   393  		},
   394  		{
   395  			name: "manager without time first name last",
   396  			managedFields: []metav1.ManagedFieldsEntry{
   397  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   398  				{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   399  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   400  			},
   401  			expected: []metav1.ManagedFieldsEntry{
   402  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   403  				{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   404  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   405  			},
   406  		},
   407  		{
   408  			name: "apply first",
   409  			managedFields: []metav1.ManagedFieldsEntry{
   410  				{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   411  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   412  			},
   413  			expected: []metav1.ManagedFieldsEntry{
   414  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   415  				{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   416  			},
   417  		},
   418  		{
   419  			name: "newest last",
   420  			managedFields: []metav1.ManagedFieldsEntry{
   421  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   422  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   423  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
   424  				{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   425  			},
   426  			expected: []metav1.ManagedFieldsEntry{
   427  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   428  				{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   429  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   430  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
   431  			},
   432  		},
   433  		{
   434  			name: "manager last",
   435  			managedFields: []metav1.ManagedFieldsEntry{
   436  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   437  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   438  				{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   439  				{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   440  			},
   441  			expected: []metav1.ManagedFieldsEntry{
   442  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   443  				{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   444  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   445  				{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   446  			},
   447  		},
   448  		{
   449  			name: "manager sorted",
   450  			managedFields: []metav1.ManagedFieldsEntry{
   451  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   452  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   453  				{Manager: "g", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   454  				{Manager: "f", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
   455  				{Manager: "i", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   456  				{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
   457  				{Manager: "h", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   458  				{Manager: "e", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2003-01-01T01:00:00Z")},
   459  				{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   460  			},
   461  			expected: []metav1.ManagedFieldsEntry{
   462  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   463  				{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   464  				{Manager: "g", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   465  				{Manager: "h", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   466  				{Manager: "i", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
   467  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
   468  				{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
   469  				{Manager: "f", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
   470  				{Manager: "e", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2003-01-01T01:00:00Z")},
   471  			},
   472  		},
   473  		{
   474  			name: "sort drops nanoseconds",
   475  			managedFields: []metav1.ManagedFieldsEntry{
   476  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 1, time.UTC)}},
   477  				{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 2, time.UTC)}},
   478  				{Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 3, time.UTC)}},
   479  			},
   480  			expected: []metav1.ManagedFieldsEntry{
   481  				{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 2, time.UTC)}},
   482  				{Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 3, time.UTC)}},
   483  				{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 1, time.UTC)}},
   484  			},
   485  		},
   486  		{
   487  			name: "entries with subresource field",
   488  			managedFields: []metav1.ManagedFieldsEntry{
   489  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Subresource: "status"},
   490  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Subresource: "scale"},
   491  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply},
   492  			},
   493  			expected: []metav1.ManagedFieldsEntry{
   494  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply},
   495  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Subresource: "scale"},
   496  				{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Subresource: "status"},
   497  			},
   498  		},
   499  	}
   500  
   501  	for _, test := range tests {
   502  		t.Run(test.name, func(t *testing.T) {
   503  			sorted, err := sortEncodedManagedFields(test.managedFields)
   504  			if err != nil {
   505  				t.Fatalf("did not expect error when sorting but got: %v", err)
   506  			}
   507  			if !reflect.DeepEqual(sorted, test.expected) {
   508  				t.Fatalf("expected:\n%v\nbut got:\n%v", test.expected, sorted)
   509  			}
   510  		})
   511  	}
   512  }
   513  
   514  func parseTimeOrPanic(s string) *metav1.Time {
   515  	t, err := time.Parse(time.RFC3339, s)
   516  	if err != nil {
   517  		panic(fmt.Sprintf("failed to parse time %s, got: %v", s, err))
   518  	}
   519  	return &metav1.Time{Time: t.UTC()}
   520  }
   521  

View as plain text