...

Source file src/sigs.k8s.io/kustomize/api/filters/patchstrategicmerge/patchstrategicmerge_test.go

Documentation: sigs.k8s.io/kustomize/api/filters/patchstrategicmerge

     1  // Copyright 2022 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package patchstrategicmerge
     5  
     6  import (
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	filtertest "sigs.k8s.io/kustomize/api/testutils/filtertest"
    12  	"sigs.k8s.io/kustomize/kyaml/yaml"
    13  )
    14  
    15  func TestFilter(t *testing.T) {
    16  	testCases := map[string]struct {
    17  		input    string
    18  		patch    *yaml.RNode
    19  		expected string
    20  	}{
    21  		"simple": {
    22  			input: `apiVersion: v1
    23  kind: Deployment
    24  metadata:
    25    name: clown
    26  spec:
    27    numReplicas: 1
    28  `,
    29  			patch: yaml.MustParse(`apiVersion: v1
    30  kind: Deployment
    31  metadata:
    32    name: clown
    33  spec:
    34    numReplicas: 999
    35  `),
    36  			expected: `apiVersion: v1
    37  kind: Deployment
    38  metadata:
    39    name: clown
    40  spec:
    41    numReplicas: 999
    42  `,
    43  		},
    44  		"nullMapEntry1": {
    45  			input: `
    46  apiVersion: example.com/v1
    47  kind: Foo
    48  metadata:
    49    name: my-foo
    50  spec:
    51    bar:
    52      B:
    53      C: Z
    54  `,
    55  			patch: yaml.MustParse(`
    56  apiVersion: example.com/v1
    57  kind: Foo
    58  metadata:
    59    name: my-foo
    60  spec:
    61    bar:
    62      C: Z
    63      D: W
    64    baz:
    65      hello: world
    66  `),
    67  			expected: `
    68  apiVersion: example.com/v1
    69  kind: Foo
    70  metadata:
    71    name: my-foo
    72  spec:
    73    bar:
    74      C: Z
    75      D: W
    76    baz:
    77      hello: world
    78  `,
    79  		},
    80  		"nullMapEntry2": {
    81  			input: `
    82  apiVersion: example.com/v1
    83  kind: Foo
    84  metadata:
    85    name: my-foo
    86  spec:
    87    bar:
    88      C: Z
    89      D: W
    90    baz:
    91      hello: world
    92  `,
    93  			patch: yaml.MustParse(`
    94  apiVersion: example.com/v1
    95  kind: Foo
    96  metadata:
    97    name: my-foo
    98  spec:
    99    bar:
   100      B:
   101      C: Z
   102  `),
   103  			expected: `
   104  apiVersion: example.com/v1
   105  kind: Foo
   106  metadata:
   107    name: my-foo
   108  spec:
   109    bar:
   110      C: Z
   111      D: W
   112    baz:
   113      hello: world
   114  `,
   115  		},
   116  		"simple patch": {
   117  			input: `
   118  apiVersion: apps/v1
   119  metadata:
   120    name: myDeploy
   121  kind: Deployment
   122  `,
   123  			patch: yaml.MustParse(`
   124  metadata:
   125    name: yourDeploy
   126  `),
   127  			expected: `
   128  apiVersion: apps/v1
   129  metadata:
   130    name: yourDeploy
   131  kind: Deployment
   132  `,
   133  		},
   134  		"container patch": {
   135  			input: `
   136  apiVersion: apps/v1
   137  metadata:
   138    name: myDeploy
   139  kind: Deployment
   140  spec:
   141    template:
   142      spec:
   143        containers:
   144        - name: foo1
   145        - name: foo2
   146        - name: foo3
   147  `,
   148  			patch: yaml.MustParse(`
   149  apiVersion: apps/v1
   150  metadata:
   151    name: myDeploy
   152  kind: Deployment
   153  spec:
   154    template:
   155      spec:
   156        containers:
   157        - name: foo0
   158  `),
   159  			expected: `
   160  apiVersion: apps/v1
   161  metadata:
   162    name: myDeploy
   163  kind: Deployment
   164  spec:
   165    template:
   166      spec:
   167        containers:
   168        - name: foo0
   169        - name: foo1
   170        - name: foo2
   171        - name: foo3
   172  `,
   173  		},
   174  		"volumes patch": {
   175  			input: `
   176  apiVersion: apps/v1
   177  metadata:
   178    name: myDeploy
   179  kind: Deployment
   180  spec:
   181    template:
   182      spec:
   183        volumes:
   184        - name: foo1
   185        - name: foo2
   186        - name: foo3
   187  `,
   188  			patch: yaml.MustParse(`
   189  apiVersion: apps/v1
   190  metadata:
   191    name: myDeploy
   192  kind: Deployment
   193  spec:
   194    template:
   195      spec:
   196        volumes:
   197        - name: foo0
   198  `),
   199  			expected: `
   200  apiVersion: apps/v1
   201  metadata:
   202    name: myDeploy
   203  kind: Deployment
   204  spec:
   205    template:
   206      spec:
   207        volumes:
   208        - name: foo0
   209        - name: foo1
   210        - name: foo2
   211        - name: foo3
   212  `,
   213  		},
   214  		"nested patch": {
   215  			input: `
   216  apiVersion: apps/v1
   217  metadata:
   218    name: myDeploy
   219  kind: Deployment
   220  spec:
   221    containers:
   222    - name: nginx
   223      args:
   224      - abc
   225  `,
   226  			patch: yaml.MustParse(`
   227  spec:
   228    containers:
   229    - name: nginx
   230      args:
   231      - def
   232  `),
   233  			expected: `
   234  apiVersion: apps/v1
   235  metadata:
   236    name: myDeploy
   237  kind: Deployment
   238  spec:
   239    containers:
   240    - name: nginx
   241      args:
   242      - def
   243  `,
   244  		},
   245  		"remove mapping - directive": {
   246  			input: `
   247  apiVersion: apps/v1
   248  kind: Deployment
   249  metadata:
   250    name: myDeploy
   251  spec:
   252    template:
   253      spec:
   254        containers:
   255        - name: test
   256          image: test
   257  `,
   258  			patch: yaml.MustParse(`
   259  apiVersion: apps/v1
   260  kind: Deployment
   261  metadata:
   262    name: myDeploy
   263  spec:
   264    template:
   265      spec:
   266        containers:
   267        - name: test
   268          image: test
   269          $patch: delete   
   270  `),
   271  			expected: `
   272  apiVersion: apps/v1
   273  kind: Deployment
   274  metadata:
   275    name: myDeploy
   276  spec:
   277    template:
   278      spec:
   279        containers: []
   280  `,
   281  		},
   282  		"replace mapping - directive": {
   283  			input: `
   284  apiVersion: apps/v1
   285  kind: Deployment
   286  metadata:
   287    name: myDeploy
   288  spec:
   289    template:
   290      spec:
   291        containers:
   292        - name: test
   293          image: test
   294  `,
   295  			patch: yaml.MustParse(`
   296  apiVersion: apps/v1
   297  kind: Deployment
   298  metadata:
   299    name: myDeploy
   300  spec:
   301    template:
   302      spec:
   303        $patch: replace
   304        containers:
   305        - name: new
   306  `),
   307  			expected: `
   308  apiVersion: apps/v1
   309  kind: Deployment
   310  metadata:
   311    name: myDeploy
   312  spec:
   313    template:
   314      spec:
   315        containers:
   316        - name: new
   317  `,
   318  		},
   319  		"merge mapping - directive": {
   320  			input: `
   321  apiVersion: apps/v1
   322  kind: Deployment
   323  metadata:
   324    name: myDeploy
   325  spec:
   326    template:
   327      spec:
   328        containers:
   329        - name: test
   330          image: test
   331  `,
   332  			patch: yaml.MustParse(`
   333  apiVersion: apps/v1
   334  kind: Deployment
   335  metadata:
   336    name: myDeploy
   337  spec:
   338    template:
   339      spec:
   340        containers:
   341        - name: test
   342          image: test1
   343          $patch: merge   
   344  `),
   345  			expected: `
   346  apiVersion: apps/v1
   347  kind: Deployment
   348  metadata:
   349    name: myDeploy
   350  spec:
   351    template:
   352      spec:
   353        containers:
   354        - name: test
   355          image: test1
   356  `,
   357  		},
   358  		"remove list - directive": {
   359  			input: `
   360  apiVersion: apps/v1
   361  kind: Deployment
   362  metadata:
   363    name: myDeploy
   364  spec:
   365    template:
   366      spec:
   367        containers:
   368        - name: test
   369          image: test
   370  `,
   371  			patch: yaml.MustParse(`
   372  apiVersion: apps/v1
   373  kind: Deployment
   374  metadata:
   375    name: myDeploy
   376  spec:
   377    template:
   378      spec:
   379        containers:
   380        - whatever
   381        - $patch: delete
   382  `),
   383  			expected: `
   384  apiVersion: apps/v1
   385  kind: Deployment
   386  metadata:
   387    name: myDeploy
   388  spec:
   389    template:
   390      spec: {}
   391  `,
   392  		},
   393  		"replace list - directive": {
   394  			input: `
   395  apiVersion: apps/v1
   396  kind: Deployment
   397  metadata:
   398    name: myDeploy
   399  spec:
   400    template:
   401      spec:
   402        containers:
   403        - name: test
   404          image: test
   405  `,
   406  			patch: yaml.MustParse(`
   407  apiVersion: apps/v1
   408  kind: Deployment
   409  metadata:
   410    name: myDeploy
   411  spec:
   412    template:
   413      spec:
   414        containers:
   415        - name: replace
   416          image: replace
   417        - $patch: replace   
   418  `),
   419  			expected: `
   420  apiVersion: apps/v1
   421  kind: Deployment
   422  metadata:
   423    name: myDeploy
   424  spec:
   425    template:
   426      spec:
   427        containers:
   428        - name: replace
   429          image: replace
   430  `,
   431  		},
   432  		"merge list - directive": {
   433  			input: `
   434  apiVersion: apps/v1
   435  kind: Deployment
   436  metadata:
   437    name: myDeploy
   438  spec:
   439    template:
   440      spec:
   441        containers:
   442        - name: test
   443          image: test
   444  `,
   445  			patch: yaml.MustParse(`
   446  apiVersion: apps/v1
   447  kind: Deployment
   448  metadata:
   449    name: myDeploy
   450  spec:
   451    template:
   452      spec:
   453        containers:
   454        - name: test2
   455          image: test2
   456        - $patch: merge   
   457  `),
   458  			expected: `
   459  apiVersion: apps/v1
   460  kind: Deployment
   461  metadata:
   462    name: myDeploy
   463  spec:
   464    template:
   465      spec:
   466        containers:
   467        - name: test2
   468          image: test2
   469        - name: test
   470          image: test
   471  `,
   472  		},
   473  		"list map keys - add a port, no names": {
   474  			input: `
   475  apiVersion: apps/v1
   476  kind: Deployment
   477  metadata:
   478   name: test-deployment
   479  spec:
   480   template:
   481     spec:
   482       containers:
   483       - image: test-image
   484         name: test-deployment
   485         ports:
   486         - containerPort: 8080
   487           protocol: TCP
   488  `,
   489  			patch: yaml.MustParse(`
   490  apiVersion: apps/v1
   491  kind: Deployment
   492  metadata:
   493   name: test-deployment
   494  spec:
   495   template:
   496     spec:
   497       containers:
   498       - image: test-image
   499         name: test-deployment
   500         ports:
   501         - containerPort: 8080
   502           protocol: UDP
   503         - containerPort: 80
   504           protocol: UDP
   505  `),
   506  			expected: `
   507  apiVersion: apps/v1
   508  kind: Deployment
   509  metadata:
   510    name: test-deployment
   511  spec:
   512    template:
   513      spec:
   514        containers:
   515        - image: test-image
   516          name: test-deployment
   517          ports:
   518          - containerPort: 8080
   519            protocol: UDP
   520          - containerPort: 80
   521            protocol: UDP
   522          - containerPort: 8080
   523            protocol: TCP
   524  `,
   525  		},
   526  		"list map keys - add name to port": {
   527  			input: `
   528  apiVersion: apps/v1
   529  kind: Deployment
   530  metadata:
   531   name: test-deployment
   532  spec:
   533   template:
   534     spec:
   535       containers:
   536       - image: test-image
   537         name: test-deployment
   538         ports:
   539         - containerPort: 8080
   540           protocol: UDP
   541         - containerPort: 8080
   542           protocol: TCP
   543  `,
   544  			patch: yaml.MustParse(`
   545  apiVersion: apps/v1
   546  kind: Deployment
   547  metadata:
   548   name: test-deployment
   549  spec:
   550   template:
   551     spec:
   552       containers:
   553       - image: test-image
   554         name: test-deployment
   555         ports:
   556         - containerPort: 8080
   557           protocol: UDP
   558           name: UDP-name-patch
   559  `),
   560  			expected: `
   561  apiVersion: apps/v1
   562  kind: Deployment
   563  metadata:
   564    name: test-deployment
   565  spec:
   566    template:
   567      spec:
   568        containers:
   569        - image: test-image
   570          name: test-deployment
   571          ports:
   572          - containerPort: 8080
   573            protocol: UDP
   574            name: UDP-name-patch
   575          - containerPort: 8080
   576            protocol: TCP
   577  `,
   578  		},
   579  		"list map keys - replace port name": {
   580  			input: `
   581  apiVersion: apps/v1
   582  kind: Deployment
   583  metadata:
   584   name: test-deployment
   585  spec:
   586   template:
   587     spec:
   588       containers:
   589       - image: test-image
   590         name: test-deployment
   591         ports:
   592         - containerPort: 8080
   593           protocol: UDP
   594           name: UDP-name-original
   595         - containerPort: 8080
   596           protocol: TCP
   597           name: TCP-name-original
   598  `,
   599  			patch: yaml.MustParse(`
   600  apiVersion: apps/v1
   601  kind: Deployment
   602  metadata:
   603   name: test-deployment
   604  spec:
   605   template:
   606     spec:
   607       containers:
   608       - image: test-image
   609         name: test-deployment
   610         ports:
   611         - containerPort: 8080
   612           protocol: UDP
   613           name: UDP-name-patch
   614  `),
   615  			expected: `
   616  apiVersion: apps/v1
   617  kind: Deployment
   618  metadata:
   619    name: test-deployment
   620  spec:
   621    template:
   622      spec:
   623        containers:
   624        - image: test-image
   625          name: test-deployment
   626          ports:
   627          - containerPort: 8080
   628            protocol: UDP
   629            name: UDP-name-patch
   630          - containerPort: 8080
   631            protocol: TCP
   632            name: TCP-name-original
   633  `,
   634  		},
   635  		"list map keys - add a port, no protocol": {
   636  			input: `
   637  apiVersion: apps/v1
   638  kind: Deployment
   639  metadata:
   640   name: test-deployment
   641  spec:
   642   template:
   643     spec:
   644       containers:
   645       - image: test-image
   646         name: test-deployment
   647         ports:
   648         - containerPort: 8080
   649  `,
   650  			patch: yaml.MustParse(`
   651  apiVersion: apps/v1
   652  kind: Deployment
   653  metadata:
   654   name: test-deployment
   655  spec:
   656   template:
   657     spec:
   658       containers:
   659       - image: test-image
   660         name: test-deployment
   661         ports:
   662         - containerPort: 80
   663  `),
   664  			expected: `
   665  apiVersion: apps/v1
   666  kind: Deployment
   667  metadata:
   668    name: test-deployment
   669  spec:
   670    template:
   671      spec:
   672        containers:
   673        - image: test-image
   674          name: test-deployment
   675          ports:
   676          - containerPort: 80
   677          - containerPort: 8080
   678  `,
   679  		},
   680  
   681  		// Test for issue #3513
   682  		// Currently broken; when one port has only containerPort, the output
   683  		// should not merge containerPort 8301 together
   684  		// This occurs because when protocol is missing on the first port,
   685  		// the merge code uses [containerPort] as the merge key rather than
   686  		// [containerPort, protocol]
   687  		"list map keys - protocol only present on some ports": {
   688  			input: `
   689  apiVersion: apps/v1
   690  kind: Deployment
   691  metadata:
   692    name: test-deployment
   693  spec:
   694    template:
   695      spec:
   696        containers:
   697        - name: consul
   698          image: "dashicorp/consul:1.9.1"
   699          ports:
   700          - containerPort: 8500
   701            name: http
   702          - containerPort: 8301
   703            protocol: "TCP"
   704          - containerPort: 8301
   705            protocol: "UDP"
   706  `,
   707  			patch: yaml.MustParse(`
   708  apiVersion: apps/v1
   709  kind: Deployment
   710  metadata:
   711    name: test-deployment
   712    labels:
   713      test: label
   714  `),
   715  			expected: `
   716  apiVersion: apps/v1
   717  kind: Deployment
   718  metadata:
   719    name: test-deployment
   720    labels:
   721      test: label
   722  spec:
   723    template:
   724      spec:
   725        containers:
   726        - name: consul
   727          image: "dashicorp/consul:1.9.1"
   728          ports:
   729          - containerPort: 8500
   730            name: http
   731          - containerPort: 8301
   732            protocol: "TCP"
   733          - containerPort: 8301
   734            protocol: "UDP"
   735  `,
   736  		},
   737  
   738  		// Issue #4628
   739  		"should retain existing null values in targets": {
   740  			input: `
   741  apiVersion: helm.toolkit.fluxcd.io/v2beta1
   742  kind: HelmRelease
   743  metadata:
   744    name: chart
   745  spec:
   746    releaseName: helm-chart
   747    timeout: 15m
   748    values:
   749      chart:
   750        replicaCount: null
   751        autoscaling: true
   752  `,
   753  			patch: yaml.MustParse(`
   754  apiVersion: helm.toolkit.fluxcd.io/v2beta1
   755  kind: HelmRelease
   756  metadata:
   757    name: chart
   758  spec:
   759    releaseName: helm-chart
   760    timeout: 15m
   761    values:
   762      deepgram-api:
   763        some: value
   764  `),
   765  			expected: `
   766  apiVersion: helm.toolkit.fluxcd.io/v2beta1
   767  kind: HelmRelease
   768  metadata:
   769    name: chart
   770  spec:
   771    releaseName: helm-chart
   772    timeout: 15m
   773    values:
   774      chart:
   775        replicaCount: null
   776        autoscaling: true
   777      deepgram-api:
   778        some: value
   779  `,
   780  		},
   781  
   782  		// Issue #4928
   783  		"support numeric keys": {
   784  			input: `
   785  apiVersion: v1
   786  kind: ConfigMap
   787  metadata:
   788    name: blabla
   789    namespace: blabla-ns
   790  data:
   791    "6443": "foobar"
   792  `,
   793  			patch: yaml.MustParse(`
   794  apiVersion: v1
   795  kind: ConfigMap
   796  metadata:
   797    name: blabla
   798    namespace: blabla-ns
   799  data:
   800    "6443": "barfoo"
   801    "9110": "foo-foo"
   802  `),
   803  			expected: `
   804  apiVersion: v1
   805  kind: ConfigMap
   806  metadata:
   807    name: blabla
   808    namespace: blabla-ns
   809  data:
   810    "6443": "barfoo"
   811    "9110": "foo-foo"
   812  `,
   813  		},
   814  
   815  		"honor different key style one": {
   816  			input: `
   817  apiVersion: v1
   818  kind: ConfigMap
   819  metadata:
   820    name: blabla
   821    namespace: blabla-ns
   822  data:
   823    '6443': "foobar"
   824  `,
   825  			patch: yaml.MustParse(`
   826  apiVersion: v1
   827  kind: ConfigMap
   828  metadata:
   829    name: blabla
   830    namespace: blabla-ns
   831  data:
   832    "6443": "barfoo"
   833    9110: "foo-foo"
   834  `),
   835  			expected: `
   836  apiVersion: v1
   837  kind: ConfigMap
   838  metadata:
   839    name: blabla
   840    namespace: blabla-ns
   841  data:
   842    '6443': "barfoo"
   843    9110: "foo-foo"
   844  `,
   845  		},
   846  
   847  		"honor different key style two": {
   848  			input: `
   849  apiVersion: v1
   850  kind: ConfigMap
   851  metadata:
   852    name: blabla
   853    namespace: blabla-ns
   854  data:
   855    "6443": "foobar"
   856  `,
   857  			patch: yaml.MustParse(`
   858  apiVersion: v1
   859  kind: ConfigMap
   860  metadata:
   861    name: blabla
   862    namespace: blabla-ns
   863  data:
   864    "6443": "barfoo"
   865    '9110': "foo-foo"
   866  `),
   867  			expected: `
   868  apiVersion: v1
   869  kind: ConfigMap
   870  metadata:
   871    name: blabla
   872    namespace: blabla-ns
   873  data:
   874    "6443": "barfoo"
   875    '9110': "foo-foo"
   876  `,
   877  		},
   878  
   879  		"different key types": {
   880  			input: `
   881  apiVersion: v1
   882  kind: ConfigMap
   883  metadata:
   884    name: blabla
   885    namespace: blabla-ns
   886  data:
   887    "6443": "key-string-double-quoted"
   888  `,
   889  			patch: yaml.MustParse(`
   890  apiVersion: v1
   891  kind: ConfigMap
   892  metadata:
   893    name: blabla
   894    namespace: blabla-ns
   895  data:
   896    6443: "key-int"
   897  `),
   898  			expected: `
   899  apiVersion: v1
   900  kind: ConfigMap
   901  metadata:
   902    name: blabla
   903    namespace: blabla-ns
   904  data:
   905    "6443": "key-int"
   906  `,
   907  		},
   908  	}
   909  
   910  	for tn, tc := range testCases {
   911  		t.Run(tn, func(t *testing.T) {
   912  			f := Filter{
   913  				Patch: tc.patch,
   914  			}
   915  			if !assert.Equal(t,
   916  				strings.TrimSpace(tc.expected),
   917  				strings.TrimSpace(
   918  					filtertest.RunFilter(t, tc.input, f))) {
   919  				t.FailNow()
   920  			}
   921  		})
   922  	}
   923  }
   924  

View as plain text