Replace godep with dep
This commit is contained in:
parent
1e7489927c
commit
bf5616c65b
14883 changed files with 3937406 additions and 361781 deletions
2
vendor/k8s.io/apimachinery/pkg/api/errors/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/api/errors/doc.go
generated
vendored
|
|
@ -15,4 +15,4 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
// Package errors provides detailed error types for api field validation.
|
||||
package errors
|
||||
package errors // import "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
|
|
|||
222
vendor/k8s.io/apimachinery/pkg/api/errors/errors_test.go
generated
vendored
Normal file
222
vendor/k8s.io/apimachinery/pkg/api/errors/errors_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
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 errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
func resource(resource string) schema.GroupResource {
|
||||
return schema.GroupResource{Group: "", Resource: resource}
|
||||
}
|
||||
func kind(kind string) schema.GroupKind {
|
||||
return schema.GroupKind{Group: "", Kind: kind}
|
||||
}
|
||||
|
||||
func TestErrorNew(t *testing.T) {
|
||||
err := NewAlreadyExists(resource("tests"), "1")
|
||||
if !IsAlreadyExists(err) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonAlreadyExists)
|
||||
}
|
||||
if IsConflict(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonConflict)
|
||||
}
|
||||
if IsNotFound(err) {
|
||||
t.Errorf(fmt.Sprintf("expected to not be %s", metav1.StatusReasonNotFound))
|
||||
}
|
||||
if IsInvalid(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonInvalid)
|
||||
}
|
||||
if IsBadRequest(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonBadRequest)
|
||||
}
|
||||
if IsForbidden(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonForbidden)
|
||||
}
|
||||
if IsServerTimeout(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonServerTimeout)
|
||||
}
|
||||
if IsMethodNotSupported(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonMethodNotAllowed)
|
||||
}
|
||||
|
||||
if !IsConflict(NewConflict(resource("tests"), "2", errors.New("message"))) {
|
||||
t.Errorf("expected to be conflict")
|
||||
}
|
||||
if !IsNotFound(NewNotFound(resource("tests"), "3")) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonNotFound)
|
||||
}
|
||||
if !IsInvalid(NewInvalid(kind("Test"), "2", nil)) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonInvalid)
|
||||
}
|
||||
if !IsBadRequest(NewBadRequest("reason")) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonBadRequest)
|
||||
}
|
||||
if !IsForbidden(NewForbidden(resource("tests"), "2", errors.New("reason"))) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonForbidden)
|
||||
}
|
||||
if !IsUnauthorized(NewUnauthorized("reason")) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonUnauthorized)
|
||||
}
|
||||
if !IsServerTimeout(NewServerTimeout(resource("tests"), "reason", 0)) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonServerTimeout)
|
||||
}
|
||||
if !IsMethodNotSupported(NewMethodNotSupported(resource("foos"), "delete")) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonMethodNotAllowed)
|
||||
}
|
||||
|
||||
if time, ok := SuggestsClientDelay(NewServerTimeout(resource("tests"), "doing something", 10)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewServerTimeout(resource("tests"), "doing something", 0)); time != 0 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewTimeoutError("test reason", 10)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewTooManyRequests("doing something", 10)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewTooManyRequests("doing something", 1)); time != 1 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewGenericServerResponse(429, "get", resource("tests"), "test", "doing something", 10, true)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewGenericServerResponse(500, "get", resource("tests"), "test", "doing something", 10, true)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewGenericServerResponse(429, "get", resource("tests"), "test", "doing something", 0, true)); time != 0 || ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewInvalid(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Err *field.Error
|
||||
Details *metav1.StatusDetails
|
||||
}{
|
||||
{
|
||||
field.Duplicate(field.NewPath("field[0].name"), "bar"),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueDuplicate,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
field.Invalid(field.NewPath("field[0].name"), "bar", "detail"),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueInvalid,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
field.NotFound(field.NewPath("field[0].name"), "bar"),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueNotFound,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
field.NotSupported(field.NewPath("field[0].name"), "bar", nil),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueNotSupported,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
field.Required(field.NewPath("field[0].name"), ""),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueRequired,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
vErr, expected := testCase.Err, testCase.Details
|
||||
expected.Causes[0].Message = vErr.ErrorBody()
|
||||
err := NewInvalid(kind("Kind"), "name", field.ErrorList{vErr})
|
||||
status := err.ErrStatus
|
||||
if status.Code != 422 || status.Reason != metav1.StatusReasonInvalid {
|
||||
t.Errorf("%d: unexpected status: %#v", i, status)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, status.Details) {
|
||||
t.Errorf("%d: expected %#v, got %#v", i, expected, status.Details)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_reasonForError(t *testing.T) {
|
||||
if e, a := metav1.StatusReasonUnknown, reasonForError(nil); e != a {
|
||||
t.Errorf("unexpected reason type: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
type TestType struct{}
|
||||
|
||||
func (obj *TestType) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
func (obj *TestType) DeepCopyObject() runtime.Object {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
clone := *obj
|
||||
return &clone
|
||||
}
|
||||
|
||||
func TestFromObject(t *testing.T) {
|
||||
table := []struct {
|
||||
obj runtime.Object
|
||||
message string
|
||||
}{
|
||||
{&metav1.Status{Message: "foobar"}, "foobar"},
|
||||
{&TestType{}, "unexpected object: &{}"},
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
if e, a := item.message, FromObject(item.obj).Error(); e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/api/meta/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/api/meta/doc.go
generated
vendored
|
|
@ -16,4 +16,4 @@ limitations under the License.
|
|||
|
||||
// Package meta provides functions for retrieving API metadata from objects
|
||||
// belonging to the Kubernetes API
|
||||
package meta
|
||||
package meta // import "k8s.io/apimachinery/pkg/api/meta"
|
||||
|
|
|
|||
51
vendor/k8s.io/apimachinery/pkg/api/meta/meta_test.go
generated
vendored
Normal file
51
vendor/k8s.io/apimachinery/pkg/api/meta/meta_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2017 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 meta
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
func TestAsPartialObjectMetadata(t *testing.T) {
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 1).RandSource(rand.NewSource(1))
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
m := &metav1.ObjectMeta{}
|
||||
f.Fuzz(m)
|
||||
partial := AsPartialObjectMetadata(m)
|
||||
if !reflect.DeepEqual(&partial.ObjectMeta, m) {
|
||||
t.Fatalf("incomplete partial object metadata: %s", diff.ObjectReflectDiff(&partial.ObjectMeta, m))
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
m := &metav1alpha1.PartialObjectMetadata{}
|
||||
f.Fuzz(&m.ObjectMeta)
|
||||
partial := AsPartialObjectMetadata(m)
|
||||
if !reflect.DeepEqual(&partial.ObjectMeta, &m.ObjectMeta) {
|
||||
t.Fatalf("incomplete partial object metadata: %s", diff.ObjectReflectDiff(&partial.ObjectMeta, &m.ObjectMeta))
|
||||
}
|
||||
}
|
||||
}
|
||||
355
vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper_test.go
generated
vendored
Normal file
355
vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
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 meta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestMultiRESTMapperResourceFor(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupVersionResource
|
||||
result schema.GroupVersionResource
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionResource{},
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionResource{},
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "unused"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionResource{},
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.ResourceFor(tc.input)
|
||||
if e, a := tc.result, actualResult; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRESTMapperResourcesFor(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupVersionResource
|
||||
result []schema.GroupVersionResource
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "unused"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
{
|
||||
name: "union and dedup",
|
||||
mapper: MultiRESTMapper{
|
||||
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "first"}}},
|
||||
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "second"}}},
|
||||
},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "first"}, {Resource: "second"}},
|
||||
},
|
||||
{
|
||||
name: "skip not and continue",
|
||||
mapper: MultiRESTMapper{
|
||||
fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}},
|
||||
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "first"}, {Resource: "second"}}},
|
||||
},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: []schema.GroupVersionResource{{Resource: "first"}, {Resource: "second"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.ResourcesFor(tc.input)
|
||||
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRESTMapperKindsFor(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupVersionResource
|
||||
result []schema.GroupVersionKind
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "unused"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
{
|
||||
name: "union and dedup",
|
||||
mapper: MultiRESTMapper{
|
||||
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "first"}}},
|
||||
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "second"}}},
|
||||
},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "first"}, {Kind: "second"}},
|
||||
},
|
||||
{
|
||||
name: "skip not and continue",
|
||||
mapper: MultiRESTMapper{
|
||||
fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}},
|
||||
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "first"}, {Kind: "second"}}},
|
||||
},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: []schema.GroupVersionKind{{Kind: "first"}, {Kind: "second"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.KindsFor(tc.input)
|
||||
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRESTMapperKindFor(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupVersionResource
|
||||
result schema.GroupVersionKind
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionKind{},
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionKind{},
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "unused"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionKind{},
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.KindFor(tc.input)
|
||||
if e, a := tc.result, actualResult; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRESTMapperRESTMappings(t *testing.T) {
|
||||
mapping1, mapping2 := &RESTMapping{}, &RESTMapping{}
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupKind
|
||||
result []*RESTMapping
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: nil,
|
||||
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: nil,
|
||||
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: nil,
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
{
|
||||
name: "return both",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{mappings: []*RESTMapping{mapping1}}, fixedRESTMapper{mappings: []*RESTMapping{mapping2}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: []*RESTMapping{mapping1, mapping2},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.RESTMappings(tc.input)
|
||||
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fixedRESTMapper struct {
|
||||
resourcesFor []schema.GroupVersionResource
|
||||
kindsFor []schema.GroupVersionKind
|
||||
resourceFor schema.GroupVersionResource
|
||||
kindFor schema.GroupVersionKind
|
||||
mappings []*RESTMapping
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
return "", m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
||||
return m.resourcesFor, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) KindsFor(resource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
|
||||
return m.kindsFor, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||
return m.resourceFor, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
return m.kindFor, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
|
||||
return nil, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) (mappings []*RESTMapping, err error) {
|
||||
return m.mappings, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) ResourceIsValid(resource schema.GroupVersionResource) bool {
|
||||
return false
|
||||
}
|
||||
346
vendor/k8s.io/apimachinery/pkg/api/meta/priority_test.go
generated
vendored
Normal file
346
vendor/k8s.io/apimachinery/pkg/api/meta/priority_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
Copyright 2016 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 meta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestPriorityRESTMapperResourceForErrorHandling(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
delegate RESTMapper
|
||||
resourcePatterns []schema.GroupVersionResource
|
||||
result schema.GroupVersionResource
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "single hit",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "single-hit"}}},
|
||||
result: schema.GroupVersionResource{Resource: "single-hit"},
|
||||
},
|
||||
{
|
||||
name: "ambiguous match",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "two", Version: "b", Resource: "second"},
|
||||
}},
|
||||
err: "matches multiple resources",
|
||||
},
|
||||
{
|
||||
name: "group selection",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "two", Version: "b", Resource: "second"},
|
||||
}},
|
||||
resourcePatterns: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: AnyVersion, Resource: AnyResource},
|
||||
},
|
||||
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
|
||||
},
|
||||
{
|
||||
name: "empty match continues",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "two", Version: "b", Resource: "second"},
|
||||
}},
|
||||
resourcePatterns: []schema.GroupVersionResource{
|
||||
{Group: "fail", Version: AnyVersion, Resource: AnyResource},
|
||||
{Group: "one", Version: AnyVersion, Resource: AnyResource},
|
||||
},
|
||||
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
|
||||
},
|
||||
{
|
||||
name: "group followed by version selection",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "two", Version: "b", Resource: "second"},
|
||||
{Group: "one", Version: "c", Resource: "third"},
|
||||
}},
|
||||
resourcePatterns: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: AnyVersion, Resource: AnyResource},
|
||||
{Group: AnyGroup, Version: "a", Resource: AnyResource},
|
||||
},
|
||||
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
|
||||
},
|
||||
{
|
||||
name: "resource selection",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "one", Version: "a", Resource: "second"},
|
||||
}},
|
||||
resourcePatterns: []schema.GroupVersionResource{
|
||||
{Group: AnyGroup, Version: AnyVersion, Resource: "second"},
|
||||
},
|
||||
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "second"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
mapper := PriorityRESTMapper{Delegate: tc.delegate, ResourcePriority: tc.resourcePatterns}
|
||||
|
||||
actualResult, actualErr := mapper.ResourceFor(schema.GroupVersionResource{})
|
||||
if e, a := tc.result, actualResult; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
if len(tc.err) == 0 && actualErr == nil {
|
||||
continue
|
||||
}
|
||||
if len(tc.err) > 0 && actualErr == nil {
|
||||
t.Errorf("%s: missing expected err: %v", tc.name, tc.err)
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(actualErr.Error(), tc.err) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityRESTMapperKindForErrorHandling(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
delegate RESTMapper
|
||||
kindPatterns []schema.GroupVersionKind
|
||||
result schema.GroupVersionKind
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "single hit",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "single-hit"}}},
|
||||
result: schema.GroupVersionKind{Kind: "single-hit"},
|
||||
},
|
||||
{
|
||||
name: "ambiguous match",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "two", Version: "b", Kind: "second"},
|
||||
}},
|
||||
err: "matches multiple kinds",
|
||||
},
|
||||
{
|
||||
name: "group selection",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "two", Version: "b", Kind: "second"},
|
||||
}},
|
||||
kindPatterns: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: AnyVersion, Kind: AnyKind},
|
||||
},
|
||||
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
|
||||
},
|
||||
{
|
||||
name: "empty match continues",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "two", Version: "b", Kind: "second"},
|
||||
}},
|
||||
kindPatterns: []schema.GroupVersionKind{
|
||||
{Group: "fail", Version: AnyVersion, Kind: AnyKind},
|
||||
{Group: "one", Version: AnyVersion, Kind: AnyKind},
|
||||
},
|
||||
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
|
||||
},
|
||||
{
|
||||
name: "group followed by version selection",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "two", Version: "b", Kind: "second"},
|
||||
{Group: "one", Version: "c", Kind: "third"},
|
||||
}},
|
||||
kindPatterns: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: AnyVersion, Kind: AnyKind},
|
||||
{Group: AnyGroup, Version: "a", Kind: AnyKind},
|
||||
},
|
||||
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
|
||||
},
|
||||
{
|
||||
name: "kind selection",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "one", Version: "a", Kind: "second"},
|
||||
}},
|
||||
kindPatterns: []schema.GroupVersionKind{
|
||||
{Group: AnyGroup, Version: AnyVersion, Kind: "second"},
|
||||
},
|
||||
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "second"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
mapper := PriorityRESTMapper{Delegate: tc.delegate, KindPriority: tc.kindPatterns}
|
||||
|
||||
actualResult, actualErr := mapper.KindFor(schema.GroupVersionResource{})
|
||||
if e, a := tc.result, actualResult; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
if len(tc.err) == 0 && actualErr == nil {
|
||||
continue
|
||||
}
|
||||
if len(tc.err) > 0 && actualErr == nil {
|
||||
t.Errorf("%s: missing expected err: %v", tc.name, tc.err)
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(actualErr.Error(), tc.err) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityRESTMapperRESTMapping(t *testing.T) {
|
||||
mapping1 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Kind: "Foo", Version: "v1alpha1"},
|
||||
}
|
||||
mapping2 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Kind: "Foo", Version: "v1"},
|
||||
}
|
||||
mapping3 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Group: "other", Kind: "Foo", Version: "v1"},
|
||||
}
|
||||
allMappers := MultiRESTMapper{
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mapping1}},
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mapping2}},
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mapping3}},
|
||||
}
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper PriorityRESTMapper
|
||||
input schema.GroupKind
|
||||
result *RESTMapping
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "IGNORE_THIS"}}}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
{
|
||||
name: "return error for ambiguous",
|
||||
mapper: PriorityRESTMapper{
|
||||
Delegate: allMappers,
|
||||
},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
err: &AmbiguousKindError{
|
||||
PartialKind: schema.GroupVersionKind{Kind: "Foo"},
|
||||
MatchingKinds: []schema.GroupVersionKind{
|
||||
{Kind: "Foo", Version: "v1alpha1"},
|
||||
{Kind: "Foo", Version: "v1"},
|
||||
{Group: "other", Kind: "Foo", Version: "v1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "accept only item",
|
||||
mapper: PriorityRESTMapper{
|
||||
Delegate: fixedRESTMapper{mappings: []*RESTMapping{mapping1}},
|
||||
},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: mapping1,
|
||||
},
|
||||
{
|
||||
name: "return single priority",
|
||||
mapper: PriorityRESTMapper{
|
||||
Delegate: allMappers,
|
||||
KindPriority: []schema.GroupVersionKind{{Version: "v1", Kind: AnyKind}, {Version: "v1alpha1", Kind: AnyKind}},
|
||||
},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: mapping2,
|
||||
},
|
||||
{
|
||||
name: "return out of group match",
|
||||
mapper: PriorityRESTMapper{
|
||||
Delegate: allMappers,
|
||||
KindPriority: []schema.GroupVersionKind{{Group: AnyGroup, Version: "v1", Kind: AnyKind}, {Group: "other", Version: AnyVersion, Kind: AnyKind}},
|
||||
},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: mapping3,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.RESTMapping(tc.input)
|
||||
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityRESTMapperRESTMappingHonorsUserVersion(t *testing.T) {
|
||||
mappingV2alpha1 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Group: "Bar", Kind: "Foo", Version: "v2alpha1"},
|
||||
}
|
||||
mappingV1 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Group: "Bar", Kind: "Foo", Version: "v1"},
|
||||
}
|
||||
|
||||
allMappers := MultiRESTMapper{
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mappingV2alpha1}},
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mappingV1}},
|
||||
}
|
||||
|
||||
mapper := PriorityRESTMapper{
|
||||
Delegate: allMappers,
|
||||
KindPriority: []schema.GroupVersionKind{{Group: "Bar", Version: "v2alpha1", Kind: AnyKind}, {Group: "Bar", Version: AnyVersion, Kind: AnyKind}},
|
||||
}
|
||||
|
||||
outMapping1, err := mapper.RESTMapping(schema.GroupKind{Group: "Bar", Kind: "Foo"}, "v1")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if outMapping1 != mappingV1 {
|
||||
t.Errorf("asked for version %v, expected mapping for %v, got mapping for %v", "v1", mappingV1.GroupVersionKind, outMapping1.GroupVersionKind)
|
||||
}
|
||||
|
||||
outMapping2, err := mapper.RESTMapping(schema.GroupKind{Group: "Bar", Kind: "Foo"}, "v2alpha1")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if outMapping2 != mappingV2alpha1 {
|
||||
t.Errorf("asked for version %v, expected mapping for %v, got mapping for %v", "v2alpha1", mappingV2alpha1.GroupVersionKind, outMapping2.GroupVersionKind)
|
||||
}
|
||||
}
|
||||
751
vendor/k8s.io/apimachinery/pkg/api/meta/restmapper_test.go
generated
vendored
Normal file
751
vendor/k8s.io/apimachinery/pkg/api/meta/restmapper_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
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 meta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type fakeConvertor struct{}
|
||||
|
||||
func (fakeConvertor) Convert(in, out, context interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ runtime.GroupVersioner) (runtime.Object, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (fakeConvertor) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
}
|
||||
|
||||
var validAccessor = resourceAccessor{}
|
||||
var validConvertor = fakeConvertor{}
|
||||
|
||||
func fakeInterfaces(version schema.GroupVersion) (*VersionInterfaces, error) {
|
||||
return &VersionInterfaces{ObjectConvertor: validConvertor, MetadataAccessor: validAccessor}, nil
|
||||
}
|
||||
|
||||
var unmatchedErr = errors.New("no version")
|
||||
|
||||
func unmatchedVersionInterfaces(version schema.GroupVersion) (*VersionInterfaces, error) {
|
||||
return nil, unmatchedErr
|
||||
}
|
||||
|
||||
func TestRESTMapperVersionAndKindForResource(t *testing.T) {
|
||||
testGroup := "test.group"
|
||||
testVersion := "test"
|
||||
testGroupVersion := schema.GroupVersion{Group: testGroup, Version: testVersion}
|
||||
|
||||
testCases := []struct {
|
||||
Resource schema.GroupVersionResource
|
||||
GroupVersionToRegister schema.GroupVersion
|
||||
ExpectedGVK schema.GroupVersionKind
|
||||
Err bool
|
||||
}{
|
||||
{Resource: schema.GroupVersionResource{Resource: "internalobjec"}, Err: true},
|
||||
{Resource: schema.GroupVersionResource{Resource: "internalObjec"}, Err: true},
|
||||
|
||||
{Resource: schema.GroupVersionResource{Resource: "internalobject"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
|
||||
{Resource: schema.GroupVersionResource{Resource: "internalobjects"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion}, fakeInterfaces)
|
||||
if len(testCase.ExpectedGVK.Kind) != 0 {
|
||||
mapper.Add(testCase.ExpectedGVK, RESTScopeNamespace)
|
||||
}
|
||||
actualGVK, err := mapper.KindFor(testCase.Resource)
|
||||
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if actualGVK != testCase.ExpectedGVK {
|
||||
t.Errorf("%d: unexpected version and kind: e=%s a=%s", i, testCase.ExpectedGVK, actualGVK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperGroupForResource(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Resource schema.GroupVersionResource
|
||||
GroupVersionKind schema.GroupVersionKind
|
||||
Err bool
|
||||
}{
|
||||
{Resource: schema.GroupVersionResource{Resource: "myObject"}, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
|
||||
{Resource: schema.GroupVersionResource{Resource: "myobject"}, GroupVersionKind: schema.GroupVersionKind{Group: "testapi2", Version: "test", Kind: "MyObject"}},
|
||||
{Resource: schema.GroupVersionResource{Resource: "myObje"}, Err: true, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
|
||||
{Resource: schema.GroupVersionResource{Resource: "myobje"}, Err: true, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testCase.GroupVersionKind.GroupVersion()}, fakeInterfaces)
|
||||
mapper.Add(testCase.GroupVersionKind, RESTScopeNamespace)
|
||||
|
||||
actualGVK, err := mapper.KindFor(testCase.Resource)
|
||||
if testCase.Err {
|
||||
if err == nil {
|
||||
t.Errorf("%d: expected error", i)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
} else if actualGVK != testCase.GroupVersionKind {
|
||||
t.Errorf("%d: expected group %q, got %q", i, testCase.GroupVersionKind, actualGVK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperKindsFor(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
PreferredOrder []schema.GroupVersion
|
||||
KindsToRegister []schema.GroupVersionKind
|
||||
PartialResourceToRequest schema.GroupVersionResource
|
||||
|
||||
ExpectedKinds []schema.GroupVersionKind
|
||||
ExpectedKindErr string
|
||||
}{
|
||||
{
|
||||
// exact matches are preferred
|
||||
Name: "groups, with group exact",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group-1", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// group prefixes work
|
||||
Name: "groups, with group prefix",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// group prefixes can be ambiguous
|
||||
Name: "groups, with ambiguous group prefix",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group-1", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
ExpectedKindErr: " matches multiple kinds ",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with preference order",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kinds"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
ExpectedKindErr: " matches multiple kinds ",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with explicit group match",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with ambiguous version match",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kinds"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
ExpectedKindErr: " matches multiple kinds ",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
tcName := testCase.Name
|
||||
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
|
||||
for _, kind := range testCase.KindsToRegister {
|
||||
mapper.Add(kind, RESTScopeNamespace)
|
||||
}
|
||||
|
||||
actualKinds, err := mapper.KindsFor(testCase.PartialResourceToRequest)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", tcName, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(testCase.ExpectedKinds, actualKinds) {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds, actualKinds)
|
||||
}
|
||||
|
||||
singleKind, err := mapper.KindFor(testCase.PartialResourceToRequest)
|
||||
if err == nil && len(testCase.ExpectedKindErr) != 0 {
|
||||
t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedKindErr)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
if len(testCase.ExpectedKindErr) == 0 {
|
||||
t.Errorf("%s: unexpected error: %v", tcName, err)
|
||||
continue
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), testCase.ExpectedKindErr) {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKindErr, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if testCase.ExpectedKinds[0] != singleKind {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds[0], singleKind)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperResourcesFor(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
PreferredOrder []schema.GroupVersion
|
||||
KindsToRegister []schema.GroupVersionKind
|
||||
PluralPartialResourceToRequest schema.GroupVersionResource
|
||||
SingularPartialResourceToRequest schema.GroupVersionResource
|
||||
|
||||
ExpectedResources []schema.GroupVersionResource
|
||||
ExpectedResourceErr string
|
||||
}{
|
||||
{
|
||||
// exact matches are preferred
|
||||
Name: "groups, with group exact",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group-1", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// group prefixes work
|
||||
Name: "groups, with group prefix",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// group prefixes can be ambiguous
|
||||
Name: "groups, with ambiguous group prefix",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group-1", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group-1", Version: "first-version", Resource: "my-kinds"},
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
ExpectedResourceErr: " matches multiple resources ",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with preference order",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "second-group", Version: "first-version", Resource: "my-kinds"},
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
ExpectedResourceErr: " matches multiple resources ",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with explicit group match",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with ambiguous version match",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
{Group: "second-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
ExpectedResourceErr: " matches multiple resources ",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
tcName := testCase.Name
|
||||
|
||||
for _, partialResource := range []schema.GroupVersionResource{testCase.PluralPartialResourceToRequest, testCase.SingularPartialResourceToRequest} {
|
||||
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
|
||||
for _, kind := range testCase.KindsToRegister {
|
||||
mapper.Add(kind, RESTScopeNamespace)
|
||||
}
|
||||
|
||||
actualResources, err := mapper.ResourcesFor(partialResource)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", tcName, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(testCase.ExpectedResources, actualResources) {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources, actualResources)
|
||||
}
|
||||
|
||||
singleResource, err := mapper.ResourceFor(partialResource)
|
||||
if err == nil && len(testCase.ExpectedResourceErr) != 0 {
|
||||
t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedResourceErr)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
if len(testCase.ExpectedResourceErr) == 0 {
|
||||
t.Errorf("%s: unexpected error: %v", tcName, err)
|
||||
continue
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), testCase.ExpectedResourceErr) {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResourceErr, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if testCase.ExpectedResources[0] != singleResource {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources[0], singleResource)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKindToResource(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
Plural, Singular string
|
||||
}{
|
||||
{Kind: "Pod", Plural: "pods", Singular: "pod"},
|
||||
|
||||
{Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"},
|
||||
|
||||
// Add "ies" when ending with "y"
|
||||
{Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"},
|
||||
// Add "es" when ending with "s"
|
||||
{Kind: "miss", Plural: "misses", Singular: "miss"},
|
||||
// Add "s" otherwise
|
||||
{Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
version := schema.GroupVersion{}
|
||||
|
||||
plural, singular := UnsafeGuessKindToResource(version.WithKind(testCase.Kind))
|
||||
if singular != version.WithResource(testCase.Singular) || plural != version.WithResource(testCase.Plural) {
|
||||
t.Errorf("%d: unexpected plural and singular: %v %v", i, plural, singular)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperResourceSingularizer(t *testing.T) {
|
||||
testGroupVersion := schema.GroupVersion{Group: "tgroup", Version: "test"}
|
||||
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
Plural string
|
||||
Singular string
|
||||
}{
|
||||
{Kind: "Pod", Plural: "pods", Singular: "pod"},
|
||||
{Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"},
|
||||
{Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"},
|
||||
{Kind: "Status", Plural: "statuses", Singular: "status"},
|
||||
|
||||
{Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"},
|
||||
// TODO this test is broken. This updates to reflect actual behavior. Kinds are expected to be singular
|
||||
// old (incorrect), coment: Don't add extra s if the original object is already plural
|
||||
{Kind: "lowercases", Plural: "lowercaseses", Singular: "lowercases"},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion}, fakeInterfaces)
|
||||
// create singular/plural mapping
|
||||
mapper.Add(testGroupVersion.WithKind(testCase.Kind), RESTScopeNamespace)
|
||||
|
||||
singular, err := mapper.ResourceSingularizer(testCase.Plural)
|
||||
if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
}
|
||||
if singular != testCase.Singular {
|
||||
t.Errorf("%d: mismatched singular: got %v, expected %v", i, singular, testCase.Singular)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperRESTMapping(t *testing.T) {
|
||||
testGroup := "tgroup"
|
||||
testGroupVersion := schema.GroupVersion{Group: testGroup, Version: "test"}
|
||||
internalGroupVersion := schema.GroupVersion{Group: testGroup, Version: "test"}
|
||||
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
APIGroupVersions []schema.GroupVersion
|
||||
DefaultVersions []schema.GroupVersion
|
||||
|
||||
Resource string
|
||||
ExpectedGroupVersion *schema.GroupVersion
|
||||
Err bool
|
||||
}{
|
||||
{Kind: "Unknown", Err: true},
|
||||
{Kind: "InternalObject", Err: true},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "Unknown", Err: true},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{}, Resource: "internalobjects", ExpectedGroupVersion: &schema.GroupVersion{Group: testGroup, Version: "test"}},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
|
||||
// TODO: add test for a resource that exists in one version but not another
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
|
||||
mapper.Add(internalGroupVersion.WithKind("InternalObject"), RESTScopeNamespace)
|
||||
|
||||
preferredVersions := []string{}
|
||||
for _, gv := range testCase.APIGroupVersions {
|
||||
preferredVersions = append(preferredVersions, gv.Version)
|
||||
}
|
||||
gk := schema.GroupKind{Group: testGroup, Kind: testCase.Kind}
|
||||
|
||||
mapping, err := mapper.RESTMapping(gk, preferredVersions...)
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
|
||||
}
|
||||
if hasErr {
|
||||
continue
|
||||
}
|
||||
if mapping.Resource != testCase.Resource {
|
||||
t.Errorf("%d: unexpected resource: %#v", i, mapping)
|
||||
}
|
||||
|
||||
if mapping.MetadataAccessor == nil || mapping.ObjectConvertor == nil {
|
||||
t.Errorf("%d: missing codec and accessor: %#v", i, mapping)
|
||||
}
|
||||
|
||||
groupVersion := testCase.ExpectedGroupVersion
|
||||
if groupVersion == nil {
|
||||
groupVersion = &testCase.APIGroupVersions[0]
|
||||
}
|
||||
if mapping.GroupVersionKind.GroupVersion() != *groupVersion {
|
||||
t.Errorf("%d: unexpected version: %#v", i, mapping)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
|
||||
expectedGroupVersion1 := schema.GroupVersion{Group: "tgroup", Version: "test1"}
|
||||
expectedGroupVersion2 := schema.GroupVersion{Group: "tgroup", Version: "test2"}
|
||||
expectedGroupVersion3 := schema.GroupVersion{Group: "tgroup", Version: "test3"}
|
||||
internalObjectGK := schema.GroupKind{Group: "tgroup", Kind: "InternalObject"}
|
||||
otherObjectGK := schema.GroupKind{Group: "tgroup", Kind: "OtherObject"}
|
||||
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, fakeInterfaces)
|
||||
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace)
|
||||
mapper.Add(expectedGroupVersion2.WithKind("OtherObject"), RESTScopeNamespace)
|
||||
|
||||
// pick default matching object kind based on search order
|
||||
mapping, err := mapper.RESTMapping(otherObjectGK)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
|
||||
mapping, err = mapper.RESTMapping(internalObjectGK)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "internalobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion1 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
|
||||
// mismatch of version
|
||||
mapping, err = mapper.RESTMapping(internalObjectGK, expectedGroupVersion2.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion1.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
// not in the search versions
|
||||
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
// explicit search order
|
||||
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion1.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion2.Version)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperRESTMappings(t *testing.T) {
|
||||
testGroup := "tgroup"
|
||||
testGroupVersion := schema.GroupVersion{Group: testGroup, Version: "v1"}
|
||||
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
APIGroupVersions []schema.GroupVersion
|
||||
DefaultVersions []schema.GroupVersion
|
||||
AddGroupVersionKind []schema.GroupVersionKind
|
||||
|
||||
ExpectedRESTMappings []*RESTMapping
|
||||
Err bool
|
||||
}{
|
||||
{Kind: "Unknown", Err: true},
|
||||
{Kind: "InternalObject", Err: true},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "Unknown", Err: true},
|
||||
|
||||
// ask for specific version - not available - thus error
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v2"}}, Err: true},
|
||||
|
||||
// ask for specific version - available - check ExpectedRESTMappings
|
||||
{
|
||||
DefaultVersions: []schema.GroupVersion{testGroupVersion},
|
||||
Kind: "InternalObject",
|
||||
APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v2"}},
|
||||
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
|
||||
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
|
||||
},
|
||||
|
||||
// ask for specific versions - only one available - check ExpectedRESTMappings
|
||||
{
|
||||
DefaultVersions: []schema.GroupVersion{testGroupVersion},
|
||||
Kind: "InternalObject",
|
||||
APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v3"}, {Group: testGroup, Version: "v2"}},
|
||||
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
|
||||
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
|
||||
},
|
||||
|
||||
// do not ask for specific version - search through default versions - check ExpectedRESTMappings
|
||||
{
|
||||
DefaultVersions: []schema.GroupVersion{testGroupVersion, {Group: testGroup, Version: "v2"}},
|
||||
Kind: "InternalObject",
|
||||
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v1"}.WithKind("InternalObject"), schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
|
||||
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v1", Kind: "InternalObject"}}, {Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
|
||||
},
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
|
||||
for _, gvk := range testCase.AddGroupVersionKind {
|
||||
mapper.Add(gvk, RESTScopeNamespace)
|
||||
}
|
||||
|
||||
preferredVersions := []string{}
|
||||
for _, gv := range testCase.APIGroupVersions {
|
||||
preferredVersions = append(preferredVersions, gv.Version)
|
||||
}
|
||||
gk := schema.GroupKind{Group: testGroup, Kind: testCase.Kind}
|
||||
|
||||
mappings, err := mapper.RESTMappings(gk, preferredVersions...)
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
|
||||
}
|
||||
if hasErr {
|
||||
continue
|
||||
}
|
||||
if len(mappings) != len(testCase.ExpectedRESTMappings) {
|
||||
t.Errorf("%d: unexpected number = %d of rest mappings was returned, expected = %d", i, len(mappings), len(testCase.ExpectedRESTMappings))
|
||||
}
|
||||
for j, mapping := range mappings {
|
||||
exp := testCase.ExpectedRESTMappings[j]
|
||||
if mapping.Resource != exp.Resource {
|
||||
t.Errorf("%d - %d: unexpected resource: %#v", i, j, mapping)
|
||||
}
|
||||
if mapping.MetadataAccessor == nil || mapping.ObjectConvertor == nil {
|
||||
t.Errorf("%d - %d: missing codec and accessor: %#v", i, j, mapping)
|
||||
}
|
||||
if mapping.GroupVersionKind != exp.GroupVersionKind {
|
||||
t.Errorf("%d - %d: unexpected GroupVersionKind: %#v", i, j, mapping)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) {
|
||||
expectedGroupVersion1 := schema.GroupVersion{Group: "tgroup", Version: "test1"}
|
||||
expectedGroupVersion2 := schema.GroupVersion{Group: "tgroup", Version: "test2"}
|
||||
internalObjectGK := schema.GroupKind{Group: "tgroup", Kind: "InternalObject"}
|
||||
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, unmatchedVersionInterfaces)
|
||||
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace)
|
||||
_, err := mapper.RESTMapping(internalObjectGK, expectedGroupVersion1.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
}
|
||||
133
vendor/k8s.io/apimachinery/pkg/api/resource/amount_test.go
generated
vendored
Normal file
133
vendor/k8s.io/apimachinery/pkg/api/resource/amount_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
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 resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInt64AmountAsInt64(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
value int64
|
||||
scale Scale
|
||||
result int64
|
||||
ok bool
|
||||
}{
|
||||
{100, 0, 100, true},
|
||||
{100, 1, 1000, true},
|
||||
{100, -5, 0, false},
|
||||
{100, 100, 0, false},
|
||||
} {
|
||||
r, ok := int64Amount{value: test.value, scale: test.scale}.AsInt64()
|
||||
if r != test.result {
|
||||
t.Errorf("%v: unexpected result: %d", test, r)
|
||||
}
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: unexpected ok: %t", test, ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64AmountAdd(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
a, b, c int64Amount
|
||||
ok bool
|
||||
}{
|
||||
{int64Amount{value: 100, scale: 1}, int64Amount{value: 10, scale: 2}, int64Amount{value: 200, scale: 1}, true},
|
||||
{int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 2}, int64Amount{value: 110, scale: 1}, true},
|
||||
{int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 100}, int64Amount{value: 1, scale: 100}, false},
|
||||
{int64Amount{value: -5, scale: 2}, int64Amount{value: 50, scale: 1}, int64Amount{value: 0, scale: 1}, true},
|
||||
{int64Amount{value: -5, scale: 2}, int64Amount{value: 5, scale: 2}, int64Amount{value: 0, scale: 2}, true},
|
||||
|
||||
{int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 1, scale: -1}, int64Amount{value: 0, scale: -1}, false},
|
||||
{int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 0, scale: -1}, int64Amount{value: mostPositive, scale: -1}, true},
|
||||
{int64Amount{value: mostPositive / 10, scale: 1}, int64Amount{value: 10, scale: 0}, int64Amount{value: mostPositive, scale: -1}, false},
|
||||
} {
|
||||
c := test.a
|
||||
ok := c.Add(test.b)
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: unexpected ok: %t", test, ok)
|
||||
}
|
||||
if ok {
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
} else {
|
||||
if c != test.a {
|
||||
t.Errorf("%v: overflow addition mutated source: %d", test, c)
|
||||
}
|
||||
}
|
||||
|
||||
// addition is commutative
|
||||
c = test.b
|
||||
if ok := c.Add(test.a); ok != test.ok {
|
||||
t.Errorf("%v: unexpected ok: %t", test, ok)
|
||||
}
|
||||
if ok {
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
} else {
|
||||
if c != test.b {
|
||||
t.Errorf("%v: overflow addition mutated source: %d", test, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestInt64AsCanonicalString(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
value int64
|
||||
scale Scale
|
||||
result string
|
||||
exponent int32
|
||||
}{
|
||||
{100, 0, "100", 0},
|
||||
{100, 1, "1", 3},
|
||||
{100, -1, "10", 0},
|
||||
{10800, -10, "1080", -9},
|
||||
} {
|
||||
r, exp := int64Amount{value: test.value, scale: test.scale}.AsCanonicalBytes(nil)
|
||||
if string(r) != test.result {
|
||||
t.Errorf("%v: unexpected result: %s", test, r)
|
||||
}
|
||||
if exp != test.exponent {
|
||||
t.Errorf("%v: unexpected exponent: %d", test, exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAmountSign(t *testing.T) {
|
||||
table := []struct {
|
||||
i int64Amount
|
||||
expect int
|
||||
}{
|
||||
{int64Amount{value: -50, scale: 1}, -1},
|
||||
{int64Amount{value: 0, scale: 1}, 0},
|
||||
{int64Amount{value: 300, scale: 1}, 1},
|
||||
{int64Amount{value: -50, scale: -8}, -1},
|
||||
{int64Amount{value: 50, scale: -8}, 1},
|
||||
{int64Amount{value: 0, scale: -8}, 0},
|
||||
{int64Amount{value: -50, scale: 0}, -1},
|
||||
{int64Amount{value: 50, scale: 0}, 1},
|
||||
{int64Amount{value: 0, scale: 0}, 0},
|
||||
}
|
||||
for _, testCase := range table {
|
||||
if result := testCase.i.Sign(); result != testCase.expect {
|
||||
t.Errorf("i: %v, Expected: %v, Actual: %v", testCase.i, testCase.expect, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
211
vendor/k8s.io/apimachinery/pkg/api/resource/math_test.go
generated
vendored
Normal file
211
vendor/k8s.io/apimachinery/pkg/api/resource/math_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
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 resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDetectOverflowAdd(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
a, b int64
|
||||
c int64
|
||||
ok bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{-1, 1, 0, true},
|
||||
{0, 1, 1, true},
|
||||
{2, 2, 4, true},
|
||||
{2, -2, 0, true},
|
||||
{-2, -2, -4, true},
|
||||
|
||||
{mostNegative, -1, 0, false},
|
||||
{mostNegative, 1, mostNegative + 1, true},
|
||||
{mostPositive, -1, mostPositive - 1, true},
|
||||
{mostPositive, 1, 0, false},
|
||||
|
||||
{mostNegative, mostPositive, -1, true},
|
||||
{mostPositive, mostNegative, -1, true},
|
||||
{mostPositive, mostPositive, 0, false},
|
||||
{mostNegative, mostNegative, 0, false},
|
||||
|
||||
{-mostPositive, mostNegative, 0, false},
|
||||
{mostNegative, -mostPositive, 0, false},
|
||||
{-mostPositive, -mostPositive, 0, false},
|
||||
} {
|
||||
c, ok := int64Add(test.a, test.b)
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: unexpected overflow: %t", test, ok)
|
||||
}
|
||||
// addition is commutative
|
||||
d, ok2 := int64Add(test.b, test.a)
|
||||
if c != d || ok != ok2 {
|
||||
t.Errorf("%v: not commutative: %d %t", test, d, ok2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectOverflowMultiply(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
a, b int64
|
||||
c int64
|
||||
ok bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{-1, 1, -1, true},
|
||||
{-1, -1, 1, true},
|
||||
{1, 1, 1, true},
|
||||
{0, 1, 0, true},
|
||||
{1, 0, 0, true},
|
||||
{2, 2, 4, true},
|
||||
{2, -2, -4, true},
|
||||
{-2, -2, 4, true},
|
||||
|
||||
{mostNegative, -1, 0, false},
|
||||
{mostNegative, 1, mostNegative, true},
|
||||
{mostPositive, -1, -mostPositive, true},
|
||||
{mostPositive, 1, mostPositive, true},
|
||||
|
||||
{mostNegative, mostPositive, 0, false},
|
||||
{mostPositive, mostNegative, 0, false},
|
||||
{mostPositive, mostPositive, 1, false},
|
||||
{mostNegative, mostNegative, 0, false},
|
||||
|
||||
{-mostPositive, mostNegative, 0, false},
|
||||
{mostNegative, -mostPositive, 0, false},
|
||||
{-mostPositive, -mostPositive, 1, false},
|
||||
} {
|
||||
c, ok := int64Multiply(test.a, test.b)
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: unexpected overflow: %t", test, ok)
|
||||
}
|
||||
// multiplication is commutative
|
||||
d, ok2 := int64Multiply(test.b, test.a)
|
||||
if c != d || ok != ok2 {
|
||||
t.Errorf("%v: not commutative: %d %t", test, d, ok2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectOverflowScale(t *testing.T) {
|
||||
for _, a := range []int64{0, -1, 1, 10, -10, mostPositive, mostNegative, -mostPositive} {
|
||||
for _, b := range []int64{1, 2, 10, 100, 1000, mostPositive} {
|
||||
expect, expectOk := int64Multiply(a, b)
|
||||
|
||||
c, ok := int64MultiplyScale(a, b)
|
||||
if c != expect {
|
||||
t.Errorf("%d*%d: unexpected result: %d", a, b, c)
|
||||
}
|
||||
if ok != expectOk {
|
||||
t.Errorf("%d*%d: unexpected overflow: %t", a, b, ok)
|
||||
}
|
||||
}
|
||||
for _, test := range []struct {
|
||||
base int64
|
||||
fn func(a int64) (int64, bool)
|
||||
}{
|
||||
{10, int64MultiplyScale10},
|
||||
{100, int64MultiplyScale100},
|
||||
{1000, int64MultiplyScale1000},
|
||||
} {
|
||||
expect, expectOk := int64Multiply(a, test.base)
|
||||
c, ok := test.fn(a)
|
||||
if c != expect {
|
||||
t.Errorf("%d*%d: unexpected result: %d", a, test.base, c)
|
||||
}
|
||||
if ok != expectOk {
|
||||
t.Errorf("%d*%d: unexpected overflow: %t", a, test.base, ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveInt64Factors(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
value int64
|
||||
max int64
|
||||
result int64
|
||||
scale int32
|
||||
}{
|
||||
{100, 10, 1, 2},
|
||||
{100, 10, 1, 2},
|
||||
{100, 100, 1, 1},
|
||||
{1, 10, 1, 0},
|
||||
} {
|
||||
r, s := removeInt64Factors(test.value, test.max)
|
||||
if r != test.result {
|
||||
t.Errorf("%v: unexpected result: %d", test, r)
|
||||
}
|
||||
if s != test.scale {
|
||||
t.Errorf("%v: unexpected scale: %d", test, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegativeScaleInt64(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
base int64
|
||||
scale Scale
|
||||
result int64
|
||||
exact bool
|
||||
}{
|
||||
{1234567, 0, 1234567, true},
|
||||
{1234567, 1, 123457, false},
|
||||
{1234567, 2, 12346, false},
|
||||
{1234567, 3, 1235, false},
|
||||
{1234567, 4, 124, false},
|
||||
|
||||
{-1234567, 0, -1234567, true},
|
||||
{-1234567, 1, -123457, false},
|
||||
{-1234567, 2, -12346, false},
|
||||
{-1234567, 3, -1235, false},
|
||||
{-1234567, 4, -124, false},
|
||||
|
||||
{1000, 0, 1000, true},
|
||||
{1000, 1, 100, true},
|
||||
{1000, 2, 10, true},
|
||||
{1000, 3, 1, true},
|
||||
{1000, 4, 1, false},
|
||||
|
||||
{-1000, 0, -1000, true},
|
||||
{-1000, 1, -100, true},
|
||||
{-1000, 2, -10, true},
|
||||
{-1000, 3, -1, true},
|
||||
{-1000, 4, -1, false},
|
||||
|
||||
{0, 0, 0, true},
|
||||
{0, 1, 0, true},
|
||||
{0, 2, 0, true},
|
||||
|
||||
// negative scale is undefined behavior
|
||||
{1000, -1, 1000, true},
|
||||
} {
|
||||
result, exact := negativeScaleInt64(test.base, test.scale)
|
||||
if result != test.result {
|
||||
t.Errorf("%v: unexpected result: %d", test, result)
|
||||
}
|
||||
if exact != test.exact {
|
||||
t.Errorf("%v: unexpected exact: %t", test, exact)
|
||||
}
|
||||
}
|
||||
}
|
||||
59
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_example_test.go
generated
vendored
Normal file
59
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_example_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
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 resource_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
)
|
||||
|
||||
func ExampleFormat() {
|
||||
memorySize := resource.NewQuantity(5*1024*1024*1024, resource.BinarySI)
|
||||
fmt.Printf("memorySize = %v\n", memorySize)
|
||||
|
||||
diskSize := resource.NewQuantity(5*1000*1000*1000, resource.DecimalSI)
|
||||
fmt.Printf("diskSize = %v\n", diskSize)
|
||||
|
||||
cores := resource.NewMilliQuantity(5300, resource.DecimalSI)
|
||||
fmt.Printf("cores = %v\n", cores)
|
||||
|
||||
// Output:
|
||||
// memorySize = 5Gi
|
||||
// diskSize = 5G
|
||||
// cores = 5300m
|
||||
}
|
||||
|
||||
func ExampleMustParse() {
|
||||
memorySize := resource.MustParse("5Gi")
|
||||
fmt.Printf("memorySize = %v (%v)\n", memorySize.Value(), memorySize.Format)
|
||||
|
||||
diskSize := resource.MustParse("5G")
|
||||
fmt.Printf("diskSize = %v (%v)\n", diskSize.Value(), diskSize.Format)
|
||||
|
||||
cores := resource.MustParse("5300m")
|
||||
fmt.Printf("milliCores = %v (%v)\n", cores.MilliValue(), cores.Format)
|
||||
|
||||
cores2 := resource.MustParse("5.4")
|
||||
fmt.Printf("milliCores = %v (%v)\n", cores2.MilliValue(), cores2.Format)
|
||||
|
||||
// Output:
|
||||
// memorySize = 5368709120 (BinarySI)
|
||||
// diskSize = 5000000000 (DecimalSI)
|
||||
// milliCores = 5300 (DecimalSI)
|
||||
// milliCores = 5400 (DecimalSI)
|
||||
}
|
||||
103
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto_test.go
generated
vendored
Normal file
103
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Copyright 2017 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 resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
inf "gopkg.in/inf.v0"
|
||||
)
|
||||
|
||||
func TestQuantityProtoMarshal(t *testing.T) {
|
||||
// Test when d is nil
|
||||
table := []struct {
|
||||
quantity string
|
||||
expect Quantity
|
||||
}{
|
||||
{"0", Quantity{i: int64Amount{value: 0, scale: 0}, s: "0", Format: DecimalSI}},
|
||||
{"100m", Quantity{i: int64Amount{value: 100, scale: -3}, s: "100m", Format: DecimalSI}},
|
||||
{"50m", Quantity{i: int64Amount{value: 50, scale: -3}, s: "50m", Format: DecimalSI}},
|
||||
{"10000T", Quantity{i: int64Amount{value: 10000, scale: 12}, s: "10000T", Format: DecimalSI}},
|
||||
}
|
||||
for _, testCase := range table {
|
||||
q := MustParse(testCase.quantity)
|
||||
// Won't currently get an error as MarshalTo can't return one
|
||||
result, _ := q.Marshal()
|
||||
q.MarshalTo(result)
|
||||
if q.Cmp(testCase.expect) != 0 {
|
||||
t.Errorf("Expected: %v, Actual: %v", testCase.expect, q)
|
||||
}
|
||||
}
|
||||
// Test when i is {0,0}
|
||||
table2 := []struct {
|
||||
dec *inf.Dec
|
||||
expect Quantity
|
||||
}{
|
||||
{dec(0, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(0, 0).Dec}, s: "0", Format: DecimalSI}},
|
||||
{dec(10, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(10, 0).Dec}, s: "10", Format: DecimalSI}},
|
||||
{dec(-10, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(-10, 0).Dec}, s: "-10", Format: DecimalSI}},
|
||||
}
|
||||
for _, testCase := range table2 {
|
||||
q := Quantity{d: infDecAmount{testCase.dec}, Format: DecimalSI}
|
||||
// Won't currently get an error as MarshalTo can't return one
|
||||
result, _ := q.Marshal()
|
||||
q.Unmarshal(result)
|
||||
if q.Cmp(testCase.expect) != 0 {
|
||||
t.Errorf("Expected: %v, Actual: %v", testCase.expect, q)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuantityProtoUnmarshal(t *testing.T) {
|
||||
// Test when d is nil
|
||||
table := []struct {
|
||||
input Quantity
|
||||
expect string
|
||||
}{
|
||||
{Quantity{i: int64Amount{value: 0, scale: 0}, s: "0", Format: DecimalSI}, "0"},
|
||||
{Quantity{i: int64Amount{value: 100, scale: -3}, s: "100m", Format: DecimalSI}, "100m"},
|
||||
{Quantity{i: int64Amount{value: 50, scale: -3}, s: "50m", Format: DecimalSI}, "50m"},
|
||||
{Quantity{i: int64Amount{value: 10000, scale: 12}, s: "10000T", Format: DecimalSI}, "10000T"},
|
||||
}
|
||||
for _, testCase := range table {
|
||||
var inputQ Quantity
|
||||
expectQ := MustParse(testCase.expect)
|
||||
inputByteArray, _ := testCase.input.Marshal()
|
||||
inputQ.Unmarshal(inputByteArray)
|
||||
if inputQ.Cmp(expectQ) != 0 {
|
||||
t.Errorf("Expected: %v, Actual: %v", inputQ, expectQ)
|
||||
}
|
||||
}
|
||||
// Test when i is {0,0}
|
||||
table2 := []struct {
|
||||
input Quantity
|
||||
expect *inf.Dec
|
||||
}{
|
||||
{Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(0, 0).Dec}, s: "0", Format: DecimalSI}, dec(0, 0).Dec},
|
||||
{Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(10, 0).Dec}, s: "10", Format: DecimalSI}, dec(10, 0).Dec},
|
||||
{Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(-10, 0).Dec}, s: "-10", Format: DecimalSI}, dec(-10, 0).Dec},
|
||||
}
|
||||
for _, testCase := range table2 {
|
||||
var inputQ Quantity
|
||||
expectQ := Quantity{d: infDecAmount{testCase.expect}, Format: DecimalSI}
|
||||
inputByteArray, _ := testCase.input.Marshal()
|
||||
inputQ.Unmarshal(inputByteArray)
|
||||
if inputQ.Cmp(expectQ) != 0 {
|
||||
t.Errorf("Expected: %v, Actual: %v", inputQ, expectQ)
|
||||
}
|
||||
}
|
||||
}
|
||||
1370
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_test.go
generated
vendored
Normal file
1370
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
85
vendor/k8s.io/apimachinery/pkg/api/resource/scale_int_test.go
generated
vendored
Normal file
85
vendor/k8s.io/apimachinery/pkg/api/resource/scale_int_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright 2015 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 resource
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScaledValueInternal(t *testing.T) {
|
||||
tests := []struct {
|
||||
unscaled *big.Int
|
||||
scale int
|
||||
newScale int
|
||||
|
||||
want int64
|
||||
}{
|
||||
// remain scale
|
||||
{big.NewInt(1000), 0, 0, 1000},
|
||||
|
||||
// scale down
|
||||
{big.NewInt(1000), 0, -3, 1},
|
||||
{big.NewInt(1000), 3, 0, 1},
|
||||
{big.NewInt(0), 3, 0, 0},
|
||||
|
||||
// always round up
|
||||
{big.NewInt(999), 3, 0, 1},
|
||||
{big.NewInt(500), 3, 0, 1},
|
||||
{big.NewInt(499), 3, 0, 1},
|
||||
{big.NewInt(1), 3, 0, 1},
|
||||
// large scaled value does not lose precision
|
||||
{big.NewInt(0).Sub(maxInt64, bigOne), 1, 0, (math.MaxInt64-1)/10 + 1},
|
||||
// large intermidiate result.
|
||||
{big.NewInt(1).Exp(big.NewInt(10), big.NewInt(100), nil), 100, 0, 1},
|
||||
|
||||
// scale up
|
||||
{big.NewInt(0), 0, 3, 0},
|
||||
{big.NewInt(1), 0, 3, 1000},
|
||||
{big.NewInt(1), -3, 0, 1000},
|
||||
{big.NewInt(1000), -3, 2, 100000000},
|
||||
{big.NewInt(0).Div(big.NewInt(math.MaxInt64), bigThousand), 0, 3,
|
||||
(math.MaxInt64 / 1000) * 1000},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
old := (&big.Int{}).Set(tt.unscaled)
|
||||
got := scaledValue(tt.unscaled, tt.scale, tt.newScale)
|
||||
if got != tt.want {
|
||||
t.Errorf("#%d: got = %v, want %v", i, got, tt.want)
|
||||
}
|
||||
if tt.unscaled.Cmp(old) != 0 {
|
||||
t.Errorf("#%d: unscaled = %v, want %v", i, tt.unscaled, old)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScaledValueSmall(b *testing.B) {
|
||||
s := big.NewInt(1000)
|
||||
for i := 0; i < b.N; i++ {
|
||||
scaledValue(s, 3, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScaledValueLarge(b *testing.B) {
|
||||
s := big.NewInt(math.MaxInt64)
|
||||
s.Mul(s, big.NewInt(1000))
|
||||
for i := 0; i < b.N; i++ {
|
||||
scaledValue(s, 10, 0)
|
||||
}
|
||||
}
|
||||
34
vendor/k8s.io/apimachinery/pkg/api/testing/BUILD
generated
vendored
Normal file
34
vendor/k8s.io/apimachinery/pkg/api/testing/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["codec.go"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/testing/fuzzer:all-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/testing/roundtrip:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
86
vendor/k8s.io/apimachinery/pkg/api/testing/codec.go
generated
vendored
Normal file
86
vendor/k8s.io/apimachinery/pkg/api/testing/codec.go
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright 2017 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 testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
|
||||
)
|
||||
|
||||
var (
|
||||
testCodecMediaType string
|
||||
testStorageCodecMediaType string
|
||||
)
|
||||
|
||||
// TestCodec returns the codec for the API version to test against, as set by the
|
||||
// KUBE_TEST_API_TYPE env var.
|
||||
func TestCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.GroupVersion) runtime.Codec {
|
||||
if len(testCodecMediaType) != 0 {
|
||||
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), testCodecMediaType)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("no serializer for %s", testCodecMediaType))
|
||||
}
|
||||
return codecs.CodecForVersions(serializerInfo.Serializer, codecs.UniversalDeserializer(), schema.GroupVersions(gvs), nil)
|
||||
}
|
||||
return codecs.LegacyCodec(gvs...)
|
||||
}
|
||||
|
||||
// TestStorageCodec returns the codec for the API version to test against used in storage, as set by the
|
||||
// KUBE_TEST_API_STORAGE_TYPE env var.
|
||||
func TestStorageCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.GroupVersion) runtime.Codec {
|
||||
if len(testStorageCodecMediaType) != 0 {
|
||||
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), testStorageCodecMediaType)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("no serializer for %s", testStorageCodecMediaType))
|
||||
}
|
||||
|
||||
// etcd2 only supports string data - we must wrap any result before returning
|
||||
// TODO: remove for etcd3 / make parameterizable
|
||||
serializer := serializerInfo.Serializer
|
||||
if !serializerInfo.EncodesAsText {
|
||||
serializer = runtime.NewBase64Serializer(serializer, serializer)
|
||||
}
|
||||
|
||||
decoder := recognizer.NewDecoder(serializer, codecs.UniversalDeserializer())
|
||||
return codecs.CodecForVersions(serializer, decoder, schema.GroupVersions(gvs), nil)
|
||||
|
||||
}
|
||||
return codecs.LegacyCodec(gvs...)
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
if apiMediaType := os.Getenv("KUBE_TEST_API_TYPE"); len(apiMediaType) > 0 {
|
||||
testCodecMediaType, _, err = mime.ParseMediaType(apiMediaType)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if storageMediaType := os.Getenv("KUBE_TEST_API_STORAGE_TYPE"); len(storageMediaType) > 0 {
|
||||
testStorageCodecMediaType, _, err = mime.ParseMediaType(storageMediaType)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
38
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/BUILD
generated
vendored
Normal file
38
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["valuefuzz_test.go"],
|
||||
library = ":go_default_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"fuzzer.go",
|
||||
"valuefuzz.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
52
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/fuzzer.go
generated
vendored
Normal file
52
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/fuzzer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2017 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 fuzzer
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
// FuzzerFuncs returns a list of func(*SomeType, c fuzz.Continue) functions.
|
||||
type FuzzerFuncs func(codecs runtimeserializer.CodecFactory) []interface{}
|
||||
|
||||
// FuzzerFor can randomly populate api objects that are destined for version.
|
||||
func FuzzerFor(funcs FuzzerFuncs, src rand.Source, codecs runtimeserializer.CodecFactory) *fuzz.Fuzzer {
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 1)
|
||||
if src != nil {
|
||||
f.RandSource(src)
|
||||
}
|
||||
f.Funcs(funcs(codecs)...)
|
||||
return f
|
||||
}
|
||||
|
||||
// MergeFuzzerFuncs will merge the given funcLists, overriding early funcs with later ones if there first
|
||||
// argument has the same type.
|
||||
func MergeFuzzerFuncs(funcs ...FuzzerFuncs) FuzzerFuncs {
|
||||
return FuzzerFuncs(func(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
result := []interface{}{}
|
||||
for _, f := range funcs {
|
||||
if f != nil {
|
||||
result = append(result, f(codecs)...)
|
||||
}
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
86
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/valuefuzz.go
generated
vendored
Normal file
86
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/valuefuzz.go
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Copyright 2017 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 fuzzer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ValueFuzz recursively changes all basic type values in an object. Any kind of references will not
|
||||
// be touch, i.e. the addresses of slices, maps, pointers will stay unchanged.
|
||||
func ValueFuzz(obj interface{}) {
|
||||
valueFuzz(reflect.ValueOf(obj))
|
||||
}
|
||||
|
||||
func valueFuzz(obj reflect.Value) {
|
||||
switch obj.Kind() {
|
||||
case reflect.Array:
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
valueFuzz(obj.Index(i))
|
||||
}
|
||||
case reflect.Slice:
|
||||
if obj.IsNil() {
|
||||
// TODO: set non-nil value
|
||||
} else {
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
valueFuzz(obj.Index(i))
|
||||
}
|
||||
}
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
if obj.IsNil() {
|
||||
// TODO: set non-nil value
|
||||
} else {
|
||||
valueFuzz(obj.Elem())
|
||||
}
|
||||
case reflect.Struct:
|
||||
for i, n := 0, obj.NumField(); i < n; i++ {
|
||||
valueFuzz(obj.Field(i))
|
||||
}
|
||||
case reflect.Map:
|
||||
if obj.IsNil() {
|
||||
// TODO: set non-nil value
|
||||
} else {
|
||||
for _, k := range obj.MapKeys() {
|
||||
// map values are not addressable. We need a copy.
|
||||
v := obj.MapIndex(k)
|
||||
copy := reflect.New(v.Type())
|
||||
copy.Elem().Set(v)
|
||||
valueFuzz(copy.Elem())
|
||||
obj.SetMapIndex(k, copy.Elem())
|
||||
}
|
||||
// TODO: set some new value
|
||||
}
|
||||
case reflect.Func: // ignore, we don't have function types in our API
|
||||
default:
|
||||
if !obj.CanSet() {
|
||||
return
|
||||
}
|
||||
switch obj.Kind() {
|
||||
case reflect.String:
|
||||
obj.SetString(obj.String() + "x")
|
||||
case reflect.Bool:
|
||||
obj.SetBool(!obj.Bool())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
obj.SetFloat(obj.Float()*2.0 + 1.0)
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||
obj.SetInt(obj.Int() + 1)
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
obj.SetUint(obj.Uint() + 1)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
73
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/valuefuzz_test.go
generated
vendored
Normal file
73
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/valuefuzz_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
Copyright 2017 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 fuzzer
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestValueFuzz(t *testing.T) {
|
||||
type (
|
||||
Y struct {
|
||||
I int
|
||||
B bool
|
||||
F float32
|
||||
U uint
|
||||
}
|
||||
X struct {
|
||||
Ptr *X
|
||||
Y Y
|
||||
Map map[string]int
|
||||
Slice []int
|
||||
}
|
||||
)
|
||||
|
||||
x := X{
|
||||
Ptr: &X{},
|
||||
Map: map[string]int{"foo": 42},
|
||||
Slice: []int{1, 2, 3},
|
||||
}
|
||||
|
||||
p := x.Ptr
|
||||
m := x.Map
|
||||
s := x.Slice
|
||||
|
||||
ValueFuzz(x)
|
||||
|
||||
if x.Ptr.Y.I == 0 {
|
||||
t.Errorf("x.Ptr.Y.I should have changed")
|
||||
}
|
||||
|
||||
if x.Map["foo"] == 42 {
|
||||
t.Errorf("x.Map[foo] should have changed")
|
||||
}
|
||||
|
||||
if x.Slice[0] == 1 {
|
||||
t.Errorf("x.Slice[0] should have changed")
|
||||
}
|
||||
|
||||
if x.Ptr != p {
|
||||
t.Errorf("x.Ptr changed")
|
||||
}
|
||||
|
||||
m["foo"] = 7
|
||||
if x.Map["foo"] != m["foo"] {
|
||||
t.Errorf("x.Map changed")
|
||||
}
|
||||
s[0] = 7
|
||||
if x.Slice[0] != s[0] {
|
||||
t.Errorf("x.Slice changed")
|
||||
}
|
||||
}
|
||||
44
vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip/BUILD
generated
vendored
Normal file
44
vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["roundtrip.go"],
|
||||
deps = [
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
"//vendor/github.com/golang/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
409
vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip/roundtrip.go
generated
vendored
Normal file
409
vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip/roundtrip.go
generated
vendored
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
/*
|
||||
Copyright 2017 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 roundtrip
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/gofuzz"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/protobuf"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
type InstallFunc func(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme)
|
||||
|
||||
// RoundTripTestForAPIGroup is convenient to call from your install package to make sure that a "bare" install of your group provides
|
||||
// enough information to round trip
|
||||
func RoundTripTestForAPIGroup(t *testing.T, installFn InstallFunc, fuzzingFuncs fuzzer.FuzzerFuncs) {
|
||||
groupFactoryRegistry := make(announced.APIGroupFactoryRegistry)
|
||||
registry := registered.NewOrDie("")
|
||||
scheme := runtime.NewScheme()
|
||||
installFn(groupFactoryRegistry, registry, scheme)
|
||||
|
||||
RoundTripTestForScheme(t, scheme, fuzzingFuncs)
|
||||
}
|
||||
|
||||
// RoundTripTestForScheme is convenient to call if you already have a scheme and want to make sure that its well-formed
|
||||
func RoundTripTestForScheme(t *testing.T, scheme *runtime.Scheme, fuzzingFuncs fuzzer.FuzzerFuncs) {
|
||||
codecFactory := runtimeserializer.NewCodecFactory(scheme)
|
||||
f := fuzzer.FuzzerFor(
|
||||
fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, fuzzingFuncs),
|
||||
rand.NewSource(rand.Int63()),
|
||||
codecFactory,
|
||||
)
|
||||
RoundTripTypesWithoutProtobuf(t, scheme, codecFactory, f, nil)
|
||||
}
|
||||
|
||||
// RoundTripProtobufTestForAPIGroup is convenient to call from your install package to make sure that a "bare" install of your group provides
|
||||
// enough information to round trip
|
||||
func RoundTripProtobufTestForAPIGroup(t *testing.T, installFn InstallFunc, fuzzingFuncs fuzzer.FuzzerFuncs) {
|
||||
groupFactoryRegistry := make(announced.APIGroupFactoryRegistry)
|
||||
registry := registered.NewOrDie("")
|
||||
scheme := runtime.NewScheme()
|
||||
installFn(groupFactoryRegistry, registry, scheme)
|
||||
|
||||
RoundTripProtobufTestForScheme(t, scheme, fuzzingFuncs)
|
||||
}
|
||||
|
||||
// RoundTripProtobufTestForScheme is convenient to call if you already have a scheme and want to make sure that its well-formed
|
||||
func RoundTripProtobufTestForScheme(t *testing.T, scheme *runtime.Scheme, fuzzingFuncs fuzzer.FuzzerFuncs) {
|
||||
codecFactory := runtimeserializer.NewCodecFactory(scheme)
|
||||
fuzzer := fuzzer.FuzzerFor(
|
||||
fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, fuzzingFuncs),
|
||||
rand.NewSource(rand.Int63()),
|
||||
codecFactory,
|
||||
)
|
||||
RoundTripTypes(t, scheme, codecFactory, fuzzer, nil)
|
||||
}
|
||||
|
||||
var FuzzIters = flag.Int("fuzz-iters", 20, "How many fuzzing iterations to do.")
|
||||
|
||||
// globalNonRoundTrippableTypes are kinds that are effectively reserved across all GroupVersions
|
||||
// They don't roundtrip
|
||||
var globalNonRoundTrippableTypes = sets.NewString(
|
||||
"ExportOptions",
|
||||
"GetOptions",
|
||||
// WatchEvent does not include kind and version and can only be deserialized
|
||||
// implicitly (if the caller expects the specific object). The watch call defines
|
||||
// the schema by content type, rather than via kind/version included in each
|
||||
// object.
|
||||
"WatchEvent",
|
||||
// ListOptions is now part of the meta group
|
||||
"ListOptions",
|
||||
// Delete options is only read in metav1
|
||||
"DeleteOptions",
|
||||
)
|
||||
|
||||
// RoundTripTypesWithoutProtobuf applies the round-trip test to all round-trippable Kinds
|
||||
// in the scheme. It will skip all the GroupVersionKinds in the skip list.
|
||||
func RoundTripTypesWithoutProtobuf(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
|
||||
roundTripTypes(t, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
|
||||
}
|
||||
|
||||
func RoundTripTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
|
||||
roundTripTypes(t, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, false)
|
||||
}
|
||||
|
||||
func roundTripTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
|
||||
for _, group := range groupsFromScheme(scheme) {
|
||||
t.Logf("starting group %q", group)
|
||||
internalVersion := schema.GroupVersion{Group: group, Version: runtime.APIVersionInternal}
|
||||
internalKindToGoType := scheme.KnownTypes(internalVersion)
|
||||
|
||||
for kind := range internalKindToGoType {
|
||||
if globalNonRoundTrippableTypes.Has(kind) {
|
||||
continue
|
||||
}
|
||||
|
||||
internalGVK := internalVersion.WithKind(kind)
|
||||
roundTripSpecificKind(t, internalGVK, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, skipProtobuf)
|
||||
}
|
||||
|
||||
t.Logf("finished group %q", group)
|
||||
}
|
||||
}
|
||||
|
||||
func RoundTripSpecificKindWithoutProtobuf(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
|
||||
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
|
||||
}
|
||||
|
||||
func RoundTripSpecificKind(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
|
||||
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, false)
|
||||
}
|
||||
|
||||
func roundTripSpecificKind(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
|
||||
if nonRoundTrippableTypes[gvk] {
|
||||
t.Logf("skipping %v", gvk)
|
||||
return
|
||||
}
|
||||
t.Logf("round tripping %v", gvk)
|
||||
|
||||
// Try a few times, since runTest uses random values.
|
||||
for i := 0; i < *FuzzIters; i++ {
|
||||
if gvk.Version == runtime.APIVersionInternal {
|
||||
roundTripToAllExternalVersions(t, scheme, codecFactory, fuzzer, gvk, nonRoundTrippableTypes, skipProtobuf)
|
||||
} else {
|
||||
roundTripOfExternalType(t, scheme, codecFactory, fuzzer, gvk, skipProtobuf)
|
||||
}
|
||||
if t.Failed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
|
||||
// fuzzer registered with the apitesting package.
|
||||
func fuzzInternalObject(t *testing.T, fuzzer *fuzz.Fuzzer, object runtime.Object) runtime.Object {
|
||||
fuzzer.Fuzz(object)
|
||||
|
||||
j, err := apimeta.TypeAccessor(object)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v for %#v", err, object)
|
||||
}
|
||||
j.SetKind("")
|
||||
j.SetAPIVersion("")
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
func groupsFromScheme(scheme *runtime.Scheme) []string {
|
||||
ret := sets.String{}
|
||||
for gvk := range scheme.AllKnownTypes() {
|
||||
ret.Insert(gvk.Group)
|
||||
}
|
||||
return ret.List()
|
||||
}
|
||||
|
||||
func roundTripToAllExternalVersions(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, internalGVK schema.GroupVersionKind, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
|
||||
object, err := scheme.New(internalGVK)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't make a %v? %v", internalGVK, err)
|
||||
}
|
||||
if _, err := apimeta.TypeAccessor(object); err != nil {
|
||||
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableInternalTypes: %v", internalGVK, err)
|
||||
}
|
||||
|
||||
fuzzInternalObject(t, fuzzer, object)
|
||||
|
||||
// find all potential serializations in the scheme.
|
||||
// TODO fix this up to handle kinds that cross registered with different names.
|
||||
for externalGVK, externalGoType := range scheme.AllKnownTypes() {
|
||||
if externalGVK.Version == runtime.APIVersionInternal {
|
||||
continue
|
||||
}
|
||||
if externalGVK.GroupKind() != internalGVK.GroupKind() {
|
||||
continue
|
||||
}
|
||||
if nonRoundTrippableTypes[externalGVK] {
|
||||
t.Logf("\tskipping %v %v", externalGVK, externalGoType)
|
||||
continue
|
||||
}
|
||||
t.Logf("\tround tripping to %v %v", externalGVK, externalGoType)
|
||||
|
||||
roundTrip(t, scheme, apitesting.TestCodec(codecFactory, externalGVK.GroupVersion()), object)
|
||||
|
||||
// TODO remove this hack after we're past the intermediate steps
|
||||
if !skipProtobuf && externalGVK.Group != "kubeadm.k8s.io" {
|
||||
s := protobuf.NewSerializer(scheme, scheme, "application/arbitrary.content.type")
|
||||
protobufCodec := codecFactory.CodecForVersions(s, s, externalGVK.GroupVersion(), nil)
|
||||
roundTrip(t, scheme, protobufCodec, object)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func roundTripOfExternalType(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, externalGVK schema.GroupVersionKind, skipProtobuf bool) {
|
||||
object, err := scheme.New(externalGVK)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't make a %v? %v", externalGVK, err)
|
||||
}
|
||||
typeAcc, err := apimeta.TypeAccessor(object)
|
||||
if err != nil {
|
||||
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableInternalTypes: %v", externalGVK, err)
|
||||
}
|
||||
|
||||
fuzzInternalObject(t, fuzzer, object)
|
||||
|
||||
externalGoType := reflect.TypeOf(object).PkgPath()
|
||||
t.Logf("\tround tripping external type %v %v", externalGVK, externalGoType)
|
||||
|
||||
typeAcc.SetKind(externalGVK.Kind)
|
||||
typeAcc.SetAPIVersion(externalGVK.GroupVersion().String())
|
||||
|
||||
roundTrip(t, scheme, json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false), object)
|
||||
|
||||
// TODO remove this hack after we're past the intermediate steps
|
||||
if !skipProtobuf {
|
||||
roundTrip(t, scheme, protobuf.NewSerializer(scheme, scheme, "application/protobuf"), object)
|
||||
}
|
||||
}
|
||||
|
||||
// roundTrip applies a single round-trip test to the given runtime object
|
||||
// using the given codec. The round-trip test ensures that an object can be
|
||||
// deep-copied, converted, marshaled and back without loss of data.
|
||||
//
|
||||
// For internal types this means
|
||||
//
|
||||
// internal -> external -> json/protobuf -> external -> internal.
|
||||
//
|
||||
// For external types this means
|
||||
//
|
||||
// external -> json/protobuf -> external.
|
||||
func roundTrip(t *testing.T, scheme *runtime.Scheme, codec runtime.Codec, object runtime.Object) {
|
||||
printer := spew.ConfigState{DisableMethods: true}
|
||||
original := object
|
||||
|
||||
// deep copy the original object
|
||||
object = object.DeepCopyObject()
|
||||
name := reflect.TypeOf(object).Elem().Name()
|
||||
if !apiequality.Semantic.DeepEqual(original, object) {
|
||||
t.Errorf("%v: DeepCopy altered the object, diff: %v", name, diff.ObjectReflectDiff(original, object))
|
||||
t.Errorf("%s", spew.Sdump(original))
|
||||
t.Errorf("%s", spew.Sdump(object))
|
||||
return
|
||||
}
|
||||
|
||||
// catch deepcopy errors early
|
||||
if !apiequality.Semantic.DeepEqual(original, object) {
|
||||
t.Errorf("%v: DeepCopy did not lead to equal object, diff: %v", name, diff.ObjectReflectDiff(original, object))
|
||||
return
|
||||
}
|
||||
|
||||
// encode (serialize) the deep copy using the provided codec
|
||||
data, err := runtime.Encode(codec, object)
|
||||
if err != nil {
|
||||
if runtime.IsNotRegisteredError(err) {
|
||||
t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", object))
|
||||
} else {
|
||||
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", object))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ensure that the deep copy is equal to the original; neither the deep
|
||||
// copy or conversion should alter the object
|
||||
// TODO eliminate this global
|
||||
if !apiequality.Semantic.DeepEqual(original, object) {
|
||||
t.Errorf("%v: encode altered the object, diff: %v", name, diff.ObjectReflectDiff(original, object))
|
||||
return
|
||||
}
|
||||
|
||||
// encode (serialize) a second time to verify that it was not varying
|
||||
secondData, err := runtime.Encode(codec, object)
|
||||
if err != nil {
|
||||
if runtime.IsNotRegisteredError(err) {
|
||||
t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", object))
|
||||
} else {
|
||||
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", object))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// serialization to the wire must be stable to ensure that we don't write twice to the DB
|
||||
// when the object hasn't changed.
|
||||
if !bytes.Equal(data, secondData) {
|
||||
t.Errorf("%v: serialization is not stable: %s", name, printer.Sprintf("%#v", object))
|
||||
}
|
||||
|
||||
// decode (deserialize) the encoded data back into an object
|
||||
obj2, err := runtime.Decode(codec, data)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v\nCodec: %#v\nData: %s\nSource: %#v", name, err, codec, dataAsString(data), printer.Sprintf("%#v", object))
|
||||
panic("failed")
|
||||
}
|
||||
|
||||
// ensure that the object produced from decoding the encoded data is equal
|
||||
// to the original object
|
||||
if !apiequality.Semantic.DeepEqual(original, obj2) {
|
||||
t.Errorf("%v: diff: %v\nCodec: %#v\nSource:\n\n%#v\n\nEncoded:\n\n%s\n\nFinal:\n\n%#v", name, diff.ObjectReflectDiff(original, obj2), codec, printer.Sprintf("%#v", original), dataAsString(data), printer.Sprintf("%#v", obj2))
|
||||
return
|
||||
}
|
||||
|
||||
// decode the encoded data into a new object (instead of letting the codec
|
||||
// create a new object)
|
||||
obj3 := reflect.New(reflect.TypeOf(object).Elem()).Interface().(runtime.Object)
|
||||
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
return
|
||||
}
|
||||
|
||||
// special case for kinds which are internal and external at the same time (many in meta.k8s.io are). For those
|
||||
// runtime.DecodeInto above will return the external variant and set the APIVersion and kind, while the input
|
||||
// object might be internal. Hence, we clear those values for obj3 for that case to correctly compare.
|
||||
intAndExt, err := internalAndExternalKind(scheme, object)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
return
|
||||
}
|
||||
if intAndExt {
|
||||
typeAcc, err := apimeta.TypeAccessor(object)
|
||||
if err != nil {
|
||||
t.Fatalf("%v: error accessing TypeMeta: %v", name, err)
|
||||
}
|
||||
if len(typeAcc.GetAPIVersion()) == 0 {
|
||||
typeAcc, err := apimeta.TypeAccessor(obj3)
|
||||
if err != nil {
|
||||
t.Fatalf("%v: error accessing TypeMeta: %v", name, err)
|
||||
}
|
||||
typeAcc.SetAPIVersion("")
|
||||
typeAcc.SetKind("")
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that the new runtime object is equal to the original after being
|
||||
// decoded into
|
||||
if !apiequality.Semantic.DeepEqual(object, obj3) {
|
||||
t.Errorf("%v: diff: %v\nCodec: %#v", name, diff.ObjectReflectDiff(object, obj3), codec)
|
||||
return
|
||||
}
|
||||
|
||||
// do structure-preserving fuzzing of the deep-copied object. If it shares anything with the original,
|
||||
// the deep-copy was actually only a shallow copy. Then original and obj3 will be different after fuzzing.
|
||||
// NOTE: we use the encoding+decoding here as an alternative, guaranteed deep-copy to compare against.
|
||||
fuzzer.ValueFuzz(object)
|
||||
if !apiequality.Semantic.DeepEqual(original, obj3) {
|
||||
t.Errorf("%v: fuzzing a copy altered the original, diff: %v", name, diff.ObjectReflectDiff(original, obj3))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func internalAndExternalKind(scheme *runtime.Scheme, object runtime.Object) (bool, error) {
|
||||
kinds, _, err := scheme.ObjectKinds(object)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
internal, external := false, false
|
||||
for _, k := range kinds {
|
||||
if k.Version == runtime.APIVersionInternal {
|
||||
internal = true
|
||||
} else {
|
||||
external = true
|
||||
}
|
||||
}
|
||||
return internal && external, nil
|
||||
}
|
||||
|
||||
// dataAsString returns the given byte array as a string; handles detecting
|
||||
// protocol buffers.
|
||||
func dataAsString(data []byte) string {
|
||||
dataString := string(data)
|
||||
if !strings.HasPrefix(dataString, "{") {
|
||||
dataString = "\n" + hex.Dump(data)
|
||||
proto.NewBuffer(make([]byte, 0, 1024)).DebugPrint("decoded object", data)
|
||||
}
|
||||
return dataString
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/api/validation/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/api/validation/doc.go
generated
vendored
|
|
@ -15,4 +15,4 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
// Package validation contains generic api type validation functions.
|
||||
package validation
|
||||
package validation // import "k8s.io/apimachinery/pkg/api/validation"
|
||||
|
|
|
|||
500
vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta_test.go
generated
vendored
Normal file
500
vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
Copyright 2017 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 validation
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
const (
|
||||
maxLengthErrMsg = "must be no more than"
|
||||
namePartErrMsg = "name part must consist of"
|
||||
nameErrMsg = "a qualified name must consist of"
|
||||
)
|
||||
|
||||
// Ensure custom name functions are allowed
|
||||
func TestValidateObjectMetaCustomName(t *testing.T) {
|
||||
errs := ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", GenerateName: "foo"},
|
||||
false,
|
||||
func(s string, prefix bool) []string {
|
||||
if s == "test" {
|
||||
return nil
|
||||
}
|
||||
return []string{"name-gen"}
|
||||
},
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if !strings.Contains(errs[0].Error(), "name-gen") {
|
||||
t.Errorf("unexpected error message: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure namespace names follow dns label format
|
||||
func TestValidateObjectMetaNamespaces(t *testing.T) {
|
||||
errs := ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", Namespace: "foo.bar"},
|
||||
true,
|
||||
func(s string, prefix bool) []string {
|
||||
return nil
|
||||
},
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if !strings.Contains(errs[0].Error(), `Invalid value: "foo.bar"`) {
|
||||
t.Errorf("unexpected error message: %v", errs)
|
||||
}
|
||||
maxLength := 63
|
||||
letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
b := make([]rune, maxLength+1)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
errs = ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", Namespace: string(b)},
|
||||
true,
|
||||
func(s string, prefix bool) []string {
|
||||
return nil
|
||||
},
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 2 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if !strings.Contains(errs[0].Error(), "Invalid value") || !strings.Contains(errs[1].Error(), "Invalid value") {
|
||||
t.Errorf("unexpected error message: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateObjectMetaOwnerReferences(t *testing.T) {
|
||||
trueVar := true
|
||||
falseVar := false
|
||||
testCases := []struct {
|
||||
description string
|
||||
ownerReferences []metav1.OwnerReference
|
||||
expectError bool
|
||||
expectedErrorMessage string
|
||||
}{
|
||||
{
|
||||
description: "simple success - third party extension.",
|
||||
ownerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "1",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
expectedErrorMessage: "",
|
||||
},
|
||||
{
|
||||
description: "simple failures - event shouldn't be set as an owner",
|
||||
ownerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "v1",
|
||||
Kind: "Event",
|
||||
Name: "name",
|
||||
UID: "1",
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
expectedErrorMessage: "is disallowed from being an owner",
|
||||
},
|
||||
{
|
||||
description: "simple controller ref success - one reference with Controller set",
|
||||
ownerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "1",
|
||||
Controller: &falseVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "2",
|
||||
Controller: &trueVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "3",
|
||||
Controller: &falseVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "4",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
expectedErrorMessage: "",
|
||||
},
|
||||
{
|
||||
description: "simple controller ref failure - two references with Controller set",
|
||||
ownerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "1",
|
||||
Controller: &falseVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "2",
|
||||
Controller: &trueVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "3",
|
||||
Controller: &trueVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "4",
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
expectedErrorMessage: "Only one reference can have Controller set to true",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
errs := ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", Namespace: "test", OwnerReferences: tc.ownerReferences},
|
||||
true,
|
||||
func(s string, prefix bool) []string {
|
||||
return nil
|
||||
},
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 0 && !tc.expectError {
|
||||
t.Errorf("unexpected error: %v in test case %v", errs, tc.description)
|
||||
}
|
||||
if len(errs) == 0 && tc.expectError {
|
||||
t.Errorf("expect error in test case %v", tc.description)
|
||||
}
|
||||
if len(errs) != 0 && !strings.Contains(errs[0].Error(), tc.expectedErrorMessage) {
|
||||
t.Errorf("unexpected error message: %v in test case %v", errs, tc.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateObjectMetaUpdateIgnoresCreationTimestamp(t *testing.T) {
|
||||
if errs := ValidateObjectMetaUpdate(
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
|
||||
field.NewPath("field"),
|
||||
); len(errs) != 0 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if errs := ValidateObjectMetaUpdate(
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
field.NewPath("field"),
|
||||
); len(errs) != 0 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if errs := ValidateObjectMetaUpdate(
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(11, 0))},
|
||||
field.NewPath("field"),
|
||||
); len(errs) != 0 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateFinalizersUpdate(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Old metav1.ObjectMeta
|
||||
New metav1.ObjectMeta
|
||||
ExpectedErr string
|
||||
}{
|
||||
"invalid adding finalizers": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a", "y/b"}},
|
||||
ExpectedErr: "y/b",
|
||||
},
|
||||
"invalid changing finalizers": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/b"}},
|
||||
ExpectedErr: "x/b",
|
||||
},
|
||||
"valid removing finalizers": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a", "y/b"}},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}},
|
||||
ExpectedErr: "",
|
||||
},
|
||||
"valid adding finalizers for objects not being deleted": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{"x/a"}},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{"x/a", "y/b"}},
|
||||
ExpectedErr: "",
|
||||
},
|
||||
}
|
||||
for name, tc := range testcases {
|
||||
errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field"))
|
||||
if len(errs) == 0 {
|
||||
if len(tc.ExpectedErr) != 0 {
|
||||
t.Errorf("case: %q, expected error to contain %q", name, tc.ExpectedErr)
|
||||
}
|
||||
} else if e, a := tc.ExpectedErr, errs.ToAggregate().Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("case: %q, expected error to contain %q, got error %q", name, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateFinalizersPreventConflictingFinalizers(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
ObjectMeta metav1.ObjectMeta
|
||||
ExpectedErr string
|
||||
}{
|
||||
"conflicting finalizers": {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{metav1.FinalizerOrphanDependents, metav1.FinalizerDeleteDependents}},
|
||||
ExpectedErr: "cannot be both set",
|
||||
},
|
||||
}
|
||||
for name, tc := range testcases {
|
||||
errs := ValidateObjectMeta(&tc.ObjectMeta, false, NameIsDNSSubdomain, field.NewPath("field"))
|
||||
if len(errs) == 0 {
|
||||
if len(tc.ExpectedErr) != 0 {
|
||||
t.Errorf("case: %q, expected error to contain %q", name, tc.ExpectedErr)
|
||||
}
|
||||
} else if e, a := tc.ExpectedErr, errs.ToAggregate().Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("case: %q, expected error to contain %q, got error %q", name, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateObjectMetaUpdatePreventsDeletionFieldMutation(t *testing.T) {
|
||||
now := metav1.NewTime(time.Unix(1000, 0).UTC())
|
||||
later := metav1.NewTime(time.Unix(2000, 0).UTC())
|
||||
gracePeriodShort := int64(30)
|
||||
gracePeriodLong := int64(40)
|
||||
|
||||
testcases := map[string]struct {
|
||||
Old metav1.ObjectMeta
|
||||
New metav1.ObjectMeta
|
||||
ExpectedNew metav1.ObjectMeta
|
||||
ExpectedErrs []string
|
||||
}{
|
||||
"valid without deletion fields": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
ExpectedErrs: []string{},
|
||||
},
|
||||
"valid with deletion fields": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedErrs: []string{},
|
||||
},
|
||||
|
||||
"invalid set deletionTimestamp": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: 1970-01-01 00:16:40 +0000 UTC: field is immutable; may only be changed via deletion"},
|
||||
},
|
||||
"invalid clear deletionTimestamp": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
ExpectedErrs: []string{}, // no errors, validation copies the old value
|
||||
},
|
||||
"invalid change deletionTimestamp": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &later},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
ExpectedErrs: []string{}, // no errors, validation copies the old value
|
||||
},
|
||||
|
||||
"invalid set deletionGracePeriodSeconds": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 30: field is immutable; may only be changed via deletion"},
|
||||
},
|
||||
"invalid clear deletionGracePeriodSeconds": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedErrs: []string{}, // no errors, validation copies the old value
|
||||
},
|
||||
"invalid change deletionGracePeriodSeconds": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodLong},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodLong},
|
||||
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 40: field is immutable; may only be changed via deletion"},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field"))
|
||||
if len(errs) != len(tc.ExpectedErrs) {
|
||||
t.Logf("%s: Expected: %#v", k, tc.ExpectedErrs)
|
||||
t.Logf("%s: Got: %#v", k, errs)
|
||||
t.Errorf("%s: expected %d errors, got %d", k, len(tc.ExpectedErrs), len(errs))
|
||||
continue
|
||||
}
|
||||
for i := range errs {
|
||||
if errs[i].Error() != tc.ExpectedErrs[i] {
|
||||
t.Errorf("%s: error #%d: expected %q, got %q", k, i, tc.ExpectedErrs[i], errs[i].Error())
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(tc.New, tc.ExpectedNew) {
|
||||
t.Errorf("%s: Expected after validation:\n%#v\ngot\n%#v", k, tc.ExpectedNew, tc.New)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestObjectMetaGenerationUpdate(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Old metav1.ObjectMeta
|
||||
New metav1.ObjectMeta
|
||||
ExpectedErrs []string
|
||||
}{
|
||||
"invalid generation change - decremented": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 4},
|
||||
ExpectedErrs: []string{"field.generation: Invalid value: 4: must not be decremented"},
|
||||
},
|
||||
"valid generation change - incremented by one": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 1},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 2},
|
||||
ExpectedErrs: []string{},
|
||||
},
|
||||
"valid generation field - not updated": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5},
|
||||
ExpectedErrs: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
errList := []string{}
|
||||
errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field"))
|
||||
if len(errs) != len(tc.ExpectedErrs) {
|
||||
t.Logf("%s: Expected: %#v", k, tc.ExpectedErrs)
|
||||
for _, err := range errs {
|
||||
errList = append(errList, err.Error())
|
||||
}
|
||||
t.Logf("%s: Got: %#v", k, errList)
|
||||
t.Errorf("%s: expected %d errors, got %d", k, len(tc.ExpectedErrs), len(errs))
|
||||
continue
|
||||
}
|
||||
for i := range errList {
|
||||
if errList[i] != tc.ExpectedErrs[i] {
|
||||
t.Errorf("%s: error #%d: expected %q, got %q", k, i, tc.ExpectedErrs[i], errList[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure trailing slash is allowed in generate name
|
||||
func TestValidateObjectMetaTrimsTrailingSlash(t *testing.T) {
|
||||
errs := ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", GenerateName: "foo-"},
|
||||
false,
|
||||
NameIsDNSSubdomain,
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAnnotations(t *testing.T) {
|
||||
successCases := []map[string]string{
|
||||
{"simple": "bar"},
|
||||
{"now-with-dashes": "bar"},
|
||||
{"1-starts-with-num": "bar"},
|
||||
{"1234": "bar"},
|
||||
{"simple/simple": "bar"},
|
||||
{"now-with-dashes/simple": "bar"},
|
||||
{"now-with-dashes/now-with-dashes": "bar"},
|
||||
{"now.with.dots/simple": "bar"},
|
||||
{"now-with.dashes-and.dots/simple": "bar"},
|
||||
{"1-num.2-num/3-num": "bar"},
|
||||
{"1234/5678": "bar"},
|
||||
{"1.2.3.4/5678": "bar"},
|
||||
{"UpperCase123": "bar"},
|
||||
{"a": strings.Repeat("b", totalAnnotationSizeLimitB-1)},
|
||||
{
|
||||
"a": strings.Repeat("b", totalAnnotationSizeLimitB/2-1),
|
||||
"c": strings.Repeat("d", totalAnnotationSizeLimitB/2-1),
|
||||
},
|
||||
}
|
||||
for i := range successCases {
|
||||
errs := ValidateAnnotations(successCases[i], field.NewPath("field"))
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("case[%d] expected success, got %#v", i, errs)
|
||||
}
|
||||
}
|
||||
|
||||
nameErrorCases := []struct {
|
||||
annotations map[string]string
|
||||
expect string
|
||||
}{
|
||||
{map[string]string{"nospecialchars^=@": "bar"}, namePartErrMsg},
|
||||
{map[string]string{"cantendwithadash-": "bar"}, namePartErrMsg},
|
||||
{map[string]string{"only/one/slash": "bar"}, nameErrMsg},
|
||||
{map[string]string{strings.Repeat("a", 254): "bar"}, maxLengthErrMsg},
|
||||
}
|
||||
for i := range nameErrorCases {
|
||||
errs := ValidateAnnotations(nameErrorCases[i].annotations, field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Errorf("case[%d]: expected failure", i)
|
||||
} else {
|
||||
if !strings.Contains(errs[0].Detail, nameErrorCases[i].expect) {
|
||||
t.Errorf("case[%d]: error details do not include %q: %q", i, nameErrorCases[i].expect, errs[0].Detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
totalSizeErrorCases := []map[string]string{
|
||||
{"a": strings.Repeat("b", totalAnnotationSizeLimitB)},
|
||||
{
|
||||
"a": strings.Repeat("b", totalAnnotationSizeLimitB/2),
|
||||
"c": strings.Repeat("d", totalAnnotationSizeLimitB/2),
|
||||
},
|
||||
}
|
||||
for i := range totalSizeErrorCases {
|
||||
errs := ValidateAnnotations(totalSizeErrorCases[i], field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Errorf("case[%d] expected failure", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
31
vendor/k8s.io/apimachinery/pkg/api/validation/path/BUILD
generated
vendored
Normal file
31
vendor/k8s.io/apimachinery/pkg/api/validation/path/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["name_test.go"],
|
||||
library = ":go_default_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["name.go"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
68
vendor/k8s.io/apimachinery/pkg/api/validation/path/name.go
generated
vendored
Normal file
68
vendor/k8s.io/apimachinery/pkg/api/validation/path/name.go
generated
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright 2015 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 path
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NameMayNotBe specifies strings that cannot be used as names specified as path segments (like the REST API or etcd store)
|
||||
var NameMayNotBe = []string{".", ".."}
|
||||
|
||||
// NameMayNotContain specifies substrings that cannot be used in names specified as path segments (like the REST API or etcd store)
|
||||
var NameMayNotContain = []string{"/", "%"}
|
||||
|
||||
// IsValidPathSegmentName validates the name can be safely encoded as a path segment
|
||||
func IsValidPathSegmentName(name string) []string {
|
||||
for _, illegalName := range NameMayNotBe {
|
||||
if name == illegalName {
|
||||
return []string{fmt.Sprintf(`may not be '%s'`, illegalName)}
|
||||
}
|
||||
}
|
||||
|
||||
var errors []string
|
||||
for _, illegalContent := range NameMayNotContain {
|
||||
if strings.Contains(name, illegalContent) {
|
||||
errors = append(errors, fmt.Sprintf(`may not contain '%s'`, illegalContent))
|
||||
}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
// IsValidPathSegmentPrefix validates the name can be used as a prefix for a name which will be encoded as a path segment
|
||||
// It does not check for exact matches with disallowed names, since an arbitrary suffix might make the name valid
|
||||
func IsValidPathSegmentPrefix(name string) []string {
|
||||
var errors []string
|
||||
for _, illegalContent := range NameMayNotContain {
|
||||
if strings.Contains(name, illegalContent) {
|
||||
errors = append(errors, fmt.Sprintf(`may not contain '%s'`, illegalContent))
|
||||
}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
// ValidatePathSegmentName validates the name can be safely encoded as a path segment
|
||||
func ValidatePathSegmentName(name string, prefix bool) []string {
|
||||
if prefix {
|
||||
return IsValidPathSegmentPrefix(name)
|
||||
} else {
|
||||
return IsValidPathSegmentName(name)
|
||||
}
|
||||
}
|
||||
168
vendor/k8s.io/apimachinery/pkg/api/validation/path/name_test.go
generated
vendored
Normal file
168
vendor/k8s.io/apimachinery/pkg/api/validation/path/name_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
Copyright 2015 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 path
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidatePathSegmentName(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Name string
|
||||
Prefix bool
|
||||
ExpectedMsg string
|
||||
}{
|
||||
"empty": {
|
||||
Name: "",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
"empty,prefix": {
|
||||
Name: "",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
"valid": {
|
||||
Name: "foo.bar.baz",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
"valid,prefix": {
|
||||
Name: "foo.bar.baz",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
// Make sure mixed case, non DNS subdomain characters are tolerated
|
||||
"valid complex": {
|
||||
Name: "sha256:ABCDEF012345@ABCDEF012345",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
// Make sure non-ascii characters are tolerated
|
||||
"valid extended charset": {
|
||||
Name: "Iñtërnâtiônàlizætiøn",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
"dot": {
|
||||
Name: ".",
|
||||
Prefix: false,
|
||||
ExpectedMsg: ".",
|
||||
},
|
||||
"dot leading": {
|
||||
Name: ".test",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
"dot,prefix": {
|
||||
Name: ".",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
"dot dot": {
|
||||
Name: "..",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "..",
|
||||
},
|
||||
"dot dot leading": {
|
||||
Name: "..test",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
"dot dot,prefix": {
|
||||
Name: "..",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
"slash": {
|
||||
Name: "foo/bar",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "/",
|
||||
},
|
||||
"slash,prefix": {
|
||||
Name: "foo/bar",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "/",
|
||||
},
|
||||
|
||||
"percent": {
|
||||
Name: "foo%bar",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "%",
|
||||
},
|
||||
"percent,prefix": {
|
||||
Name: "foo%bar",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "%",
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
msgs := ValidatePathSegmentName(tc.Name, tc.Prefix)
|
||||
if len(tc.ExpectedMsg) == 0 && len(msgs) > 0 {
|
||||
t.Errorf("%s: expected no message, got %v", k, msgs)
|
||||
}
|
||||
if len(tc.ExpectedMsg) > 0 && len(msgs) == 0 {
|
||||
t.Errorf("%s: expected error message, got none", k)
|
||||
}
|
||||
if len(tc.ExpectedMsg) > 0 && !strings.Contains(msgs[0], tc.ExpectedMsg) {
|
||||
t.Errorf("%s: expected message containing %q, got %v", k, tc.ExpectedMsg, msgs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateWithMultiErrors(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Name string
|
||||
Prefix bool
|
||||
ExpectedMsg []string
|
||||
}{
|
||||
"slash,percent": {
|
||||
Name: "foo//bar%",
|
||||
Prefix: false,
|
||||
ExpectedMsg: []string{"may not contain '/'", "may not contain '%'"},
|
||||
},
|
||||
"slash,percent,prefix": {
|
||||
Name: "foo//bar%",
|
||||
Prefix: true,
|
||||
ExpectedMsg: []string{"may not contain '/'", "may not contain '%'"},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
msgs := ValidatePathSegmentName(tc.Name, tc.Prefix)
|
||||
if len(tc.ExpectedMsg) == 0 && len(msgs) > 0 {
|
||||
t.Errorf("%s: expected no message, got %v", k, msgs)
|
||||
}
|
||||
if len(tc.ExpectedMsg) > 0 && len(msgs) == 0 {
|
||||
t.Errorf("%s: expected error message, got none", k)
|
||||
}
|
||||
if len(tc.ExpectedMsg) > 0 {
|
||||
for i := 0; i < len(tc.ExpectedMsg); i++ {
|
||||
if msgs[i] != tc.ExpectedMsg[i] {
|
||||
t.Errorf("%s: expected message containing %q, got %v", k, tc.ExpectedMsg[i], msgs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue