/* 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" ) // portListParser sets the default value of key "protocol" to "TCP" var portListParser = func() *typed.Parser { parser, err := typed.NewParser(`types: - name: v1 map: fields: - name: containerPorts type: list: elementType: map: fields: - name: port type: scalar: numeric - name: protocol default: "TCP" type: scalar: string - name: name type: scalar: string elementRelationship: associative keys: - port - protocol `) if err != nil { panic(err) } return parser }() func TestDefaultKeysFlat(t *testing.T) { tests := map[string]TestCase{ "apply_missing_defaulted_key_A": { Ops: []Operation{ Apply{ Manager: "default", APIVersion: "v1", Object: ` containerPorts: - port: 80 `, }, }, APIVersion: "v1", Object: ` containerPorts: - port: 80 `, Managed: fieldpath.ManagedFields{ "default": fieldpath.NewVersionedSet( _NS( _P("containerPorts", _KBF("port", 80, "protocol", "TCP")), _P("containerPorts", _KBF("port", 80, "protocol", "TCP"), "port"), ), "v1", false, ), }, }, "apply_missing_defaulted_key_B": { Ops: []Operation{ Apply{ Manager: "default", APIVersion: "v1", Object: ` containerPorts: - port: 80 - port: 80 protocol: UDP `, }, }, APIVersion: "v1", Object: ` containerPorts: - port: 80 - port: 80 protocol: UDP `, Managed: fieldpath.ManagedFields{ "default": fieldpath.NewVersionedSet( _NS( _P("containerPorts", _KBF("port", 80, "protocol", "TCP")), _P("containerPorts", _KBF("port", 80, "protocol", "TCP"), "port"), _P("containerPorts", _KBF("port", 80, "protocol", "UDP")), _P("containerPorts", _KBF("port", 80, "protocol", "UDP"), "port"), _P("containerPorts", _KBF("port", 80, "protocol", "UDP"), "protocol"), ), "v1", false, ), }, }, "apply_missing_defaulted_key_with_conflict": { Ops: []Operation{ Apply{ Manager: "apply-one", APIVersion: "v1", Object: ` containerPorts: - port: 80 protocol: TCP name: foo `, }, Apply{ Manager: "apply-two", APIVersion: "v1", Object: ` containerPorts: - port: 80 name: bar `, Conflicts: merge.Conflicts{ merge.Conflict{Manager: "apply-one", Path: _P("containerPorts", _KBF("port", 80, "protocol", "TCP"), "name")}, }, }, }, APIVersion: "v1", Object: ` containerPorts: - port: 80 protocol: TCP name: foo `, Managed: fieldpath.ManagedFields{ "apply-one": fieldpath.NewVersionedSet( _NS( _P("containerPorts", _KBF("port", 80, "protocol", "TCP")), _P("containerPorts", _KBF("port", 80, "protocol", "TCP"), "port"), _P("containerPorts", _KBF("port", 80, "protocol", "TCP"), "protocol"), _P("containerPorts", _KBF("port", 80, "protocol", "TCP"), "name"), ), "v1", false, ), }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { if err := test.Test(portListParser); err != nil { t.Fatal(err) } }) } } func TestDefaultKeysFlatErrors(t *testing.T) { tests := map[string]TestCase{ "apply_missing_undefaulted_defaulted_key": { Ops: []Operation{ Apply{ Manager: "default", APIVersion: "v1", Object: ` containerPorts: - protocol: TCP `, }, }, }, "apply_missing_defaulted_key_ambiguous_A": { Ops: []Operation{ Apply{ Manager: "default", APIVersion: "v1", Object: ` containerPorts: - port: 80 - port: 80 `, }, }, }, "apply_missing_defaulted_key_ambiguous_B": { Ops: []Operation{ Apply{ Manager: "default", APIVersion: "v1", Object: ` containerPorts: - port: 80 - port: 80 protocol: TCP `, }, }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { if test.Test(portListParser) == nil { t.Fatal("Should fail") } }) } } // bookParser sets the default value of key: // * "chapter" to 1 // * "section" to "A" // * "page" to 2, // * "line" to 3, var bookParser = func() *typed.Parser { parser, err := typed.NewParser(`types: - name: v1 map: fields: - name: book type: list: elementType: map: fields: - name: chapter default: 1 type: scalar: numeric - name: section default: "A" type: scalar: string - name: sentences type: list: elementType: map: fields: - name: page default: 2.0 type: scalar: numeric - name: line default: 3 type: scalar: numeric - name: text type: scalar: string elementRelationship: associative keys: - page - line elementRelationship: associative keys: - chapter - section `) if err != nil { panic(err) } return parser }() func TestDefaultKeysNested(t *testing.T) { tests := map[string]TestCase{ "apply_missing_every_key_nested": { Ops: []Operation{ Apply{ Manager: "default", APIVersion: "v1", Object: ` book: - sentences: - text: blah `, }, }, APIVersion: "v1", Object: ` book: - sentences: - text: blah `, Managed: fieldpath.ManagedFields{ "default": fieldpath.NewVersionedSet( _NS( _P( "book", _KBF("chapter", 1, "section", "A"), ), _P( "book", _KBF("chapter", 1, "section", "A"), "sentences", _KBF("page", 2, "line", 3), ), _P( "book", _KBF("chapter", 1, "section", "A"), "sentences", _KBF("page", 2, "line", 3), "text", ), ), "v1", false, ), }, }, "apply_integer_key_with_float_default": { Ops: []Operation{ Apply{ Manager: "default", APIVersion: "v1", Object: ` book: - sentences: - text: blah `, }, Apply{ Manager: "default", APIVersion: "v1", Object: ` book: - sentences: - text: blah page: 2 `, }, }, APIVersion: "v1", Object: ` book: - sentences: - text: blah page: 2 `, Managed: fieldpath.ManagedFields{ "default": fieldpath.NewVersionedSet( _NS( _P( "book", _KBF("chapter", 1, "section", "A"), ), _P( "book", _KBF("chapter", 1, "section", "A"), "sentences", _KBF("page", 2, "line", 3), ), _P( "book", _KBF("chapter", 1, "section", "A"), "sentences", _KBF("page", 2, "line", 3), "text", ), _P( "book", _KBF("chapter", 1, "section", "A"), "sentences", _KBF("page", 2, "line", 3), "page", ), ), "v1", false, ), }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { if err := test.Test(bookParser); err != nil { t.Fatal(err) } }) } }