...

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

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

     1  /*
     2  Copyright 2021 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 managedfields
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/runtime/schema"
    26  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    27  )
    28  
    29  func TestTransformManagedFieldsToSubresource(t *testing.T) {
    30  	testTime, _ := time.ParseInLocation("2006-Jan-02", "2013-Feb-03", time.Local)
    31  	managedFieldTime := metav1.NewTime(testTime)
    32  
    33  	tests := []struct {
    34  		desc     string
    35  		input    []metav1.ManagedFieldsEntry
    36  		expected []metav1.ManagedFieldsEntry
    37  	}{
    38  		{
    39  			desc: "filter one entry and transform it into a subresource entry",
    40  			input: []metav1.ManagedFieldsEntry{
    41  				{
    42  					Manager:    "manager-1",
    43  					Operation:  metav1.ManagedFieldsOperationApply,
    44  					APIVersion: "apps/v1",
    45  					FieldsType: "FieldsV1",
    46  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:another-field":{}}}`)},
    47  				},
    48  				{
    49  					Manager:    "manager-2",
    50  					Operation:  metav1.ManagedFieldsOperationApply,
    51  					APIVersion: "apps/v1",
    52  					FieldsType: "FieldsV1",
    53  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
    54  					Time:       &managedFieldTime,
    55  				},
    56  			},
    57  			expected: []metav1.ManagedFieldsEntry{
    58  				{
    59  					Manager:    "manager-2",
    60  					Operation:  metav1.ManagedFieldsOperationApply,
    61  					APIVersion: "autoscaling/v1",
    62  					FieldsType: "FieldsV1",
    63  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
    64  					Time:       &managedFieldTime,
    65  				},
    66  			},
    67  		},
    68  		{
    69  			desc: "transform all entries",
    70  			input: []metav1.ManagedFieldsEntry{
    71  				{
    72  					Manager:    "manager-1",
    73  					Operation:  metav1.ManagedFieldsOperationApply,
    74  					APIVersion: "apps/v1",
    75  					FieldsType: "FieldsV1",
    76  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
    77  				},
    78  				{
    79  					Manager:    "manager-2",
    80  					Operation:  metav1.ManagedFieldsOperationApply,
    81  					APIVersion: "apps/v1",
    82  					FieldsType: "FieldsV1",
    83  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
    84  				},
    85  				{
    86  					Manager:     "manager-3",
    87  					Operation:   metav1.ManagedFieldsOperationApply,
    88  					APIVersion:  "apps/v1",
    89  					FieldsType:  "FieldsV1",
    90  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
    91  					Subresource: "scale",
    92  				},
    93  			},
    94  			expected: []metav1.ManagedFieldsEntry{
    95  				{
    96  					Manager:    "manager-1",
    97  					Operation:  metav1.ManagedFieldsOperationApply,
    98  					APIVersion: "autoscaling/v1",
    99  					FieldsType: "FieldsV1",
   100  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   101  				},
   102  				{
   103  					Manager:    "manager-2",
   104  					Operation:  metav1.ManagedFieldsOperationApply,
   105  					APIVersion: "autoscaling/v1",
   106  					FieldsType: "FieldsV1",
   107  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   108  				},
   109  				{
   110  					Manager:     "manager-3",
   111  					Operation:   metav1.ManagedFieldsOperationApply,
   112  					APIVersion:  "autoscaling/v1",
   113  					FieldsType:  "FieldsV1",
   114  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   115  					Subresource: "scale",
   116  				},
   117  			},
   118  		},
   119  		{
   120  			desc: "drops fields if the api version is unknown",
   121  			input: []metav1.ManagedFieldsEntry{
   122  				{
   123  					Manager:    "manager-1",
   124  					Operation:  metav1.ManagedFieldsOperationApply,
   125  					APIVersion: "apps/v10",
   126  					FieldsType: "FieldsV1",
   127  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   128  				},
   129  			},
   130  			expected: nil,
   131  		},
   132  	}
   133  
   134  	for _, test := range tests {
   135  		handler := NewScaleHandler(
   136  			test.input,
   137  			schema.GroupVersion{Group: "apps", Version: "v1"},
   138  			defaultMappings(),
   139  		)
   140  		subresourceEntries, err := handler.ToSubresource()
   141  		if err != nil {
   142  			t.Fatalf("test %q - expected no error but got %v", test.desc, err)
   143  		}
   144  
   145  		if !reflect.DeepEqual(subresourceEntries, test.expected) {
   146  			t.Fatalf("test %q - expected output to be:\n%v\n\nbut got:\n%v", test.desc, test.expected, subresourceEntries)
   147  		}
   148  	}
   149  }
   150  
   151  func TestTransformingManagedFieldsToParent(t *testing.T) {
   152  	tests := []struct {
   153  		desc        string
   154  		parent      []metav1.ManagedFieldsEntry
   155  		subresource []metav1.ManagedFieldsEntry
   156  		expected    []metav1.ManagedFieldsEntry
   157  	}{
   158  		{
   159  			desc: "different-managers: apply -> update",
   160  			parent: []metav1.ManagedFieldsEntry{
   161  				{
   162  					Manager:    "test",
   163  					Operation:  metav1.ManagedFieldsOperationApply,
   164  					APIVersion: "apps/v1",
   165  					FieldsType: "FieldsV1",
   166  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   167  				},
   168  			},
   169  			subresource: []metav1.ManagedFieldsEntry{
   170  				{
   171  					Manager:     "scale",
   172  					Operation:   metav1.ManagedFieldsOperationUpdate,
   173  					APIVersion:  "autoscaling/v1",
   174  					FieldsType:  "FieldsV1",
   175  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   176  					Subresource: "scale",
   177  				},
   178  			},
   179  			expected: []metav1.ManagedFieldsEntry{
   180  				{
   181  					Manager:    "test",
   182  					Operation:  metav1.ManagedFieldsOperationApply,
   183  					APIVersion: "apps/v1",
   184  					FieldsType: "FieldsV1",
   185  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   186  				},
   187  				{
   188  					Manager:     "scale",
   189  					Operation:   metav1.ManagedFieldsOperationUpdate,
   190  					APIVersion:  "apps/v1",
   191  					FieldsType:  "FieldsV1",
   192  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   193  					Subresource: "scale",
   194  				},
   195  			},
   196  		},
   197  		{
   198  			desc: "different-managers: apply -> apply",
   199  			parent: []metav1.ManagedFieldsEntry{
   200  				{
   201  					Manager:    "test",
   202  					Operation:  metav1.ManagedFieldsOperationApply,
   203  					APIVersion: "apps/v1",
   204  					FieldsType: "FieldsV1",
   205  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   206  				},
   207  			},
   208  			subresource: []metav1.ManagedFieldsEntry{
   209  				{
   210  					Manager:     "scale",
   211  					Operation:   metav1.ManagedFieldsOperationApply,
   212  					APIVersion:  "autoscaling/v1",
   213  					FieldsType:  "FieldsV1",
   214  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   215  					Subresource: "scale",
   216  				},
   217  			},
   218  			expected: []metav1.ManagedFieldsEntry{
   219  				{
   220  					Manager:     "scale",
   221  					Operation:   metav1.ManagedFieldsOperationApply,
   222  					APIVersion:  "apps/v1",
   223  					FieldsType:  "FieldsV1",
   224  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   225  					Subresource: "scale",
   226  				},
   227  				{
   228  					Manager:    "test",
   229  					Operation:  metav1.ManagedFieldsOperationApply,
   230  					APIVersion: "apps/v1",
   231  					FieldsType: "FieldsV1",
   232  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   233  				},
   234  			},
   235  		},
   236  		{
   237  			desc: "different-managers: update -> update",
   238  			parent: []metav1.ManagedFieldsEntry{
   239  				{
   240  					Manager:    "test",
   241  					Operation:  metav1.ManagedFieldsOperationUpdate,
   242  					APIVersion: "apps/v1",
   243  					FieldsType: "FieldsV1",
   244  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   245  				},
   246  			},
   247  			subresource: []metav1.ManagedFieldsEntry{
   248  				{
   249  					Manager:     "scale",
   250  					Operation:   metav1.ManagedFieldsOperationUpdate,
   251  					APIVersion:  "autoscaling/v1",
   252  					FieldsType:  "FieldsV1",
   253  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   254  					Subresource: "scale",
   255  				},
   256  			},
   257  			expected: []metav1.ManagedFieldsEntry{
   258  				{
   259  					Manager:     "scale",
   260  					Operation:   metav1.ManagedFieldsOperationUpdate,
   261  					APIVersion:  "apps/v1",
   262  					FieldsType:  "FieldsV1",
   263  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   264  					Subresource: "scale",
   265  				},
   266  				{
   267  					Manager:    "test",
   268  					Operation:  metav1.ManagedFieldsOperationUpdate,
   269  					APIVersion: "apps/v1",
   270  					FieldsType: "FieldsV1",
   271  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   272  				},
   273  			},
   274  		},
   275  		{
   276  			desc: "different-managers: update -> apply",
   277  			parent: []metav1.ManagedFieldsEntry{
   278  				{
   279  					Manager:    "test",
   280  					Operation:  metav1.ManagedFieldsOperationUpdate,
   281  					APIVersion: "apps/v1",
   282  					FieldsType: "FieldsV1",
   283  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   284  				},
   285  			},
   286  			subresource: []metav1.ManagedFieldsEntry{
   287  				{
   288  					Manager:     "scale",
   289  					Operation:   metav1.ManagedFieldsOperationApply,
   290  					APIVersion:  "autoscaling/v1",
   291  					FieldsType:  "FieldsV1",
   292  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   293  					Subresource: "scale",
   294  				},
   295  			},
   296  			expected: []metav1.ManagedFieldsEntry{
   297  				{
   298  					Manager:     "scale",
   299  					Operation:   metav1.ManagedFieldsOperationApply,
   300  					APIVersion:  "apps/v1",
   301  					FieldsType:  "FieldsV1",
   302  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   303  					Subresource: "scale",
   304  				},
   305  				{
   306  					Manager:    "test",
   307  					Operation:  metav1.ManagedFieldsOperationUpdate,
   308  					APIVersion: "apps/v1",
   309  					FieldsType: "FieldsV1",
   310  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   311  				},
   312  			},
   313  		},
   314  		{
   315  			desc: "same manager: apply -> apply",
   316  			parent: []metav1.ManagedFieldsEntry{
   317  				{
   318  					Manager:    "test",
   319  					Operation:  metav1.ManagedFieldsOperationApply,
   320  					APIVersion: "apps/v1",
   321  					FieldsType: "FieldsV1",
   322  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   323  				},
   324  			},
   325  			subresource: []metav1.ManagedFieldsEntry{
   326  				{
   327  					Manager:     "test",
   328  					Operation:   metav1.ManagedFieldsOperationApply,
   329  					APIVersion:  "autoscaling/v1",
   330  					FieldsType:  "FieldsV1",
   331  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   332  					Subresource: "scale",
   333  				},
   334  			},
   335  			expected: []metav1.ManagedFieldsEntry{
   336  				{
   337  					Manager:    "test",
   338  					Operation:  metav1.ManagedFieldsOperationApply,
   339  					APIVersion: "apps/v1",
   340  					FieldsType: "FieldsV1",
   341  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   342  				},
   343  				{
   344  					Manager:     "test",
   345  					Operation:   metav1.ManagedFieldsOperationApply,
   346  					APIVersion:  "apps/v1",
   347  					FieldsType:  "FieldsV1",
   348  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   349  					Subresource: "scale",
   350  				},
   351  			},
   352  		},
   353  		{
   354  			desc: "same manager: update -> update",
   355  			parent: []metav1.ManagedFieldsEntry{
   356  				{
   357  					Manager:    "test",
   358  					Operation:  metav1.ManagedFieldsOperationUpdate,
   359  					APIVersion: "apps/v1",
   360  					FieldsType: "FieldsV1",
   361  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   362  				},
   363  			},
   364  			subresource: []metav1.ManagedFieldsEntry{
   365  				{
   366  					Manager:     "test",
   367  					Operation:   metav1.ManagedFieldsOperationUpdate,
   368  					APIVersion:  "autoscaling/v1",
   369  					FieldsType:  "FieldsV1",
   370  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   371  					Subresource: "scale",
   372  				},
   373  			},
   374  			expected: []metav1.ManagedFieldsEntry{
   375  				{
   376  					Manager:    "test",
   377  					Operation:  metav1.ManagedFieldsOperationUpdate,
   378  					APIVersion: "apps/v1",
   379  					FieldsType: "FieldsV1",
   380  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   381  				},
   382  				{
   383  					Manager:     "test",
   384  					Operation:   metav1.ManagedFieldsOperationUpdate,
   385  					APIVersion:  "apps/v1",
   386  					FieldsType:  "FieldsV1",
   387  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   388  					Subresource: "scale",
   389  				},
   390  			},
   391  		},
   392  		{
   393  			desc: "same manager: update -> apply",
   394  			parent: []metav1.ManagedFieldsEntry{
   395  				{
   396  					Manager:    "test",
   397  					Operation:  metav1.ManagedFieldsOperationUpdate,
   398  					APIVersion: "apps/v1",
   399  					FieldsType: "FieldsV1",
   400  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   401  				},
   402  			},
   403  			subresource: []metav1.ManagedFieldsEntry{
   404  				{
   405  					Manager:     "test",
   406  					Operation:   metav1.ManagedFieldsOperationApply,
   407  					APIVersion:  "autoscaling/v1",
   408  					FieldsType:  "FieldsV1",
   409  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   410  					Subresource: "scale",
   411  				},
   412  			},
   413  			expected: []metav1.ManagedFieldsEntry{
   414  				{
   415  					Manager:     "test",
   416  					Operation:   metav1.ManagedFieldsOperationApply,
   417  					APIVersion:  "apps/v1",
   418  					FieldsType:  "FieldsV1",
   419  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   420  					Subresource: "scale",
   421  				},
   422  				{
   423  					Manager:    "test",
   424  					Operation:  metav1.ManagedFieldsOperationUpdate,
   425  					APIVersion: "apps/v1",
   426  					FieldsType: "FieldsV1",
   427  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   428  				},
   429  			},
   430  		},
   431  		{
   432  			desc: "same manager: apply -> update",
   433  			parent: []metav1.ManagedFieldsEntry{
   434  				{
   435  					Manager:    "test",
   436  					Operation:  metav1.ManagedFieldsOperationApply,
   437  					APIVersion: "apps/v1",
   438  					FieldsType: "FieldsV1",
   439  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   440  				},
   441  			},
   442  			subresource: []metav1.ManagedFieldsEntry{
   443  				{
   444  					Manager:     "test",
   445  					Operation:   metav1.ManagedFieldsOperationUpdate,
   446  					APIVersion:  "autoscaling/v1",
   447  					FieldsType:  "FieldsV1",
   448  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   449  					Subresource: "scale",
   450  				},
   451  			},
   452  			expected: []metav1.ManagedFieldsEntry{
   453  				{
   454  					Manager:    "test",
   455  					Operation:  metav1.ManagedFieldsOperationApply,
   456  					APIVersion: "apps/v1",
   457  					FieldsType: "FieldsV1",
   458  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   459  				},
   460  				{
   461  					Manager:     "test",
   462  					Operation:   metav1.ManagedFieldsOperationUpdate,
   463  					APIVersion:  "apps/v1",
   464  					FieldsType:  "FieldsV1",
   465  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   466  					Subresource: "scale",
   467  				},
   468  			},
   469  		},
   470  		{
   471  			desc: "subresource doesn't own the path anymore",
   472  			parent: []metav1.ManagedFieldsEntry{
   473  				{
   474  					Manager:    "test",
   475  					Operation:  metav1.ManagedFieldsOperationApply,
   476  					APIVersion: "apps/v1",
   477  					FieldsType: "FieldsV1",
   478  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   479  				},
   480  			},
   481  			subresource: []metav1.ManagedFieldsEntry{
   482  				{
   483  					Manager:     "scale",
   484  					Operation:   metav1.ManagedFieldsOperationUpdate,
   485  					APIVersion:  "autoscaling/v1",
   486  					FieldsType:  "FieldsV1",
   487  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:status":{"f:replicas":{}}}`)},
   488  					Subresource: "scale",
   489  				},
   490  			},
   491  			expected: []metav1.ManagedFieldsEntry{
   492  				{
   493  					Manager:    "test",
   494  					Operation:  metav1.ManagedFieldsOperationApply,
   495  					APIVersion: "apps/v1",
   496  					FieldsType: "FieldsV1",
   497  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   498  				},
   499  			},
   500  		},
   501  		{
   502  			desc: "Subresource steals all the fields of the parent resource",
   503  			parent: []metav1.ManagedFieldsEntry{
   504  				{
   505  					Manager:    "test",
   506  					Operation:  metav1.ManagedFieldsOperationApply,
   507  					APIVersion: "apps/v1",
   508  					FieldsType: "FieldsV1",
   509  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   510  				},
   511  			},
   512  			subresource: []metav1.ManagedFieldsEntry{
   513  				{
   514  					Manager:     "scale",
   515  					Operation:   metav1.ManagedFieldsOperationUpdate,
   516  					APIVersion:  "autoscaling/v1",
   517  					FieldsType:  "FieldsV1",
   518  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   519  					Subresource: "scale",
   520  				},
   521  			},
   522  			expected: []metav1.ManagedFieldsEntry{
   523  				{
   524  					Manager:     "scale",
   525  					Operation:   metav1.ManagedFieldsOperationUpdate,
   526  					APIVersion:  "apps/v1",
   527  					FieldsType:  "FieldsV1",
   528  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   529  					Subresource: "scale",
   530  				},
   531  			},
   532  		},
   533  		{
   534  			desc: "apply without stealing",
   535  			parent: []metav1.ManagedFieldsEntry{
   536  				{
   537  					Manager:    "test",
   538  					Operation:  metav1.ManagedFieldsOperationApply,
   539  					APIVersion: "apps/v1",
   540  					FieldsType: "FieldsV1",
   541  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   542  				},
   543  			},
   544  			subresource: []metav1.ManagedFieldsEntry{
   545  				{
   546  					Manager:    "test",
   547  					Operation:  metav1.ManagedFieldsOperationApply,
   548  					APIVersion: "autoscaling/v1",
   549  					FieldsType: "FieldsV1",
   550  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   551  				},
   552  				{
   553  					Manager:     "test",
   554  					Operation:   metav1.ManagedFieldsOperationApply,
   555  					APIVersion:  "autoscaling/v1",
   556  					FieldsType:  "FieldsV1",
   557  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   558  					Subresource: "scale",
   559  				},
   560  			},
   561  			expected: []metav1.ManagedFieldsEntry{
   562  				{
   563  					Manager:    "test",
   564  					Operation:  metav1.ManagedFieldsOperationApply,
   565  					APIVersion: "apps/v1",
   566  					FieldsType: "FieldsV1",
   567  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
   568  				},
   569  				{
   570  					Manager:     "test",
   571  					Operation:   metav1.ManagedFieldsOperationApply,
   572  					APIVersion:  "apps/v1",
   573  					FieldsType:  "FieldsV1",
   574  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   575  					Subresource: "scale",
   576  				},
   577  			},
   578  		},
   579  		{
   580  			desc: "drops the entry if the api version is unknown",
   581  			parent: []metav1.ManagedFieldsEntry{
   582  				{
   583  					Manager:    "test",
   584  					Operation:  metav1.ManagedFieldsOperationApply,
   585  					APIVersion: "apps/v1",
   586  					FieldsType: "FieldsV1",
   587  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   588  				},
   589  				{
   590  					Manager:    "another-manager",
   591  					Operation:  metav1.ManagedFieldsOperationApply,
   592  					APIVersion: "apps/v10",
   593  					FieldsType: "FieldsV1",
   594  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   595  				},
   596  			},
   597  			subresource: []metav1.ManagedFieldsEntry{
   598  				{
   599  					Manager:    "scale",
   600  					Operation:  metav1.ManagedFieldsOperationUpdate,
   601  					APIVersion: "autoscaling/v1",
   602  					FieldsType: "FieldsV1",
   603  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   604  				},
   605  			},
   606  			expected: []metav1.ManagedFieldsEntry{
   607  				{
   608  					Manager:    "scale",
   609  					Operation:  metav1.ManagedFieldsOperationUpdate,
   610  					APIVersion: "apps/v1",
   611  					FieldsType: "FieldsV1",
   612  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   613  				},
   614  			},
   615  		},
   616  	}
   617  
   618  	for _, test := range tests {
   619  		t.Run(test.desc, func(t *testing.T) {
   620  			handler := NewScaleHandler(
   621  				test.parent,
   622  				schema.GroupVersion{Group: "apps", Version: "v1"},
   623  				defaultMappings(),
   624  			)
   625  			parentEntries, err := handler.ToParent(test.subresource)
   626  			if err != nil {
   627  				t.Fatalf("test: %q - expected no error but got %v", test.desc, err)
   628  			}
   629  			if !reflect.DeepEqual(parentEntries, test.expected) {
   630  				t.Fatalf("test: %q - expected output to be:\n%v\n\nbut got:\n%v", test.desc, test.expected, parentEntries)
   631  			}
   632  		})
   633  	}
   634  }
   635  
   636  func TestTransformingManagedFieldsToParentMultiVersion(t *testing.T) {
   637  	tests := []struct {
   638  		desc         string
   639  		groupVersion schema.GroupVersion
   640  		mappings     ResourcePathMappings
   641  		parent       []metav1.ManagedFieldsEntry
   642  		subresource  []metav1.ManagedFieldsEntry
   643  		expected     []metav1.ManagedFieldsEntry
   644  	}{
   645  		{
   646  			desc:         "multi-version",
   647  			groupVersion: schema.GroupVersion{Group: "apps", Version: "v1"},
   648  			mappings: ResourcePathMappings{
   649  				"apps/v1": fieldpath.MakePathOrDie("spec", "the-replicas"),
   650  				"apps/v2": fieldpath.MakePathOrDie("spec", "not-the-replicas"),
   651  			},
   652  			parent: []metav1.ManagedFieldsEntry{
   653  				{
   654  					Manager:    "test",
   655  					Operation:  metav1.ManagedFieldsOperationApply,
   656  					APIVersion: "apps/v1",
   657  					FieldsType: "FieldsV1",
   658  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:the-replicas":{},"f:selector":{}}}`)},
   659  				},
   660  				{
   661  					Manager:    "test-other",
   662  					Operation:  metav1.ManagedFieldsOperationApply,
   663  					APIVersion: "apps/v2",
   664  					FieldsType: "FieldsV1",
   665  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:not-the-replicas":{},"f:selector":{}}}`)},
   666  				},
   667  			},
   668  			subresource: []metav1.ManagedFieldsEntry{
   669  				{
   670  					Manager:     "scale",
   671  					Operation:   metav1.ManagedFieldsOperationUpdate,
   672  					APIVersion:  "autoscaling/v1",
   673  					FieldsType:  "FieldsV1",
   674  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   675  					Subresource: "scale",
   676  				},
   677  			},
   678  			expected: []metav1.ManagedFieldsEntry{
   679  				{
   680  					Manager:    "test",
   681  					Operation:  metav1.ManagedFieldsOperationApply,
   682  					APIVersion: "apps/v1",
   683  					FieldsType: "FieldsV1",
   684  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   685  				},
   686  				{
   687  					Manager:    "test-other",
   688  					Operation:  metav1.ManagedFieldsOperationApply,
   689  					APIVersion: "apps/v2",
   690  					FieldsType: "FieldsV1",
   691  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   692  				},
   693  				{
   694  					Manager:     "scale",
   695  					Operation:   metav1.ManagedFieldsOperationUpdate,
   696  					APIVersion:  "apps/v1",
   697  					FieldsType:  "FieldsV1",
   698  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:the-replicas":{}}}`)},
   699  					Subresource: "scale",
   700  				},
   701  			},
   702  		},
   703  		{
   704  			desc:         "Custom resource without scale subresource, scaling a version with `scale`",
   705  			groupVersion: schema.GroupVersion{Group: "mygroup", Version: "v1"},
   706  			mappings: ResourcePathMappings{
   707  				"mygroup/v1": fieldpath.MakePathOrDie("spec", "the-replicas"),
   708  				"mygroup/v2": nil,
   709  			},
   710  			parent: []metav1.ManagedFieldsEntry{
   711  				{
   712  					Manager:    "test",
   713  					Operation:  metav1.ManagedFieldsOperationApply,
   714  					APIVersion: "mygroup/v1",
   715  					FieldsType: "FieldsV1",
   716  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:the-replicas":{},"f:selector":{}}}`)},
   717  				},
   718  				{
   719  					Manager:    "test-other",
   720  					Operation:  metav1.ManagedFieldsOperationApply,
   721  					APIVersion: "mygroup/v2",
   722  					FieldsType: "FieldsV1",
   723  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:test-other":{}}}`)},
   724  				},
   725  			},
   726  			subresource: []metav1.ManagedFieldsEntry{
   727  				{
   728  					Manager:     "scale",
   729  					Operation:   metav1.ManagedFieldsOperationUpdate,
   730  					APIVersion:  "autoscaling/v1",
   731  					FieldsType:  "FieldsV1",
   732  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
   733  					Subresource: "scale",
   734  				},
   735  			},
   736  			expected: []metav1.ManagedFieldsEntry{
   737  				{
   738  					Manager:    "test",
   739  					Operation:  metav1.ManagedFieldsOperationApply,
   740  					APIVersion: "mygroup/v1",
   741  					FieldsType: "FieldsV1",
   742  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
   743  				},
   744  				{
   745  					Manager:    "test-other",
   746  					Operation:  metav1.ManagedFieldsOperationApply,
   747  					APIVersion: "mygroup/v2",
   748  					FieldsType: "FieldsV1",
   749  					FieldsV1:   &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:test-other":{}}}`)},
   750  				},
   751  				{
   752  					Manager:     "scale",
   753  					Operation:   metav1.ManagedFieldsOperationUpdate,
   754  					APIVersion:  "mygroup/v1",
   755  					FieldsType:  "FieldsV1",
   756  					FieldsV1:    &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:the-replicas":{}}}`)},
   757  					Subresource: "scale",
   758  				},
   759  			},
   760  		},
   761  	}
   762  
   763  	for _, test := range tests {
   764  		t.Run(test.desc, func(t *testing.T) {
   765  			handler := NewScaleHandler(
   766  				test.parent,
   767  				test.groupVersion,
   768  				test.mappings,
   769  			)
   770  			parentEntries, err := handler.ToParent(test.subresource)
   771  			if err != nil {
   772  				t.Fatalf("test: %q - expected no error but got %v", test.desc, err)
   773  			}
   774  			if !reflect.DeepEqual(parentEntries, test.expected) {
   775  				t.Fatalf("test: %q - expected output to be:\n%v\n\nbut got:\n%v", test.desc, test.expected, parentEntries)
   776  			}
   777  		})
   778  	}
   779  }
   780  
   781  func defaultMappings() ResourcePathMappings {
   782  	return ResourcePathMappings{
   783  		"apps/v1": fieldpath.MakePathOrDie("spec", "replicas"),
   784  	}
   785  }
   786  

View as plain text