/* Copyright 2019 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package merge_test import ( "testing" "sigs.k8s.io/structured-merge-diff/v4/fieldpath" . "sigs.k8s.io/structured-merge-diff/v4/internal/fixture" "sigs.k8s.io/structured-merge-diff/v4/merge" "sigs.k8s.io/structured-merge-diff/v4/typed" ) var duplicatesParser = func() Parser { parser, err := typed.NewParser(`types: - name: type map: fields: - name: list type: namedType: associativeList - name: unrelated type: scalar: numeric - name: set type: namedType: set - name: associativeList list: elementType: namedType: myElement elementRelationship: associative keys: - name - name: myElement map: fields: - name: name type: scalar: string - name: value1 type: scalar: numeric - name: value2 type: scalar: numeric - name: set list: elementType: scalar: numeric elementRelationship: associative `) if err != nil { panic(err) } return SameVersionParser{T: parser.Type("type")} }() func TestDuplicates(t *testing.T) { tests := map[string]TestCase{ "sets/ownership/duplicates": { Ops: []Operation{ Update{ Manager: "updater-one", Object: ` set: [1, 1, 3, 4] `, APIVersion: "v1", }, }, Managed: fieldpath.ManagedFields{ "updater-one": fieldpath.NewVersionedSet( _NS( _P("set"), _P("set", _V(1)), _P("set", _V(3)), _P("set", _V(4)), ), "v1", false, ), }, }, "sets/ownership/add_duplicate": { Ops: []Operation{ Update{ Manager: "updater-one", Object: ` set: [1, 3, 4] `, APIVersion: "v1", }, Update{ Manager: "updater-two", Object: ` set: [1, 1, 3, 4] `, APIVersion: "v1", }, }, Managed: fieldpath.ManagedFields{ "updater-one": fieldpath.NewVersionedSet( _NS( _P("set"), _P("set", _V(3)), _P("set", _V(4)), ), "v1", false, ), "updater-two": fieldpath.NewVersionedSet( _NS( _P("set", _V(1)), ), "v1", false, ), }, }, "sets/ownership/remove_duplicate": { Ops: []Operation{ Update{ Manager: "updater-one", Object: ` set: [1, 1, 3, 4] `, APIVersion: "v1", }, Update{ Manager: "updater-two", Object: ` set: [1, 3, 4] `, APIVersion: "v1", }, }, Managed: fieldpath.ManagedFields{ "updater-one": fieldpath.NewVersionedSet( _NS( _P("set"), _P("set", _V(3)), _P("set", _V(4)), ), "v1", false, ), "updater-two": fieldpath.NewVersionedSet( _NS( _P("set", _V(1)), ), "v1", false, ), }, }, "sets/merging/remove_duplicate": { Ops: []Operation{ Update{ Manager: "updater", Object: ` set: [1, 1, 3, 4] `, APIVersion: "v1", }, Apply{ Manager: "applier", Object: ` set: [1] `, APIVersion: "v1", Conflicts: merge.Conflicts{ {Manager: "updater", Path: _P("set", _V(1))}, }, }, ForceApply{ Manager: "applier", Object: ` set: [1] `, APIVersion: "v1", }, }, Object: ` set: [1, 3, 4] `, APIVersion: "v1", Managed: fieldpath.ManagedFields{ "updater": fieldpath.NewVersionedSet( _NS( _P("set"), _P("set", _V(3)), _P("set", _V(4)), ), "v1", false, ), "applier": fieldpath.NewVersionedSet( _NS( _P("set", _V(1)), ), "v1", true, ), }, }, "sets/merging/ignore_duplicate": { Ops: []Operation{ Update{ Manager: "updater", Object: ` set: [1, 1, 3, 4] `, APIVersion: "v1", }, Apply{ Manager: "applier", Object: ` set: [5] `, APIVersion: "v1", }, }, Object: ` set: [1, 1, 3, 4, 5] `, APIVersion: "v1", Managed: fieldpath.ManagedFields{ "updater": fieldpath.NewVersionedSet( _NS( _P("set"), _P("set", _V(1)), _P("set", _V(3)), _P("set", _V(4)), ), "v1", false, ), "applier": fieldpath.NewVersionedSet( _NS( _P("set", _V(5)), ), "v1", true, ), }, }, "list/ownership/duplicated_items": { Ops: []Operation{ Update{ Manager: "updater", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, }, // `name: a` is only owned once. Managed: fieldpath.ManagedFields{ "updater": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "a")), _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", false, ), }, }, "list/ownership/change_duplicated_items": { Ops: []Operation{ Update{ Manager: "updater-one", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, Update{ Manager: "updater-two", Object: ` list: - name: a value1: 1 - name: a value1: 3 - name: b value1: 3 `, APIVersion: "v1", }, }, // `name: a` is only owned once, by actor who changed some of it. Managed: fieldpath.ManagedFields{ "updater-one": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", false, ), "updater-two": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "a")), ), "v1", false, ), }, }, "list/ownership/change_fields_duplicated_items": { Ops: []Operation{ Update{ Manager: "updater-one", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, Update{ Manager: "updater-two", Object: ` list: - name: a value1: 1 - name: a value1: 2 value2: 3 # New field - name: b value1: 3 `, APIVersion: "v1", }, }, Managed: fieldpath.ManagedFields{ "updater-one": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", false, ), "updater-two": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "a")), ), "v1", false, ), }, }, "list/ownership/add_duplicated_items_different_field": { Ops: []Operation{ Update{ Manager: "updater-one", Object: ` list: - name: a value1: 1 - name: b value1: 3 `, APIVersion: "v1", }, Update{ Manager: "updater-two", Object: ` list: - name: a value1: 1 - name: a value2: 3 # New field - name: b value1: 3 `, APIVersion: "v1", }, }, Managed: fieldpath.ManagedFields{ "updater-one": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", false, ), "updater-two": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "a")), ), "v1", false, ), }, }, "list/ownership/add_unrelated_to_list_with_duplicates": { Ops: []Operation{ Update{ Manager: "updater-one", Object: ` list: - name: a value1: 1 - name: a value1: 2 `, APIVersion: "v1", }, Update{ Manager: "updater-two", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, }, Managed: fieldpath.ManagedFields{ "updater-one": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "a")), ), "v1", false, ), "updater-two": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", false, ), }, }, "list/merge/unrelated_with_duplicated_items": { Ops: []Operation{ Update{ Manager: "updater", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, ForceApply{ Manager: "applier", Object: ` unrelated: 5 `, APIVersion: "v1", }, }, Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 unrelated: 5 `, APIVersion: "v1", Managed: fieldpath.ManagedFields{ "updater": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "a")), _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", false, ), "applier": fieldpath.NewVersionedSet( _NS( _P("unrelated"), ), "v1", true, ), }, }, // TODO: Owning the key is a little messed-up. "list/merge/change_duplicated_item": { Ops: []Operation{ Update{ Manager: "updater", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, Apply{ Manager: "applier", Object: ` list: - name: a value1: 3 `, APIVersion: "v1", Conflicts: merge.Conflicts{ {Manager: "updater", Path: _P("list", _KBF("name", "a"))}, }, }, ForceApply{ Manager: "applier", Object: ` list: - name: a value1: 3 `, APIVersion: "v1", }, }, Object: ` list: - name: a value1: 3 - name: b value1: 3 `, APIVersion: "v1", Managed: fieldpath.ManagedFields{ "updater": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", false, ), "applier": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "a")), _P("list", _KBF("name", "a"), "name"), _P("list", _KBF("name", "a"), "value1"), ), "v1", true, ), }, }, "list/merge/unchanged_duplicated_item": { Ops: []Operation{ Update{ Manager: "updater", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, Apply{ Manager: "applier", Object: ` list: - name: a value1: 2 `, APIVersion: "v1", Conflicts: merge.Conflicts{ {Manager: "updater", Path: _P("list", _KBF("name", "a"))}, }, }, ForceApply{ Manager: "applier", Object: ` list: - name: a value1: 3 `, APIVersion: "v1", }, }, Object: ` list: - name: a value1: 3 - name: b value1: 3 `, APIVersion: "v1", Managed: fieldpath.ManagedFields{ "updater": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", false, ), "applier": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "a")), _P("list", _KBF("name", "a"), "name"), _P("list", _KBF("name", "a"), "value1"), ), "v1", true, ), }, }, "list/merge/change_non_duplicated_item": { Ops: []Operation{ Update{ Manager: "updater", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, ForceApply{ Manager: "applier", Object: ` list: - name: b value1: 4 `, APIVersion: "v1", }, }, Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 4 `, APIVersion: "v1", Managed: fieldpath.ManagedFields{ "updater": fieldpath.NewVersionedSet( _NS( _P("list"), _P("list", _KBF("name", "a")), _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), ), "v1", false, ), "applier": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", true, ), }, }, "list/merge/apply_update_duplicates_apply_without": { Ops: []Operation{ Apply{ Manager: "applier", Object: ` list: - name: a value1: 1 - name: b value1: 3 `, APIVersion: "v1", }, Update{ Manager: "updater", Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", }, Apply{ Manager: "applier", Object: ` list: - name: b value1: 3 `, APIVersion: "v1", }, }, Object: ` list: - name: a value1: 1 - name: a value1: 2 - name: b value1: 3 `, APIVersion: "v1", Managed: fieldpath.ManagedFields{ "applier": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "b")), _P("list", _KBF("name", "b"), "name"), _P("list", _KBF("name", "b"), "value1"), ), "v1", true, ), "updater": fieldpath.NewVersionedSet( _NS( _P("list", _KBF("name", "a")), ), "v1", false, ), }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { if err := test.Test(duplicatesParser); err != nil { t.Fatal(err) } }) } }