...

Source file src/sigs.k8s.io/structured-merge-diff/v4/merge/duplicates_test.go

Documentation: sigs.k8s.io/structured-merge-diff/v4/merge

     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 merge_test
    18  
    19  import (
    20  	"testing"
    21  
    22  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    23  	. "sigs.k8s.io/structured-merge-diff/v4/internal/fixture"
    24  	"sigs.k8s.io/structured-merge-diff/v4/merge"
    25  	"sigs.k8s.io/structured-merge-diff/v4/typed"
    26  )
    27  
    28  var duplicatesParser = func() Parser {
    29  	parser, err := typed.NewParser(`types:
    30  - name: type
    31    map:
    32      fields:
    33        - name: list
    34          type:
    35            namedType: associativeList
    36        - name: unrelated
    37          type:
    38            scalar: numeric
    39        - name: set
    40          type:
    41            namedType: set
    42  - name: associativeList
    43    list:
    44      elementType:
    45        namedType: myElement
    46      elementRelationship: associative
    47      keys:
    48      - name
    49  - name: myElement
    50    map:
    51      fields:
    52      - name: name
    53        type:
    54          scalar: string
    55      - name: value1
    56        type:
    57          scalar: numeric
    58      - name: value2
    59        type:
    60          scalar: numeric
    61  - name: set
    62    list:
    63      elementType:
    64        scalar: numeric
    65      elementRelationship: associative
    66  `)
    67  	if err != nil {
    68  		panic(err)
    69  	}
    70  	return SameVersionParser{T: parser.Type("type")}
    71  }()
    72  
    73  func TestDuplicates(t *testing.T) {
    74  	tests := map[string]TestCase{
    75  		"sets/ownership/duplicates": {
    76  			Ops: []Operation{
    77  				Update{
    78  					Manager: "updater-one",
    79  					Object: `
    80  						set: [1, 1, 3, 4]
    81  					`,
    82  					APIVersion: "v1",
    83  				},
    84  			},
    85  			Managed: fieldpath.ManagedFields{
    86  				"updater-one": fieldpath.NewVersionedSet(
    87  					_NS(
    88  						_P("set"),
    89  						_P("set", _V(1)),
    90  						_P("set", _V(3)),
    91  						_P("set", _V(4)),
    92  					),
    93  					"v1",
    94  					false,
    95  				),
    96  			},
    97  		},
    98  		"sets/ownership/add_duplicate": {
    99  			Ops: []Operation{
   100  				Update{
   101  					Manager: "updater-one",
   102  					Object: `
   103  						set: [1, 3, 4]
   104  					`,
   105  					APIVersion: "v1",
   106  				},
   107  				Update{
   108  					Manager: "updater-two",
   109  					Object: `
   110  						set: [1, 1, 3, 4]
   111  					`,
   112  					APIVersion: "v1",
   113  				},
   114  			},
   115  			Managed: fieldpath.ManagedFields{
   116  				"updater-one": fieldpath.NewVersionedSet(
   117  					_NS(
   118  						_P("set"),
   119  						_P("set", _V(3)),
   120  						_P("set", _V(4)),
   121  					),
   122  					"v1",
   123  					false,
   124  				),
   125  				"updater-two": fieldpath.NewVersionedSet(
   126  					_NS(
   127  						_P("set", _V(1)),
   128  					),
   129  					"v1",
   130  					false,
   131  				),
   132  			},
   133  		},
   134  		"sets/ownership/remove_duplicate": {
   135  			Ops: []Operation{
   136  				Update{
   137  					Manager: "updater-one",
   138  					Object: `
   139  						set: [1, 1, 3, 4]
   140  					`,
   141  					APIVersion: "v1",
   142  				},
   143  				Update{
   144  					Manager: "updater-two",
   145  					Object: `
   146  						set: [1, 3, 4]
   147  					`,
   148  					APIVersion: "v1",
   149  				},
   150  			},
   151  			Managed: fieldpath.ManagedFields{
   152  				"updater-one": fieldpath.NewVersionedSet(
   153  					_NS(
   154  						_P("set"),
   155  						_P("set", _V(3)),
   156  						_P("set", _V(4)),
   157  					),
   158  					"v1",
   159  					false,
   160  				),
   161  				"updater-two": fieldpath.NewVersionedSet(
   162  					_NS(
   163  						_P("set", _V(1)),
   164  					),
   165  					"v1",
   166  					false,
   167  				),
   168  			},
   169  		},
   170  		"sets/merging/remove_duplicate": {
   171  			Ops: []Operation{
   172  				Update{
   173  					Manager: "updater",
   174  					Object: `
   175  						set: [1, 1, 3, 4]
   176  					`,
   177  					APIVersion: "v1",
   178  				},
   179  				Apply{
   180  					Manager: "applier",
   181  					Object: `
   182  						set: [1]
   183  					`,
   184  					APIVersion: "v1",
   185  					Conflicts: merge.Conflicts{
   186  						{Manager: "updater", Path: _P("set", _V(1))},
   187  					},
   188  				},
   189  				ForceApply{
   190  					Manager: "applier",
   191  					Object: `
   192  						set: [1]
   193  					`,
   194  					APIVersion: "v1",
   195  				},
   196  			},
   197  			Object: `
   198  				set: [1, 3, 4]
   199  			`,
   200  			APIVersion: "v1",
   201  			Managed: fieldpath.ManagedFields{
   202  				"updater": fieldpath.NewVersionedSet(
   203  					_NS(
   204  						_P("set"),
   205  						_P("set", _V(3)),
   206  						_P("set", _V(4)),
   207  					),
   208  					"v1",
   209  					false,
   210  				),
   211  				"applier": fieldpath.NewVersionedSet(
   212  					_NS(
   213  						_P("set", _V(1)),
   214  					),
   215  					"v1",
   216  					true,
   217  				),
   218  			},
   219  		},
   220  		"sets/merging/ignore_duplicate": {
   221  			Ops: []Operation{
   222  				Update{
   223  					Manager: "updater",
   224  					Object: `
   225  						set: [1, 1, 3, 4]
   226  					`,
   227  					APIVersion: "v1",
   228  				},
   229  				Apply{
   230  					Manager: "applier",
   231  					Object: `
   232  						set: [5]
   233  					`,
   234  					APIVersion: "v1",
   235  				},
   236  			},
   237  			Object: `
   238  				set: [1, 1, 3, 4, 5]
   239  			`,
   240  			APIVersion: "v1",
   241  			Managed: fieldpath.ManagedFields{
   242  				"updater": fieldpath.NewVersionedSet(
   243  					_NS(
   244  						_P("set"),
   245  						_P("set", _V(1)),
   246  						_P("set", _V(3)),
   247  						_P("set", _V(4)),
   248  					),
   249  					"v1",
   250  					false,
   251  				),
   252  				"applier": fieldpath.NewVersionedSet(
   253  					_NS(
   254  						_P("set", _V(5)),
   255  					),
   256  					"v1",
   257  					true,
   258  				),
   259  			},
   260  		},
   261  		"list/ownership/duplicated_items": {
   262  			Ops: []Operation{
   263  				Update{
   264  					Manager: "updater",
   265  					Object: `
   266  						list:
   267  						- name: a
   268  						  value1: 1
   269  						- name: a
   270  						  value1: 2
   271  						- name: b
   272  						  value1: 3
   273  					`,
   274  					APIVersion: "v1",
   275  				},
   276  			},
   277  			// `name: a` is only owned once.
   278  			Managed: fieldpath.ManagedFields{
   279  				"updater": fieldpath.NewVersionedSet(
   280  					_NS(
   281  						_P("list"),
   282  						_P("list", _KBF("name", "a")),
   283  						_P("list", _KBF("name", "b")),
   284  						_P("list", _KBF("name", "b"), "name"),
   285  						_P("list", _KBF("name", "b"), "value1"),
   286  					),
   287  					"v1",
   288  					false,
   289  				),
   290  			},
   291  		},
   292  		"list/ownership/change_duplicated_items": {
   293  			Ops: []Operation{
   294  				Update{
   295  					Manager: "updater-one",
   296  					Object: `
   297  						list:
   298  						- name: a
   299  						  value1: 1
   300  						- name: a
   301  						  value1: 2
   302  						- name: b
   303  						  value1: 3
   304  					`,
   305  					APIVersion: "v1",
   306  				},
   307  				Update{
   308  					Manager: "updater-two",
   309  					Object: `
   310  						list:
   311  						- name: a
   312  						  value1: 1
   313  						- name: a
   314  						  value1: 3
   315  						- name: b
   316  						  value1: 3
   317  					`,
   318  					APIVersion: "v1",
   319  				},
   320  			},
   321  			// `name: a` is only owned once, by actor who changed some of it.
   322  			Managed: fieldpath.ManagedFields{
   323  				"updater-one": fieldpath.NewVersionedSet(
   324  					_NS(
   325  						_P("list"),
   326  						_P("list", _KBF("name", "b")),
   327  						_P("list", _KBF("name", "b"), "name"),
   328  						_P("list", _KBF("name", "b"), "value1"),
   329  					),
   330  					"v1",
   331  					false,
   332  				),
   333  				"updater-two": fieldpath.NewVersionedSet(
   334  					_NS(
   335  						_P("list", _KBF("name", "a")),
   336  					),
   337  					"v1",
   338  					false,
   339  				),
   340  			},
   341  		},
   342  		"list/ownership/change_fields_duplicated_items": {
   343  			Ops: []Operation{
   344  				Update{
   345  					Manager: "updater-one",
   346  					Object: `
   347  						list:
   348  						- name: a
   349  						  value1: 1
   350  						- name: a
   351  						  value1: 2
   352  						- name: b
   353  						  value1: 3
   354  					`,
   355  					APIVersion: "v1",
   356  				},
   357  				Update{
   358  					Manager: "updater-two",
   359  					Object: `
   360  						list:
   361  						- name: a
   362  						  value1: 1
   363  						- name: a
   364  						  value1: 2
   365  						  value2: 3 # New field
   366  						- name: b
   367  						  value1: 3
   368  					`,
   369  					APIVersion: "v1",
   370  				},
   371  			},
   372  			Managed: fieldpath.ManagedFields{
   373  				"updater-one": fieldpath.NewVersionedSet(
   374  					_NS(
   375  						_P("list"),
   376  						_P("list", _KBF("name", "b")),
   377  						_P("list", _KBF("name", "b"), "name"),
   378  						_P("list", _KBF("name", "b"), "value1"),
   379  					),
   380  					"v1",
   381  					false,
   382  				),
   383  				"updater-two": fieldpath.NewVersionedSet(
   384  					_NS(
   385  						_P("list", _KBF("name", "a")),
   386  					),
   387  					"v1",
   388  					false,
   389  				),
   390  			},
   391  		},
   392  		"list/ownership/add_duplicated_items_different_field": {
   393  			Ops: []Operation{
   394  				Update{
   395  					Manager: "updater-one",
   396  					Object: `
   397  						list:
   398  						- name: a
   399  						  value1: 1
   400  						- name: b
   401  						  value1: 3
   402  					`,
   403  					APIVersion: "v1",
   404  				},
   405  				Update{
   406  					Manager: "updater-two",
   407  					Object: `
   408  						list:
   409  						- name: a
   410  						  value1: 1
   411  						- name: a
   412  						  value2: 3 # New field
   413  						- name: b
   414  						  value1: 3
   415  					`,
   416  					APIVersion: "v1",
   417  				},
   418  			},
   419  			Managed: fieldpath.ManagedFields{
   420  				"updater-one": fieldpath.NewVersionedSet(
   421  					_NS(
   422  						_P("list"),
   423  						_P("list", _KBF("name", "b")),
   424  						_P("list", _KBF("name", "b"), "name"),
   425  						_P("list", _KBF("name", "b"), "value1"),
   426  					),
   427  					"v1",
   428  					false,
   429  				),
   430  				"updater-two": fieldpath.NewVersionedSet(
   431  					_NS(
   432  						_P("list", _KBF("name", "a")),
   433  					),
   434  					"v1",
   435  					false,
   436  				),
   437  			},
   438  		},
   439  		"list/ownership/add_unrelated_to_list_with_duplicates": {
   440  			Ops: []Operation{
   441  				Update{
   442  					Manager: "updater-one",
   443  					Object: `
   444  						list:
   445  						- name: a
   446  						  value1: 1
   447  						- name: a
   448  						  value1: 2
   449  					`,
   450  					APIVersion: "v1",
   451  				},
   452  				Update{
   453  					Manager: "updater-two",
   454  					Object: `
   455  						list:
   456  						- name: a
   457  						  value1: 1
   458  						- name: a
   459  						  value1: 2
   460  						- name: b
   461  						  value1: 3
   462  					`,
   463  					APIVersion: "v1",
   464  				},
   465  			},
   466  			Managed: fieldpath.ManagedFields{
   467  				"updater-one": fieldpath.NewVersionedSet(
   468  					_NS(
   469  						_P("list"),
   470  						_P("list", _KBF("name", "a")),
   471  					),
   472  					"v1",
   473  					false,
   474  				),
   475  				"updater-two": fieldpath.NewVersionedSet(
   476  					_NS(
   477  						_P("list", _KBF("name", "b")),
   478  						_P("list", _KBF("name", "b"), "name"),
   479  						_P("list", _KBF("name", "b"), "value1"),
   480  					),
   481  					"v1",
   482  					false,
   483  				),
   484  			},
   485  		},
   486  		"list/merge/unrelated_with_duplicated_items": {
   487  			Ops: []Operation{
   488  				Update{
   489  					Manager: "updater",
   490  					Object: `
   491  						list:
   492  						- name: a
   493  						  value1: 1
   494  						- name: a
   495  						  value1: 2
   496  						- name: b
   497  						  value1: 3
   498  					`,
   499  					APIVersion: "v1",
   500  				},
   501  				ForceApply{
   502  					Manager: "applier",
   503  					Object: `
   504  						unrelated: 5
   505  					`,
   506  					APIVersion: "v1",
   507  				},
   508  			},
   509  			Object: `
   510  				list:
   511  				- name: a
   512  				  value1: 1
   513  				- name: a
   514  				  value1: 2
   515  				- name: b
   516  				  value1: 3
   517  				unrelated: 5
   518  			`,
   519  			APIVersion: "v1",
   520  			Managed: fieldpath.ManagedFields{
   521  				"updater": fieldpath.NewVersionedSet(
   522  					_NS(
   523  						_P("list"),
   524  						_P("list", _KBF("name", "a")),
   525  						_P("list", _KBF("name", "b")),
   526  						_P("list", _KBF("name", "b"), "name"),
   527  						_P("list", _KBF("name", "b"), "value1"),
   528  					),
   529  					"v1",
   530  					false,
   531  				),
   532  				"applier": fieldpath.NewVersionedSet(
   533  					_NS(
   534  						_P("unrelated"),
   535  					),
   536  					"v1",
   537  					true,
   538  				),
   539  			},
   540  		},
   541  		// TODO: Owning the key is a little messed-up.
   542  		"list/merge/change_duplicated_item": {
   543  			Ops: []Operation{
   544  				Update{
   545  					Manager: "updater",
   546  					Object: `
   547  						list:
   548  						- name: a
   549  						  value1: 1
   550  						- name: a
   551  						  value1: 2
   552  						- name: b
   553  						  value1: 3
   554  					`,
   555  					APIVersion: "v1",
   556  				},
   557  				Apply{
   558  					Manager: "applier",
   559  					Object: `
   560  						list:
   561  						- name: a
   562  						  value1: 3
   563  					`,
   564  					APIVersion: "v1",
   565  					Conflicts: merge.Conflicts{
   566  						{Manager: "updater", Path: _P("list", _KBF("name", "a"))},
   567  					},
   568  				},
   569  				ForceApply{
   570  					Manager: "applier",
   571  					Object: `
   572  						list:
   573  						- name: a
   574  						  value1: 3
   575  					`,
   576  					APIVersion: "v1",
   577  				},
   578  			},
   579  			Object: `
   580  				list:
   581  				- name: a
   582  				  value1: 3
   583  				- name: b
   584  				  value1: 3
   585  			`,
   586  			APIVersion: "v1",
   587  			Managed: fieldpath.ManagedFields{
   588  				"updater": fieldpath.NewVersionedSet(
   589  					_NS(
   590  						_P("list"),
   591  						_P("list", _KBF("name", "b")),
   592  						_P("list", _KBF("name", "b"), "name"),
   593  						_P("list", _KBF("name", "b"), "value1"),
   594  					),
   595  					"v1",
   596  					false,
   597  				),
   598  				"applier": fieldpath.NewVersionedSet(
   599  					_NS(
   600  						_P("list", _KBF("name", "a")),
   601  						_P("list", _KBF("name", "a"), "name"),
   602  						_P("list", _KBF("name", "a"), "value1"),
   603  					),
   604  					"v1",
   605  					true,
   606  				),
   607  			},
   608  		},
   609  
   610  		"list/merge/unchanged_duplicated_item": {
   611  			Ops: []Operation{
   612  				Update{
   613  					Manager: "updater",
   614  					Object: `
   615  						list:
   616  						- name: a
   617  						  value1: 1
   618  						- name: a
   619  						  value1: 2
   620  						- name: b
   621  						  value1: 3
   622  					`,
   623  					APIVersion: "v1",
   624  				},
   625  				Apply{
   626  					Manager: "applier",
   627  					Object: `
   628  						list:
   629  						- name: a
   630  						  value1: 2
   631  					`,
   632  					APIVersion: "v1",
   633  					Conflicts: merge.Conflicts{
   634  						{Manager: "updater", Path: _P("list", _KBF("name", "a"))},
   635  					},
   636  				},
   637  				ForceApply{
   638  					Manager: "applier",
   639  					Object: `
   640  						list:
   641  						- name: a
   642  						  value1: 3
   643  					`,
   644  					APIVersion: "v1",
   645  				},
   646  			},
   647  			Object: `
   648  				list:
   649  				- name: a
   650  				  value1: 3
   651  				- name: b
   652  				  value1: 3
   653  			`,
   654  			APIVersion: "v1",
   655  			Managed: fieldpath.ManagedFields{
   656  				"updater": fieldpath.NewVersionedSet(
   657  					_NS(
   658  						_P("list"),
   659  						_P("list", _KBF("name", "b")),
   660  						_P("list", _KBF("name", "b"), "name"),
   661  						_P("list", _KBF("name", "b"), "value1"),
   662  					),
   663  					"v1",
   664  					false,
   665  				),
   666  				"applier": fieldpath.NewVersionedSet(
   667  					_NS(
   668  						_P("list", _KBF("name", "a")),
   669  						_P("list", _KBF("name", "a"), "name"),
   670  						_P("list", _KBF("name", "a"), "value1"),
   671  					),
   672  					"v1",
   673  					true,
   674  				),
   675  			},
   676  		},
   677  		"list/merge/change_non_duplicated_item": {
   678  			Ops: []Operation{
   679  				Update{
   680  					Manager: "updater",
   681  					Object: `
   682  						list:
   683  						- name: a
   684  						  value1: 1
   685  						- name: a
   686  						  value1: 2
   687  						- name: b
   688  						  value1: 3
   689  					`,
   690  					APIVersion: "v1",
   691  				},
   692  				ForceApply{
   693  					Manager: "applier",
   694  					Object: `
   695  						list:
   696  						- name: b
   697  						  value1: 4
   698  					`,
   699  					APIVersion: "v1",
   700  				},
   701  			},
   702  			Object: `
   703  				list:
   704  				- name: a
   705  				  value1: 1
   706  				- name: a
   707  				  value1: 2
   708  				- name: b
   709  				  value1: 4
   710  			`,
   711  			APIVersion: "v1",
   712  			Managed: fieldpath.ManagedFields{
   713  				"updater": fieldpath.NewVersionedSet(
   714  					_NS(
   715  						_P("list"),
   716  						_P("list", _KBF("name", "a")),
   717  						_P("list", _KBF("name", "b")),
   718  						_P("list", _KBF("name", "b"), "name"),
   719  					),
   720  					"v1",
   721  					false,
   722  				),
   723  				"applier": fieldpath.NewVersionedSet(
   724  					_NS(
   725  						_P("list", _KBF("name", "b")),
   726  						_P("list", _KBF("name", "b"), "name"),
   727  						_P("list", _KBF("name", "b"), "value1"),
   728  					),
   729  					"v1",
   730  					true,
   731  				),
   732  			},
   733  		},
   734  		"list/merge/apply_update_duplicates_apply_without": {
   735  			Ops: []Operation{
   736  				Apply{
   737  					Manager: "applier",
   738  					Object: `
   739  						list:
   740  						- name: a
   741  						  value1: 1
   742  						- name: b
   743  						  value1: 3
   744  					`,
   745  					APIVersion: "v1",
   746  				},
   747  				Update{
   748  					Manager: "updater",
   749  					Object: `
   750  						list:
   751  						- name: a
   752  						  value1: 1
   753  						- name: a
   754  						  value1: 2
   755  						- name: b
   756  						  value1: 3
   757  					`,
   758  					APIVersion: "v1",
   759  				},
   760  				Apply{
   761  					Manager: "applier",
   762  					Object: `
   763  						list:
   764  						- name: b
   765  						  value1: 3
   766  					`,
   767  					APIVersion: "v1",
   768  				},
   769  			},
   770  			Object: `
   771  				list:
   772  				- name: a
   773  				  value1: 1
   774  				- name: a
   775  				  value1: 2
   776  				- name: b
   777  				  value1: 3
   778  			`,
   779  			APIVersion: "v1",
   780  			Managed: fieldpath.ManagedFields{
   781  				"applier": fieldpath.NewVersionedSet(
   782  					_NS(
   783  						_P("list", _KBF("name", "b")),
   784  						_P("list", _KBF("name", "b"), "name"),
   785  						_P("list", _KBF("name", "b"), "value1"),
   786  					),
   787  					"v1",
   788  					true,
   789  				),
   790  				"updater": fieldpath.NewVersionedSet(
   791  					_NS(
   792  						_P("list", _KBF("name", "a")),
   793  					),
   794  					"v1",
   795  					false,
   796  				),
   797  			},
   798  		},
   799  	}
   800  
   801  	for name, test := range tests {
   802  		t.Run(name, func(t *testing.T) {
   803  			if err := test.Test(duplicatesParser); err != nil {
   804  				t.Fatal(err)
   805  			}
   806  		})
   807  	}
   808  }
   809  

View as plain text