mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Related PR: https://github.com/kubernetes/kubernetes/pull/30313 PR #30313 fixed duplicate errors for invalid aggregate errors in https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/util/helpers.go However, duplicate aggregate errors that went through https://github.com/kubernetes/kubernetes/blob/master/pkg/util/validation/field/errors.go were not affected by that patch. This patch adds duplicate aggregate error checking to `pkg/util/validation/field/errors.go` \##### Before `$ kubectl set env rc/idling-echo-1 test-abc=1234` ``` error: ReplicationController "idling-echo-1" is invalid: [spec.template.spec.containers[0].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName", spec.template.spec.containers[1].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName", spec.template.spec.containers[0].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName", spec.template.spec.containers[1].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName"] ``` `$ kubectl set env rc/node-1 test-abc=1234` ``` error: ReplicationController "idling-echo-1" is invalid: [spec.template.spec.containers[0].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName", spec.template.spec.containers[1].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName"] ``` \##### After `$ kubectl set env rc/idling-echo-1 test-abc=1234` ``` error: ReplicationController "idling-echo-1" is invalid: [spec.template.spec.containers[0].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName", spec.template.spec.containers[1].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName"] ``` `$ kubectl set env rc/node-1 test-abc=1234` ``` error: ReplicationController "node-1" is invalid: spec.template.spec.containers[0].env[0].name: Invalid value: "test-abc": must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName" ```
		
			
				
	
	
		
			159 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2014 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 field
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
)
 | 
						|
 | 
						|
func TestMakeFuncs(t *testing.T) {
 | 
						|
	testCases := []struct {
 | 
						|
		fn       func() *Error
 | 
						|
		expected ErrorType
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			func() *Error { return Invalid(NewPath("f"), "v", "d") },
 | 
						|
			ErrorTypeInvalid,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			func() *Error { return NotSupported(NewPath("f"), "v", nil) },
 | 
						|
			ErrorTypeNotSupported,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			func() *Error { return Duplicate(NewPath("f"), "v") },
 | 
						|
			ErrorTypeDuplicate,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			func() *Error { return NotFound(NewPath("f"), "v") },
 | 
						|
			ErrorTypeNotFound,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			func() *Error { return Required(NewPath("f"), "d") },
 | 
						|
			ErrorTypeRequired,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			func() *Error { return InternalError(NewPath("f"), fmt.Errorf("e")) },
 | 
						|
			ErrorTypeInternal,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, testCase := range testCases {
 | 
						|
		err := testCase.fn()
 | 
						|
		if err.Type != testCase.expected {
 | 
						|
			t.Errorf("expected Type %q, got %q", testCase.expected, err.Type)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestErrorUsefulMessage(t *testing.T) {
 | 
						|
	s := Invalid(NewPath("foo"), "bar", "deet").Error()
 | 
						|
	t.Logf("message: %v", s)
 | 
						|
	for _, part := range []string{"foo", "bar", "deet", ErrorTypeInvalid.String()} {
 | 
						|
		if !strings.Contains(s, part) {
 | 
						|
			t.Errorf("error message did not contain expected part '%v'", part)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	type complicated struct {
 | 
						|
		Baz   int
 | 
						|
		Qux   string
 | 
						|
		Inner interface{}
 | 
						|
		KV    map[string]int
 | 
						|
	}
 | 
						|
	s = Invalid(
 | 
						|
		NewPath("foo"),
 | 
						|
		&complicated{
 | 
						|
			Baz:   1,
 | 
						|
			Qux:   "aoeu",
 | 
						|
			Inner: &complicated{Qux: "asdf"},
 | 
						|
			KV:    map[string]int{"Billy": 2},
 | 
						|
		},
 | 
						|
		"detail",
 | 
						|
	).Error()
 | 
						|
	t.Logf("message: %v", s)
 | 
						|
	for _, part := range []string{
 | 
						|
		"foo", ErrorTypeInvalid.String(),
 | 
						|
		"Baz", "Qux", "Inner", "KV", "detail",
 | 
						|
		"1", "aoeu", "asdf", "Billy", "2",
 | 
						|
	} {
 | 
						|
		if !strings.Contains(s, part) {
 | 
						|
			t.Errorf("error message did not contain expected part '%v'", part)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestToAggregate(t *testing.T) {
 | 
						|
	testCases := struct {
 | 
						|
		ErrList         []ErrorList
 | 
						|
		NumExpectedErrs []int
 | 
						|
	}{
 | 
						|
		[]ErrorList{
 | 
						|
			nil,
 | 
						|
			{},
 | 
						|
			{Invalid(NewPath("f"), "v", "d")},
 | 
						|
			{Invalid(NewPath("f"), "v", "d"), Invalid(NewPath("f"), "v", "d")},
 | 
						|
			{Invalid(NewPath("f"), "v", "d"), InternalError(NewPath(""), fmt.Errorf("e"))},
 | 
						|
		},
 | 
						|
		[]int{
 | 
						|
			0,
 | 
						|
			0,
 | 
						|
			1,
 | 
						|
			1,
 | 
						|
			2,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	if len(testCases.ErrList) != len(testCases.NumExpectedErrs) {
 | 
						|
		t.Errorf("Mismatch: length of NumExpectedErrs does not match length of ErrList")
 | 
						|
	}
 | 
						|
	for i, tc := range testCases.ErrList {
 | 
						|
		agg := tc.ToAggregate()
 | 
						|
		numErrs := 0
 | 
						|
 | 
						|
		if agg != nil {
 | 
						|
			numErrs = len(agg.Errors())
 | 
						|
		}
 | 
						|
		if numErrs != testCases.NumExpectedErrs[i] {
 | 
						|
			t.Errorf("[%d] Expected %d, got %d", i, testCases.NumExpectedErrs[i], numErrs)
 | 
						|
		}
 | 
						|
 | 
						|
		if len(tc) == 0 {
 | 
						|
			if agg != nil {
 | 
						|
				t.Errorf("[%d] Expected nil, got %#v", i, agg)
 | 
						|
			}
 | 
						|
		} else if agg == nil {
 | 
						|
			t.Errorf("[%d] Expected non-nil", i)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestErrListFilter(t *testing.T) {
 | 
						|
	list := ErrorList{
 | 
						|
		Invalid(NewPath("test.field"), "", ""),
 | 
						|
		Invalid(NewPath("field.test"), "", ""),
 | 
						|
		Duplicate(NewPath("test"), "value"),
 | 
						|
	}
 | 
						|
	if len(list.Filter(NewErrorTypeMatcher(ErrorTypeDuplicate))) != 2 {
 | 
						|
		t.Errorf("should not filter")
 | 
						|
	}
 | 
						|
	if len(list.Filter(NewErrorTypeMatcher(ErrorTypeInvalid))) != 1 {
 | 
						|
		t.Errorf("should filter")
 | 
						|
	}
 | 
						|
}
 |