Replace godep with dep
This commit is contained in:
parent
1e7489927c
commit
bf5616c65b
14883 changed files with 3937406 additions and 361781 deletions
222
vendor/k8s.io/apimachinery/Godeps/Godeps.json
generated
vendored
Normal file
222
vendor/k8s.io/apimachinery/Godeps/Godeps.json
generated
vendored
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
{
|
||||
"ImportPath": "k8s.io/apimachinery",
|
||||
"GoVersion": "go1.8",
|
||||
"GodepVersion": "v79",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/PuerkitoBio/purell",
|
||||
"Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/PuerkitoBio/urlesc",
|
||||
"Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/davecgh/go-spew/spew",
|
||||
"Rev": "782f4967f2dc4564575ca782fe2d04090b5faca8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/spdystream",
|
||||
"Rev": "449fdfce4d962303d702fec724ef0ad181c92528"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/spdystream/spdy",
|
||||
"Rev": "449fdfce4d962303d702fec724ef0ad181c92528"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/elazarl/goproxy",
|
||||
"Rev": "c4fc26588b6ef8af07a191fcb6476387bdd46711"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/emicklei/go-restful",
|
||||
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/emicklei/go-restful/log",
|
||||
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/evanphx/json-patch",
|
||||
"Rev": "944e07253867aacae43c04b2e6a239005443f33a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/spec",
|
||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/swag",
|
||||
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/proto",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/sortkeys",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/glog",
|
||||
"Rev": "44145f04b68cf362d9c4df2182967c2275eaefed"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/groupcache/lru",
|
||||
"Rev": "02826c3e79038b59d737d3b1c0a1d937f71a4433"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/proto",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/google/gofuzz",
|
||||
"Rev": "44d81051d367757e1c7c6a5a86423ece9afcf63c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/golang-lru",
|
||||
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/golang-lru/simplelru",
|
||||
"Rev": "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/json-iterator/go",
|
||||
"Rev": "36b14963da70d11297d313183d7e6388c8510e1e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mailru/easyjson/buffer",
|
||||
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mailru/easyjson/jlexer",
|
||||
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mailru/easyjson/jwriter",
|
||||
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mxk/go-flowrate/flowrate",
|
||||
"Rev": "cca7078d478f8520f85629ad7c68962d31ed7682"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pborman/uuid",
|
||||
"Rev": "ca53cad383cad2479bbba7f7a1a05797ec1386e4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pmezard/go-difflib/difflib",
|
||||
"Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/spf13/pflag",
|
||||
"Rev": "9ff6c6923cfffbcd502984b8e0c80539a94968b7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/assert",
|
||||
"Rev": "f6abca593680b2315d2075e0f5e2a9751e3f431a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/require",
|
||||
"Rev": "f6abca593680b2315d2075e0f5e2a9751e3f431a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html",
|
||||
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html/atom",
|
||||
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/http2",
|
||||
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/http2/hpack",
|
||||
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/idna",
|
||||
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/lex/httplex",
|
||||
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/websocket",
|
||||
"Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/cases",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/internal",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/internal/tag",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/language",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/runes",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/secure/bidirule",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/secure/precis",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/transform",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/unicode/bidi",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/unicode/norm",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/width",
|
||||
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/inf.v0",
|
||||
"Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/yaml.v2",
|
||||
"Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi/pkg/common",
|
||||
"Rev": "868f2f29720b192240e18284659231b440f9cda5"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
vendor/k8s.io/apimachinery/Godeps/Readme
generated
vendored
Normal file
5
vendor/k8s.io/apimachinery/Godeps/Readme
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
||||
21
vendor/k8s.io/apimachinery/OWNERS
generated
vendored
Normal file
21
vendor/k8s.io/apimachinery/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
approvers:
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- deads2k
|
||||
- sttts
|
||||
- liggitt
|
||||
- caesarxuchao
|
||||
reviewers:
|
||||
- thockin
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- gmarek
|
||||
- sttts
|
||||
- ncdc
|
||||
- tallclair
|
||||
29
vendor/k8s.io/apimachinery/README.md
generated
vendored
Normal file
29
vendor/k8s.io/apimachinery/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# apimachinery
|
||||
|
||||
Scheme, typing, encoding, decoding, and conversion packages for Kubernetes and Kubernetes-like API objects.
|
||||
|
||||
|
||||
## Purpose
|
||||
|
||||
This library is a shared dependency for servers and clients to work with Kubernetes API infrastructure without direct
|
||||
type dependencies. It's first comsumers are `k8s.io/kubernetes`, `k8s.io/client-go`, and `k8s.io/apiserver`.
|
||||
|
||||
|
||||
## Compatibility
|
||||
|
||||
There are *NO compatibility guarantees* for this repository. It is in direct support of Kubernetes, so branches
|
||||
will track Kubernetes and be compatible with that repo. As we more cleanly separate the layers, we will review the
|
||||
compatibility guarantee.
|
||||
|
||||
|
||||
## Where does it come from?
|
||||
|
||||
`apimachinery` is synced from https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery.
|
||||
Code changes are made in that location, merged into `k8s.io/kubernetes` and later synced here.
|
||||
|
||||
|
||||
## Things you should *NOT* do
|
||||
|
||||
1. Add API types to this repo. This is for the machinery, not for the types.
|
||||
2. Directly modify any files under `pkg` in this repo. Those are driven from `k8s.io/kuberenetes/staging/src/k8s.io/apimachinery`.
|
||||
3. Expect compatibility. This repo is direct support of Kubernetes and the API isn't yet stable enough for API guarantees.
|
||||
66
vendor/k8s.io/apimachinery/hack/godep-deps.sh
generated
vendored
Executable file
66
vendor/k8s.io/apimachinery/hack/godep-deps.sh
generated
vendored
Executable file
|
|
@ -0,0 +1,66 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
# overall flow
|
||||
# 1. make a clean gopath
|
||||
# 2. godep restore based on k8s.io/kuberentes provided manifest
|
||||
# 3. go get anything unlisted. This handles deps from k8s.io/*
|
||||
# 4. remove old vendoring data
|
||||
# 5. vendor packages we need
|
||||
# 6. remove anything vendored from k8s.io/* from vendor, but not manifest.
|
||||
# This allows go get to work and still be able to flatten dependencies.
|
||||
# 6. copy new vendored packages and save them
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
goPath=$(mktemp -d "${TMPDIR:-/tmp/}$(basename 0).XXXXXXXXXXXX")
|
||||
echo ${goPath}
|
||||
|
||||
export GOPATH=${goPath}
|
||||
|
||||
mkdir -p ${goPath}/src/k8s.io/apimachinery
|
||||
cp -R . ${goPath}/src/k8s.io/apimachinery
|
||||
|
||||
pushd ${goPath}/src/k8s.io/apimachinery
|
||||
rm -rf vendor || true
|
||||
|
||||
# restore what we have in our new manifest that we've sync
|
||||
godep restore
|
||||
|
||||
# the manifest doesn't include any levels of k8s.io dependencies so load them using the go get
|
||||
# assume you sync all the repos at the same time, the leves you get will be correct
|
||||
go get -d ./... || true
|
||||
|
||||
# save the new levels of dependencies
|
||||
rm -rf vendor || true
|
||||
rm -rf Godeps || true
|
||||
godep save ./...
|
||||
popd
|
||||
|
||||
# remove the vendor dir we have and move the one we just made
|
||||
rm -rf vendor || true
|
||||
rm -rf Godeps || true
|
||||
git rm -rf vendor || true
|
||||
git rm -rf Godeps || true
|
||||
mv ${goPath}/src/k8s.io/apimachinery/vendor .
|
||||
mv ${goPath}/src/k8s.io/apimachinery/Godeps .
|
||||
git add vendor
|
||||
git add Godeps
|
||||
git commit -m "sync: resync vendor folder"
|
||||
|
||||
65
vendor/k8s.io/apimachinery/hack/sync-from-kubernetes.sh
generated
vendored
Executable file
65
vendor/k8s.io/apimachinery/hack/sync-from-kubernetes.sh
generated
vendored
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
# overall flow
|
||||
# 1. fetch the current level of k8s.io/kubernetes
|
||||
# 2. check out the k8s.io/kubernetes HEAD into a separate branch
|
||||
# 3. rewrite the history on that branch to *only* include staging/src/k8s.io/apimachinery
|
||||
# 4. locate all commits between the last time we sync'ed and now
|
||||
# 5. switch back to the starting branch
|
||||
# 6. for each commit, cherry-pick it (which will keep authorship) into current branch
|
||||
# 7. update metadata files indicating which commits we've sync'ed to
|
||||
|
||||
set -e
|
||||
|
||||
ROOT=$(dirname "${BASH_SOURCE}")/..
|
||||
dir=$(mktemp -d "${TMPDIR:-/tmp/}$(basename 0).XXXXXXXXXXXX")
|
||||
|
||||
git remote add upstream-kube git@github.com:kubernetes/kubernetes.git || true
|
||||
git fetch upstream-kube
|
||||
|
||||
currBranch=$(git rev-parse --abbrev-ref HEAD)
|
||||
previousKubeSHA=$(cat kubernetes-sha)
|
||||
previousBranchSHA=$(cat filter-branch-sha)
|
||||
|
||||
git branch -D kube-sync || true
|
||||
git checkout upstream-kube/master -b kube-sync
|
||||
git reset --hard upstream-kube/master
|
||||
newKubeSHA=$(git log --oneline --format='%H' kube-sync -1)
|
||||
|
||||
# this command rewrite git history to *only* include staging/src/k8s.io/apimachinery
|
||||
git filter-branch -f --subdirectory-filter staging/src/k8s.io/apimachinery HEAD
|
||||
|
||||
newBranchSHA=$(git log --oneline --format='%H' kube-sync -1)
|
||||
git log --no-merges --format='%H' --reverse ${previousBranchSHA}..HEAD > ${dir}/commits
|
||||
|
||||
git checkout ${currBranch}
|
||||
|
||||
while read commitSHA; do
|
||||
echo "working ${commitSHA}"
|
||||
git cherry-pick ${commitSHA}
|
||||
done <${dir}/commits
|
||||
|
||||
# update the vendored godeps
|
||||
${ROOT}/hack/godep-deps.sh
|
||||
|
||||
# track the k8s.io/kubernetes commit SHA so we can always determine which level of kube this repo matches
|
||||
# track the filtered branch commit SHA so that we can determine which commits need to be picked
|
||||
echo ${newKubeSHA} > kubernetes-sha
|
||||
echo ${newBranchSHA} > filter-branch-sha
|
||||
git commit -m "sync(k8s.io/kubernetes): ${newKubeSHA}" -- kubernetes-sha filter-branch-sha
|
||||
|
||||
6
vendor/k8s.io/apimachinery/pkg/OWNERS
generated
vendored
Normal file
6
vendor/k8s.io/apimachinery/pkg/OWNERS
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
approvers:
|
||||
- caesarxuchao
|
||||
- deads2k
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- liggitt
|
||||
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])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
64
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/announced_test.go
generated
vendored
Normal file
64
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/announced_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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 announced
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
func TestFactoryRegistry(t *testing.T) {
|
||||
regA := make(APIGroupFactoryRegistry)
|
||||
regB := make(APIGroupFactoryRegistry)
|
||||
|
||||
if err := regA.AnnounceGroup(&GroupMetaFactoryArgs{
|
||||
GroupName: "foo",
|
||||
VersionPreferenceOrder: []string{"v2", "v1"},
|
||||
RootScopedKinds: sets.NewString("namespaces"),
|
||||
}); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if err := regA.AnnounceGroupVersion(&GroupVersionFactoryArgs{
|
||||
GroupName: "foo",
|
||||
VersionName: "v1",
|
||||
}); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if err := regA.AnnounceGroupVersion(&GroupVersionFactoryArgs{
|
||||
GroupName: "foo",
|
||||
VersionName: "v2",
|
||||
}); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if err := regB.AnnouncePreconstructedFactory(NewGroupMetaFactory(
|
||||
&GroupMetaFactoryArgs{
|
||||
GroupName: "foo",
|
||||
VersionPreferenceOrder: []string{"v2", "v1"},
|
||||
RootScopedKinds: sets.NewString("namespaces"),
|
||||
},
|
||||
VersionToSchemeFunc{"v1": nil, "v2": nil},
|
||||
)); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(regA, regB) {
|
||||
t.Errorf("Expected both ways of registering to be equivalent, but they were not.\n\n%#v\n\n%#v\n", regA, regB)
|
||||
}
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/apimachinery/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/apimachinery/doc.go
generated
vendored
|
|
@ -17,4 +17,4 @@ limitations under the License.
|
|||
// Package apimachinery contains the generic API machinery code that
|
||||
// is common to both server and clients.
|
||||
// This package should never import specific API objects.
|
||||
package apimachinery
|
||||
package apimachinery // import "k8s.io/apimachinery/pkg/apimachinery"
|
||||
|
|
|
|||
71
vendor/k8s.io/apimachinery/pkg/apimachinery/registered/registered_test.go
generated
vendored
Normal file
71
vendor/k8s.io/apimachinery/pkg/apimachinery/registered/registered_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
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 registered
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apimachinery"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestAllPreferredGroupVersions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
groupMetas []apimachinery.GroupMeta
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
groupMetas: []apimachinery.GroupMeta{
|
||||
{
|
||||
GroupVersion: schema.GroupVersion{Group: "group1", Version: "v1"},
|
||||
},
|
||||
{
|
||||
GroupVersion: schema.GroupVersion{Group: "group2", Version: "v2"},
|
||||
},
|
||||
{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
},
|
||||
},
|
||||
expect: "group1/v1,group2/v2,v1",
|
||||
},
|
||||
{
|
||||
groupMetas: []apimachinery.GroupMeta{
|
||||
{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
},
|
||||
},
|
||||
expect: "v1",
|
||||
},
|
||||
{
|
||||
groupMetas: []apimachinery.GroupMeta{},
|
||||
expect: "",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
m, err := NewAPIRegistrationManager("")
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure to make a manager: %v", err)
|
||||
}
|
||||
for _, groupMeta := range testCase.groupMetas {
|
||||
m.RegisterGroup(groupMeta)
|
||||
}
|
||||
output := m.AllPreferredGroupVersions()
|
||||
if testCase.expect != output {
|
||||
t.Errorf("Error. expect: %s, got: %s", testCase.expect, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
43
vendor/k8s.io/apimachinery/pkg/apimachinery/types_test.go
generated
vendored
Normal file
43
vendor/k8s.io/apimachinery/pkg/apimachinery/types_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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 apimachinery
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
gm := GroupMeta{
|
||||
GroupVersion: schema.GroupVersion{
|
||||
Group: "test",
|
||||
Version: "v1",
|
||||
},
|
||||
GroupVersions: []schema.GroupVersion{{Group: "test", Version: "v1"}},
|
||||
}
|
||||
|
||||
gm.AddVersionInterfaces(schema.GroupVersion{Group: "test", Version: "v1"}, nil)
|
||||
if e, a := 1, len(gm.InterfacesByVersion); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
// GroupVersions is unchanged
|
||||
if e, a := 1, len(gm.GroupVersions); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
35
vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer/BUILD
generated
vendored
Normal file
35
vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fuzzer.go"],
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource: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/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
171
vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer/fuzzer.go
generated
vendored
Normal file
171
vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer/fuzzer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
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 (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func genericFuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(q *resource.Quantity, c fuzz.Continue) {
|
||||
*q = *resource.NewQuantity(c.Int63n(1000), resource.DecimalExponent)
|
||||
},
|
||||
func(j *int, c fuzz.Continue) {
|
||||
*j = int(c.Int31())
|
||||
},
|
||||
func(j **int, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
i := int(c.Int31())
|
||||
*j = &i
|
||||
} else {
|
||||
*j = nil
|
||||
}
|
||||
},
|
||||
func(j *runtime.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
},
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
// TODO: uncomment when round trip starts from a versioned object
|
||||
if true { //c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
// We do not set TypeMeta here because it is not carried through a round trip
|
||||
Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&metav1.Status{}, &metav1.APIGroup{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(r *runtime.RawExtension, c fuzz.Continue) {
|
||||
// Pick an arbitrary type and fuzz it
|
||||
types := []runtime.Object{&metav1.Status{}, &metav1.APIGroup{}}
|
||||
obj := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(obj)
|
||||
|
||||
// Find a codec for converting the object to raw bytes. This is necessary for the
|
||||
// api version and kind to be correctly set be serialization.
|
||||
var codec = apitesting.TestCodec(codecs, metav1.SchemeGroupVersion)
|
||||
|
||||
// Convert the object to raw bytes
|
||||
bytes, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to encode object: %v", err))
|
||||
}
|
||||
|
||||
// strip trailing newlines which do not survive roundtrips
|
||||
for len(bytes) >= 1 && bytes[len(bytes)-1] == 10 {
|
||||
bytes = bytes[:len(bytes)-1]
|
||||
}
|
||||
|
||||
// Set the bytes field on the RawExtension
|
||||
r.Raw = bytes
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func v1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(j *metav1.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
},
|
||||
func(j *metav1.ObjectMeta, c fuzz.Continue) {
|
||||
j.Name = c.RandString()
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
j.UID = types.UID(c.RandString())
|
||||
j.GenerateName = c.RandString()
|
||||
|
||||
var sec, nsec int64
|
||||
c.Fuzz(&sec)
|
||||
c.Fuzz(&nsec)
|
||||
j.CreationTimestamp = metav1.Unix(sec, nsec).Rfc3339Copy()
|
||||
},
|
||||
func(j *metav1.ListMeta, c fuzz.Continue) {
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func v1alpha1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(r *metav1alpha1.TableRow, c fuzz.Continue) {
|
||||
c.Fuzz(&r.Object)
|
||||
c.Fuzz(&r.Conditions)
|
||||
if len(r.Conditions) == 0 {
|
||||
r.Conditions = nil
|
||||
}
|
||||
n := c.Intn(10)
|
||||
if n > 0 {
|
||||
r.Cells = make([]interface{}, n)
|
||||
}
|
||||
for i := range r.Cells {
|
||||
t := c.Intn(6)
|
||||
switch t {
|
||||
case 0:
|
||||
r.Cells[i] = c.RandString()
|
||||
case 1:
|
||||
r.Cells[i] = c.Uint64()
|
||||
case 2:
|
||||
r.Cells[i] = c.RandBool()
|
||||
case 3:
|
||||
x := map[string]interface{}{}
|
||||
for j := c.Intn(10) + 1; j >= 0; j-- {
|
||||
x[c.RandString()] = c.RandString()
|
||||
}
|
||||
r.Cells[i] = x
|
||||
case 4:
|
||||
x := make([]interface{}, c.Intn(10))
|
||||
for i := range x {
|
||||
x[i] = c.Uint64()
|
||||
}
|
||||
r.Cells[i] = x
|
||||
default:
|
||||
r.Cells[i] = nil
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var Funcs = fuzzer.MergeFuzzerFuncs(
|
||||
genericFuzzerFuncs,
|
||||
v1FuzzerFuncs,
|
||||
v1alpha1FuzzerFuncs,
|
||||
)
|
||||
89
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register_test.go
generated
vendored
Normal file
89
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
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 internalversion
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
|
||||
func TestListOptions(t *testing.T) {
|
||||
// verify round trip conversion
|
||||
ten := int64(10)
|
||||
in := &metav1.ListOptions{
|
||||
LabelSelector: "a=1",
|
||||
FieldSelector: "b=1",
|
||||
ResourceVersion: "10",
|
||||
TimeoutSeconds: &ten,
|
||||
Watch: true,
|
||||
}
|
||||
out := &ListOptions{}
|
||||
if err := scheme.Convert(in, out, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actual := &metav1.ListOptions{}
|
||||
if err := scheme.Convert(out, actual, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(in, actual) {
|
||||
t.Errorf("unexpected: %s", diff.ObjectReflectDiff(in, actual))
|
||||
}
|
||||
|
||||
// verify failing conversion
|
||||
for i, failingObject := range []*metav1.ListOptions{
|
||||
{LabelSelector: "a!!!"},
|
||||
{FieldSelector: "a!!!"},
|
||||
} {
|
||||
out = &ListOptions{}
|
||||
if err := scheme.Convert(failingObject, out, nil); err == nil {
|
||||
t.Errorf("%d: unexpected conversion: %#v", i, out)
|
||||
}
|
||||
}
|
||||
|
||||
// verify kind registration
|
||||
if gvk, unversioned, err := scheme.ObjectKind(in); err != nil || unversioned || gvk != metav1.SchemeGroupVersion.WithKind("ListOptions") {
|
||||
t.Errorf("unexpected: %v %v %v", gvk, unversioned, err)
|
||||
}
|
||||
if gvk, unversioned, err := scheme.ObjectKind(out); err != nil || unversioned || gvk != SchemeGroupVersion.WithKind("ListOptions") {
|
||||
t.Errorf("unexpected: %v %v %v", gvk, unversioned, err)
|
||||
}
|
||||
|
||||
actual = &metav1.ListOptions{}
|
||||
if err := ParameterCodec.DecodeParameters(url.Values{"watch": []string{"1"}}, metav1.SchemeGroupVersion, actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !actual.Watch {
|
||||
t.Errorf("unexpected watch decode: %#v", actual)
|
||||
}
|
||||
|
||||
// check ParameterCodec
|
||||
query, err := ParameterCodec.EncodeParameters(in, metav1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actual = &metav1.ListOptions{}
|
||||
if err := ParameterCodec.DecodeParameters(query, metav1.SchemeGroupVersion, actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(in, actual) {
|
||||
t.Errorf("unexpected: %s", diff.ObjectReflectDiff(in, actual))
|
||||
}
|
||||
}
|
||||
28
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/roundtrip_test.go
generated
vendored
Normal file
28
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/roundtrip_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
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 internalversion
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/fuzzer"
|
||||
)
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
roundtrip.RoundTripTestForScheme(t, scheme, fuzzer.Funcs)
|
||||
}
|
||||
133
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref_test.go
generated
vendored
Normal file
133
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type metaObj struct {
|
||||
ObjectMeta
|
||||
TypeMeta
|
||||
}
|
||||
|
||||
func TestNewControllerRef(t *testing.T) {
|
||||
gvk := schema.GroupVersionKind{
|
||||
Group: "group",
|
||||
Version: "v1",
|
||||
Kind: "Kind",
|
||||
}
|
||||
obj1 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
Name: "name",
|
||||
UID: "uid1",
|
||||
},
|
||||
}
|
||||
controllerRef := NewControllerRef(obj1, gvk)
|
||||
if controllerRef.UID != obj1.UID {
|
||||
t.Errorf("Incorrect UID: %s", controllerRef.UID)
|
||||
}
|
||||
if controllerRef.Controller == nil || *controllerRef.Controller != true {
|
||||
t.Error("Controller must be set to true")
|
||||
}
|
||||
if controllerRef.BlockOwnerDeletion == nil || *controllerRef.BlockOwnerDeletion != true {
|
||||
t.Error("BlockOwnerDeletion must be set to true")
|
||||
}
|
||||
if controllerRef.APIVersion == "" ||
|
||||
controllerRef.Kind == "" ||
|
||||
controllerRef.Name == "" {
|
||||
t.Errorf("All controllerRef fields must be set: %v", controllerRef)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetControllerOf(t *testing.T) {
|
||||
gvk := schema.GroupVersionKind{
|
||||
Group: "group",
|
||||
Version: "v1",
|
||||
Kind: "Kind",
|
||||
}
|
||||
obj1 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid1",
|
||||
Name: "name1",
|
||||
},
|
||||
}
|
||||
controllerRef := NewControllerRef(obj1, gvk)
|
||||
var falseRef = false
|
||||
obj2 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid2",
|
||||
Name: "name1",
|
||||
OwnerReferences: []OwnerReference{
|
||||
{
|
||||
Name: "owner1",
|
||||
Controller: &falseRef,
|
||||
},
|
||||
*controllerRef,
|
||||
{
|
||||
Name: "owner2",
|
||||
Controller: &falseRef,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if GetControllerOf(obj1) != nil {
|
||||
t.Error("GetControllerOf must return null")
|
||||
}
|
||||
c := GetControllerOf(obj2)
|
||||
if c.Name != controllerRef.Name || c.UID != controllerRef.UID {
|
||||
t.Errorf("Incorrect result of GetControllerOf: %v", c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsControlledBy(t *testing.T) {
|
||||
gvk := schema.GroupVersionKind{
|
||||
Group: "group",
|
||||
Version: "v1",
|
||||
Kind: "Kind",
|
||||
}
|
||||
obj1 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid1",
|
||||
},
|
||||
}
|
||||
obj2 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid2",
|
||||
OwnerReferences: []OwnerReference{
|
||||
*NewControllerRef(obj1, gvk),
|
||||
},
|
||||
},
|
||||
}
|
||||
obj3 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid3",
|
||||
OwnerReferences: []OwnerReference{
|
||||
*NewControllerRef(obj2, gvk),
|
||||
},
|
||||
},
|
||||
}
|
||||
if !IsControlledBy(obj2, obj1) || !IsControlledBy(obj3, obj2) {
|
||||
t.Error("Incorrect IsControlledBy result: false")
|
||||
}
|
||||
if IsControlledBy(obj3, obj1) {
|
||||
t.Error("Incorrect IsControlledBy result: true")
|
||||
}
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go
generated
vendored
|
|
@ -19,4 +19,4 @@ limitations under the License.
|
|||
// +k8s:defaulter-gen=TypeMeta
|
||||
|
||||
// +groupName=meta.k8s.io
|
||||
package v1
|
||||
package v1 // import "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
|
|||
153
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration_test.go
generated
vendored
Normal file
153
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
type DurationHolder struct {
|
||||
D Duration `json:"d"`
|
||||
}
|
||||
|
||||
func TestDurationMarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Duration
|
||||
result string
|
||||
}{
|
||||
{Duration{5 * time.Second}, "d: 5s\n"},
|
||||
{Duration{2 * time.Minute}, "d: 2m0s\n"},
|
||||
{Duration{time.Hour + 3*time.Millisecond}, "d: 1h0m0.003s\n"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := DurationHolder{c.input}
|
||||
result, err := yaml.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: %q: %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: %q: expected %q, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result Duration
|
||||
}{
|
||||
{"d: 0s\n", Duration{}},
|
||||
{"d: 5s\n", Duration{5 * time.Second}},
|
||||
{"d: 2m0s\n", Duration{2 * time.Minute}},
|
||||
{"d: 1h0m0.003s\n", Duration{time.Hour + 3*time.Millisecond}},
|
||||
|
||||
// Units with zero values can optionally be dropped
|
||||
{"d: 2m\n", Duration{2 * time.Minute}},
|
||||
{"d: 1h0.003s\n", Duration{time.Hour + 3*time.Millisecond}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result DurationHolder
|
||||
if err := yaml.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input %q: %v", c.input, err)
|
||||
}
|
||||
if result.D != c.result {
|
||||
t.Errorf("Failed to unmarshal input %q: expected %q, got %q", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Duration
|
||||
result string
|
||||
}{
|
||||
{Duration{5 * time.Second}, `{"d":"5s"}`},
|
||||
{Duration{2 * time.Minute}, `{"d":"2m0s"}`},
|
||||
{Duration{time.Hour + 3*time.Millisecond}, `{"d":"1h0m0.003s"}`},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := DurationHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: %q: %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: %q: expected %q, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result Duration
|
||||
}{
|
||||
{`{"d":"0s"}`, Duration{}},
|
||||
{`{"d":"5s"}`, Duration{5 * time.Second}},
|
||||
{`{"d":"2m0s"}`, Duration{2 * time.Minute}},
|
||||
{`{"d":"1h0m0.003s"}`, Duration{time.Hour + 3*time.Millisecond}},
|
||||
|
||||
// Units with zero values can optionally be dropped
|
||||
{`{"d":"2m"}`, Duration{2 * time.Minute}},
|
||||
{`{"d":"1h0.003s"}`, Duration{time.Hour + 3*time.Millisecond}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result DurationHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input %q: %v", c.input, err)
|
||||
}
|
||||
if result.D != c.result {
|
||||
t.Errorf("Failed to unmarshal input %q: expected %q, got %q", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationMarshalJSONUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Duration
|
||||
}{
|
||||
{Duration{}},
|
||||
{Duration{5 * time.Second}},
|
||||
{Duration{2 * time.Minute}},
|
||||
{Duration{time.Hour + 3*time.Millisecond}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
input := DurationHolder{c.input}
|
||||
jsonMarshalled, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("%d-1: Failed to marshal input: '%v': %v", i, input, err)
|
||||
}
|
||||
|
||||
var result DurationHolder
|
||||
if err := yaml.Unmarshal(jsonMarshalled, &result); err != nil {
|
||||
t.Errorf("%d-2: Failed to unmarshal '%+v': %v", i, string(jsonMarshalled), err)
|
||||
}
|
||||
|
||||
if input.D != result.D {
|
||||
t.Errorf("%d-4: Failed to marshal input '%#v': got %#v", i, input, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
78
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go
generated
vendored
Normal file
78
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
type GroupVersionHolder struct {
|
||||
GV GroupVersion `json:"val"`
|
||||
}
|
||||
|
||||
func TestGroupVersionUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input []byte
|
||||
expect GroupVersion
|
||||
}{
|
||||
{[]byte(`{"val": "v1"}`), GroupVersion{"", "v1"}},
|
||||
{[]byte(`{"val": "extensions/v1beta1"}`), GroupVersion{"extensions", "v1beta1"}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result GroupVersionHolder
|
||||
// test golang lib's JSON codec
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("JSON codec failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result.GV, c.expect) {
|
||||
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
|
||||
}
|
||||
// test the json-iterator codec
|
||||
if err := jsoniter.ConfigFastest.Unmarshal(c.input, &result); err != nil {
|
||||
t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result.GV, c.expect) {
|
||||
t.Errorf("json-iterator codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupVersionMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input GroupVersion
|
||||
expect []byte
|
||||
}{
|
||||
{GroupVersion{"", "v1"}, []byte(`{"val":"v1"}`)},
|
||||
{GroupVersion{"extensions", "v1beta1"}, []byte(`{"val":"extensions/v1beta1"}`)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := GroupVersionHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input '%v': %v", input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, c.expect) {
|
||||
t.Errorf("Failed to marshal input '%+v': expected: %s, got: %s", input, c.expect, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
154
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers_test.go
generated
vendored
Normal file
154
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
func TestLabelSelectorAsSelector(t *testing.T) {
|
||||
matchLabels := map[string]string{"foo": "bar"}
|
||||
matchExpressions := []LabelSelectorRequirement{{
|
||||
Key: "baz",
|
||||
Operator: LabelSelectorOpIn,
|
||||
Values: []string{"qux", "norf"},
|
||||
}}
|
||||
mustParse := func(s string) labels.Selector {
|
||||
out, e := labels.Parse(s)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return out
|
||||
}
|
||||
tc := []struct {
|
||||
in *LabelSelector
|
||||
out labels.Selector
|
||||
expectErr bool
|
||||
}{
|
||||
{in: nil, out: labels.Nothing()},
|
||||
{in: &LabelSelector{}, out: labels.Everything()},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels},
|
||||
out: mustParse("foo=bar"),
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions},
|
||||
out: mustParse("baz in (norf,qux)"),
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions},
|
||||
out: mustParse("baz in (norf,qux),foo=bar"),
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{
|
||||
MatchExpressions: []LabelSelectorRequirement{{
|
||||
Key: "baz",
|
||||
Operator: LabelSelectorOpExists,
|
||||
Values: []string{"qux", "norf"},
|
||||
}},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tc {
|
||||
out, err := LabelSelectorAsSelector(tc.in)
|
||||
if err == nil && tc.expectErr {
|
||||
t.Errorf("[%v]expected error but got none.", i)
|
||||
}
|
||||
if err != nil && !tc.expectErr {
|
||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(out, tc.out) {
|
||||
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelSelectorAsMap(t *testing.T) {
|
||||
matchLabels := map[string]string{"foo": "bar"}
|
||||
matchExpressions := func(operator LabelSelectorOperator, values []string) []LabelSelectorRequirement {
|
||||
return []LabelSelectorRequirement{{
|
||||
Key: "baz",
|
||||
Operator: operator,
|
||||
Values: values,
|
||||
}}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
in *LabelSelector
|
||||
out map[string]string
|
||||
errString string
|
||||
}{
|
||||
{in: nil, out: nil},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels},
|
||||
out: map[string]string{"foo": "bar"},
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf"})},
|
||||
out: map[string]string{"foo": "bar", "baz": "norf"},
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf"})},
|
||||
out: map[string]string{"baz": "norf"},
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf", "qux"})},
|
||||
out: map[string]string{"foo": "bar"},
|
||||
errString: "without a single value cannot be converted",
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpNotIn, []string{"norf", "qux"})},
|
||||
out: map[string]string{},
|
||||
errString: "cannot be converted",
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpExists, []string{})},
|
||||
out: map[string]string{"foo": "bar"},
|
||||
errString: "cannot be converted",
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpDoesNotExist, []string{})},
|
||||
out: map[string]string{},
|
||||
errString: "cannot be converted",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
out, err := LabelSelectorAsMap(tc.in)
|
||||
if err == nil && len(tc.errString) > 0 {
|
||||
t.Errorf("[%v]expected error but got none.", i)
|
||||
continue
|
||||
}
|
||||
if err != nil && len(tc.errString) == 0 {
|
||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if err != nil && len(tc.errString) > 0 && !strings.Contains(err.Error(), tc.errString) {
|
||||
t.Errorf("[%v]expected error with %q but got: %v", i, tc.errString, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(out, tc.out) {
|
||||
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
120
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels_test.go
generated
vendored
Normal file
120
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCloneSelectorAndAddLabel(t *testing.T) {
|
||||
labels := map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo2": "bar2",
|
||||
"foo3": "bar3",
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
labels map[string]string
|
||||
labelKey string
|
||||
labelValue string
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
labels: labels,
|
||||
want: labels,
|
||||
},
|
||||
{
|
||||
labels: labels,
|
||||
labelKey: "foo4",
|
||||
labelValue: "89",
|
||||
want: map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo2": "bar2",
|
||||
"foo3": "bar3",
|
||||
"foo4": "89",
|
||||
},
|
||||
},
|
||||
{
|
||||
labels: nil,
|
||||
labelKey: "foo4",
|
||||
labelValue: "12",
|
||||
want: map[string]string{
|
||||
"foo4": "12",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
ls_in := LabelSelector{MatchLabels: tc.labels}
|
||||
ls_out := LabelSelector{MatchLabels: tc.want}
|
||||
|
||||
got := CloneSelectorAndAddLabel(&ls_in, tc.labelKey, tc.labelValue)
|
||||
if !reflect.DeepEqual(got, &ls_out) {
|
||||
t.Errorf("got %v, want %v", got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelToSelector(t *testing.T) {
|
||||
labels := map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo2": "bar2",
|
||||
"foo3": "bar3",
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
labels map[string]string
|
||||
labelKey string
|
||||
labelValue string
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
labels: labels,
|
||||
want: labels,
|
||||
},
|
||||
{
|
||||
labels: labels,
|
||||
labelKey: "foo4",
|
||||
labelValue: "89",
|
||||
want: map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo2": "bar2",
|
||||
"foo3": "bar3",
|
||||
"foo4": "89",
|
||||
},
|
||||
},
|
||||
{
|
||||
labels: nil,
|
||||
labelKey: "foo4",
|
||||
labelValue: "12",
|
||||
want: map[string]string{
|
||||
"foo4": "12",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
ls_in := LabelSelector{MatchLabels: tc.labels}
|
||||
ls_out := LabelSelector{MatchLabels: tc.want}
|
||||
|
||||
got := AddLabelToSelector(&ls_in, tc.labelKey, tc.labelValue)
|
||||
if !reflect.DeepEqual(got, &ls_out) {
|
||||
t.Errorf("got %v, want %v", got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
139
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_test.go
generated
vendored
Normal file
139
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
type MicroTimeHolder struct {
|
||||
T MicroTime `json:"t"`
|
||||
}
|
||||
|
||||
func TestMicroTimeMarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input MicroTime
|
||||
result string
|
||||
}{
|
||||
{MicroTime{}, "t: null\n"},
|
||||
{DateMicro(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: 1998-05-05T05:05:05.000000Z\n"},
|
||||
{DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05.000000Z\n"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := MicroTimeHolder{c.input}
|
||||
result, err := yaml.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMicroTimeUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result MicroTime
|
||||
}{
|
||||
{"t: null\n", MicroTime{}},
|
||||
{"t: 1998-05-05T05:05:05.000000Z\n", MicroTime{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result MicroTimeHolder
|
||||
if err := yaml.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.T != c.result {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMicroTimeMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input MicroTime
|
||||
result string
|
||||
}{
|
||||
{MicroTime{}, "{\"t\":null}"},
|
||||
{DateMicro(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "{\"t\":\"1998-05-05T05:05:05.000000Z\"}"},
|
||||
{DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "{\"t\":\"1998-05-05T05:05:05.000000Z\"}"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := MicroTimeHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMicroTimeUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result MicroTime
|
||||
}{
|
||||
{"{\"t\":null}", MicroTime{}},
|
||||
{"{\"t\":\"1998-05-05T05:05:05.000000Z\"}", MicroTime{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result MicroTimeHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.T != c.result {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMicroTimeProto(t *testing.T) {
|
||||
cases := []struct {
|
||||
input MicroTime
|
||||
}{
|
||||
{MicroTime{}},
|
||||
{DateMicro(1998, time.May, 5, 1, 5, 5, 50, time.Local)},
|
||||
{DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.Local)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := c.input
|
||||
data, err := input.Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
time := MicroTime{}
|
||||
if err := time.Unmarshal(data); err != nil {
|
||||
t.Fatalf("Failed to unmarshal output: '%v': %v", input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, time) {
|
||||
t.Errorf("Marshal->Unmarshal is not idempotent: '%v' vs '%v'", input, time)
|
||||
}
|
||||
}
|
||||
}
|
||||
173
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_test.go
generated
vendored
Normal file
173
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
type TimeHolder struct {
|
||||
T Time `json:"t"`
|
||||
}
|
||||
|
||||
func TestTimeMarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Time
|
||||
result string
|
||||
}{
|
||||
{Time{}, "t: null\n"},
|
||||
{Date(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: 1998-05-05T05:05:05Z\n"},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05Z\n"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := TimeHolder{c.input}
|
||||
result, err := yaml.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result Time
|
||||
}{
|
||||
{"t: null\n", Time{}},
|
||||
{"t: 1998-05-05T05:05:05Z\n", Time{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result TimeHolder
|
||||
if err := yaml.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.T != c.result {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Time
|
||||
result string
|
||||
}{
|
||||
{Time{}, "{\"t\":null}"},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "{\"t\":\"1998-05-05T05:05:05Z\"}"},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "{\"t\":\"1998-05-05T05:05:05Z\"}"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := TimeHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result Time
|
||||
}{
|
||||
{"{\"t\":null}", Time{}},
|
||||
{"{\"t\":\"1998-05-05T05:05:05Z\"}", Time{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result TimeHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.T != c.result {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeMarshalJSONUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Time
|
||||
}{
|
||||
{Time{}},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 50, time.Local).Rfc3339Copy()},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 0, time.Local).Rfc3339Copy()},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
input := TimeHolder{c.input}
|
||||
jsonMarshalled, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("%d-1: Failed to marshal input: '%v': %v", i, input, err)
|
||||
}
|
||||
|
||||
var result TimeHolder
|
||||
err = yaml.Unmarshal(jsonMarshalled, &result)
|
||||
if err != nil {
|
||||
t.Errorf("%d-2: Failed to unmarshal '%+v': %v", i, string(jsonMarshalled), err)
|
||||
}
|
||||
|
||||
iN, iO := input.T.Zone()
|
||||
oN, oO := result.T.Zone()
|
||||
if iN != oN || iO != oO {
|
||||
t.Errorf("%d-3: Time zones differ before and after serialization %s:%d %s:%d", i, iN, iO, oN, oO)
|
||||
}
|
||||
|
||||
if input.T.UnixNano() != result.T.UnixNano() {
|
||||
t.Errorf("%d-4: Failed to marshal input '%#v': got %#v", i, input, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeProto(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Time
|
||||
}{
|
||||
{Time{}},
|
||||
{Date(1998, time.May, 5, 1, 5, 5, 0, time.Local)},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 0, time.Local)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := c.input
|
||||
data, err := input.Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
time := Time{}
|
||||
if err := time.Unmarshal(data); err != nil {
|
||||
t.Fatalf("Failed to unmarshal output: '%v': %v", input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, time) {
|
||||
t.Errorf("Marshal->Unmarshal is not idempotent: '%v' vs '%v'", input, time)
|
||||
}
|
||||
}
|
||||
}
|
||||
134
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/types_test.go
generated
vendored
Normal file
134
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/types_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
func TestVerbsUgorjiMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input APIResource
|
||||
result string
|
||||
}{
|
||||
{APIResource{}, `{"name":"","singularName":"","namespaced":false,"kind":"","verbs":null}`},
|
||||
{APIResource{Verbs: Verbs([]string{})}, `{"name":"","singularName":"","namespaced":false,"kind":"","verbs":[]}`},
|
||||
{APIResource{Verbs: Verbs([]string{"delete"})}, `{"name":"","singularName":"","namespaced":false,"kind":"","verbs":["delete"]}`},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
result, err := json.Marshal(&c.input)
|
||||
if err != nil {
|
||||
t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("[%d] Failed to marshal input: '%v': expected '%v', got '%v'", i, c.input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result APIResource
|
||||
}{
|
||||
{`{}`, APIResource{}},
|
||||
{`{"verbs":null}`, APIResource{}},
|
||||
{`{"verbs":[]}`, APIResource{Verbs: Verbs([]string{})}},
|
||||
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
var result APIResource
|
||||
if err := jsoniter.ConfigFastest.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, c.result) {
|
||||
t.Errorf("[%d] Failed to unmarshal input '%v': expected %+v, got %+v", i, c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestUgorjiMarshalJSONWithOmit tests that we don't have regressions regarding nil and empty slices with "omit"
|
||||
func TestUgorjiMarshalJSONWithOmit(t *testing.T) {
|
||||
cases := []struct {
|
||||
input LabelSelector
|
||||
result string
|
||||
}{
|
||||
{LabelSelector{}, `{}`},
|
||||
{LabelSelector{MatchExpressions: []LabelSelectorRequirement{}}, `{}`},
|
||||
{LabelSelector{MatchExpressions: []LabelSelectorRequirement{{}}}, `{"matchExpressions":[{"key":"","operator":""}]}`},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
result, err := json.Marshal(&c.input)
|
||||
if err != nil {
|
||||
t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("[%d] Failed to marshal input: '%v': expected '%v', got '%v'", i, c.input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerbsUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result APIResource
|
||||
}{
|
||||
{`{}`, APIResource{}},
|
||||
{`{"verbs":null}`, APIResource{}},
|
||||
{`{"verbs":[]}`, APIResource{Verbs: Verbs([]string{})}},
|
||||
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
var result APIResource
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, c.result) {
|
||||
t.Errorf("[%d] Failed to unmarshal input '%v': expected %+v, got %+v", i, c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerbsProto(t *testing.T) {
|
||||
cases := []APIResource{
|
||||
{},
|
||||
{Verbs: Verbs([]string{})},
|
||||
{Verbs: Verbs([]string{"delete"})},
|
||||
}
|
||||
|
||||
for _, input := range cases {
|
||||
data, err := input.Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
resource := APIResource{}
|
||||
if err := resource.Unmarshal(data); err != nil {
|
||||
t.Fatalf("Failed to unmarshal output: '%v': %v", input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, resource) {
|
||||
t.Errorf("Marshal->Unmarshal is not idempotent: '%v' vs '%v'", input, resource)
|
||||
}
|
||||
}
|
||||
}
|
||||
60
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_test.go
generated
vendored
Normal file
60
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
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 unstructured
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// TestCodecOfUnstructuredList tests that there are no data races in Encode().
|
||||
// i.e. that it does not mutate the object being encoded.
|
||||
func TestCodecOfUnstructuredList(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
concurrency := 10
|
||||
list := UnstructuredList{
|
||||
Object: map[string]interface{}{},
|
||||
}
|
||||
wg.Add(concurrency)
|
||||
for i := 0; i < concurrency; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
assert.NoError(t, UnstructuredJSONScheme.Encode(&list, ioutil.Discard))
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestUnstructuredList(t *testing.T) {
|
||||
list := &UnstructuredList{
|
||||
Object: map[string]interface{}{"kind": "List", "apiVersion": "v1"},
|
||||
Items: []Unstructured{
|
||||
{Object: map[string]interface{}{"kind": "Pod", "apiVersion": "v1", "metadata": map[string]interface{}{"name": "test"}}},
|
||||
},
|
||||
}
|
||||
content := list.UnstructuredContent()
|
||||
items := content["items"].([]interface{})
|
||||
if len(items) != 1 {
|
||||
t.Fatalf("unexpected items: %#v", items)
|
||||
}
|
||||
if getNestedField(items[0].(map[string]interface{}), "metadata", "name") != "test" {
|
||||
t.Fatalf("unexpected fields: %#v", items[0])
|
||||
}
|
||||
}
|
||||
94
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation/validation_test.go
generated
vendored
Normal file
94
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation/validation_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
func TestValidateLabels(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"},
|
||||
{"UpperCaseAreOK123": "bar"},
|
||||
{"goodvalue": "123_-.BaR"},
|
||||
}
|
||||
for i := range successCases {
|
||||
errs := ValidateLabels(successCases[i], field.NewPath("field"))
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("case[%d] expected success, got %#v", i, errs)
|
||||
}
|
||||
}
|
||||
|
||||
namePartErrMsg := "name part must consist of"
|
||||
nameErrMsg := "a qualified name must consist of"
|
||||
labelErrMsg := "a valid label must be an empty string or consist of"
|
||||
maxLengthErrMsg := "must be no more than"
|
||||
|
||||
labelNameErrorCases := []struct {
|
||||
labels 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 labelNameErrorCases {
|
||||
errs := ValidateLabels(labelNameErrorCases[i].labels, field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Errorf("case[%d]: expected failure", i)
|
||||
} else {
|
||||
if !strings.Contains(errs[0].Detail, labelNameErrorCases[i].expect) {
|
||||
t.Errorf("case[%d]: error details do not include %q: %q", i, labelNameErrorCases[i].expect, errs[0].Detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
labelValueErrorCases := []struct {
|
||||
labels map[string]string
|
||||
expect string
|
||||
}{
|
||||
{map[string]string{"toolongvalue": strings.Repeat("a", 64)}, maxLengthErrMsg},
|
||||
{map[string]string{"backslashesinvalue": "some\\bad\\value"}, labelErrMsg},
|
||||
{map[string]string{"nocommasallowed": "bad,value"}, labelErrMsg},
|
||||
{map[string]string{"strangecharsinvalue": "?#$notsogood"}, labelErrMsg},
|
||||
}
|
||||
for i := range labelValueErrorCases {
|
||||
errs := ValidateLabels(labelValueErrorCases[i].labels, field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Errorf("case[%d]: expected failure", i)
|
||||
} else {
|
||||
if !strings.Contains(errs[0].Detail, labelValueErrorCases[i].expect) {
|
||||
t.Errorf("case[%d]: error details do not include %q: %q", i, labelValueErrorCases[i].expect, errs[0].Detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/BUILD
generated
vendored
Normal file
40
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema: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/apis/testapigroup/fuzzer:all-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/testapigroup/install:all-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/testapigroup/v1:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
22
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/doc.go
generated
vendored
Normal file
22
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +groupName=testapigroup.apimachinery.k8s.io
|
||||
//
|
||||
// package testapigroup contains an testapigroup API used to demonstrate how to create api groups. Moreover, this is
|
||||
// used within tests.
|
||||
package testapigroup // import "k8s.io/apimachinery/pkg/apis/testapigroup"
|
||||
33
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/fuzzer/BUILD
generated
vendored
Normal file
33
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/fuzzer/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fuzzer.go"],
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz: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/apis/testapigroup:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime: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"],
|
||||
)
|
||||
99
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/fuzzer/fuzzer.go
generated
vendored
Normal file
99
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/fuzzer/fuzzer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
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 fuzzer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/apis/testapigroup"
|
||||
"k8s.io/apimachinery/pkg/apis/testapigroup/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
// overrideMetaFuncs override some generic fuzzer funcs from k8s.io/apimachinery in order to have more realistic
|
||||
// values in a Kubernetes context.
|
||||
func overrideMetaFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
// TODO: uncomment when round trip starts from a versioned object
|
||||
if true { //c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
// We do not set TypeMeta here because it is not carried through a round trip
|
||||
Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&testapigroup.Carp{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(r *runtime.RawExtension, c fuzz.Continue) {
|
||||
// Pick an arbitrary type and fuzz it
|
||||
types := []runtime.Object{&testapigroup.Carp{}}
|
||||
obj := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(obj)
|
||||
|
||||
// Convert the object to raw bytes
|
||||
bytes, err := runtime.Encode(apitesting.TestCodec(codecs, v1.SchemeGroupVersion), obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to encode object: %v", err))
|
||||
}
|
||||
|
||||
// Set the bytes field on the RawExtension
|
||||
r.Raw = bytes
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testapigroupFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(s *testapigroup.CarpSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s)
|
||||
// has a default value
|
||||
ttl := int64(30)
|
||||
if c.RandBool() {
|
||||
ttl = int64(c.Uint32())
|
||||
}
|
||||
s.TerminationGracePeriodSeconds = &ttl
|
||||
|
||||
if s.SchedulerName == "" {
|
||||
s.SchedulerName = "default-scheduler"
|
||||
}
|
||||
},
|
||||
func(j *testapigroup.CarpPhase, c fuzz.Continue) {
|
||||
statuses := []testapigroup.CarpPhase{"Pending", "Running", "Succeeded", "Failed", "Unknown"}
|
||||
*j = statuses[c.Rand.Intn(len(statuses))]
|
||||
},
|
||||
func(rp *testapigroup.RestartPolicy, c fuzz.Continue) {
|
||||
policies := []testapigroup.RestartPolicy{"Always", "Never", "OnFailure"}
|
||||
*rp = policies[c.Rand.Intn(len(policies))]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Funcs returns the fuzzer functions for the testapigroup.
|
||||
var Funcs = fuzzer.MergeFuzzerFuncs(
|
||||
overrideMetaFuncs,
|
||||
testapigroupFuncs,
|
||||
)
|
||||
42
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/install/BUILD
generated
vendored
Normal file
42
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/install/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["install.go"],
|
||||
deps = [
|
||||
"//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/testapigroup:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["roundtrip_test.go"],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/testapigroup/fuzzer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
43
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/install/install.go
generated
vendored
Normal file
43
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/install/install.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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 install installs the certificates API group, making it available as
|
||||
// an option to all of the API encoding/decoding machinery.
|
||||
package install
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
"k8s.io/apimachinery/pkg/apis/testapigroup"
|
||||
"k8s.io/apimachinery/pkg/apis/testapigroup/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Install registers the API group and adds types to a scheme
|
||||
func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
|
||||
if err := announced.NewGroupMetaFactory(
|
||||
&announced.GroupMetaFactoryArgs{
|
||||
GroupName: testapigroup.GroupName,
|
||||
VersionPreferenceOrder: []string{v1.SchemeGroupVersion.Version},
|
||||
AddInternalObjectsToScheme: testapigroup.AddToScheme,
|
||||
},
|
||||
announced.VersionToSchemeFunc{
|
||||
v1.SchemeGroupVersion.Version: v1.AddToScheme,
|
||||
},
|
||||
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
28
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/install/roundtrip_test.go
generated
vendored
Normal file
28
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/install/roundtrip_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
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 install
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
|
||||
testapigroupfuzzer "k8s.io/apimachinery/pkg/apis/testapigroup/fuzzer"
|
||||
)
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
roundtrip.RoundTripTestForAPIGroup(t, Install, testapigroupfuzzer.Funcs)
|
||||
}
|
||||
51
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/register.go
generated
vendored
Normal file
51
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/register.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 testapigroup
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "testapigroup.apimachinery.k8s.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
|
||||
// Kind takes an unqualified kind and returns a Group qualified GroupKind
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Carp{},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
138
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/types.go
generated
vendored
Normal file
138
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
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 testapigroup
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type (
|
||||
ConditionStatus string
|
||||
CarpConditionType string
|
||||
CarpPhase string
|
||||
RestartPolicy string
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Carp is a collection of containers, used as either input (create, update) or as output (list, get).
|
||||
type Carp struct {
|
||||
metav1.TypeMeta
|
||||
// +optional
|
||||
metav1.ObjectMeta
|
||||
|
||||
// Spec defines the behavior of a carp.
|
||||
// +optional
|
||||
Spec CarpSpec
|
||||
|
||||
// Status represents the current information about a carp. This data may not be up
|
||||
// to date.
|
||||
// +optional
|
||||
Status CarpStatus
|
||||
}
|
||||
|
||||
// CarpStatus represents information about the status of a carp. Status may trail the actual
|
||||
// state of a system.
|
||||
type CarpStatus struct {
|
||||
// +optional
|
||||
Phase CarpPhase
|
||||
// +optional
|
||||
Conditions []CarpCondition
|
||||
// A human readable message indicating details about why the carp is in this state.
|
||||
// +optional
|
||||
Message string
|
||||
// A brief CamelCase message indicating details about why the carp is in this state. e.g. 'OutOfDisk'
|
||||
// +optional
|
||||
Reason string
|
||||
|
||||
// +optional
|
||||
HostIP string
|
||||
// +optional
|
||||
CarpIP string
|
||||
|
||||
// Date and time at which the object was acknowledged by the Kubelet.
|
||||
// This is before the Kubelet pulled the container image(s) for the carp.
|
||||
// +optional
|
||||
StartTime *metav1.Time
|
||||
}
|
||||
|
||||
type CarpCondition struct {
|
||||
Type CarpConditionType
|
||||
Status ConditionStatus
|
||||
// +optional
|
||||
LastProbeTime metav1.Time
|
||||
// +optional
|
||||
LastTransitionTime metav1.Time
|
||||
// +optional
|
||||
Reason string
|
||||
// +optional
|
||||
Message string
|
||||
}
|
||||
|
||||
// CarpSpec is a description of a carp
|
||||
type CarpSpec struct {
|
||||
// +optional
|
||||
RestartPolicy RestartPolicy
|
||||
// Optional duration in seconds the carp needs to terminate gracefully. May be decreased in delete request.
|
||||
// Value must be non-negative integer. The value zero indicates delete immediately.
|
||||
// If this value is nil, the default grace period will be used instead.
|
||||
// The grace period is the duration in seconds after the processes running in the carp are sent
|
||||
// a termination signal and the time when the processes are forcibly halted with a kill signal.
|
||||
// Set this value longer than the expected cleanup time for your process.
|
||||
// +optional
|
||||
TerminationGracePeriodSeconds *int64
|
||||
// Optional duration in seconds relative to the StartTime that the carp may be active on a node
|
||||
// before the system actively tries to terminate the carp; value must be positive integer
|
||||
// +optional
|
||||
ActiveDeadlineSeconds *int64
|
||||
// NodeSelector is a selector which must be true for the carp to fit on a node
|
||||
// +optional
|
||||
NodeSelector map[string]string
|
||||
|
||||
// ServiceAccountName is the name of the ServiceAccount to use to run this carp
|
||||
// The carp will be allowed to use secrets referenced by the ServiceAccount
|
||||
ServiceAccountName string
|
||||
|
||||
// NodeName is a request to schedule this carp onto a specific node. If it is non-empty,
|
||||
// the scheduler simply schedules this carp onto that node, assuming that it fits resource
|
||||
// requirements.
|
||||
// +optional
|
||||
NodeName string
|
||||
// Specifies the hostname of the Carp.
|
||||
// If not specified, the carp's hostname will be set to a system-defined value.
|
||||
// +optional
|
||||
Hostname string
|
||||
// If specified, the fully qualified Carp hostname will be "<hostname>.<subdomain>.<carp namespace>.svc.<cluster domain>".
|
||||
// If not specified, the carp will not have a domainname at all.
|
||||
// +optional
|
||||
Subdomain string
|
||||
// If specified, the carp will be dispatched by specified scheduler.
|
||||
// If not specified, the carp will be dispatched by default scheduler.
|
||||
// +optional
|
||||
SchedulerName string
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CarpList is a list of Carps.
|
||||
type CarpList struct {
|
||||
metav1.TypeMeta
|
||||
// +optional
|
||||
metav1.ListMeta
|
||||
|
||||
Items []Carp
|
||||
}
|
||||
50
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/BUILD
generated
vendored
Normal file
50
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"conversion.go",
|
||||
"defaults.go",
|
||||
"doc.go",
|
||||
"generated.pb.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"types_swagger_doc_generated.go",
|
||||
"zz_generated.conversion.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
"zz_generated.defaults.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/sortkeys:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/testapigroup:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "go_default_library_protos",
|
||||
srcs = ["generated.proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
26
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/conversion.go
generated
vendored
Normal file
26
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/conversion.go
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
// Add non-generated conversion functions here. Currently there are none.
|
||||
return nil
|
||||
}
|
||||
26
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/defaults.go
generated
vendored
Normal file
26
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/defaults.go
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||
// return RegisterDefaults(scheme)
|
||||
return nil
|
||||
}
|
||||
23
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/doc.go
generated
vendored
Normal file
23
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=k8s.io/apimachinery/pkg/apis/testapigroup
|
||||
// +k8s:openapi-gen=false
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
|
||||
// +groupName=testapigroup.apimachinery.k8s.io
|
||||
package v1 // import "k8s.io/apimachinery/pkg/apis/testapigroup/v1"
|
||||
2009
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/generated.pb.go
generated
vendored
Normal file
2009
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/generated.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
212
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/generated.proto
generated
vendored
Normal file
212
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/generated.proto
generated
vendored
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
|
||||
|
||||
syntax = 'proto2';
|
||||
|
||||
package k8s.io.apimachinery.pkg.apis.testapigroup.v1;
|
||||
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1";
|
||||
|
||||
// Carp is a collection of containers, used as either input (create, update) or as output (list, get).
|
||||
message Carp {
|
||||
// Standard object's metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// Specification of the desired behavior of the carp.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
|
||||
// +optional
|
||||
optional CarpSpec spec = 2;
|
||||
|
||||
// Most recently observed status of the carp.
|
||||
// This data may not be up to date.
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
|
||||
// +optional
|
||||
optional CarpStatus status = 3;
|
||||
}
|
||||
|
||||
message CarpCondition {
|
||||
// Type is the type of the condition.
|
||||
// Currently only Ready.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#carp-conditions
|
||||
optional string type = 1;
|
||||
|
||||
// Status is the status of the condition.
|
||||
// Can be True, False, Unknown.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#carp-conditions
|
||||
optional string status = 2;
|
||||
|
||||
// Last time we probed the condition.
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastProbeTime = 3;
|
||||
|
||||
// Last time the condition transitioned from one status to another.
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 4;
|
||||
|
||||
// Unique, one-word, CamelCase reason for the condition's last transition.
|
||||
// +optional
|
||||
optional string reason = 5;
|
||||
|
||||
// Human-readable message indicating details about last transition.
|
||||
// +optional
|
||||
optional string message = 6;
|
||||
}
|
||||
|
||||
// CarpList is a list of Carps.
|
||||
message CarpList {
|
||||
// Standard list metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// List of carps.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carps
|
||||
repeated Carp items = 2;
|
||||
}
|
||||
|
||||
// CarpSpec is a description of a carp
|
||||
message CarpSpec {
|
||||
// Restart policy for all containers within the carp.
|
||||
// One of Always, OnFailure, Never.
|
||||
// Default to Always.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#restartpolicy
|
||||
// +optional
|
||||
optional string restartPolicy = 3;
|
||||
|
||||
// Optional duration in seconds the carp needs to terminate gracefully. May be decreased in delete request.
|
||||
// Value must be non-negative integer. The value zero indicates delete immediately.
|
||||
// If this value is nil, the default grace period will be used instead.
|
||||
// The grace period is the duration in seconds after the processes running in the carp are sent
|
||||
// a termination signal and the time when the processes are forcibly halted with a kill signal.
|
||||
// Set this value longer than the expected cleanup time for your process.
|
||||
// Defaults to 30 seconds.
|
||||
// +optional
|
||||
optional int64 terminationGracePeriodSeconds = 4;
|
||||
|
||||
// Optional duration in seconds the carp may be active on the node relative to
|
||||
// StartTime before the system will actively try to mark it failed and kill associated containers.
|
||||
// Value must be a positive integer.
|
||||
// +optional
|
||||
optional int64 activeDeadlineSeconds = 5;
|
||||
|
||||
// NodeSelector is a selector which must be true for the carp to fit on a node.
|
||||
// Selector which must match a node's labels for the carp to be scheduled on that node.
|
||||
// More info: http://kubernetes.io/docs/user-guide/node-selection/README
|
||||
// +optional
|
||||
map<string, string> nodeSelector = 7;
|
||||
|
||||
// ServiceAccountName is the name of the ServiceAccount to use to run this carp.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md
|
||||
// +optional
|
||||
optional string serviceAccountName = 8;
|
||||
|
||||
// DeprecatedServiceAccount is a depreciated alias for ServiceAccountName.
|
||||
// Deprecated: Use serviceAccountName instead.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional string serviceAccount = 9;
|
||||
|
||||
// NodeName is a request to schedule this carp onto a specific node. If it is non-empty,
|
||||
// the scheduler simply schedules this carp onto that node, assuming that it fits resource
|
||||
// requirements.
|
||||
// +optional
|
||||
optional string nodeName = 10;
|
||||
|
||||
// Host networking requested for this carp. Use the host's network namespace.
|
||||
// If this option is set, the ports that will be used must be specified.
|
||||
// Default to false.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional bool hostNetwork = 11;
|
||||
|
||||
// Use the host's pid namespace.
|
||||
// Optional: Default to false.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional bool hostPID = 12;
|
||||
|
||||
// Use the host's ipc namespace.
|
||||
// Optional: Default to false.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional bool hostIPC = 13;
|
||||
|
||||
// Specifies the hostname of the Carp
|
||||
// If not specified, the carp's hostname will be set to a system-defined value.
|
||||
// +optional
|
||||
optional string hostname = 16;
|
||||
|
||||
// If specified, the fully qualified Carp hostname will be "<hostname>.<subdomain>.<carp namespace>.svc.<cluster domain>".
|
||||
// If not specified, the carp will not have a domainname at all.
|
||||
// +optional
|
||||
optional string subdomain = 17;
|
||||
|
||||
// If specified, the carp will be dispatched by specified scheduler.
|
||||
// If not specified, the carp will be dispatched by default scheduler.
|
||||
// +optional
|
||||
optional string schedulername = 19;
|
||||
}
|
||||
|
||||
// CarpStatus represents information about the status of a carp. Status may trail the actual
|
||||
// state of a system.
|
||||
message CarpStatus {
|
||||
// Current condition of the carp.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#carp-phase
|
||||
// +optional
|
||||
optional string phase = 1;
|
||||
|
||||
// Current service state of carp.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#carp-conditions
|
||||
// +optional
|
||||
repeated CarpCondition conditions = 2;
|
||||
|
||||
// A human readable message indicating details about why the carp is in this condition.
|
||||
// +optional
|
||||
optional string message = 3;
|
||||
|
||||
// A brief CamelCase message indicating details about why the carp is in this state.
|
||||
// e.g. 'OutOfDisk'
|
||||
// +optional
|
||||
optional string reason = 4;
|
||||
|
||||
// IP address of the host to which the carp is assigned. Empty if not yet scheduled.
|
||||
// +optional
|
||||
optional string hostIP = 5;
|
||||
|
||||
// IP address allocated to the carp. Routable at least within the cluster.
|
||||
// Empty if not yet allocated.
|
||||
// +optional
|
||||
optional string carpIP = 6;
|
||||
|
||||
// RFC 3339 date and time at which the object was acknowledged by the Kubelet.
|
||||
// This is before the Kubelet pulled the container image(s) for the carp.
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time startTime = 7;
|
||||
}
|
||||
|
||||
63
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/register.go
generated
vendored
Normal file
63
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/register.go
generated
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "testapigroup.apimachinery.k8s.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
|
||||
|
||||
// Kind takes an unqualified kind and returns a Group qualified GroupKind
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
|
||||
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addKnownTypes, addConversionFuncs, addDefaultingFuncs)
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Carp{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
||||
196
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/types.go
generated
vendored
Normal file
196
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/types.go
generated
vendored
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
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 v1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type (
|
||||
ConditionStatus string
|
||||
CarpConditionType string
|
||||
CarpPhase string
|
||||
RestartPolicy string
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Carp is a collection of containers, used as either input (create, update) or as output (list, get).
|
||||
type Carp struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// Standard object's metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Specification of the desired behavior of the carp.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
|
||||
// +optional
|
||||
Spec CarpSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
// Most recently observed status of the carp.
|
||||
// This data may not be up to date.
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
|
||||
// +optional
|
||||
Status CarpStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// CarpStatus represents information about the status of a carp. Status may trail the actual
|
||||
// state of a system.
|
||||
type CarpStatus struct {
|
||||
// Current condition of the carp.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#carp-phase
|
||||
// +optional
|
||||
Phase CarpPhase `json:"phase,omitempty" protobuf:"bytes,1,opt,name=phase,casttype=CarpPhase"`
|
||||
// Current service state of carp.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#carp-conditions
|
||||
// +optional
|
||||
Conditions []CarpCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,2,rep,name=conditions"`
|
||||
// A human readable message indicating details about why the carp is in this condition.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"`
|
||||
// A brief CamelCase message indicating details about why the carp is in this state.
|
||||
// e.g. 'OutOfDisk'
|
||||
// +optional
|
||||
Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"`
|
||||
|
||||
// IP address of the host to which the carp is assigned. Empty if not yet scheduled.
|
||||
// +optional
|
||||
HostIP string `json:"hostIP,omitempty" protobuf:"bytes,5,opt,name=hostIP"`
|
||||
// IP address allocated to the carp. Routable at least within the cluster.
|
||||
// Empty if not yet allocated.
|
||||
// +optional
|
||||
CarpIP string `json:"carpIP,omitempty" protobuf:"bytes,6,opt,name=carpIP"`
|
||||
|
||||
// RFC 3339 date and time at which the object was acknowledged by the Kubelet.
|
||||
// This is before the Kubelet pulled the container image(s) for the carp.
|
||||
// +optional
|
||||
StartTime *metav1.Time `json:"startTime,omitempty" protobuf:"bytes,7,opt,name=startTime"`
|
||||
}
|
||||
|
||||
type CarpCondition struct {
|
||||
// Type is the type of the condition.
|
||||
// Currently only Ready.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#carp-conditions
|
||||
Type CarpConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=CarpConditionType"`
|
||||
// Status is the status of the condition.
|
||||
// Can be True, False, Unknown.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#carp-conditions
|
||||
Status ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=ConditionStatus"`
|
||||
// Last time we probed the condition.
|
||||
// +optional
|
||||
LastProbeTime metav1.Time `json:"lastProbeTime,omitempty" protobuf:"bytes,3,opt,name=lastProbeTime"`
|
||||
// Last time the condition transitioned from one status to another.
|
||||
// +optional
|
||||
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,4,opt,name=lastTransitionTime"`
|
||||
// Unique, one-word, CamelCase reason for the condition's last transition.
|
||||
// +optional
|
||||
Reason string `json:"reason,omitempty" protobuf:"bytes,5,opt,name=reason"`
|
||||
// Human-readable message indicating details about last transition.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"`
|
||||
}
|
||||
|
||||
// CarpSpec is a description of a carp
|
||||
type CarpSpec struct {
|
||||
// Restart policy for all containers within the carp.
|
||||
// One of Always, OnFailure, Never.
|
||||
// Default to Always.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carp-states#restartpolicy
|
||||
// +optional
|
||||
RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" protobuf:"bytes,3,opt,name=restartPolicy,casttype=RestartPolicy"`
|
||||
// Optional duration in seconds the carp needs to terminate gracefully. May be decreased in delete request.
|
||||
// Value must be non-negative integer. The value zero indicates delete immediately.
|
||||
// If this value is nil, the default grace period will be used instead.
|
||||
// The grace period is the duration in seconds after the processes running in the carp are sent
|
||||
// a termination signal and the time when the processes are forcibly halted with a kill signal.
|
||||
// Set this value longer than the expected cleanup time for your process.
|
||||
// Defaults to 30 seconds.
|
||||
// +optional
|
||||
TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty" protobuf:"varint,4,opt,name=terminationGracePeriodSeconds"`
|
||||
// Optional duration in seconds the carp may be active on the node relative to
|
||||
// StartTime before the system will actively try to mark it failed and kill associated containers.
|
||||
// Value must be a positive integer.
|
||||
// +optional
|
||||
ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,5,opt,name=activeDeadlineSeconds"`
|
||||
// NodeSelector is a selector which must be true for the carp to fit on a node.
|
||||
// Selector which must match a node's labels for the carp to be scheduled on that node.
|
||||
// More info: http://kubernetes.io/docs/user-guide/node-selection/README
|
||||
// +optional
|
||||
NodeSelector map[string]string `json:"nodeSelector,omitempty" protobuf:"bytes,7,rep,name=nodeSelector"`
|
||||
|
||||
// ServiceAccountName is the name of the ServiceAccount to use to run this carp.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md
|
||||
// +optional
|
||||
ServiceAccountName string `json:"serviceAccountName,omitempty" protobuf:"bytes,8,opt,name=serviceAccountName"`
|
||||
// DeprecatedServiceAccount is a depreciated alias for ServiceAccountName.
|
||||
// Deprecated: Use serviceAccountName instead.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
DeprecatedServiceAccount string `json:"serviceAccount,omitempty" protobuf:"bytes,9,opt,name=serviceAccount"`
|
||||
|
||||
// NodeName is a request to schedule this carp onto a specific node. If it is non-empty,
|
||||
// the scheduler simply schedules this carp onto that node, assuming that it fits resource
|
||||
// requirements.
|
||||
// +optional
|
||||
NodeName string `json:"nodeName,omitempty" protobuf:"bytes,10,opt,name=nodeName"`
|
||||
// Host networking requested for this carp. Use the host's network namespace.
|
||||
// If this option is set, the ports that will be used must be specified.
|
||||
// Default to false.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
HostNetwork bool `json:"hostNetwork,omitempty" protobuf:"varint,11,opt,name=hostNetwork"`
|
||||
// Use the host's pid namespace.
|
||||
// Optional: Default to false.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
HostPID bool `json:"hostPID,omitempty" protobuf:"varint,12,opt,name=hostPID"`
|
||||
// Use the host's ipc namespace.
|
||||
// Optional: Default to false.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
HostIPC bool `json:"hostIPC,omitempty" protobuf:"varint,13,opt,name=hostIPC"`
|
||||
// Specifies the hostname of the Carp
|
||||
// If not specified, the carp's hostname will be set to a system-defined value.
|
||||
// +optional
|
||||
Hostname string `json:"hostname,omitempty" protobuf:"bytes,16,opt,name=hostname"`
|
||||
// If specified, the fully qualified Carp hostname will be "<hostname>.<subdomain>.<carp namespace>.svc.<cluster domain>".
|
||||
// If not specified, the carp will not have a domainname at all.
|
||||
// +optional
|
||||
Subdomain string `json:"subdomain,omitempty" protobuf:"bytes,17,opt,name=subdomain"`
|
||||
// If specified, the carp will be dispatched by specified scheduler.
|
||||
// If not specified, the carp will be dispatched by default scheduler.
|
||||
// +optional
|
||||
SchedulerName string `json:"schedulername,omitempty" protobuf:"bytes,19,opt,name=schedulername"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CarpList is a list of Carps.
|
||||
type CarpList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// Standard list metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// List of carps.
|
||||
// More info: http://kubernetes.io/docs/user-guide/carps
|
||||
Items []Carp `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
17
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/types_swagger_doc_generated.go
generated
vendored
Normal file
17
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/types_swagger_doc_generated.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
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 v1
|
||||
226
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/zz_generated.conversion.go
generated
vendored
Normal file
226
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/zz_generated.conversion.go
generated
vendored
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by conversion-gen. Do not edit it manually!
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
testapigroup "k8s.io/apimachinery/pkg/apis/testapigroup"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
localSchemeBuilder.Register(RegisterConversions)
|
||||
}
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedConversionFuncs(
|
||||
Convert_v1_Carp_To_testapigroup_Carp,
|
||||
Convert_testapigroup_Carp_To_v1_Carp,
|
||||
Convert_v1_CarpCondition_To_testapigroup_CarpCondition,
|
||||
Convert_testapigroup_CarpCondition_To_v1_CarpCondition,
|
||||
Convert_v1_CarpList_To_testapigroup_CarpList,
|
||||
Convert_testapigroup_CarpList_To_v1_CarpList,
|
||||
Convert_v1_CarpSpec_To_testapigroup_CarpSpec,
|
||||
Convert_testapigroup_CarpSpec_To_v1_CarpSpec,
|
||||
Convert_v1_CarpStatus_To_testapigroup_CarpStatus,
|
||||
Convert_testapigroup_CarpStatus_To_v1_CarpStatus,
|
||||
)
|
||||
}
|
||||
|
||||
func autoConvert_v1_Carp_To_testapigroup_Carp(in *Carp, out *testapigroup.Carp, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if err := Convert_v1_CarpSpec_To_testapigroup_CarpSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1_CarpStatus_To_testapigroup_CarpStatus(&in.Status, &out.Status, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_Carp_To_testapigroup_Carp is an autogenerated conversion function.
|
||||
func Convert_v1_Carp_To_testapigroup_Carp(in *Carp, out *testapigroup.Carp, s conversion.Scope) error {
|
||||
return autoConvert_v1_Carp_To_testapigroup_Carp(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_testapigroup_Carp_To_v1_Carp(in *testapigroup.Carp, out *Carp, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if err := Convert_testapigroup_CarpSpec_To_v1_CarpSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_testapigroup_CarpStatus_To_v1_CarpStatus(&in.Status, &out.Status, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_testapigroup_Carp_To_v1_Carp is an autogenerated conversion function.
|
||||
func Convert_testapigroup_Carp_To_v1_Carp(in *testapigroup.Carp, out *Carp, s conversion.Scope) error {
|
||||
return autoConvert_testapigroup_Carp_To_v1_Carp(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_CarpCondition_To_testapigroup_CarpCondition(in *CarpCondition, out *testapigroup.CarpCondition, s conversion.Scope) error {
|
||||
out.Type = testapigroup.CarpConditionType(in.Type)
|
||||
out.Status = testapigroup.ConditionStatus(in.Status)
|
||||
out.LastProbeTime = in.LastProbeTime
|
||||
out.LastTransitionTime = in.LastTransitionTime
|
||||
out.Reason = in.Reason
|
||||
out.Message = in.Message
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_CarpCondition_To_testapigroup_CarpCondition is an autogenerated conversion function.
|
||||
func Convert_v1_CarpCondition_To_testapigroup_CarpCondition(in *CarpCondition, out *testapigroup.CarpCondition, s conversion.Scope) error {
|
||||
return autoConvert_v1_CarpCondition_To_testapigroup_CarpCondition(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_testapigroup_CarpCondition_To_v1_CarpCondition(in *testapigroup.CarpCondition, out *CarpCondition, s conversion.Scope) error {
|
||||
out.Type = CarpConditionType(in.Type)
|
||||
out.Status = ConditionStatus(in.Status)
|
||||
out.LastProbeTime = in.LastProbeTime
|
||||
out.LastTransitionTime = in.LastTransitionTime
|
||||
out.Reason = in.Reason
|
||||
out.Message = in.Message
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_testapigroup_CarpCondition_To_v1_CarpCondition is an autogenerated conversion function.
|
||||
func Convert_testapigroup_CarpCondition_To_v1_CarpCondition(in *testapigroup.CarpCondition, out *CarpCondition, s conversion.Scope) error {
|
||||
return autoConvert_testapigroup_CarpCondition_To_v1_CarpCondition(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_CarpList_To_testapigroup_CarpList(in *CarpList, out *testapigroup.CarpList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]testapigroup.Carp, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_v1_Carp_To_testapigroup_Carp(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_CarpList_To_testapigroup_CarpList is an autogenerated conversion function.
|
||||
func Convert_v1_CarpList_To_testapigroup_CarpList(in *CarpList, out *testapigroup.CarpList, s conversion.Scope) error {
|
||||
return autoConvert_v1_CarpList_To_testapigroup_CarpList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_testapigroup_CarpList_To_v1_CarpList(in *testapigroup.CarpList, out *CarpList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Carp, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_testapigroup_Carp_To_v1_Carp(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_testapigroup_CarpList_To_v1_CarpList is an autogenerated conversion function.
|
||||
func Convert_testapigroup_CarpList_To_v1_CarpList(in *testapigroup.CarpList, out *CarpList, s conversion.Scope) error {
|
||||
return autoConvert_testapigroup_CarpList_To_v1_CarpList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_CarpSpec_To_testapigroup_CarpSpec(in *CarpSpec, out *testapigroup.CarpSpec, s conversion.Scope) error {
|
||||
out.RestartPolicy = testapigroup.RestartPolicy(in.RestartPolicy)
|
||||
out.TerminationGracePeriodSeconds = (*int64)(unsafe.Pointer(in.TerminationGracePeriodSeconds))
|
||||
out.ActiveDeadlineSeconds = (*int64)(unsafe.Pointer(in.ActiveDeadlineSeconds))
|
||||
out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector))
|
||||
out.ServiceAccountName = in.ServiceAccountName
|
||||
// INFO: in.DeprecatedServiceAccount opted out of conversion generation
|
||||
out.NodeName = in.NodeName
|
||||
// INFO: in.HostNetwork opted out of conversion generation
|
||||
// INFO: in.HostPID opted out of conversion generation
|
||||
// INFO: in.HostIPC opted out of conversion generation
|
||||
out.Hostname = in.Hostname
|
||||
out.Subdomain = in.Subdomain
|
||||
out.SchedulerName = in.SchedulerName
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_CarpSpec_To_testapigroup_CarpSpec is an autogenerated conversion function.
|
||||
func Convert_v1_CarpSpec_To_testapigroup_CarpSpec(in *CarpSpec, out *testapigroup.CarpSpec, s conversion.Scope) error {
|
||||
return autoConvert_v1_CarpSpec_To_testapigroup_CarpSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_testapigroup_CarpSpec_To_v1_CarpSpec(in *testapigroup.CarpSpec, out *CarpSpec, s conversion.Scope) error {
|
||||
out.RestartPolicy = RestartPolicy(in.RestartPolicy)
|
||||
out.TerminationGracePeriodSeconds = (*int64)(unsafe.Pointer(in.TerminationGracePeriodSeconds))
|
||||
out.ActiveDeadlineSeconds = (*int64)(unsafe.Pointer(in.ActiveDeadlineSeconds))
|
||||
out.NodeSelector = *(*map[string]string)(unsafe.Pointer(&in.NodeSelector))
|
||||
out.ServiceAccountName = in.ServiceAccountName
|
||||
out.NodeName = in.NodeName
|
||||
out.Hostname = in.Hostname
|
||||
out.Subdomain = in.Subdomain
|
||||
out.SchedulerName = in.SchedulerName
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_testapigroup_CarpSpec_To_v1_CarpSpec is an autogenerated conversion function.
|
||||
func Convert_testapigroup_CarpSpec_To_v1_CarpSpec(in *testapigroup.CarpSpec, out *CarpSpec, s conversion.Scope) error {
|
||||
return autoConvert_testapigroup_CarpSpec_To_v1_CarpSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_CarpStatus_To_testapigroup_CarpStatus(in *CarpStatus, out *testapigroup.CarpStatus, s conversion.Scope) error {
|
||||
out.Phase = testapigroup.CarpPhase(in.Phase)
|
||||
out.Conditions = *(*[]testapigroup.CarpCondition)(unsafe.Pointer(&in.Conditions))
|
||||
out.Message = in.Message
|
||||
out.Reason = in.Reason
|
||||
out.HostIP = in.HostIP
|
||||
out.CarpIP = in.CarpIP
|
||||
out.StartTime = (*meta_v1.Time)(unsafe.Pointer(in.StartTime))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_CarpStatus_To_testapigroup_CarpStatus is an autogenerated conversion function.
|
||||
func Convert_v1_CarpStatus_To_testapigroup_CarpStatus(in *CarpStatus, out *testapigroup.CarpStatus, s conversion.Scope) error {
|
||||
return autoConvert_v1_CarpStatus_To_testapigroup_CarpStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_testapigroup_CarpStatus_To_v1_CarpStatus(in *testapigroup.CarpStatus, out *CarpStatus, s conversion.Scope) error {
|
||||
out.Phase = CarpPhase(in.Phase)
|
||||
out.Conditions = *(*[]CarpCondition)(unsafe.Pointer(&in.Conditions))
|
||||
out.Message = in.Message
|
||||
out.Reason = in.Reason
|
||||
out.HostIP = in.HostIP
|
||||
out.CarpIP = in.CarpIP
|
||||
out.StartTime = (*meta_v1.Time)(unsafe.Pointer(in.StartTime))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_testapigroup_CarpStatus_To_v1_CarpStatus is an autogenerated conversion function.
|
||||
func Convert_testapigroup_CarpStatus_To_v1_CarpStatus(in *testapigroup.CarpStatus, out *CarpStatus, s conversion.Scope) error {
|
||||
return autoConvert_testapigroup_CarpStatus_To_v1_CarpStatus(in, out, s)
|
||||
}
|
||||
215
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/zz_generated.deepcopy.go
generated
vendored
Normal file
215
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/zz_generated.deepcopy.go
generated
vendored
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(RegisterDeepCopies)
|
||||
}
|
||||
|
||||
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
|
||||
// to allow building arbitrary schemes.
|
||||
//
|
||||
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
|
||||
func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedDeepCopyFuncs(
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Carp).DeepCopyInto(out.(*Carp))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Carp{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CarpCondition).DeepCopyInto(out.(*CarpCondition))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CarpCondition{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CarpList).DeepCopyInto(out.(*CarpList))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CarpList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CarpSpec).DeepCopyInto(out.(*CarpSpec))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CarpSpec{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CarpStatus).DeepCopyInto(out.(*CarpStatus))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CarpStatus{})},
|
||||
)
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Carp) DeepCopyInto(out *Carp) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Carp.
|
||||
func (in *Carp) DeepCopy() *Carp {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Carp)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Carp) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CarpCondition) DeepCopyInto(out *CarpCondition) {
|
||||
*out = *in
|
||||
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CarpCondition.
|
||||
func (in *CarpCondition) DeepCopy() *CarpCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CarpCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CarpList) DeepCopyInto(out *CarpList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Carp, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CarpList.
|
||||
func (in *CarpList) DeepCopy() *CarpList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CarpList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CarpList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CarpSpec) DeepCopyInto(out *CarpSpec) {
|
||||
*out = *in
|
||||
if in.TerminationGracePeriodSeconds != nil {
|
||||
in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ActiveDeadlineSeconds != nil {
|
||||
in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.NodeSelector != nil {
|
||||
in, out := &in.NodeSelector, &out.NodeSelector
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CarpSpec.
|
||||
func (in *CarpSpec) DeepCopy() *CarpSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CarpSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CarpStatus) DeepCopyInto(out *CarpStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]CarpCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.StartTime != nil {
|
||||
in, out := &in.StartTime, &out.StartTime
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(meta_v1.Time)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CarpStatus.
|
||||
func (in *CarpStatus) DeepCopy() *CarpStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CarpStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
32
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/zz_generated.defaults.go
generated
vendored
Normal file
32
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/v1/zz_generated.defaults.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by defaulter-gen. Do not edit it manually!
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
// All generated defaulters are covering - they call all nested defaulters.
|
||||
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
return nil
|
||||
}
|
||||
215
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/zz_generated.deepcopy.go
generated
vendored
Normal file
215
vendor/k8s.io/apimachinery/pkg/apis/testapigroup/zz_generated.deepcopy.go
generated
vendored
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package testapigroup
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(RegisterDeepCopies)
|
||||
}
|
||||
|
||||
// RegisterDeepCopies adds deep-copy functions to the given scheme. Public
|
||||
// to allow building arbitrary schemes.
|
||||
//
|
||||
// Deprecated: deepcopy registration will go away when static deepcopy is fully implemented.
|
||||
func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedDeepCopyFuncs(
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*Carp).DeepCopyInto(out.(*Carp))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&Carp{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CarpCondition).DeepCopyInto(out.(*CarpCondition))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CarpCondition{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CarpList).DeepCopyInto(out.(*CarpList))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CarpList{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CarpSpec).DeepCopyInto(out.(*CarpSpec))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CarpSpec{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CarpStatus).DeepCopyInto(out.(*CarpStatus))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CarpStatus{})},
|
||||
)
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Carp) DeepCopyInto(out *Carp) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Carp.
|
||||
func (in *Carp) DeepCopy() *Carp {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Carp)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Carp) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CarpCondition) DeepCopyInto(out *CarpCondition) {
|
||||
*out = *in
|
||||
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CarpCondition.
|
||||
func (in *CarpCondition) DeepCopy() *CarpCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CarpCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CarpList) DeepCopyInto(out *CarpList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Carp, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CarpList.
|
||||
func (in *CarpList) DeepCopy() *CarpList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CarpList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CarpList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CarpSpec) DeepCopyInto(out *CarpSpec) {
|
||||
*out = *in
|
||||
if in.TerminationGracePeriodSeconds != nil {
|
||||
in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.ActiveDeadlineSeconds != nil {
|
||||
in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.NodeSelector != nil {
|
||||
in, out := &in.NodeSelector, &out.NodeSelector
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CarpSpec.
|
||||
func (in *CarpSpec) DeepCopy() *CarpSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CarpSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CarpStatus) DeepCopyInto(out *CarpStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]CarpCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.StartTime != nil {
|
||||
in, out := &in.StartTime, &out.StartTime
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(v1.Time)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CarpStatus.
|
||||
func (in *CarpStatus) DeepCopy() *CarpStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CarpStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
826
vendor/k8s.io/apimachinery/pkg/conversion/converter_test.go
generated
vendored
Normal file
826
vendor/k8s.io/apimachinery/pkg/conversion/converter_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,826 @@
|
|||
/*
|
||||
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 conversion
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
|
||||
var fuzzIters = flag.Int("fuzz-iters", 50, "How many fuzzing iterations to do.")
|
||||
|
||||
// Test a weird version/kind embedding format.
|
||||
type MyWeirdCustomEmbeddedVersionKindField struct {
|
||||
ID string `json:"ID,omitempty"`
|
||||
APIVersion string `json:"myVersionKey,omitempty"`
|
||||
ObjectKind string `json:"myKindKey,omitempty"`
|
||||
Z string `json:"Z,omitempty"`
|
||||
Y uint64 `json:"Y,omitempty"`
|
||||
}
|
||||
|
||||
type TestType1 struct {
|
||||
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
|
||||
A string `json:"A,omitempty"`
|
||||
B int `json:"B,omitempty"`
|
||||
C int8 `json:"C,omitempty"`
|
||||
D int16 `json:"D,omitempty"`
|
||||
E int32 `json:"E,omitempty"`
|
||||
F int64 `json:"F,omitempty"`
|
||||
G uint `json:"G,omitempty"`
|
||||
H uint8 `json:"H,omitempty"`
|
||||
I uint16 `json:"I,omitempty"`
|
||||
J uint32 `json:"J,omitempty"`
|
||||
K uint64 `json:"K,omitempty"`
|
||||
L bool `json:"L,omitempty"`
|
||||
M map[string]int `json:"M,omitempty"`
|
||||
N map[string]TestType2 `json:"N,omitempty"`
|
||||
O *TestType2 `json:"O,omitempty"`
|
||||
P []TestType2 `json:"Q,omitempty"`
|
||||
}
|
||||
|
||||
type TestType2 struct {
|
||||
A string `json:"A,omitempty"`
|
||||
B int `json:"B,omitempty"`
|
||||
}
|
||||
|
||||
type ExternalTestType2 struct {
|
||||
A string `json:"A,omitempty"`
|
||||
B int `json:"B,omitempty"`
|
||||
}
|
||||
type ExternalTestType1 struct {
|
||||
MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
|
||||
A string `json:"A,omitempty"`
|
||||
B int `json:"B,omitempty"`
|
||||
C int8 `json:"C,omitempty"`
|
||||
D int16 `json:"D,omitempty"`
|
||||
E int32 `json:"E,omitempty"`
|
||||
F int64 `json:"F,omitempty"`
|
||||
G uint `json:"G,omitempty"`
|
||||
H uint8 `json:"H,omitempty"`
|
||||
I uint16 `json:"I,omitempty"`
|
||||
J uint32 `json:"J,omitempty"`
|
||||
K uint64 `json:"K,omitempty"`
|
||||
L bool `json:"L,omitempty"`
|
||||
M map[string]int `json:"M,omitempty"`
|
||||
N map[string]ExternalTestType2 `json:"N,omitempty"`
|
||||
O *ExternalTestType2 `json:"O,omitempty"`
|
||||
P []ExternalTestType2 `json:"Q,omitempty"`
|
||||
}
|
||||
|
||||
func testLogger(t *testing.T) DebugLogger {
|
||||
// We don't set logger to eliminate rubbish logs in tests.
|
||||
// If you want to switch it, simply switch it to: "return t"
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestConverter_byteSlice(t *testing.T) {
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
src := []byte{1, 2, 3}
|
||||
dest := []byte{}
|
||||
err := c.Convert(&src, &dest, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error")
|
||||
}
|
||||
if e, a := src, dest; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expected %#v, got %#v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_MismatchedTypes(t *testing.T) {
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
|
||||
err := c.RegisterConversionFunc(
|
||||
func(in *[]string, out *int, s Scope) error {
|
||||
if str, err := strconv.Atoi((*in)[0]); err != nil {
|
||||
return err
|
||||
} else {
|
||||
*out = str
|
||||
return nil
|
||||
}
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
src := []string{"5"}
|
||||
var dest *int
|
||||
err = c.Convert(&src, &dest, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if e, a := 5, *dest; e != a {
|
||||
t.Errorf("expected %#v, got %#v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_DefaultConvert(t *testing.T) {
|
||||
type A struct {
|
||||
Foo string
|
||||
Baz int
|
||||
}
|
||||
type B struct {
|
||||
Bar string
|
||||
Baz int
|
||||
}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
c.nameFunc = func(t reflect.Type) string { return "MyType" }
|
||||
|
||||
// Ensure conversion funcs can call DefaultConvert to get default behavior,
|
||||
// then fixup remaining fields manually
|
||||
err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
|
||||
if err := s.DefaultConvert(in, out, IgnoreMissingFields); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Bar = in.Foo
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
x := A{"hello, intrepid test reader!", 3}
|
||||
y := B{}
|
||||
|
||||
err = c.Convert(&x, &y, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if e, a := x.Foo, y.Bar; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := x.Baz, y.Baz; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_DeepCopy(t *testing.T) {
|
||||
type A struct {
|
||||
Foo *string
|
||||
Bar []string
|
||||
Baz interface{}
|
||||
Qux map[string]string
|
||||
}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
|
||||
foo, baz := "foo", "baz"
|
||||
x := A{
|
||||
Foo: &foo,
|
||||
Bar: []string{"bar"},
|
||||
Baz: &baz,
|
||||
Qux: map[string]string{"qux": "qux"},
|
||||
}
|
||||
y := A{}
|
||||
|
||||
if err := c.Convert(&x, &y, 0, nil); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
*x.Foo = "foo2"
|
||||
x.Bar[0] = "bar2"
|
||||
*x.Baz.(*string) = "baz2"
|
||||
x.Qux["qux"] = "qux2"
|
||||
if e, a := *x.Foo, *y.Foo; e == a {
|
||||
t.Errorf("expected difference between %v and %v", e, a)
|
||||
}
|
||||
if e, a := x.Bar, y.Bar; reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expected difference between %v and %v", e, a)
|
||||
}
|
||||
if e, a := *x.Baz.(*string), *y.Baz.(*string); e == a {
|
||||
t.Errorf("expected difference between %v and %v", e, a)
|
||||
}
|
||||
if e, a := x.Qux, y.Qux; reflect.DeepEqual(e, a) {
|
||||
t.Errorf("expected difference between %v and %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_CallsRegisteredFunctions(t *testing.T) {
|
||||
type A struct {
|
||||
Foo string
|
||||
Baz int
|
||||
}
|
||||
type B struct {
|
||||
Bar string
|
||||
Baz int
|
||||
}
|
||||
type C struct{}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
|
||||
out.Bar = in.Foo
|
||||
return s.Convert(&in.Baz, &out.Baz, 0)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
err = c.RegisterConversionFunc(func(in *B, out *A, s Scope) error {
|
||||
out.Foo = in.Bar
|
||||
return s.Convert(&in.Baz, &out.Baz, 0)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
x := A{"hello, intrepid test reader!", 3}
|
||||
y := B{}
|
||||
|
||||
err = c.Convert(&x, &y, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if e, a := x.Foo, y.Bar; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := x.Baz, y.Baz; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
z := B{"all your test are belong to us", 42}
|
||||
w := A{}
|
||||
|
||||
err = c.Convert(&z, &w, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if e, a := z.Bar, w.Foo; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := z.Baz, w.Baz; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
err = c.RegisterConversionFunc(func(in *A, out *C, s Scope) error {
|
||||
return fmt.Errorf("C can't store an A, silly")
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
err = c.Convert(&A{}, &C{}, 0, nil)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_IgnoredConversion(t *testing.T) {
|
||||
type A struct{}
|
||||
type B struct{}
|
||||
|
||||
count := 0
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
|
||||
count++
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if err := c.RegisterIgnoredConversion(&A{}, &B{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a := A{}
|
||||
b := B{}
|
||||
if err := c.Convert(&a, &b, 0, nil); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Errorf("unexpected number of conversion invocations")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_IgnoredConversionNested(t *testing.T) {
|
||||
type C string
|
||||
type A struct {
|
||||
C C
|
||||
}
|
||||
type B struct {
|
||||
C C
|
||||
}
|
||||
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
typed := C("")
|
||||
if err := c.RegisterIgnoredConversion(&typed, &typed); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a := A{C: C("test")}
|
||||
b := B{C: C("other")}
|
||||
if err := c.Convert(&a, &b, AllowDifferentFieldTypeNames, nil); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if b.C != C("other") {
|
||||
t.Errorf("expected no conversion of field C: %#v", b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_GeneratedConversionOverriden(t *testing.T) {
|
||||
type A struct{}
|
||||
type B struct{}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if err := c.RegisterGeneratedConversionFunc(func(in *A, out *B, s Scope) error {
|
||||
return fmt.Errorf("generated function should be overriden")
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
a := A{}
|
||||
b := B{}
|
||||
if err := c.Convert(&a, &b, 0, nil); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_WithConversionOverriden(t *testing.T) {
|
||||
type A struct{}
|
||||
type B struct{}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
|
||||
return fmt.Errorf("conversion function should be overriden")
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if err := c.RegisterGeneratedConversionFunc(func(in *A, out *B, s Scope) error {
|
||||
return fmt.Errorf("generated function should be overriden")
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
ext := NewConversionFuncs()
|
||||
ext.Add(func(in *A, out *B, s Scope) error {
|
||||
return nil
|
||||
})
|
||||
newc := c.WithConversions(ext)
|
||||
|
||||
a := A{}
|
||||
b := B{}
|
||||
if err := c.Convert(&a, &b, 0, nil); err == nil || err.Error() != "conversion function should be overriden" {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if err := newc.Convert(&a, &b, 0, nil); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_MapsStringArrays(t *testing.T) {
|
||||
type A struct {
|
||||
Foo string
|
||||
Baz int
|
||||
Other string
|
||||
}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
if err := c.RegisterConversionFunc(func(input *[]string, out *string, s Scope) error {
|
||||
if len(*input) == 0 {
|
||||
*out = ""
|
||||
}
|
||||
*out = (*input)[0]
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
x := map[string][]string{
|
||||
"Foo": {"bar"},
|
||||
"Baz": {"1"},
|
||||
"Other": {"", "test"},
|
||||
"other": {"wrong"},
|
||||
}
|
||||
y := A{"test", 2, "something"}
|
||||
|
||||
if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames, nil); err == nil {
|
||||
t.Error("unexpected non-error")
|
||||
}
|
||||
|
||||
if err := c.RegisterConversionFunc(func(input *[]string, out *int, s Scope) error {
|
||||
if len(*input) == 0 {
|
||||
*out = 0
|
||||
}
|
||||
str := (*input)[0]
|
||||
i, err := strconv.Atoi(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*out = i
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames, nil); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(y, A{"bar", 1, ""}) {
|
||||
t.Errorf("unexpected result: %#v", y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_MapsStringArraysWithMappingKey(t *testing.T) {
|
||||
type A struct {
|
||||
Foo string `json:"test"`
|
||||
Baz int
|
||||
Other string
|
||||
}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
if err := c.RegisterConversionFunc(func(input *[]string, out *string, s Scope) error {
|
||||
if len(*input) == 0 {
|
||||
*out = ""
|
||||
}
|
||||
*out = (*input)[0]
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
x := map[string][]string{
|
||||
"Foo": {"bar"},
|
||||
"test": {"baz"},
|
||||
}
|
||||
y := A{"", 0, ""}
|
||||
|
||||
if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames|IgnoreMissingFields, &Meta{}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(y, A{"bar", 0, ""}) {
|
||||
t.Errorf("unexpected result: %#v", y)
|
||||
}
|
||||
|
||||
mapping := func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string) {
|
||||
if s := destTag.Get("json"); len(s) > 0 {
|
||||
return strings.SplitN(s, ",", 2)[0], key
|
||||
}
|
||||
return key, key
|
||||
}
|
||||
|
||||
if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames|IgnoreMissingFields, &Meta{KeyNameMapping: mapping}); err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(y, A{"baz", 0, ""}) {
|
||||
t.Errorf("unexpected result: %#v", y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_fuzz(t *testing.T) {
|
||||
// Use the same types from the scheme test.
|
||||
table := []struct {
|
||||
from, to, check interface{}
|
||||
}{
|
||||
{&TestType1{}, &ExternalTestType1{}, &TestType1{}},
|
||||
{&ExternalTestType1{}, &TestType1{}, &ExternalTestType1{}},
|
||||
}
|
||||
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 100)
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.nameFunc = func(t reflect.Type) string {
|
||||
// Hide the fact that we don't have separate packages for these things.
|
||||
return map[reflect.Type]string{
|
||||
reflect.TypeOf(TestType1{}): "TestType1",
|
||||
reflect.TypeOf(ExternalTestType1{}): "TestType1",
|
||||
reflect.TypeOf(TestType2{}): "TestType2",
|
||||
reflect.TypeOf(ExternalTestType2{}): "TestType2",
|
||||
}[t]
|
||||
}
|
||||
c.Debug = testLogger(t)
|
||||
|
||||
for i, item := range table {
|
||||
for j := 0; j < *fuzzIters; j++ {
|
||||
f.Fuzz(item.from)
|
||||
err := c.Convert(item.from, item.to, 0, nil)
|
||||
if err != nil {
|
||||
t.Errorf("(%v, %v): unexpected error: %v", i, j, err)
|
||||
continue
|
||||
}
|
||||
err = c.Convert(item.to, item.check, 0, nil)
|
||||
if err != nil {
|
||||
t.Errorf("(%v, %v): unexpected error: %v", i, j, err)
|
||||
continue
|
||||
}
|
||||
if e, a := item.from, item.check; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("(%v, %v): unexpected diff: %v", i, j, diff.ObjectDiff(e, a))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_MapElemAddr(t *testing.T) {
|
||||
type Foo struct {
|
||||
A map[int]int
|
||||
}
|
||||
type Bar struct {
|
||||
A map[string]string
|
||||
}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
err := c.RegisterConversionFunc(
|
||||
func(in *int, out *string, s Scope) error {
|
||||
*out = fmt.Sprintf("%v", *in)
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
err = c.RegisterConversionFunc(
|
||||
func(in *string, out *int, s Scope) error {
|
||||
if str, err := strconv.Atoi(*in); err != nil {
|
||||
return err
|
||||
} else {
|
||||
*out = str
|
||||
return nil
|
||||
}
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
f := fuzz.New().NilChance(0).NumElements(3, 3)
|
||||
first := Foo{}
|
||||
second := Bar{}
|
||||
f.Fuzz(&first)
|
||||
err = c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
third := Foo{}
|
||||
err = c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil)
|
||||
if e, a := first, third; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected diff: %v", diff.ObjectDiff(e, a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_tags(t *testing.T) {
|
||||
type Foo struct {
|
||||
A string `test:"foo"`
|
||||
}
|
||||
type Bar struct {
|
||||
A string `test:"bar"`
|
||||
}
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
err := c.RegisterConversionFunc(
|
||||
func(in *string, out *string, s Scope) error {
|
||||
if e, a := "foo", s.SrcTag().Get("test"); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "bar", s.DestTag().Get("test"); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
err = c.Convert(&Foo{}, &Bar{}, AllowDifferentFieldTypeNames, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_meta(t *testing.T) {
|
||||
type Foo struct{ A string }
|
||||
type Bar struct{ A string }
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
checks := 0
|
||||
err := c.RegisterConversionFunc(
|
||||
func(in *Foo, out *Bar, s Scope) error {
|
||||
if s.Meta() == nil {
|
||||
t.Errorf("Meta did not get passed!")
|
||||
}
|
||||
checks++
|
||||
s.Convert(&in.A, &out.A, 0)
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
err = c.RegisterConversionFunc(
|
||||
func(in *string, out *string, s Scope) error {
|
||||
if s.Meta() == nil {
|
||||
t.Errorf("Meta did not get passed a second time!")
|
||||
}
|
||||
checks++
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if checks != 2 {
|
||||
t.Errorf("Registered functions did not get called.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_flags(t *testing.T) {
|
||||
type Foo struct{ A string }
|
||||
type Bar struct{ A string }
|
||||
table := []struct {
|
||||
from, to interface{}
|
||||
flags FieldMatchingFlags
|
||||
shouldSucceed bool
|
||||
}{
|
||||
// Check that DestFromSource allows extra fields only in source.
|
||||
{
|
||||
from: &struct{ A string }{},
|
||||
to: &struct{ A, B string }{},
|
||||
flags: DestFromSource,
|
||||
shouldSucceed: false,
|
||||
}, {
|
||||
from: &struct{ A, B string }{},
|
||||
to: &struct{ A string }{},
|
||||
flags: DestFromSource,
|
||||
shouldSucceed: true,
|
||||
},
|
||||
|
||||
// Check that SourceToDest allows for extra fields only in dest.
|
||||
{
|
||||
from: &struct{ A string }{},
|
||||
to: &struct{ A, B string }{},
|
||||
flags: SourceToDest,
|
||||
shouldSucceed: true,
|
||||
}, {
|
||||
from: &struct{ A, B string }{},
|
||||
to: &struct{ A string }{},
|
||||
flags: SourceToDest,
|
||||
shouldSucceed: false,
|
||||
},
|
||||
|
||||
// Check that IgnoreMissingFields makes the above failure cases pass.
|
||||
{
|
||||
from: &struct{ A string }{},
|
||||
to: &struct{ A, B string }{},
|
||||
flags: DestFromSource | IgnoreMissingFields,
|
||||
shouldSucceed: true,
|
||||
}, {
|
||||
from: &struct{ A, B string }{},
|
||||
to: &struct{ A string }{},
|
||||
flags: SourceToDest | IgnoreMissingFields,
|
||||
shouldSucceed: true,
|
||||
},
|
||||
|
||||
// Check that the field type name must match unless
|
||||
// AllowDifferentFieldTypeNames is specified.
|
||||
{
|
||||
from: &struct{ A, B Foo }{},
|
||||
to: &struct{ A Bar }{},
|
||||
flags: DestFromSource,
|
||||
shouldSucceed: false,
|
||||
}, {
|
||||
from: &struct{ A Foo }{},
|
||||
to: &struct{ A, B Bar }{},
|
||||
flags: SourceToDest,
|
||||
shouldSucceed: false,
|
||||
}, {
|
||||
from: &struct{ A, B Foo }{},
|
||||
to: &struct{ A Bar }{},
|
||||
flags: DestFromSource | AllowDifferentFieldTypeNames,
|
||||
shouldSucceed: true,
|
||||
}, {
|
||||
from: &struct{ A Foo }{},
|
||||
to: &struct{ A, B Bar }{},
|
||||
flags: SourceToDest | AllowDifferentFieldTypeNames,
|
||||
shouldSucceed: true,
|
||||
},
|
||||
}
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 100)
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
c.Debug = testLogger(t)
|
||||
|
||||
for i, item := range table {
|
||||
for j := 0; j < *fuzzIters; j++ {
|
||||
f.Fuzz(item.from)
|
||||
err := c.Convert(item.from, item.to, item.flags, nil)
|
||||
if item.shouldSucceed && err != nil {
|
||||
t.Errorf("(%v, %v): unexpected error: %v", i, j, err)
|
||||
continue
|
||||
}
|
||||
if !item.shouldSucceed && err == nil {
|
||||
t.Errorf("(%v, %v): unexpected non-error", i, j)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConverter_FieldRename(t *testing.T) {
|
||||
type WeirdMeta struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
type NameMeta struct {
|
||||
Name string
|
||||
}
|
||||
type TypeMeta struct {
|
||||
Type string
|
||||
}
|
||||
type A struct {
|
||||
WeirdMeta
|
||||
}
|
||||
type B struct {
|
||||
TypeMeta
|
||||
NameMeta
|
||||
}
|
||||
|
||||
c := NewConverter(DefaultNameFunc)
|
||||
err := c.SetStructFieldCopy(WeirdMeta{}, "WeirdMeta", TypeMeta{}, "TypeMeta")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
err = c.SetStructFieldCopy(WeirdMeta{}, "WeirdMeta", NameMeta{}, "NameMeta")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
err = c.SetStructFieldCopy(TypeMeta{}, "TypeMeta", WeirdMeta{}, "WeirdMeta")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
err = c.SetStructFieldCopy(NameMeta{}, "NameMeta", WeirdMeta{}, "WeirdMeta")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
c.Debug = testLogger(t)
|
||||
|
||||
aVal := &A{
|
||||
WeirdMeta: WeirdMeta{
|
||||
Name: "Foo",
|
||||
Type: "Bar",
|
||||
},
|
||||
}
|
||||
|
||||
bVal := &B{
|
||||
TypeMeta: TypeMeta{"Bar"},
|
||||
NameMeta: NameMeta{"Foo"},
|
||||
}
|
||||
|
||||
table := map[string]struct {
|
||||
from, to, expect interface{}
|
||||
flags FieldMatchingFlags
|
||||
}{
|
||||
"to": {
|
||||
aVal,
|
||||
&B{},
|
||||
bVal,
|
||||
AllowDifferentFieldTypeNames | SourceToDest | IgnoreMissingFields,
|
||||
},
|
||||
"from": {
|
||||
bVal,
|
||||
&A{},
|
||||
aVal,
|
||||
AllowDifferentFieldTypeNames | SourceToDest,
|
||||
},
|
||||
"toDestFirst": {
|
||||
aVal,
|
||||
&B{},
|
||||
bVal,
|
||||
AllowDifferentFieldTypeNames,
|
||||
},
|
||||
"fromDestFirst": {
|
||||
bVal,
|
||||
&A{},
|
||||
aVal,
|
||||
AllowDifferentFieldTypeNames | IgnoreMissingFields,
|
||||
},
|
||||
}
|
||||
|
||||
for name, item := range table {
|
||||
err := c.Convert(item.from, item.to, item.flags, nil)
|
||||
if err != nil {
|
||||
t.Errorf("%v: unexpected error: %v", name, err)
|
||||
continue
|
||||
}
|
||||
if e, a := item.expect, item.to; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%v: unexpected diff: %v", name, diff.ObjectDiff(e, a))
|
||||
}
|
||||
}
|
||||
}
|
||||
161
vendor/k8s.io/apimachinery/pkg/conversion/deep_copy_test.go
generated
vendored
Normal file
161
vendor/k8s.io/apimachinery/pkg/conversion/deep_copy_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
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 conversion
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
func TestDeepCopy(t *testing.T) {
|
||||
semantic := EqualitiesOrDie()
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 100)
|
||||
table := []interface{}{
|
||||
map[string]string{},
|
||||
int(5),
|
||||
"hello world",
|
||||
struct {
|
||||
A, B, C struct {
|
||||
D map[string]int
|
||||
}
|
||||
X []int
|
||||
Y []byte
|
||||
}{},
|
||||
}
|
||||
for _, obj := range table {
|
||||
obj2, err := NewCloner().DeepCopy(obj)
|
||||
if err != nil {
|
||||
t.Errorf("Error: couldn't copy %#v", obj)
|
||||
continue
|
||||
}
|
||||
if e, a := obj, obj2; !semantic.DeepEqual(e, a) {
|
||||
t.Errorf("expected %#v\ngot %#v", e, a)
|
||||
}
|
||||
|
||||
obj3 := reflect.New(reflect.TypeOf(obj)).Interface()
|
||||
f.Fuzz(obj3)
|
||||
obj4, err := NewCloner().DeepCopy(obj3)
|
||||
if err != nil {
|
||||
t.Errorf("Error: couldn't copy %#v", obj)
|
||||
continue
|
||||
}
|
||||
if e, a := obj3, obj4; !semantic.DeepEqual(e, a) {
|
||||
t.Errorf("expected %#v\ngot %#v", e, a)
|
||||
}
|
||||
f.Fuzz(obj3)
|
||||
}
|
||||
}
|
||||
|
||||
func copyOrDie(t *testing.T, in interface{}) interface{} {
|
||||
out, err := NewCloner().DeepCopy(in)
|
||||
if err != nil {
|
||||
t.Fatalf("DeepCopy failed: %#q: %v", in, err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestDeepCopySliceSeparate(t *testing.T) {
|
||||
x := []int{5}
|
||||
y := copyOrDie(t, x).([]int)
|
||||
x[0] = 3
|
||||
if y[0] == 3 {
|
||||
t.Errorf("deep copy wasn't deep: %#q %#q", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepCopyArraySeparate(t *testing.T) {
|
||||
x := [1]int{5}
|
||||
y := copyOrDie(t, x).([1]int)
|
||||
x[0] = 3
|
||||
if y[0] == 3 {
|
||||
t.Errorf("deep copy wasn't deep: %#q %#q", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepCopyMapSeparate(t *testing.T) {
|
||||
x := map[string]int{"foo": 5}
|
||||
y := copyOrDie(t, x).(map[string]int)
|
||||
x["foo"] = 3
|
||||
if y["foo"] == 3 {
|
||||
t.Errorf("deep copy wasn't deep: %#q %#q", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepCopyPointerSeparate(t *testing.T) {
|
||||
z := 5
|
||||
x := &z
|
||||
y := copyOrDie(t, x).(*int)
|
||||
*x = 3
|
||||
if *y == 3 {
|
||||
t.Errorf("deep copy wasn't deep: %#q %#q", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepCopyStruct(t *testing.T) {
|
||||
type Foo struct {
|
||||
A int
|
||||
}
|
||||
type Bar struct {
|
||||
Foo
|
||||
F *Foo
|
||||
}
|
||||
a := &Bar{Foo{1}, &Foo{2}}
|
||||
b := copyOrDie(t, a).(*Bar)
|
||||
a.A = 3
|
||||
a.F.A = 4
|
||||
|
||||
if b.A != 1 || b.F.A != 2 {
|
||||
t.Errorf("deep copy wasn't deep: %#v, %#v", a, b)
|
||||
}
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
|
||||
func BenchmarkDeepCopy(b *testing.B) {
|
||||
table := []interface{}{
|
||||
map[string]string{},
|
||||
int(5),
|
||||
"hello world",
|
||||
struct {
|
||||
A, B, C struct {
|
||||
D map[string]int
|
||||
}
|
||||
X []int
|
||||
Y []byte
|
||||
}{},
|
||||
}
|
||||
|
||||
f := fuzz.New().RandSource(rand.NewSource(1)).NilChance(.5).NumElements(0, 100)
|
||||
for i := range table {
|
||||
out := table[i]
|
||||
obj := reflect.New(reflect.TypeOf(out)).Interface()
|
||||
f.Fuzz(obj)
|
||||
table[i] = obj
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
var r interface{}
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := range table {
|
||||
r, _ = NewCloner().DeepCopy(table[j])
|
||||
}
|
||||
}
|
||||
result = r
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/conversion/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/conversion/doc.go
generated
vendored
|
|
@ -21,4 +21,4 @@ limitations under the License.
|
|||
// but for the fields which did not change, copying is automated. This makes it
|
||||
// easy to modify the structures you use in memory without affecting the format
|
||||
// you store on disk or respond to in your external API calls.
|
||||
package conversion
|
||||
package conversion // import "k8s.io/apimachinery/pkg/conversion"
|
||||
|
|
|
|||
38
vendor/k8s.io/apimachinery/pkg/conversion/helper_test.go
generated
vendored
Normal file
38
vendor/k8s.io/apimachinery/pkg/conversion/helper_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
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 conversion
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestInvalidPtrValueKind(t *testing.T) {
|
||||
var simple interface{}
|
||||
switch obj := simple.(type) {
|
||||
default:
|
||||
_, err := EnforcePtr(obj)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error on invalid kind")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnforceNilPtr(t *testing.T) {
|
||||
var nilPtr *struct{}
|
||||
_, err := EnforcePtr(nilPtr)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error on nil pointer")
|
||||
}
|
||||
}
|
||||
212
vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert_test.go
generated
vendored
Normal file
212
vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
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 queryparams_test
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/conversion/queryparams"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type namedString string
|
||||
type namedBool bool
|
||||
|
||||
type bar struct {
|
||||
Float1 float32 `json:"float1"`
|
||||
Float2 float64 `json:"float2"`
|
||||
Int1 int64 `json:"int1,omitempty"`
|
||||
Int2 int32 `json:"int2,omitempty"`
|
||||
Int3 int16 `json:"int3,omitempty"`
|
||||
Str1 string `json:"str1,omitempty"`
|
||||
Ignored int
|
||||
Ignored2 string
|
||||
}
|
||||
|
||||
func (obj *bar) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
|
||||
type foo struct {
|
||||
Str string `json:"str"`
|
||||
Integer int `json:"integer,omitempty"`
|
||||
Slice []string `json:"slice,omitempty"`
|
||||
Boolean bool `json:"boolean,omitempty"`
|
||||
NamedStr namedString `json:"namedStr,omitempty"`
|
||||
NamedBool namedBool `json:"namedBool,omitempty"`
|
||||
Foobar bar `json:"foobar,omitempty"`
|
||||
Testmap map[string]string `json:"testmap,omitempty"`
|
||||
}
|
||||
|
||||
func (obj *foo) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
|
||||
type baz struct {
|
||||
Ptr *int `json:"ptr"`
|
||||
Bptr *bool `json:"bptr,omitempty"`
|
||||
}
|
||||
|
||||
func (obj *baz) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
|
||||
// childStructs tests some of the types we serialize to query params for log API calls
|
||||
// notably, the nested time struct
|
||||
type childStructs struct {
|
||||
Container string `json:"container,omitempty"`
|
||||
Follow bool `json:"follow,omitempty"`
|
||||
Previous bool `json:"previous,omitempty"`
|
||||
SinceSeconds *int64 `json:"sinceSeconds,omitempty"`
|
||||
SinceTime *metav1.Time `json:"sinceTime,omitempty"`
|
||||
EmptyTime *metav1.Time `json:"emptyTime"`
|
||||
}
|
||||
|
||||
func (obj *childStructs) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
|
||||
func validateResult(t *testing.T, input interface{}, actual, expected url.Values) {
|
||||
local := url.Values{}
|
||||
for k, v := range expected {
|
||||
local[k] = v
|
||||
}
|
||||
for k, v := range actual {
|
||||
if ev, ok := local[k]; !ok || !reflect.DeepEqual(ev, v) {
|
||||
if !ok {
|
||||
t.Errorf("%#v: actual value key %s not found in expected map", input, k)
|
||||
} else {
|
||||
t.Errorf("%#v: values don't match: actual: %#v, expected: %#v", input, v, ev)
|
||||
}
|
||||
}
|
||||
delete(local, k)
|
||||
}
|
||||
if len(local) > 0 {
|
||||
t.Errorf("%#v: expected map has keys that were not found in actual map: %#v", input, local)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
sinceSeconds := int64(123)
|
||||
sinceTime := metav1.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC)
|
||||
|
||||
tests := []struct {
|
||||
input interface{}
|
||||
expected url.Values
|
||||
}{
|
||||
{
|
||||
input: &foo{
|
||||
Str: "hello",
|
||||
},
|
||||
expected: url.Values{"str": {"hello"}},
|
||||
},
|
||||
{
|
||||
input: &foo{
|
||||
Str: "test string",
|
||||
Slice: []string{"one", "two", "three"},
|
||||
Integer: 234,
|
||||
Boolean: true,
|
||||
},
|
||||
expected: url.Values{"str": {"test string"}, "slice": {"one", "two", "three"}, "integer": {"234"}, "boolean": {"true"}},
|
||||
},
|
||||
{
|
||||
input: &foo{
|
||||
Str: "named types",
|
||||
NamedStr: "value1",
|
||||
NamedBool: true,
|
||||
},
|
||||
expected: url.Values{"str": {"named types"}, "namedStr": {"value1"}, "namedBool": {"true"}},
|
||||
},
|
||||
{
|
||||
input: &foo{
|
||||
Str: "don't ignore embedded struct",
|
||||
Foobar: bar{
|
||||
Float1: 5.0,
|
||||
},
|
||||
},
|
||||
expected: url.Values{"str": {"don't ignore embedded struct"}, "float1": {"5"}, "float2": {"0"}},
|
||||
},
|
||||
{
|
||||
// Ignore untagged fields
|
||||
input: &bar{
|
||||
Float1: 23.5,
|
||||
Float2: 100.7,
|
||||
Int1: 1,
|
||||
Int2: 2,
|
||||
Int3: 3,
|
||||
Ignored: 1,
|
||||
Ignored2: "ignored",
|
||||
},
|
||||
expected: url.Values{"float1": {"23.5"}, "float2": {"100.7"}, "int1": {"1"}, "int2": {"2"}, "int3": {"3"}},
|
||||
},
|
||||
{
|
||||
// include fields that are not tagged omitempty
|
||||
input: &foo{
|
||||
NamedStr: "named str",
|
||||
},
|
||||
expected: url.Values{"str": {""}, "namedStr": {"named str"}},
|
||||
},
|
||||
{
|
||||
input: &baz{
|
||||
Ptr: intp(5),
|
||||
Bptr: boolp(true),
|
||||
},
|
||||
expected: url.Values{"ptr": {"5"}, "bptr": {"true"}},
|
||||
},
|
||||
{
|
||||
input: &baz{
|
||||
Bptr: boolp(true),
|
||||
},
|
||||
expected: url.Values{"ptr": {""}, "bptr": {"true"}},
|
||||
},
|
||||
{
|
||||
input: &baz{
|
||||
Ptr: intp(5),
|
||||
},
|
||||
expected: url.Values{"ptr": {"5"}},
|
||||
},
|
||||
{
|
||||
input: &childStructs{
|
||||
Container: "mycontainer",
|
||||
Follow: true,
|
||||
Previous: true,
|
||||
SinceSeconds: &sinceSeconds,
|
||||
SinceTime: &sinceTime, // test a custom marshaller
|
||||
EmptyTime: nil, // test a nil custom marshaller without omitempty
|
||||
},
|
||||
expected: url.Values{"container": {"mycontainer"}, "follow": {"true"}, "previous": {"true"}, "sinceSeconds": {"123"}, "sinceTime": {"2000-01-01T12:34:56Z"}, "emptyTime": {""}},
|
||||
},
|
||||
{
|
||||
input: &childStructs{
|
||||
Container: "mycontainer",
|
||||
Follow: true,
|
||||
Previous: true,
|
||||
SinceSeconds: &sinceSeconds,
|
||||
SinceTime: nil, // test a nil custom marshaller with omitempty
|
||||
},
|
||||
expected: url.Values{"container": {"mycontainer"}, "follow": {"true"}, "previous": {"true"}, "sinceSeconds": {"123"}, "emptyTime": {""}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
result, err := queryparams.Convert(test.input)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error while converting %#v: %v", test.input, err)
|
||||
}
|
||||
validateResult(t, test.input, result, test.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func intp(n int) *int { return &n }
|
||||
|
||||
func boolp(b bool) *bool { return &b }
|
||||
2
vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/conversion/queryparams/doc.go
generated
vendored
|
|
@ -16,4 +16,4 @@ limitations under the License.
|
|||
|
||||
// Package queryparams provides conversion from versioned
|
||||
// runtime objects to URL query values
|
||||
package queryparams
|
||||
package queryparams // import "k8s.io/apimachinery/pkg/conversion/queryparams"
|
||||
|
|
|
|||
2
vendor/k8s.io/apimachinery/pkg/conversion/unstructured/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/conversion/unstructured/doc.go
generated
vendored
|
|
@ -16,4 +16,4 @@ limitations under the License.
|
|||
|
||||
// Package unstructured provides conversion from runtime objects
|
||||
// to map[string]interface{} representation.
|
||||
package unstructured
|
||||
package unstructured // import "k8s.io/apimachinery/pkg/conversion/unstructured"
|
||||
|
|
|
|||
28
vendor/k8s.io/apimachinery/pkg/conversion/unstructured/testing/BUILD
generated
vendored
Normal file
28
vendor/k8s.io/apimachinery/pkg/conversion/unstructured/testing/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["converter_test.go"],
|
||||
deps = [
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/require:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
539
vendor/k8s.io/apimachinery/pkg/conversion/unstructured/testing/converter_test.go
generated
vendored
Normal file
539
vendor/k8s.io/apimachinery/pkg/conversion/unstructured/testing/converter_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// These tests are in a separate package to break cyclic dependency in tests.
|
||||
// Unstructured type depends on unstructured converter package but we want to test how the converter handles
|
||||
// the Unstructured type so we need to import both.
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
conversionunstructured "k8s.io/apimachinery/pkg/conversion/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Definte a number of test types.
|
||||
type A struct {
|
||||
A int `json:"aa,omitempty"`
|
||||
B string `json:"ab,omitempty"`
|
||||
C bool `json:"ac,omitempty"`
|
||||
}
|
||||
|
||||
type B struct {
|
||||
A A `json:"ba"`
|
||||
B string `json:"bb"`
|
||||
C map[string]string `json:"bc"`
|
||||
D []string `json:"bd"`
|
||||
}
|
||||
|
||||
type C struct {
|
||||
A []A `json:"ca"`
|
||||
B `json:",inline"`
|
||||
C string `json:"cc"`
|
||||
D *int64 `json:"cd"`
|
||||
E map[string]int `json:"ce"`
|
||||
F []bool `json:"cf"`
|
||||
G []int `json:"cg"`
|
||||
H float32 `json:"ch"`
|
||||
I []interface{} `json:"ci"`
|
||||
}
|
||||
|
||||
type D struct {
|
||||
A []interface{} `json:"da"`
|
||||
}
|
||||
|
||||
type E struct {
|
||||
A interface{} `json:"ea"`
|
||||
}
|
||||
|
||||
type F struct {
|
||||
A string `json:"fa"`
|
||||
B map[string]string `json:"fb"`
|
||||
C []A `json:"fc"`
|
||||
D int `json:"fd"`
|
||||
E float32 `json:"fe"`
|
||||
F []string `json:"ff"`
|
||||
G []int `json:"fg"`
|
||||
H []bool `json:"fh"`
|
||||
I []float32 `json:"fi"`
|
||||
}
|
||||
|
||||
type G struct {
|
||||
CustomValue1 CustomValue `json:"customValue1"`
|
||||
CustomValue2 *CustomValue `json:"customValue2"`
|
||||
CustomPointer1 CustomPointer `json:"customPointer1"`
|
||||
CustomPointer2 *CustomPointer `json:"customPointer2"`
|
||||
}
|
||||
|
||||
type CustomValue struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// MarshalJSON has a value receiver on this type.
|
||||
func (c CustomValue) MarshalJSON() ([]byte, error) {
|
||||
return c.data, nil
|
||||
}
|
||||
|
||||
type CustomPointer struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// MarshalJSON has a pointer receiver on this type.
|
||||
func (c *CustomPointer) MarshalJSON() ([]byte, error) {
|
||||
return c.data, nil
|
||||
}
|
||||
|
||||
func doRoundTrip(t *testing.T, item interface{}) {
|
||||
data, err := json.Marshal(item)
|
||||
if err != nil {
|
||||
t.Errorf("Error when marshaling object: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
unstr := make(map[string]interface{})
|
||||
err = json.Unmarshal(data, &unstr)
|
||||
if err != nil {
|
||||
t.Errorf("Error when unmarshaling to unstructured: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
data, err = json.Marshal(unstr)
|
||||
if err != nil {
|
||||
t.Errorf("Error when marshaling unstructured: %v", err)
|
||||
return
|
||||
}
|
||||
unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
|
||||
err = json.Unmarshal(data, &unmarshalledObj)
|
||||
if err != nil {
|
||||
t.Errorf("Error when unmarshaling to object: %v", err)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(item, unmarshalledObj) {
|
||||
t.Errorf("Object changed during JSON operations, diff: %v", diff.ObjectReflectDiff(item, unmarshalledObj))
|
||||
return
|
||||
}
|
||||
|
||||
newUnstr, err := conversionunstructured.DefaultConverter.ToUnstructured(item)
|
||||
if err != nil {
|
||||
t.Errorf("ToUnstructured failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
|
||||
err = conversionunstructured.DefaultConverter.FromUnstructured(newUnstr, newObj)
|
||||
if err != nil {
|
||||
t.Errorf("FromUnstructured failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(item, newObj) {
|
||||
t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(item, newObj))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
intVal := int64(42)
|
||||
testCases := []struct {
|
||||
obj interface{}
|
||||
}{
|
||||
{
|
||||
obj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Foo",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// This (among others) tests nil map, slice and pointer.
|
||||
obj: &C{
|
||||
C: "ccc",
|
||||
},
|
||||
},
|
||||
{
|
||||
// This (among others) tests empty map and slice.
|
||||
obj: &C{
|
||||
A: []A{},
|
||||
C: "ccc",
|
||||
E: map[string]int{},
|
||||
I: []interface{}{},
|
||||
},
|
||||
},
|
||||
{
|
||||
obj: &C{
|
||||
A: []A{
|
||||
{
|
||||
A: 1,
|
||||
B: "11",
|
||||
C: true,
|
||||
},
|
||||
{
|
||||
A: 2,
|
||||
B: "22",
|
||||
C: false,
|
||||
},
|
||||
},
|
||||
B: B{
|
||||
A: A{
|
||||
A: 3,
|
||||
B: "33",
|
||||
},
|
||||
B: "bbb",
|
||||
C: map[string]string{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
},
|
||||
D: []string{"s1", "s2"},
|
||||
},
|
||||
C: "ccc",
|
||||
D: &intVal,
|
||||
E: map[string]int{
|
||||
"k1": 1,
|
||||
"k2": 2,
|
||||
},
|
||||
F: []bool{true, false, false},
|
||||
G: []int{1, 2, 5},
|
||||
H: 3.3,
|
||||
I: []interface{}{nil, nil, nil},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Test slice of interface{} with empty slices.
|
||||
obj: &D{
|
||||
A: []interface{}{[]interface{}{}, []interface{}{}},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Test slice of interface{} with different values.
|
||||
obj: &D{
|
||||
A: []interface{}{3.0, "3.0", nil},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
doRoundTrip(t, testCases[i].obj)
|
||||
if t.Failed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that:
|
||||
// 1) serialized json -> object
|
||||
// 2) serialized json -> map[string]interface{} -> object
|
||||
// produces the same object.
|
||||
func doUnrecognized(t *testing.T, jsonData string, item interface{}, expectedErr error) {
|
||||
unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
|
||||
err := json.Unmarshal([]byte(jsonData), &unmarshalledObj)
|
||||
if (err != nil) != (expectedErr != nil) {
|
||||
t.Errorf("Unexpected error when unmarshaling to object: %v, expected: %v", err, expectedErr)
|
||||
return
|
||||
}
|
||||
|
||||
unstr := make(map[string]interface{})
|
||||
err = json.Unmarshal([]byte(jsonData), &unstr)
|
||||
if err != nil {
|
||||
t.Errorf("Error when unmarshaling to unstructured: %v", err)
|
||||
return
|
||||
}
|
||||
newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface()
|
||||
err = conversionunstructured.DefaultConverter.FromUnstructured(unstr, newObj)
|
||||
if (err != nil) != (expectedErr != nil) {
|
||||
t.Errorf("Unexpected error in FromUnstructured: %v, expected: %v", err, expectedErr)
|
||||
}
|
||||
|
||||
if expectedErr == nil && !reflect.DeepEqual(unmarshalledObj, newObj) {
|
||||
t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(unmarshalledObj, newObj))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnrecognized(t *testing.T) {
|
||||
testCases := []struct {
|
||||
data string
|
||||
obj interface{}
|
||||
err error
|
||||
}{
|
||||
{
|
||||
data: "{\"da\":[3.0,\"3.0\",null]}",
|
||||
obj: &D{},
|
||||
},
|
||||
{
|
||||
data: "{\"ea\":[3.0,\"3.0\",null]}",
|
||||
obj: &E{},
|
||||
},
|
||||
{
|
||||
data: "{\"ea\":[null,null,null]}",
|
||||
obj: &E{},
|
||||
},
|
||||
{
|
||||
data: "{\"ea\":[[],[null]]}",
|
||||
obj: &E{},
|
||||
},
|
||||
{
|
||||
data: "{\"ea\":{\"a\":[],\"b\":null}}",
|
||||
obj: &E{},
|
||||
},
|
||||
{
|
||||
data: "{\"fa\":\"fa\",\"fb\":{\"a\":\"a\"}}",
|
||||
obj: &F{},
|
||||
},
|
||||
{
|
||||
data: "{\"fa\":\"fa\",\"fb\":{\"a\":null}}",
|
||||
obj: &F{},
|
||||
},
|
||||
{
|
||||
data: "{\"fc\":[null]}",
|
||||
obj: &F{},
|
||||
},
|
||||
{
|
||||
data: "{\"fc\":[{\"aa\":123,\"ab\":\"bbb\"}]}",
|
||||
obj: &F{},
|
||||
},
|
||||
{
|
||||
// Only unknown fields
|
||||
data: "{\"fx\":[{\"aa\":123,\"ab\":\"bbb\"}],\"fz\":123}",
|
||||
obj: &F{},
|
||||
},
|
||||
{
|
||||
data: "{\"fc\":[{\"aa\":\"aaa\",\"ab\":\"bbb\"}]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal string into Go value of type int"),
|
||||
},
|
||||
{
|
||||
data: "{\"fd\":123,\"fe\":3.5}",
|
||||
obj: &F{},
|
||||
},
|
||||
{
|
||||
data: "{\"ff\":[\"abc\"],\"fg\":[123],\"fh\":[true,false]}",
|
||||
obj: &F{},
|
||||
},
|
||||
{
|
||||
// Invalid string data
|
||||
data: "{\"fa\":123}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"),
|
||||
},
|
||||
{
|
||||
// Invalid string data
|
||||
data: "{\"fa\":13.5}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"),
|
||||
},
|
||||
{
|
||||
// Invalid string data
|
||||
data: "{\"fa\":true}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal bool into Go value of type string"),
|
||||
},
|
||||
{
|
||||
// Invalid []string data
|
||||
data: "{\"ff\":123}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []string"),
|
||||
},
|
||||
{
|
||||
// Invalid []string data
|
||||
data: "{\"ff\":3.5}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []string"),
|
||||
},
|
||||
{
|
||||
// Invalid []string data
|
||||
data: "{\"ff\":[123,345]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"),
|
||||
},
|
||||
{
|
||||
// Invalid []int data
|
||||
data: "{\"fg\":123}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []int"),
|
||||
},
|
||||
{
|
||||
// Invalid []int data
|
||||
data: "{\"fg\":\"abc\"}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal string into Go value of type []int"),
|
||||
},
|
||||
{
|
||||
// Invalid []int data
|
||||
data: "{\"fg\":[\"abc\"]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal string into Go value of type int"),
|
||||
},
|
||||
{
|
||||
// Invalid []int data
|
||||
data: "{\"fg\":[3.5]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number 3.5 into Go value of type int"),
|
||||
},
|
||||
{
|
||||
// Invalid []int data
|
||||
data: "{\"fg\":[true,false]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number 3.5 into Go value of type int"),
|
||||
},
|
||||
{
|
||||
// Invalid []bool data
|
||||
data: "{\"fh\":123}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []bool"),
|
||||
},
|
||||
{
|
||||
// Invalid []bool data
|
||||
data: "{\"fh\":\"abc\"}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal string into Go value of type []bool"),
|
||||
},
|
||||
{
|
||||
// Invalid []bool data
|
||||
data: "{\"fh\":[\"abc\"]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal string into Go value of type bool"),
|
||||
},
|
||||
{
|
||||
// Invalid []bool data
|
||||
data: "{\"fh\":[3.5]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type bool"),
|
||||
},
|
||||
{
|
||||
// Invalid []bool data
|
||||
data: "{\"fh\":[123]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type bool"),
|
||||
},
|
||||
{
|
||||
// Invalid []float data
|
||||
data: "{\"fi\":123}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal number into Go value of type []float32"),
|
||||
},
|
||||
{
|
||||
// Invalid []float data
|
||||
data: "{\"fi\":\"abc\"}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal string into Go value of type []float32"),
|
||||
},
|
||||
{
|
||||
// Invalid []float data
|
||||
data: "{\"fi\":[\"abc\"]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal string into Go value of type float32"),
|
||||
},
|
||||
{
|
||||
// Invalid []float data
|
||||
data: "{\"fi\":[true]}",
|
||||
obj: &F{},
|
||||
err: fmt.Errorf("json: cannot unmarshal bool into Go value of type float32"),
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testCases {
|
||||
doUnrecognized(t, testCases[i].data, testCases[i].obj, testCases[i].err)
|
||||
if t.Failed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloatIntConversion(t *testing.T) {
|
||||
unstr := map[string]interface{}{"fd": float64(3)}
|
||||
|
||||
var obj F
|
||||
if err := conversionunstructured.DefaultConverter.FromUnstructured(unstr, &obj); err != nil {
|
||||
t.Errorf("Unexpected error in FromUnstructured: %v", err)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(unstr)
|
||||
if err != nil {
|
||||
t.Fatalf("Error when marshaling unstructured: %v", err)
|
||||
}
|
||||
var unmarshalled F
|
||||
if err := json.Unmarshal(data, &unmarshalled); err != nil {
|
||||
t.Fatalf("Error when unmarshaling to object: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(obj, unmarshalled) {
|
||||
t.Errorf("Incorrect conversion, diff: %v", diff.ObjectReflectDiff(obj, unmarshalled))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomToUnstructured(t *testing.T) {
|
||||
testcases := []struct {
|
||||
Data string
|
||||
Expected interface{}
|
||||
}{
|
||||
{Data: `null`, Expected: nil},
|
||||
{Data: `true`, Expected: true},
|
||||
{Data: `false`, Expected: false},
|
||||
{Data: `[]`, Expected: []interface{}{}},
|
||||
{Data: `[1]`, Expected: []interface{}{int64(1)}},
|
||||
{Data: `{}`, Expected: map[string]interface{}{}},
|
||||
{Data: `{"a":1}`, Expected: map[string]interface{}{"a": int64(1)}},
|
||||
{Data: `0`, Expected: int64(0)},
|
||||
{Data: `0.0`, Expected: float64(0)},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
tc := tc
|
||||
t.Run(tc.Data, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result, err := conversionunstructured.DefaultConverter.ToUnstructured(&G{
|
||||
CustomValue1: CustomValue{data: []byte(tc.Data)},
|
||||
CustomValue2: &CustomValue{data: []byte(tc.Data)},
|
||||
CustomPointer1: CustomPointer{data: []byte(tc.Data)},
|
||||
CustomPointer2: &CustomPointer{data: []byte(tc.Data)},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
for field, fieldResult := range result {
|
||||
assert.Equal(t, tc.Expected, fieldResult, field)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomToUnstructuredTopLevel(t *testing.T) {
|
||||
// Only objects are supported at the top level
|
||||
topLevelCases := []interface{}{
|
||||
&CustomValue{data: []byte(`{"a":1}`)},
|
||||
&CustomPointer{data: []byte(`{"a":1}`)},
|
||||
}
|
||||
expected := map[string]interface{}{"a": int64(1)}
|
||||
for i, obj := range topLevelCases {
|
||||
obj := obj
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
result, err := conversionunstructured.DefaultConverter.ToUnstructured(obj)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/fields/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/fields/doc.go
generated
vendored
|
|
@ -16,4 +16,4 @@ limitations under the License.
|
|||
|
||||
// Package fields implements a simple field system, parsing and matching
|
||||
// selectors with sets of fields.
|
||||
package fields
|
||||
package fields // import "k8s.io/apimachinery/pkg/fields"
|
||||
|
|
|
|||
57
vendor/k8s.io/apimachinery/pkg/fields/fields_test.go
generated
vendored
Normal file
57
vendor/k8s.io/apimachinery/pkg/fields/fields_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
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 fields
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func matches(t *testing.T, ls Set, want string) {
|
||||
if ls.String() != want {
|
||||
t.Errorf("Expected '%s', but got '%s'", want, ls.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetString(t *testing.T) {
|
||||
matches(t, Set{"x": "y"}, "x=y")
|
||||
matches(t, Set{"foo": "bar"}, "foo=bar")
|
||||
matches(t, Set{"foo": "bar", "baz": "qup"}, "baz=qup,foo=bar")
|
||||
}
|
||||
|
||||
func TestFieldHas(t *testing.T) {
|
||||
fieldHasTests := []struct {
|
||||
Ls Fields
|
||||
Key string
|
||||
Has bool
|
||||
}{
|
||||
{Set{"x": "y"}, "x", true},
|
||||
{Set{"x": ""}, "x", true},
|
||||
{Set{"x": "y"}, "foo", false},
|
||||
}
|
||||
for _, lh := range fieldHasTests {
|
||||
if has := lh.Ls.Has(lh.Key); has != lh.Has {
|
||||
t.Errorf("%#v.Has(%#v) => %v, expected %v", lh.Ls, lh.Key, has, lh.Has)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldGet(t *testing.T) {
|
||||
ls := Set{"x": "y"}
|
||||
if ls.Get("x") != "y" {
|
||||
t.Errorf("Set.Get is broken")
|
||||
}
|
||||
}
|
||||
397
vendor/k8s.io/apimachinery/pkg/fields/selector_test.go
generated
vendored
Normal file
397
vendor/k8s.io/apimachinery/pkg/fields/selector_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
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 fields
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSplitTerms(t *testing.T) {
|
||||
testcases := map[string][]string{
|
||||
// Simple selectors
|
||||
`a`: {`a`},
|
||||
`a=avalue`: {`a=avalue`},
|
||||
`a=avalue,b=bvalue`: {`a=avalue`, `b=bvalue`},
|
||||
`a=avalue,b==bvalue,c!=cvalue`: {`a=avalue`, `b==bvalue`, `c!=cvalue`},
|
||||
|
||||
// Empty terms
|
||||
``: nil,
|
||||
`a=a,`: {`a=a`, ``},
|
||||
`,a=a`: {``, `a=a`},
|
||||
|
||||
// Escaped values
|
||||
`k=\,,k2=v2`: {`k=\,`, `k2=v2`}, // escaped comma in value
|
||||
`k=\\,k2=v2`: {`k=\\`, `k2=v2`}, // escaped backslash, unescaped comma
|
||||
`k=\\\,,k2=v2`: {`k=\\\,`, `k2=v2`}, // escaped backslash and comma
|
||||
`k=\a\b\`: {`k=\a\b\`}, // non-escape sequences
|
||||
`k=\`: {`k=\`}, // orphan backslash
|
||||
|
||||
// Multi-byte
|
||||
`함=수,목=록`: {`함=수`, `목=록`},
|
||||
}
|
||||
|
||||
for selector, expectedTerms := range testcases {
|
||||
if terms := splitTerms(selector); !reflect.DeepEqual(terms, expectedTerms) {
|
||||
t.Errorf("splitSelectors(`%s`): Expected\n%#v\ngot\n%#v", selector, expectedTerms, terms)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitTerm(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
lhs string
|
||||
op string
|
||||
rhs string
|
||||
ok bool
|
||||
}{
|
||||
// Simple terms
|
||||
`a=value`: {lhs: `a`, op: `=`, rhs: `value`, ok: true},
|
||||
`b==value`: {lhs: `b`, op: `==`, rhs: `value`, ok: true},
|
||||
`c!=value`: {lhs: `c`, op: `!=`, rhs: `value`, ok: true},
|
||||
|
||||
// Empty or invalid terms
|
||||
``: {lhs: ``, op: ``, rhs: ``, ok: false},
|
||||
`a`: {lhs: ``, op: ``, rhs: ``, ok: false},
|
||||
|
||||
// Escaped values
|
||||
`k=\,`: {lhs: `k`, op: `=`, rhs: `\,`, ok: true},
|
||||
`k=\=`: {lhs: `k`, op: `=`, rhs: `\=`, ok: true},
|
||||
`k=\\\a\b\=\,\`: {lhs: `k`, op: `=`, rhs: `\\\a\b\=\,\`, ok: true},
|
||||
|
||||
// Multi-byte
|
||||
`함=수`: {lhs: `함`, op: `=`, rhs: `수`, ok: true},
|
||||
}
|
||||
|
||||
for term, expected := range testcases {
|
||||
lhs, op, rhs, ok := splitTerm(term)
|
||||
if lhs != expected.lhs || op != expected.op || rhs != expected.rhs || ok != expected.ok {
|
||||
t.Errorf(
|
||||
"splitTerm(`%s`): Expected\n%s,%s,%s,%v\nGot\n%s,%s,%s,%v",
|
||||
term,
|
||||
expected.lhs, expected.op, expected.rhs, expected.ok,
|
||||
lhs, op, rhs, ok,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEscapeValue(t *testing.T) {
|
||||
// map values to their normalized escaped values
|
||||
testcases := map[string]string{
|
||||
``: ``,
|
||||
`a`: `a`,
|
||||
`=`: `\=`,
|
||||
`,`: `\,`,
|
||||
`\`: `\\`,
|
||||
`\=\,\`: `\\\=\\\,\\`,
|
||||
}
|
||||
|
||||
for unescapedValue, escapedValue := range testcases {
|
||||
actualEscaped := EscapeValue(unescapedValue)
|
||||
if actualEscaped != escapedValue {
|
||||
t.Errorf("EscapeValue(%s): expected %s, got %s", unescapedValue, escapedValue, actualEscaped)
|
||||
}
|
||||
|
||||
actualUnescaped, err := UnescapeValue(escapedValue)
|
||||
if err != nil {
|
||||
t.Errorf("UnescapeValue(%s): unexpected error %v", escapedValue, err)
|
||||
}
|
||||
if actualUnescaped != unescapedValue {
|
||||
t.Errorf("UnescapeValue(%s): expected %s, got %s", escapedValue, unescapedValue, actualUnescaped)
|
||||
}
|
||||
}
|
||||
|
||||
// test invalid escape sequences
|
||||
invalidTestcases := []string{
|
||||
`\`, // orphan slash is invalid
|
||||
`\\\`, // orphan slash is invalid
|
||||
`\a`, // unrecognized escape sequence is invalid
|
||||
}
|
||||
for _, invalidValue := range invalidTestcases {
|
||||
_, err := UnescapeValue(invalidValue)
|
||||
if _, ok := err.(InvalidEscapeSequence); !ok || err == nil {
|
||||
t.Errorf("UnescapeValue(%s): expected invalid escape sequence error, got %#v", invalidValue, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectorParse(t *testing.T) {
|
||||
testGoodStrings := []string{
|
||||
"x=a,y=b,z=c",
|
||||
"",
|
||||
"x!=a,y=b",
|
||||
`x=a||y\=b`,
|
||||
`x=a\=\=b`,
|
||||
}
|
||||
testBadStrings := []string{
|
||||
"x=a||y=b",
|
||||
"x==a==b",
|
||||
"x=a,b",
|
||||
"x in (a)",
|
||||
"x in (a,b,c)",
|
||||
"x",
|
||||
}
|
||||
for _, test := range testGoodStrings {
|
||||
lq, err := ParseSelector(test)
|
||||
if err != nil {
|
||||
t.Errorf("%v: error %v (%#v)\n", test, err, err)
|
||||
}
|
||||
if test != lq.String() {
|
||||
t.Errorf("%v restring gave: %v\n", test, lq.String())
|
||||
}
|
||||
}
|
||||
for _, test := range testBadStrings {
|
||||
_, err := ParseSelector(test)
|
||||
if err == nil {
|
||||
t.Errorf("%v: did not get expected error\n", test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterministicParse(t *testing.T) {
|
||||
s1, err := ParseSelector("x=a,a=x")
|
||||
s2, err2 := ParseSelector("a=x,x=a")
|
||||
if err != nil || err2 != nil {
|
||||
t.Errorf("Unexpected parse error")
|
||||
}
|
||||
if s1.String() != s2.String() {
|
||||
t.Errorf("Non-deterministic parse")
|
||||
}
|
||||
}
|
||||
|
||||
func expectMatch(t *testing.T, selector string, ls Set) {
|
||||
lq, err := ParseSelector(selector)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to parse %v as a selector\n", selector)
|
||||
return
|
||||
}
|
||||
if !lq.Matches(ls) {
|
||||
t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls)
|
||||
}
|
||||
}
|
||||
|
||||
func expectNoMatch(t *testing.T, selector string, ls Set) {
|
||||
lq, err := ParseSelector(selector)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to parse %v as a selector\n", selector)
|
||||
return
|
||||
}
|
||||
if lq.Matches(ls) {
|
||||
t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEverything(t *testing.T) {
|
||||
if !Everything().Matches(Set{"x": "y"}) {
|
||||
t.Errorf("Nil selector didn't match")
|
||||
}
|
||||
if !Everything().Empty() {
|
||||
t.Errorf("Everything was not empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectorMatches(t *testing.T) {
|
||||
expectMatch(t, "", Set{"x": "y"})
|
||||
expectMatch(t, "x=y", Set{"x": "y"})
|
||||
expectMatch(t, "x=y,z=w", Set{"x": "y", "z": "w"})
|
||||
expectMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "a"})
|
||||
expectMatch(t, "notin=in", Set{"notin": "in"}) // in and notin in exactMatch
|
||||
expectNoMatch(t, "x=y", Set{"x": "z"})
|
||||
expectNoMatch(t, "x=y,z=w", Set{"x": "w", "z": "w"})
|
||||
expectNoMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "w"})
|
||||
|
||||
fieldset := Set{
|
||||
"foo": "bar",
|
||||
"baz": "blah",
|
||||
"complex": `=value\,\`,
|
||||
}
|
||||
expectMatch(t, "foo=bar", fieldset)
|
||||
expectMatch(t, "baz=blah", fieldset)
|
||||
expectMatch(t, "foo=bar,baz=blah", fieldset)
|
||||
expectMatch(t, `foo=bar,baz=blah,complex=\=value\\\,\\`, fieldset)
|
||||
expectNoMatch(t, "foo=blah", fieldset)
|
||||
expectNoMatch(t, "baz=bar", fieldset)
|
||||
expectNoMatch(t, "foo=bar,foobar=bar,baz=blah", fieldset)
|
||||
}
|
||||
|
||||
func TestOneTermEqualSelector(t *testing.T) {
|
||||
if !OneTermEqualSelector("x", "y").Matches(Set{"x": "y"}) {
|
||||
t.Errorf("No match when match expected.")
|
||||
}
|
||||
if OneTermEqualSelector("x", "y").Matches(Set{"x": "z"}) {
|
||||
t.Errorf("Match when none expected.")
|
||||
}
|
||||
}
|
||||
|
||||
func expectMatchDirect(t *testing.T, selector, ls Set) {
|
||||
if !SelectorFromSet(selector).Matches(ls) {
|
||||
t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls)
|
||||
}
|
||||
}
|
||||
|
||||
func expectNoMatchDirect(t *testing.T, selector, ls Set) {
|
||||
if SelectorFromSet(selector).Matches(ls) {
|
||||
t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMatches(t *testing.T) {
|
||||
labelset := Set{
|
||||
"foo": "bar",
|
||||
"baz": "blah",
|
||||
}
|
||||
expectMatchDirect(t, Set{}, labelset)
|
||||
expectMatchDirect(t, Set{"foo": "bar"}, labelset)
|
||||
expectMatchDirect(t, Set{"baz": "blah"}, labelset)
|
||||
expectMatchDirect(t, Set{"foo": "bar", "baz": "blah"}, labelset)
|
||||
expectNoMatchDirect(t, Set{"foo": "=blah"}, labelset)
|
||||
expectNoMatchDirect(t, Set{"baz": "=bar"}, labelset)
|
||||
expectNoMatchDirect(t, Set{"foo": "=bar", "foobar": "bar", "baz": "blah"}, labelset)
|
||||
}
|
||||
|
||||
func TestNilMapIsValid(t *testing.T) {
|
||||
selector := Set(nil).AsSelector()
|
||||
if selector == nil {
|
||||
t.Errorf("Selector for nil set should be Everything")
|
||||
}
|
||||
if !selector.Empty() {
|
||||
t.Errorf("Selector for nil set should be Empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetIsEmpty(t *testing.T) {
|
||||
if !(Set{}).AsSelector().Empty() {
|
||||
t.Errorf("Empty set should be empty")
|
||||
}
|
||||
if !(andTerm(nil)).Empty() {
|
||||
t.Errorf("Nil andTerm should be empty")
|
||||
}
|
||||
if (&hasTerm{}).Empty() {
|
||||
t.Errorf("hasTerm should not be empty")
|
||||
}
|
||||
if (¬HasTerm{}).Empty() {
|
||||
t.Errorf("notHasTerm should not be empty")
|
||||
}
|
||||
if !(andTerm{andTerm{}}).Empty() {
|
||||
t.Errorf("Nested andTerm should be empty")
|
||||
}
|
||||
if (andTerm{&hasTerm{"a", "b"}}).Empty() {
|
||||
t.Errorf("Nested andTerm should not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequiresExactMatch(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
S Selector
|
||||
Label string
|
||||
Value string
|
||||
Found bool
|
||||
}{
|
||||
"empty set": {Set{}.AsSelector(), "test", "", false},
|
||||
"empty hasTerm": {&hasTerm{}, "test", "", false},
|
||||
"skipped hasTerm": {&hasTerm{"a", "b"}, "test", "", false},
|
||||
"valid hasTerm": {&hasTerm{"test", "b"}, "test", "b", true},
|
||||
"valid hasTerm no value": {&hasTerm{"test", ""}, "test", "", true},
|
||||
"valid notHasTerm": {¬HasTerm{"test", "b"}, "test", "", false},
|
||||
"valid notHasTerm no value": {¬HasTerm{"test", ""}, "test", "", false},
|
||||
"nil andTerm": {andTerm(nil), "test", "", false},
|
||||
"empty andTerm": {andTerm{}, "test", "", false},
|
||||
"nested andTerm": {andTerm{andTerm{}}, "test", "", false},
|
||||
"nested andTerm matches": {andTerm{&hasTerm{"test", "b"}}, "test", "b", true},
|
||||
"andTerm with non-match": {andTerm{&hasTerm{}, &hasTerm{"test", "b"}}, "test", "b", true},
|
||||
}
|
||||
for k, v := range testCases {
|
||||
value, found := v.S.RequiresExactMatch(v.Label)
|
||||
if value != v.Value {
|
||||
t.Errorf("%s: expected value %s, got %s", k, v.Value, value)
|
||||
}
|
||||
if found != v.Found {
|
||||
t.Errorf("%s: expected found %t, got %t", k, v.Found, found)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransform(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
selector string
|
||||
transform func(field, value string) (string, string, error)
|
||||
result string
|
||||
isEmpty bool
|
||||
}{
|
||||
{
|
||||
name: "empty selector",
|
||||
selector: "",
|
||||
transform: func(field, value string) (string, string, error) { return field, value, nil },
|
||||
result: "",
|
||||
isEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "no-op transform",
|
||||
selector: "a=b,c=d",
|
||||
transform: func(field, value string) (string, string, error) { return field, value, nil },
|
||||
result: "a=b,c=d",
|
||||
isEmpty: false,
|
||||
},
|
||||
{
|
||||
name: "transform one field",
|
||||
selector: "a=b,c=d",
|
||||
transform: func(field, value string) (string, string, error) {
|
||||
if field == "a" {
|
||||
return "e", "f", nil
|
||||
}
|
||||
return field, value, nil
|
||||
},
|
||||
result: "e=f,c=d",
|
||||
isEmpty: false,
|
||||
},
|
||||
{
|
||||
name: "remove field to make empty",
|
||||
selector: "a=b",
|
||||
transform: func(field, value string) (string, string, error) { return "", "", nil },
|
||||
result: "",
|
||||
isEmpty: true,
|
||||
},
|
||||
{
|
||||
name: "remove only one field",
|
||||
selector: "a=b,c=d,e=f",
|
||||
transform: func(field, value string) (string, string, error) {
|
||||
if field == "c" {
|
||||
return "", "", nil
|
||||
}
|
||||
return field, value, nil
|
||||
},
|
||||
result: "a=b,e=f",
|
||||
isEmpty: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
result, err := ParseAndTransformSelector(tc.selector, tc.transform)
|
||||
if err != nil {
|
||||
t.Errorf("[%d] unexpected error during Transform: %v", i, err)
|
||||
}
|
||||
if result.Empty() != tc.isEmpty {
|
||||
t.Errorf("[%d] expected empty: %t, got: %t", i, tc.isEmpty, result.Empty())
|
||||
}
|
||||
if result.String() != tc.result {
|
||||
t.Errorf("[%d] unexpected result: %s", i, result.String())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/labels/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/labels/doc.go
generated
vendored
|
|
@ -16,4 +16,4 @@ limitations under the License.
|
|||
|
||||
// Package labels implements a simple label system, parsing and matching
|
||||
// selectors with sets of labels.
|
||||
package labels
|
||||
package labels // import "k8s.io/apimachinery/pkg/labels"
|
||||
|
|
|
|||
231
vendor/k8s.io/apimachinery/pkg/labels/labels_test.go
generated
vendored
Normal file
231
vendor/k8s.io/apimachinery/pkg/labels/labels_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
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 labels
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func matches(t *testing.T, ls Set, want string) {
|
||||
if ls.String() != want {
|
||||
t.Errorf("Expected '%s', but got '%s'", want, ls.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetString(t *testing.T) {
|
||||
matches(t, Set{"x": "y"}, "x=y")
|
||||
matches(t, Set{"foo": "bar"}, "foo=bar")
|
||||
matches(t, Set{"foo": "bar", "baz": "qup"}, "baz=qup,foo=bar")
|
||||
|
||||
// TODO: Make our label representation robust enough to handle labels
|
||||
// with ",=!" characters in their names.
|
||||
}
|
||||
|
||||
func TestLabelHas(t *testing.T) {
|
||||
labelHasTests := []struct {
|
||||
Ls Labels
|
||||
Key string
|
||||
Has bool
|
||||
}{
|
||||
{Set{"x": "y"}, "x", true},
|
||||
{Set{"x": ""}, "x", true},
|
||||
{Set{"x": "y"}, "foo", false},
|
||||
}
|
||||
for _, lh := range labelHasTests {
|
||||
if has := lh.Ls.Has(lh.Key); has != lh.Has {
|
||||
t.Errorf("%#v.Has(%#v) => %v, expected %v", lh.Ls, lh.Key, has, lh.Has)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelGet(t *testing.T) {
|
||||
ls := Set{"x": "y"}
|
||||
if ls.Get("x") != "y" {
|
||||
t.Errorf("Set.Get is broken")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelConflict(t *testing.T) {
|
||||
tests := []struct {
|
||||
labels1 map[string]string
|
||||
labels2 map[string]string
|
||||
conflict bool
|
||||
}{
|
||||
{
|
||||
labels1: map[string]string{},
|
||||
labels2: map[string]string{},
|
||||
conflict: false,
|
||||
},
|
||||
{
|
||||
labels1: map[string]string{"env": "test"},
|
||||
labels2: map[string]string{"infra": "true"},
|
||||
conflict: false,
|
||||
},
|
||||
{
|
||||
labels1: map[string]string{"env": "test"},
|
||||
labels2: map[string]string{"infra": "true", "env": "test"},
|
||||
conflict: false,
|
||||
},
|
||||
{
|
||||
labels1: map[string]string{"env": "test"},
|
||||
labels2: map[string]string{"env": "dev"},
|
||||
conflict: true,
|
||||
},
|
||||
{
|
||||
labels1: map[string]string{"env": "test", "infra": "false"},
|
||||
labels2: map[string]string{"infra": "true", "color": "blue"},
|
||||
conflict: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
conflict := Conflicts(Set(test.labels1), Set(test.labels2))
|
||||
if conflict != test.conflict {
|
||||
t.Errorf("expected: %v but got: %v", test.conflict, conflict)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelMerge(t *testing.T) {
|
||||
tests := []struct {
|
||||
labels1 map[string]string
|
||||
labels2 map[string]string
|
||||
mergedLabels map[string]string
|
||||
}{
|
||||
{
|
||||
labels1: map[string]string{},
|
||||
labels2: map[string]string{},
|
||||
mergedLabels: map[string]string{},
|
||||
},
|
||||
{
|
||||
labels1: map[string]string{"infra": "true"},
|
||||
labels2: map[string]string{},
|
||||
mergedLabels: map[string]string{"infra": "true"},
|
||||
},
|
||||
{
|
||||
labels1: map[string]string{"infra": "true"},
|
||||
labels2: map[string]string{"env": "test", "color": "blue"},
|
||||
mergedLabels: map[string]string{"infra": "true", "env": "test", "color": "blue"},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
mergedLabels := Merge(Set(test.labels1), Set(test.labels2))
|
||||
if !Equals(mergedLabels, test.mergedLabels) {
|
||||
t.Errorf("expected: %v but got: %v", test.mergedLabels, mergedLabels)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelSelectorParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
selector string
|
||||
labels map[string]string
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
selector: "",
|
||||
labels: map[string]string{},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
selector: "x=a",
|
||||
labels: map[string]string{"x": "a"},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
selector: "x=a,y=b,z=c",
|
||||
labels: map[string]string{"x": "a", "y": "b", "z": "c"},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
selector: " x = a , y = b , z = c ",
|
||||
labels: map[string]string{"x": "a", "y": "b", "z": "c"},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
selector: "color=green,env=test,service=front",
|
||||
labels: map[string]string{"color": "green", "env": "test", "service": "front"},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
selector: "color=green, env=test, service=front",
|
||||
labels: map[string]string{"color": "green", "env": "test", "service": "front"},
|
||||
valid: true,
|
||||
},
|
||||
{
|
||||
selector: ",",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x,y",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x=$y",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x!=y",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x==y",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x=a||y=b",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x in (y)",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x notin (y)",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
{
|
||||
selector: "x y",
|
||||
labels: map[string]string{},
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
labels, err := ConvertSelectorToLabelsMap(test.selector)
|
||||
if test.valid && err != nil {
|
||||
t.Errorf("selector: %s, expected no error but got: %s", test.selector, err)
|
||||
} else if !test.valid && err == nil {
|
||||
t.Errorf("selector: %s, expected an error", test.selector)
|
||||
}
|
||||
|
||||
if !Equals(Set(labels), test.labels) {
|
||||
t.Errorf("expected: %s but got: %s", test.labels, labels)
|
||||
}
|
||||
}
|
||||
}
|
||||
575
vendor/k8s.io/apimachinery/pkg/labels/selector_test.go
generated
vendored
Normal file
575
vendor/k8s.io/apimachinery/pkg/labels/selector_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,575 @@
|
|||
/*
|
||||
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 labels
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
func TestSelectorParse(t *testing.T) {
|
||||
testGoodStrings := []string{
|
||||
"x=a,y=b,z=c",
|
||||
"",
|
||||
"x!=a,y=b",
|
||||
"x=",
|
||||
"x= ",
|
||||
"x=,z= ",
|
||||
"x= ,z= ",
|
||||
"!x",
|
||||
"x>1",
|
||||
"x>1,z<5",
|
||||
}
|
||||
testBadStrings := []string{
|
||||
"x=a||y=b",
|
||||
"x==a==b",
|
||||
"!x=a",
|
||||
"x<a",
|
||||
}
|
||||
for _, test := range testGoodStrings {
|
||||
lq, err := Parse(test)
|
||||
if err != nil {
|
||||
t.Errorf("%v: error %v (%#v)\n", test, err, err)
|
||||
}
|
||||
if strings.Replace(test, " ", "", -1) != lq.String() {
|
||||
t.Errorf("%v restring gave: %v\n", test, lq.String())
|
||||
}
|
||||
}
|
||||
for _, test := range testBadStrings {
|
||||
_, err := Parse(test)
|
||||
if err == nil {
|
||||
t.Errorf("%v: did not get expected error\n", test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterministicParse(t *testing.T) {
|
||||
s1, err := Parse("x=a,a=x")
|
||||
s2, err2 := Parse("a=x,x=a")
|
||||
if err != nil || err2 != nil {
|
||||
t.Errorf("Unexpected parse error")
|
||||
}
|
||||
if s1.String() != s2.String() {
|
||||
t.Errorf("Non-deterministic parse")
|
||||
}
|
||||
}
|
||||
|
||||
func expectMatch(t *testing.T, selector string, ls Set) {
|
||||
lq, err := Parse(selector)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to parse %v as a selector\n", selector)
|
||||
return
|
||||
}
|
||||
if !lq.Matches(ls) {
|
||||
t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls)
|
||||
}
|
||||
}
|
||||
|
||||
func expectNoMatch(t *testing.T, selector string, ls Set) {
|
||||
lq, err := Parse(selector)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to parse %v as a selector\n", selector)
|
||||
return
|
||||
}
|
||||
if lq.Matches(ls) {
|
||||
t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEverything(t *testing.T) {
|
||||
if !Everything().Matches(Set{"x": "y"}) {
|
||||
t.Errorf("Nil selector didn't match")
|
||||
}
|
||||
if !Everything().Empty() {
|
||||
t.Errorf("Everything was not empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectorMatches(t *testing.T) {
|
||||
expectMatch(t, "", Set{"x": "y"})
|
||||
expectMatch(t, "x=y", Set{"x": "y"})
|
||||
expectMatch(t, "x=y,z=w", Set{"x": "y", "z": "w"})
|
||||
expectMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "a"})
|
||||
expectMatch(t, "notin=in", Set{"notin": "in"}) // in and notin in exactMatch
|
||||
expectMatch(t, "x", Set{"x": "z"})
|
||||
expectMatch(t, "!x", Set{"y": "z"})
|
||||
expectMatch(t, "x>1", Set{"x": "2"})
|
||||
expectMatch(t, "x<1", Set{"x": "0"})
|
||||
expectNoMatch(t, "x=z", Set{})
|
||||
expectNoMatch(t, "x=y", Set{"x": "z"})
|
||||
expectNoMatch(t, "x=y,z=w", Set{"x": "w", "z": "w"})
|
||||
expectNoMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "w"})
|
||||
expectNoMatch(t, "x", Set{"y": "z"})
|
||||
expectNoMatch(t, "!x", Set{"x": "z"})
|
||||
expectNoMatch(t, "x>1", Set{"x": "0"})
|
||||
expectNoMatch(t, "x<1", Set{"x": "2"})
|
||||
|
||||
labelset := Set{
|
||||
"foo": "bar",
|
||||
"baz": "blah",
|
||||
}
|
||||
expectMatch(t, "foo=bar", labelset)
|
||||
expectMatch(t, "baz=blah", labelset)
|
||||
expectMatch(t, "foo=bar,baz=blah", labelset)
|
||||
expectNoMatch(t, "foo=blah", labelset)
|
||||
expectNoMatch(t, "baz=bar", labelset)
|
||||
expectNoMatch(t, "foo=bar,foobar=bar,baz=blah", labelset)
|
||||
}
|
||||
|
||||
func expectMatchDirect(t *testing.T, selector, ls Set) {
|
||||
if !SelectorFromSet(selector).Matches(ls) {
|
||||
t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls)
|
||||
}
|
||||
}
|
||||
|
||||
func expectNoMatchDirect(t *testing.T, selector, ls Set) {
|
||||
if SelectorFromSet(selector).Matches(ls) {
|
||||
t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMatches(t *testing.T) {
|
||||
labelset := Set{
|
||||
"foo": "bar",
|
||||
"baz": "blah",
|
||||
}
|
||||
expectMatchDirect(t, Set{}, labelset)
|
||||
expectMatchDirect(t, Set{"foo": "bar"}, labelset)
|
||||
expectMatchDirect(t, Set{"baz": "blah"}, labelset)
|
||||
expectMatchDirect(t, Set{"foo": "bar", "baz": "blah"}, labelset)
|
||||
|
||||
//TODO: bad values not handled for the moment in SelectorFromSet
|
||||
//expectNoMatchDirect(t, Set{"foo": "=blah"}, labelset)
|
||||
//expectNoMatchDirect(t, Set{"baz": "=bar"}, labelset)
|
||||
//expectNoMatchDirect(t, Set{"foo": "=bar", "foobar": "bar", "baz": "blah"}, labelset)
|
||||
}
|
||||
|
||||
func TestNilMapIsValid(t *testing.T) {
|
||||
selector := Set(nil).AsSelector()
|
||||
if selector == nil {
|
||||
t.Errorf("Selector for nil set should be Everything")
|
||||
}
|
||||
if !selector.Empty() {
|
||||
t.Errorf("Selector for nil set should be Empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetIsEmpty(t *testing.T) {
|
||||
if !(Set{}).AsSelector().Empty() {
|
||||
t.Errorf("Empty set should be empty")
|
||||
}
|
||||
if !(NewSelector()).Empty() {
|
||||
t.Errorf("Nil Selector should be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLexer(t *testing.T) {
|
||||
testcases := []struct {
|
||||
s string
|
||||
t Token
|
||||
}{
|
||||
{"", EndOfStringToken},
|
||||
{",", CommaToken},
|
||||
{"notin", NotInToken},
|
||||
{"in", InToken},
|
||||
{"=", EqualsToken},
|
||||
{"==", DoubleEqualsToken},
|
||||
{">", GreaterThanToken},
|
||||
{"<", LessThanToken},
|
||||
//Note that Lex returns the longest valid token found
|
||||
{"!", DoesNotExistToken},
|
||||
{"!=", NotEqualsToken},
|
||||
{"(", OpenParToken},
|
||||
{")", ClosedParToken},
|
||||
//Non-"special" characters are considered part of an identifier
|
||||
{"~", IdentifierToken},
|
||||
{"||", IdentifierToken},
|
||||
}
|
||||
for _, v := range testcases {
|
||||
l := &Lexer{s: v.s, pos: 0}
|
||||
token, lit := l.Lex()
|
||||
if token != v.t {
|
||||
t.Errorf("Got %d it should be %d for '%s'", token, v.t, v.s)
|
||||
}
|
||||
if v.t != ErrorToken && lit != v.s {
|
||||
t.Errorf("Got '%s' it should be '%s'", lit, v.s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func min(l, r int) (m int) {
|
||||
m = r
|
||||
if l < r {
|
||||
m = l
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func TestLexerSequence(t *testing.T) {
|
||||
testcases := []struct {
|
||||
s string
|
||||
t []Token
|
||||
}{
|
||||
{"key in ( value )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, ClosedParToken}},
|
||||
{"key notin ( value )", []Token{IdentifierToken, NotInToken, OpenParToken, IdentifierToken, ClosedParToken}},
|
||||
{"key in ( value1, value2 )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, CommaToken, IdentifierToken, ClosedParToken}},
|
||||
{"key", []Token{IdentifierToken}},
|
||||
{"!key", []Token{DoesNotExistToken, IdentifierToken}},
|
||||
{"()", []Token{OpenParToken, ClosedParToken}},
|
||||
{"x in (),y", []Token{IdentifierToken, InToken, OpenParToken, ClosedParToken, CommaToken, IdentifierToken}},
|
||||
{"== != (), = notin", []Token{DoubleEqualsToken, NotEqualsToken, OpenParToken, ClosedParToken, CommaToken, EqualsToken, NotInToken}},
|
||||
{"key>2", []Token{IdentifierToken, GreaterThanToken, IdentifierToken}},
|
||||
{"key<1", []Token{IdentifierToken, LessThanToken, IdentifierToken}},
|
||||
}
|
||||
for _, v := range testcases {
|
||||
var literals []string
|
||||
var tokens []Token
|
||||
l := &Lexer{s: v.s, pos: 0}
|
||||
for {
|
||||
token, lit := l.Lex()
|
||||
if token == EndOfStringToken {
|
||||
break
|
||||
}
|
||||
tokens = append(tokens, token)
|
||||
literals = append(literals, lit)
|
||||
}
|
||||
if len(tokens) != len(v.t) {
|
||||
t.Errorf("Bad number of tokens for '%s %d, %d", v.s, len(tokens), len(v.t))
|
||||
}
|
||||
for i := 0; i < min(len(tokens), len(v.t)); i++ {
|
||||
if tokens[i] != v.t[i] {
|
||||
t.Errorf("Test '%s': Mismatching in token type found '%v' it should be '%v'", v.s, tokens[i], v.t[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestParserLookahead(t *testing.T) {
|
||||
testcases := []struct {
|
||||
s string
|
||||
t []Token
|
||||
}{
|
||||
{"key in ( value )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, ClosedParToken, EndOfStringToken}},
|
||||
{"key notin ( value )", []Token{IdentifierToken, NotInToken, OpenParToken, IdentifierToken, ClosedParToken, EndOfStringToken}},
|
||||
{"key in ( value1, value2 )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, CommaToken, IdentifierToken, ClosedParToken, EndOfStringToken}},
|
||||
{"key", []Token{IdentifierToken, EndOfStringToken}},
|
||||
{"!key", []Token{DoesNotExistToken, IdentifierToken, EndOfStringToken}},
|
||||
{"()", []Token{OpenParToken, ClosedParToken, EndOfStringToken}},
|
||||
{"", []Token{EndOfStringToken}},
|
||||
{"x in (),y", []Token{IdentifierToken, InToken, OpenParToken, ClosedParToken, CommaToken, IdentifierToken, EndOfStringToken}},
|
||||
{"== != (), = notin", []Token{DoubleEqualsToken, NotEqualsToken, OpenParToken, ClosedParToken, CommaToken, EqualsToken, NotInToken, EndOfStringToken}},
|
||||
{"key>2", []Token{IdentifierToken, GreaterThanToken, IdentifierToken, EndOfStringToken}},
|
||||
{"key<1", []Token{IdentifierToken, LessThanToken, IdentifierToken, EndOfStringToken}},
|
||||
}
|
||||
for _, v := range testcases {
|
||||
p := &Parser{l: &Lexer{s: v.s, pos: 0}, position: 0}
|
||||
p.scan()
|
||||
if len(p.scannedItems) != len(v.t) {
|
||||
t.Errorf("Expected %d items found %d", len(v.t), len(p.scannedItems))
|
||||
}
|
||||
for {
|
||||
token, lit := p.lookahead(KeyAndOperator)
|
||||
|
||||
token2, lit2 := p.consume(KeyAndOperator)
|
||||
if token == EndOfStringToken {
|
||||
break
|
||||
}
|
||||
if token != token2 || lit != lit2 {
|
||||
t.Errorf("Bad values")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequirementConstructor(t *testing.T) {
|
||||
requirementConstructorTests := []struct {
|
||||
Key string
|
||||
Op selection.Operator
|
||||
Vals sets.String
|
||||
Success bool
|
||||
}{
|
||||
{"x", selection.In, nil, false},
|
||||
{"x", selection.NotIn, sets.NewString(), false},
|
||||
{"x", selection.In, sets.NewString("foo"), true},
|
||||
{"x", selection.NotIn, sets.NewString("foo"), true},
|
||||
{"x", selection.Exists, nil, true},
|
||||
{"x", selection.DoesNotExist, nil, true},
|
||||
{"1foo", selection.In, sets.NewString("bar"), true},
|
||||
{"1234", selection.In, sets.NewString("bar"), true},
|
||||
{"y", selection.GreaterThan, sets.NewString("1"), true},
|
||||
{"z", selection.LessThan, sets.NewString("6"), true},
|
||||
{"foo", selection.GreaterThan, sets.NewString("bar"), false},
|
||||
{"barz", selection.LessThan, sets.NewString("blah"), false},
|
||||
{strings.Repeat("a", 254), selection.Exists, nil, false}, //breaks DNS rule that len(key) <= 253
|
||||
}
|
||||
for _, rc := range requirementConstructorTests {
|
||||
if _, err := NewRequirement(rc.Key, rc.Op, rc.Vals.List()); err == nil && !rc.Success {
|
||||
t.Errorf("expected error with key:%#v op:%v vals:%v, got no error", rc.Key, rc.Op, rc.Vals)
|
||||
} else if err != nil && rc.Success {
|
||||
t.Errorf("expected no error with key:%#v op:%v vals:%v, got:%v", rc.Key, rc.Op, rc.Vals, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToString(t *testing.T) {
|
||||
var req Requirement
|
||||
toStringTests := []struct {
|
||||
In *internalSelector
|
||||
Out string
|
||||
Valid bool
|
||||
}{
|
||||
|
||||
{&internalSelector{
|
||||
getRequirement("x", selection.In, sets.NewString("abc", "def"), t),
|
||||
getRequirement("y", selection.NotIn, sets.NewString("jkl"), t),
|
||||
getRequirement("z", selection.Exists, nil, t)},
|
||||
"x in (abc,def),y notin (jkl),z", true},
|
||||
{&internalSelector{
|
||||
getRequirement("x", selection.NotIn, sets.NewString("abc", "def"), t),
|
||||
getRequirement("y", selection.NotEquals, sets.NewString("jkl"), t),
|
||||
getRequirement("z", selection.DoesNotExist, nil, t)},
|
||||
"x notin (abc,def),y!=jkl,!z", true},
|
||||
{&internalSelector{
|
||||
getRequirement("x", selection.In, sets.NewString("abc", "def"), t),
|
||||
req}, // adding empty req for the trailing ','
|
||||
"x in (abc,def),", false},
|
||||
{&internalSelector{
|
||||
getRequirement("x", selection.NotIn, sets.NewString("abc"), t),
|
||||
getRequirement("y", selection.In, sets.NewString("jkl", "mno"), t),
|
||||
getRequirement("z", selection.NotIn, sets.NewString(""), t)},
|
||||
"x notin (abc),y in (jkl,mno),z notin ()", true},
|
||||
{&internalSelector{
|
||||
getRequirement("x", selection.Equals, sets.NewString("abc"), t),
|
||||
getRequirement("y", selection.DoubleEquals, sets.NewString("jkl"), t),
|
||||
getRequirement("z", selection.NotEquals, sets.NewString("a"), t),
|
||||
getRequirement("z", selection.Exists, nil, t)},
|
||||
"x=abc,y==jkl,z!=a,z", true},
|
||||
{&internalSelector{
|
||||
getRequirement("x", selection.GreaterThan, sets.NewString("2"), t),
|
||||
getRequirement("y", selection.LessThan, sets.NewString("8"), t),
|
||||
getRequirement("z", selection.Exists, nil, t)},
|
||||
"x>2,y<8,z", true},
|
||||
}
|
||||
for _, ts := range toStringTests {
|
||||
if out := ts.In.String(); out == "" && ts.Valid {
|
||||
t.Errorf("%#v.String() => '%v' expected no error", ts.In, out)
|
||||
} else if out != ts.Out {
|
||||
t.Errorf("%#v.String() => '%v' want '%v'", ts.In, out, ts.Out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequirementSelectorMatching(t *testing.T) {
|
||||
var req Requirement
|
||||
labelSelectorMatchingTests := []struct {
|
||||
Set Set
|
||||
Sel Selector
|
||||
Match bool
|
||||
}{
|
||||
{Set{"x": "foo", "y": "baz"}, &internalSelector{
|
||||
req,
|
||||
}, false},
|
||||
{Set{"x": "foo", "y": "baz"}, &internalSelector{
|
||||
getRequirement("x", selection.In, sets.NewString("foo"), t),
|
||||
getRequirement("y", selection.NotIn, sets.NewString("alpha"), t),
|
||||
}, true},
|
||||
{Set{"x": "foo", "y": "baz"}, &internalSelector{
|
||||
getRequirement("x", selection.In, sets.NewString("foo"), t),
|
||||
getRequirement("y", selection.In, sets.NewString("alpha"), t),
|
||||
}, false},
|
||||
{Set{"y": ""}, &internalSelector{
|
||||
getRequirement("x", selection.NotIn, sets.NewString(""), t),
|
||||
getRequirement("y", selection.Exists, nil, t),
|
||||
}, true},
|
||||
{Set{"y": ""}, &internalSelector{
|
||||
getRequirement("x", selection.DoesNotExist, nil, t),
|
||||
getRequirement("y", selection.Exists, nil, t),
|
||||
}, true},
|
||||
{Set{"y": ""}, &internalSelector{
|
||||
getRequirement("x", selection.NotIn, sets.NewString(""), t),
|
||||
getRequirement("y", selection.DoesNotExist, nil, t),
|
||||
}, false},
|
||||
{Set{"y": "baz"}, &internalSelector{
|
||||
getRequirement("x", selection.In, sets.NewString(""), t),
|
||||
}, false},
|
||||
{Set{"z": "2"}, &internalSelector{
|
||||
getRequirement("z", selection.GreaterThan, sets.NewString("1"), t),
|
||||
}, true},
|
||||
{Set{"z": "v2"}, &internalSelector{
|
||||
getRequirement("z", selection.GreaterThan, sets.NewString("1"), t),
|
||||
}, false},
|
||||
}
|
||||
for _, lsm := range labelSelectorMatchingTests {
|
||||
if match := lsm.Sel.Matches(lsm.Set); match != lsm.Match {
|
||||
t.Errorf("%+v.Matches(%#v) => %v, want %v", lsm.Sel, lsm.Set, match, lsm.Match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetSelectorParser(t *testing.T) {
|
||||
setSelectorParserTests := []struct {
|
||||
In string
|
||||
Out Selector
|
||||
Match bool
|
||||
Valid bool
|
||||
}{
|
||||
{"", NewSelector(), true, true},
|
||||
{"\rx", internalSelector{
|
||||
getRequirement("x", selection.Exists, nil, t),
|
||||
}, true, true},
|
||||
{"this-is-a-dns.domain.com/key-with-dash", internalSelector{
|
||||
getRequirement("this-is-a-dns.domain.com/key-with-dash", selection.Exists, nil, t),
|
||||
}, true, true},
|
||||
{"this-is-another-dns.domain.com/key-with-dash in (so,what)", internalSelector{
|
||||
getRequirement("this-is-another-dns.domain.com/key-with-dash", selection.In, sets.NewString("so", "what"), t),
|
||||
}, true, true},
|
||||
{"0.1.2.domain/99 notin (10.10.100.1, tick.tack.clock)", internalSelector{
|
||||
getRequirement("0.1.2.domain/99", selection.NotIn, sets.NewString("10.10.100.1", "tick.tack.clock"), t),
|
||||
}, true, true},
|
||||
{"foo in (abc)", internalSelector{
|
||||
getRequirement("foo", selection.In, sets.NewString("abc"), t),
|
||||
}, true, true},
|
||||
{"x notin\n (abc)", internalSelector{
|
||||
getRequirement("x", selection.NotIn, sets.NewString("abc"), t),
|
||||
}, true, true},
|
||||
{"x notin \t (abc,def)", internalSelector{
|
||||
getRequirement("x", selection.NotIn, sets.NewString("abc", "def"), t),
|
||||
}, true, true},
|
||||
{"x in (abc,def)", internalSelector{
|
||||
getRequirement("x", selection.In, sets.NewString("abc", "def"), t),
|
||||
}, true, true},
|
||||
{"x in (abc,)", internalSelector{
|
||||
getRequirement("x", selection.In, sets.NewString("abc", ""), t),
|
||||
}, true, true},
|
||||
{"x in ()", internalSelector{
|
||||
getRequirement("x", selection.In, sets.NewString(""), t),
|
||||
}, true, true},
|
||||
{"x notin (abc,,def),bar,z in (),w", internalSelector{
|
||||
getRequirement("bar", selection.Exists, nil, t),
|
||||
getRequirement("w", selection.Exists, nil, t),
|
||||
getRequirement("x", selection.NotIn, sets.NewString("abc", "", "def"), t),
|
||||
getRequirement("z", selection.In, sets.NewString(""), t),
|
||||
}, true, true},
|
||||
{"x,y in (a)", internalSelector{
|
||||
getRequirement("y", selection.In, sets.NewString("a"), t),
|
||||
getRequirement("x", selection.Exists, nil, t),
|
||||
}, false, true},
|
||||
{"x=a", internalSelector{
|
||||
getRequirement("x", selection.Equals, sets.NewString("a"), t),
|
||||
}, true, true},
|
||||
{"x>1", internalSelector{
|
||||
getRequirement("x", selection.GreaterThan, sets.NewString("1"), t),
|
||||
}, true, true},
|
||||
{"x<7", internalSelector{
|
||||
getRequirement("x", selection.LessThan, sets.NewString("7"), t),
|
||||
}, true, true},
|
||||
{"x=a,y!=b", internalSelector{
|
||||
getRequirement("x", selection.Equals, sets.NewString("a"), t),
|
||||
getRequirement("y", selection.NotEquals, sets.NewString("b"), t),
|
||||
}, true, true},
|
||||
{"x=a,y!=b,z in (h,i,j)", internalSelector{
|
||||
getRequirement("x", selection.Equals, sets.NewString("a"), t),
|
||||
getRequirement("y", selection.NotEquals, sets.NewString("b"), t),
|
||||
getRequirement("z", selection.In, sets.NewString("h", "i", "j"), t),
|
||||
}, true, true},
|
||||
{"x=a||y=b", internalSelector{}, false, false},
|
||||
{"x,,y", nil, true, false},
|
||||
{",x,y", nil, true, false},
|
||||
{"x nott in (y)", nil, true, false},
|
||||
{"x notin ( )", internalSelector{
|
||||
getRequirement("x", selection.NotIn, sets.NewString(""), t),
|
||||
}, true, true},
|
||||
{"x notin (, a)", internalSelector{
|
||||
getRequirement("x", selection.NotIn, sets.NewString("", "a"), t),
|
||||
}, true, true},
|
||||
{"a in (xyz),", nil, true, false},
|
||||
{"a in (xyz)b notin ()", nil, true, false},
|
||||
{"a ", internalSelector{
|
||||
getRequirement("a", selection.Exists, nil, t),
|
||||
}, true, true},
|
||||
{"a in (x,y,notin, z,in)", internalSelector{
|
||||
getRequirement("a", selection.In, sets.NewString("in", "notin", "x", "y", "z"), t),
|
||||
}, true, true}, // operator 'in' inside list of identifiers
|
||||
{"a in (xyz abc)", nil, false, false}, // no comma
|
||||
{"a notin(", nil, true, false}, // bad formed
|
||||
{"a (", nil, false, false}, // cpar
|
||||
{"(", nil, false, false}, // opar
|
||||
}
|
||||
|
||||
for _, ssp := range setSelectorParserTests {
|
||||
if sel, err := Parse(ssp.In); err != nil && ssp.Valid {
|
||||
t.Errorf("Parse(%s) => %v expected no error", ssp.In, err)
|
||||
} else if err == nil && !ssp.Valid {
|
||||
t.Errorf("Parse(%s) => %+v expected error", ssp.In, sel)
|
||||
} else if ssp.Match && !reflect.DeepEqual(sel, ssp.Out) {
|
||||
t.Errorf("Parse(%s) => parse output '%#v' doesn't match '%#v' expected match", ssp.In, sel, ssp.Out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getRequirement(key string, op selection.Operator, vals sets.String, t *testing.T) Requirement {
|
||||
req, err := NewRequirement(key, op, vals.List())
|
||||
if err != nil {
|
||||
t.Errorf("NewRequirement(%v, %v, %v) resulted in error:%v", key, op, vals, err)
|
||||
return Requirement{}
|
||||
}
|
||||
return *req
|
||||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
sel Selector
|
||||
key string
|
||||
operator selection.Operator
|
||||
values []string
|
||||
refSelector Selector
|
||||
}{
|
||||
{
|
||||
"keyInOperator",
|
||||
internalSelector{},
|
||||
"key",
|
||||
selection.In,
|
||||
[]string{"value"},
|
||||
internalSelector{Requirement{"key", selection.In, []string{"value"}}},
|
||||
},
|
||||
{
|
||||
"keyEqualsOperator",
|
||||
internalSelector{Requirement{"key", selection.In, []string{"value"}}},
|
||||
"key2",
|
||||
selection.Equals,
|
||||
[]string{"value2"},
|
||||
internalSelector{
|
||||
Requirement{"key", selection.In, []string{"value"}},
|
||||
Requirement{"key2", selection.Equals, []string{"value2"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, ts := range testCases {
|
||||
req, err := NewRequirement(ts.key, ts.operator, ts.values)
|
||||
if err != nil {
|
||||
t.Errorf("%s - Unable to create labels.Requirement", ts.name)
|
||||
}
|
||||
ts.sel = ts.sel.Add(*req)
|
||||
if !reflect.DeepEqual(ts.sel, ts.refSelector) {
|
||||
t.Errorf("%s - Expected %v found %v", ts.name, ts.refSelector, ts.sel)
|
||||
}
|
||||
}
|
||||
}
|
||||
115
vendor/k8s.io/apimachinery/pkg/runtime/conversion_test.go
generated
vendored
Normal file
115
vendor/k8s.io/apimachinery/pkg/runtime/conversion_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
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 runtime_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
runtimetesting "k8s.io/apimachinery/pkg/runtime/testing"
|
||||
)
|
||||
|
||||
func TestStringMapConversion(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "external"}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.Log(t)
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("Complex"), &runtimetesting.InternalComplex{})
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("Complex"), &runtimetesting.ExternalComplex{})
|
||||
|
||||
testCases := map[string]struct {
|
||||
input map[string][]string
|
||||
errFn func(error) bool
|
||||
expected runtime.Object
|
||||
}{
|
||||
"ignores omitempty": {
|
||||
input: map[string][]string{
|
||||
"String": {"not_used"},
|
||||
"string": {"value"},
|
||||
"int": {"1"},
|
||||
"Integer64": {"2"},
|
||||
},
|
||||
expected: &runtimetesting.ExternalComplex{String: "value", Integer: 1},
|
||||
},
|
||||
"returns error on bad int": {
|
||||
input: map[string][]string{
|
||||
"int": {"a"},
|
||||
},
|
||||
errFn: func(err error) bool { return err != nil },
|
||||
expected: &runtimetesting.ExternalComplex{},
|
||||
},
|
||||
"parses int64": {
|
||||
input: map[string][]string{
|
||||
"Int64": {"-1"},
|
||||
},
|
||||
expected: &runtimetesting.ExternalComplex{Int64: -1},
|
||||
},
|
||||
"returns error on bad int64": {
|
||||
input: map[string][]string{
|
||||
"Int64": {"a"},
|
||||
},
|
||||
errFn: func(err error) bool { return err != nil },
|
||||
expected: &runtimetesting.ExternalComplex{},
|
||||
},
|
||||
"parses boolean true": {
|
||||
input: map[string][]string{
|
||||
"bool": {"true"},
|
||||
},
|
||||
expected: &runtimetesting.ExternalComplex{Bool: true},
|
||||
},
|
||||
"parses boolean any value": {
|
||||
input: map[string][]string{
|
||||
"bool": {"foo"},
|
||||
},
|
||||
expected: &runtimetesting.ExternalComplex{Bool: true},
|
||||
},
|
||||
"parses boolean false": {
|
||||
input: map[string][]string{
|
||||
"bool": {"false"},
|
||||
},
|
||||
expected: &runtimetesting.ExternalComplex{Bool: false},
|
||||
},
|
||||
"parses boolean empty value": {
|
||||
input: map[string][]string{
|
||||
"bool": {""},
|
||||
},
|
||||
expected: &runtimetesting.ExternalComplex{Bool: true},
|
||||
},
|
||||
"parses boolean no value": {
|
||||
input: map[string][]string{
|
||||
"bool": {},
|
||||
},
|
||||
expected: &runtimetesting.ExternalComplex{Bool: false},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testCases {
|
||||
out := &runtimetesting.ExternalComplex{}
|
||||
if err := scheme.Convert(&tc.input, out, nil); (tc.errFn == nil && err != nil) || (tc.errFn != nil && !tc.errFn(err)) {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
} else if err != nil {
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(out, tc.expected) {
|
||||
t.Errorf("%s: unexpected output: %#v", k, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/runtime/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/runtime/doc.go
generated
vendored
|
|
@ -42,4 +42,4 @@ limitations under the License.
|
|||
// As a bonus, a few common types useful from all api objects and versions
|
||||
// are provided in types.go.
|
||||
|
||||
package runtime
|
||||
package runtime // import "k8s.io/apimachinery/pkg/runtime"
|
||||
|
|
|
|||
256
vendor/k8s.io/apimachinery/pkg/runtime/embedded_test.go
generated
vendored
Normal file
256
vendor/k8s.io/apimachinery/pkg/runtime/embedded_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
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 runtime_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
runtimetesting "k8s.io/apimachinery/pkg/runtime/testing"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
|
||||
func TestDecodeEmptyRawExtensionAsObject(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"}
|
||||
externalGVK := externalGV.WithKind("ObjectTest")
|
||||
|
||||
s := runtime.NewScheme()
|
||||
s.AddKnownTypes(internalGV, &runtimetesting.ObjectTest{})
|
||||
s.AddKnownTypeWithName(externalGVK, &runtimetesting.ObjectTestExternal{})
|
||||
|
||||
codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV)
|
||||
|
||||
obj, gvk, err := codec.Decode([]byte(`{"kind":"`+externalGVK.Kind+`","apiVersion":"`+externalGV.String()+`","items":[{}]}`), nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
test := obj.(*runtimetesting.ObjectTest)
|
||||
if unk, ok := test.Items[0].(*runtime.Unknown); !ok || unk.Kind != "" || unk.APIVersion != "" || string(unk.Raw) != "{}" || unk.ContentType != runtime.ContentTypeJSON {
|
||||
t.Fatalf("unexpected object: %#v", test.Items[0])
|
||||
}
|
||||
if *gvk != externalGVK {
|
||||
t.Fatalf("unexpected kind: %#v", gvk)
|
||||
}
|
||||
|
||||
obj, gvk, err = codec.Decode([]byte(`{"kind":"`+externalGVK.Kind+`","apiVersion":"`+externalGV.String()+`","items":[{"kind":"Other","apiVersion":"v1"}]}`), nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
test = obj.(*runtimetesting.ObjectTest)
|
||||
if unk, ok := test.Items[0].(*runtime.Unknown); !ok || unk.Kind != "" || unk.APIVersion != "" || string(unk.Raw) != `{"kind":"Other","apiVersion":"v1"}` || unk.ContentType != runtime.ContentTypeJSON {
|
||||
t.Fatalf("unexpected object: %#v", test.Items[0])
|
||||
}
|
||||
if *gvk != externalGVK {
|
||||
t.Fatalf("unexpected kind: %#v", gvk)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArrayOfRuntimeObject(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"}
|
||||
|
||||
s := runtime.NewScheme()
|
||||
s.AddKnownTypes(internalGV, &runtimetesting.EmbeddedTest{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("EmbeddedTest"), &runtimetesting.EmbeddedTestExternal{})
|
||||
s.AddKnownTypes(internalGV, &runtimetesting.ObjectTest{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("ObjectTest"), &runtimetesting.ObjectTestExternal{})
|
||||
|
||||
codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV)
|
||||
|
||||
innerItems := []runtime.Object{
|
||||
&runtimetesting.EmbeddedTest{ID: "baz"},
|
||||
}
|
||||
items := []runtime.Object{
|
||||
&runtimetesting.EmbeddedTest{ID: "foo"},
|
||||
&runtimetesting.EmbeddedTest{ID: "bar"},
|
||||
// TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization
|
||||
&runtime.Unknown{
|
||||
Raw: []byte(`{"apiVersion":"unknown.group/unknown","foo":"bar","kind":"OtherTest"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
},
|
||||
&runtimetesting.ObjectTest{
|
||||
Items: runtime.NewEncodableList(codec, innerItems),
|
||||
},
|
||||
}
|
||||
internal := &runtimetesting.ObjectTest{
|
||||
Items: runtime.NewEncodableList(codec, items),
|
||||
}
|
||||
wire, err := runtime.Encode(codec, internal)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("Wire format is:\n%s\n", string(wire))
|
||||
|
||||
obj := &runtimetesting.ObjectTestExternal{}
|
||||
if err := json.Unmarshal(wire, obj); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("exact wire is: %s", string(obj.Items[0].Raw))
|
||||
|
||||
items[3] = &runtimetesting.ObjectTest{Items: innerItems}
|
||||
internal.Items = items
|
||||
|
||||
decoded, err := runtime.Decode(codec, wire)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
list, err := meta.ExtractList(decoded)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if errs := runtime.DecodeList(list, codec); len(errs) > 0 {
|
||||
t.Fatalf("unexpected error: %v", errs)
|
||||
}
|
||||
|
||||
list2, err := meta.ExtractList(list[3])
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if errs := runtime.DecodeList(list2, codec); len(errs) > 0 {
|
||||
t.Fatalf("unexpected error: %v", errs)
|
||||
}
|
||||
if err := meta.SetList(list[3], list2); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// we want DecodeList to set type meta if possible, even on runtime.Unknown objects
|
||||
internal.Items[2].(*runtime.Unknown).TypeMeta = runtime.TypeMeta{Kind: "OtherTest", APIVersion: "unknown.group/unknown"}
|
||||
if e, a := internal.Items, list; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("mismatched decoded: %s", diff.ObjectGoPrintSideBySide(e, a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNestedObject(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"}
|
||||
embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest")
|
||||
|
||||
s := runtime.NewScheme()
|
||||
s.AddKnownTypes(internalGV, &runtimetesting.EmbeddedTest{})
|
||||
s.AddKnownTypeWithName(embeddedTestExternalGVK, &runtimetesting.EmbeddedTestExternal{})
|
||||
|
||||
codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV)
|
||||
|
||||
inner := &runtimetesting.EmbeddedTest{
|
||||
ID: "inner",
|
||||
}
|
||||
outer := &runtimetesting.EmbeddedTest{
|
||||
ID: "outer",
|
||||
Object: runtime.NewEncodable(codec, inner),
|
||||
}
|
||||
|
||||
wire, err := runtime.Encode(codec, outer)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected encode error '%v'", err)
|
||||
}
|
||||
|
||||
t.Logf("Wire format is:\n%v\n", string(wire))
|
||||
|
||||
decoded, err := runtime.Decode(codec, wire)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected decode error %v", err)
|
||||
}
|
||||
|
||||
// for later tests
|
||||
outer.Object = inner
|
||||
|
||||
if e, a := outer, decoded; reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected unequal %#v %#v", e, a)
|
||||
}
|
||||
|
||||
obj, err := runtime.Decode(codec, decoded.(*runtimetesting.EmbeddedTest).Object.(*runtime.Unknown).Raw)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
decoded.(*runtimetesting.EmbeddedTest).Object = obj
|
||||
if e, a := outer, decoded; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected equal %#v %#v", e, a)
|
||||
}
|
||||
|
||||
// test JSON decoding of the external object, which should preserve
|
||||
// raw bytes
|
||||
var externalViaJSON runtimetesting.EmbeddedTestExternal
|
||||
err = json.Unmarshal(wire, &externalViaJSON)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected decode error %v", err)
|
||||
}
|
||||
if externalViaJSON.Kind == "" || externalViaJSON.APIVersion == "" || externalViaJSON.ID != "outer" {
|
||||
t.Errorf("Expected objects to have type info set, got %#v", externalViaJSON)
|
||||
}
|
||||
if len(externalViaJSON.EmptyObject.Raw) > 0 {
|
||||
t.Errorf("Expected deserialization of empty nested objects into empty bytes, got %#v", externalViaJSON)
|
||||
}
|
||||
|
||||
// test JSON decoding, too, since Decode uses yaml unmarshalling.
|
||||
// Generic Unmarshalling of JSON cannot load the nested objects because there is
|
||||
// no default schema set. Consumers wishing to get direct JSON decoding must use
|
||||
// the external representation
|
||||
var decodedViaJSON runtimetesting.EmbeddedTest
|
||||
err = json.Unmarshal(wire, &decodedViaJSON)
|
||||
if err == nil {
|
||||
t.Fatal("Expeceted decode error")
|
||||
}
|
||||
if _, ok := err.(*json.UnmarshalTypeError); !ok {
|
||||
t.Fatalf("Unexpected decode error: %v", err)
|
||||
}
|
||||
if a := decodedViaJSON; a.Object != nil || a.EmptyObject != nil {
|
||||
t.Errorf("Expected embedded objects to be nil: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDeepCopyOfRuntimeObject checks to make sure that runtime.Objects's can be passed through DeepCopy with fidelity
|
||||
func TestDeepCopyOfRuntimeObject(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"}
|
||||
embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest")
|
||||
|
||||
s := runtime.NewScheme()
|
||||
s.AddKnownTypes(internalGV, &runtimetesting.EmbeddedTest{})
|
||||
s.AddKnownTypeWithName(embeddedTestExternalGVK, &runtimetesting.EmbeddedTestExternal{})
|
||||
|
||||
original := &runtimetesting.EmbeddedTest{
|
||||
ID: "outer",
|
||||
Object: &runtimetesting.EmbeddedTest{
|
||||
ID: "inner",
|
||||
},
|
||||
}
|
||||
|
||||
codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV)
|
||||
|
||||
originalData, err := runtime.Encode(codec, original)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("originalRole = %v\n", string(originalData))
|
||||
|
||||
copyOfOriginal := original.DeepCopy()
|
||||
copiedData, err := runtime.Encode(codec, copyOfOriginal)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("copyOfRole = %v\n", string(copiedData))
|
||||
|
||||
if !reflect.DeepEqual(original, copyOfOriginal) {
|
||||
t.Errorf("expected \n%v\n, got \n%v", string(originalData), string(copiedData))
|
||||
}
|
||||
}
|
||||
113
vendor/k8s.io/apimachinery/pkg/runtime/extension_test.go
generated
vendored
Normal file
113
vendor/k8s.io/apimachinery/pkg/runtime/extension_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
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 runtime_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestEmbeddedRawExtensionMarshal(t *testing.T) {
|
||||
type test struct {
|
||||
Ext runtime.RawExtension
|
||||
}
|
||||
|
||||
extension := test{Ext: runtime.RawExtension{Raw: []byte(`{"foo":"bar"}`)}}
|
||||
data, err := json.Marshal(extension)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if string(data) != `{"Ext":{"foo":"bar"}}` {
|
||||
t.Errorf("unexpected data: %s", string(data))
|
||||
}
|
||||
}
|
||||
func TestEmbeddedRawExtensionUnmarshal(t *testing.T) {
|
||||
type test struct {
|
||||
Ext runtime.RawExtension
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
orig test
|
||||
}{
|
||||
"non-empty object": {
|
||||
orig: test{Ext: runtime.RawExtension{Raw: []byte(`{"foo":"bar"}`)}},
|
||||
},
|
||||
"empty object": {
|
||||
orig: test{Ext: runtime.RawExtension{}},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testCases {
|
||||
new := test{}
|
||||
data, _ := json.Marshal(tc.orig)
|
||||
if err := json.Unmarshal(data, &new); err != nil {
|
||||
t.Errorf("%s: umarshal error: %v", k, err)
|
||||
}
|
||||
if !reflect.DeepEqual(tc.orig, new) {
|
||||
t.Errorf("%s: unmarshaled struct differs from original: %v %v", k, tc.orig, new)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbeddedRawExtensionRoundTrip(t *testing.T) {
|
||||
type test struct {
|
||||
Ext runtime.RawExtension
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
orig test
|
||||
}{
|
||||
"non-empty object": {
|
||||
orig: test{Ext: runtime.RawExtension{Raw: []byte(`{"foo":"bar"}`)}},
|
||||
},
|
||||
"empty object": {
|
||||
orig: test{Ext: runtime.RawExtension{}},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testCases {
|
||||
new1 := test{}
|
||||
new2 := test{}
|
||||
data, err := json.Marshal(tc.orig)
|
||||
if err != nil {
|
||||
t.Errorf("1st marshal error: %v", err)
|
||||
}
|
||||
if err = json.Unmarshal(data, &new1); err != nil {
|
||||
t.Errorf("1st unmarshal error: %v", err)
|
||||
}
|
||||
newData, err := json.Marshal(new1)
|
||||
if err != nil {
|
||||
t.Errorf("2st marshal error: %v", err)
|
||||
}
|
||||
if err = json.Unmarshal(newData, &new2); err != nil {
|
||||
t.Errorf("2nd unmarshal error: %v", err)
|
||||
}
|
||||
if !bytes.Equal(data, newData) {
|
||||
t.Errorf("%s: re-marshaled data differs from original: %v %v", k, data, newData)
|
||||
}
|
||||
if !reflect.DeepEqual(tc.orig, new1) {
|
||||
t.Errorf("%s: unmarshaled struct differs from original: %v %v", k, tc.orig, new1)
|
||||
}
|
||||
if !reflect.DeepEqual(new1, new2) {
|
||||
t.Errorf("%s: re-unmarshaled struct differs from original: %v %v", k, new1, new2)
|
||||
}
|
||||
}
|
||||
}
|
||||
136
vendor/k8s.io/apimachinery/pkg/runtime/schema/group_version_test.go
generated
vendored
Normal file
136
vendor/k8s.io/apimachinery/pkg/runtime/schema/group_version_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
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 schema
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGroupVersionParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
out GroupVersion
|
||||
err func(error) bool
|
||||
}{
|
||||
{input: "v1", out: GroupVersion{Version: "v1"}},
|
||||
{input: "v2", out: GroupVersion{Version: "v2"}},
|
||||
{input: "/v1", out: GroupVersion{Version: "v1"}},
|
||||
{input: "v1/", out: GroupVersion{Group: "v1"}},
|
||||
{input: "/v1/", err: func(err error) bool { return err.Error() == "unexpected GroupVersion string: /v1/" }},
|
||||
{input: "v1/a", out: GroupVersion{Group: "v1", Version: "a"}},
|
||||
}
|
||||
for i, test := range tests {
|
||||
out, err := ParseGroupVersion(test.input)
|
||||
if test.err == nil && err != nil || err == nil && test.err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if test.err != nil && !test.err(err) {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if out != test.out {
|
||||
t.Errorf("%d: unexpected output: %#v", i, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupResourceParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
out GroupResource
|
||||
}{
|
||||
{input: "v1", out: GroupResource{Resource: "v1"}},
|
||||
{input: ".v1", out: GroupResource{Group: "v1"}},
|
||||
{input: "v1.", out: GroupResource{Resource: "v1"}},
|
||||
{input: "v1.a", out: GroupResource{Group: "a", Resource: "v1"}},
|
||||
{input: "b.v1.a", out: GroupResource{Group: "v1.a", Resource: "b"}},
|
||||
}
|
||||
for i, test := range tests {
|
||||
out := ParseGroupResource(test.input)
|
||||
if out != test.out {
|
||||
t.Errorf("%d: unexpected output: %#v", i, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResourceArg(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
gvr *GroupVersionResource
|
||||
gr GroupResource
|
||||
}{
|
||||
{input: "v1", gr: GroupResource{Resource: "v1"}},
|
||||
{input: ".v1", gr: GroupResource{Group: "v1"}},
|
||||
{input: "v1.", gr: GroupResource{Resource: "v1"}},
|
||||
{input: "v1.a", gr: GroupResource{Group: "a", Resource: "v1"}},
|
||||
{input: "b.v1.a", gvr: &GroupVersionResource{Group: "a", Version: "v1", Resource: "b"}, gr: GroupResource{Group: "v1.a", Resource: "b"}},
|
||||
}
|
||||
for i, test := range tests {
|
||||
gvr, gr := ParseResourceArg(test.input)
|
||||
if (gvr != nil && test.gvr == nil) || (gvr == nil && test.gvr != nil) || (test.gvr != nil && *gvr != *test.gvr) {
|
||||
t.Errorf("%d: unexpected output: %#v", i, gvr)
|
||||
}
|
||||
if gr != test.gr {
|
||||
t.Errorf("%d: unexpected output: %#v", i, gr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKindForGroupVersionKinds(t *testing.T) {
|
||||
gvks := GroupVersions{
|
||||
GroupVersion{Group: "batch", Version: "v1"},
|
||||
GroupVersion{Group: "batch", Version: "v2alpha1"},
|
||||
GroupVersion{Group: "policy", Version: "v1beta1"},
|
||||
}
|
||||
cases := []struct {
|
||||
input []GroupVersionKind
|
||||
target GroupVersionKind
|
||||
ok bool
|
||||
}{
|
||||
{
|
||||
input: []GroupVersionKind{{Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"}},
|
||||
target: GroupVersionKind{Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
input: []GroupVersionKind{{Group: "batch", Version: "v3alpha1", Kind: "CronJob"}},
|
||||
target: GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
input: []GroupVersionKind{{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"}},
|
||||
target: GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
input: []GroupVersionKind{{Group: "apps", Version: "v1alpha1", Kind: "StatefulSet"}},
|
||||
target: GroupVersionKind{},
|
||||
ok: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
target, ok := gvks.KindForGroupVersionKinds(c.input)
|
||||
if c.target != target {
|
||||
t.Errorf("%d: unexpected target: %v, expected %v", i, target, c.target)
|
||||
}
|
||||
if c.ok != ok {
|
||||
t.Errorf("%d: unexpected ok: %v, expected %v", i, ok, c.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
861
vendor/k8s.io/apimachinery/pkg/runtime/scheme_test.go
generated
vendored
Normal file
861
vendor/k8s.io/apimachinery/pkg/runtime/scheme_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,861 @@
|
|||
/*
|
||||
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 runtime_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
runtimetesting "k8s.io/apimachinery/pkg/runtime/testing"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
|
||||
var fuzzIters = flag.Int("fuzz-iters", 50, "How many fuzzing iterations to do.")
|
||||
|
||||
func TestScheme(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{})
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
|
||||
|
||||
// If set, would clear TypeMeta during conversion.
|
||||
//scheme.AddIgnoredConversionType(&TypeMeta{}, &TypeMeta{})
|
||||
|
||||
// test that scheme is an ObjectTyper
|
||||
var _ runtime.ObjectTyper = scheme
|
||||
|
||||
internalToExternalCalls := 0
|
||||
externalToInternalCalls := 0
|
||||
|
||||
// Register functions to verify that scope.Meta() gets set correctly.
|
||||
err := scheme.AddConversionFuncs(
|
||||
func(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error {
|
||||
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
internalToExternalCalls++
|
||||
return nil
|
||||
},
|
||||
func(in *runtimetesting.ExternalSimple, out *runtimetesting.InternalSimple, scope conversion.Scope) error {
|
||||
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
externalToInternalCalls++
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
codec := codecs.LegacyCodec(externalGV)
|
||||
info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
jsonserializer := info.Serializer
|
||||
|
||||
simple := &runtimetesting.InternalSimple{
|
||||
TestString: "foo",
|
||||
}
|
||||
|
||||
// Test Encode, Decode, DecodeInto, and DecodeToVersion
|
||||
obj := runtime.Object(simple)
|
||||
data, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
obj2, err := runtime.Decode(codec, data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := obj2.(*runtimetesting.InternalSimple); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if e, a := simple, obj2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
|
||||
}
|
||||
|
||||
obj3 := &runtimetesting.InternalSimple{}
|
||||
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// clearing TypeMeta is a function of the scheme, which we do not test here (ConvertToVersion
|
||||
// does not automatically clear TypeMeta anymore).
|
||||
simple.TypeMeta = runtime.TypeMeta{Kind: "Simple", APIVersion: externalGV.String()}
|
||||
if e, a := simple, obj3; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
|
||||
}
|
||||
|
||||
obj4, err := runtime.Decode(jsonserializer, data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := obj4.(*runtimetesting.ExternalSimple); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
|
||||
// Test Convert
|
||||
external := &runtimetesting.ExternalSimple{}
|
||||
err = scheme.Convert(simple, external, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if e, a := simple.TestString, external.TestString; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
// Encode and Convert should each have caused an increment.
|
||||
if e, a := 2, internalToExternalCalls; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
// DecodeInto and Decode should each have caused an increment because of a conversion
|
||||
if e, a := 2, externalToInternalCalls; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadJSONRejection(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
jsonserializer := info.Serializer
|
||||
|
||||
badJSONMissingKind := []byte(`{ }`)
|
||||
if _, err := runtime.Decode(jsonserializer, badJSONMissingKind); err == nil {
|
||||
t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
|
||||
}
|
||||
badJSONUnknownType := []byte(`{"kind": "bar"}`)
|
||||
if _, err1 := runtime.Decode(jsonserializer, badJSONUnknownType); err1 == nil {
|
||||
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
|
||||
}
|
||||
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
|
||||
if err2 := DecodeInto(badJSONKindMismatch, &Node{}); err2 == nil {
|
||||
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
|
||||
}*/
|
||||
}
|
||||
|
||||
func TestExternalToInternalMapping(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &runtimetesting.InternalOptionalExtensionType{})
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &runtimetesting.ExternalOptionalExtensionType{})
|
||||
|
||||
codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
|
||||
|
||||
table := []struct {
|
||||
obj runtime.Object
|
||||
encoded string
|
||||
}{
|
||||
{
|
||||
&runtimetesting.InternalOptionalExtensionType{Extension: nil},
|
||||
`{"kind":"OptionalExtensionType","apiVersion":"` + externalGV.String() + `"}`,
|
||||
},
|
||||
}
|
||||
|
||||
for i, item := range table {
|
||||
gotDecoded, err := runtime.Decode(codec, []byte(item.encoded))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error '%v' (%v)", err, item.encoded)
|
||||
} else if e, a := item.obj, gotDecoded; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtensionMapping(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("ExtensionType"), &runtimetesting.InternalExtensionType{})
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &runtimetesting.InternalOptionalExtensionType{})
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("ExtensionType"), &runtimetesting.ExternalExtensionType{})
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &runtimetesting.ExternalOptionalExtensionType{})
|
||||
|
||||
// register external first when the object is the same in both schemes, so ObjectVersionAndKind reports the
|
||||
// external version.
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("A"), &runtimetesting.ExtensionA{})
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("B"), &runtimetesting.ExtensionB{})
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("A"), &runtimetesting.ExtensionA{})
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("B"), &runtimetesting.ExtensionB{})
|
||||
|
||||
codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
|
||||
|
||||
table := []struct {
|
||||
obj runtime.Object
|
||||
expected runtime.Object
|
||||
encoded string
|
||||
}{
|
||||
{
|
||||
&runtimetesting.InternalExtensionType{
|
||||
Extension: runtime.NewEncodable(codec, &runtimetesting.ExtensionA{TestString: "foo"}),
|
||||
},
|
||||
&runtimetesting.InternalExtensionType{
|
||||
Extension: &runtime.Unknown{
|
||||
Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
},
|
||||
},
|
||||
// apiVersion is set in the serialized object for easier consumption by clients
|
||||
`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}}
|
||||
`,
|
||||
}, {
|
||||
&runtimetesting.InternalExtensionType{Extension: runtime.NewEncodable(codec, &runtimetesting.ExtensionB{TestString: "bar"})},
|
||||
&runtimetesting.InternalExtensionType{
|
||||
Extension: &runtime.Unknown{
|
||||
Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
},
|
||||
},
|
||||
// apiVersion is set in the serialized object for easier consumption by clients
|
||||
`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}}
|
||||
`,
|
||||
}, {
|
||||
&runtimetesting.InternalExtensionType{Extension: nil},
|
||||
&runtimetesting.InternalExtensionType{
|
||||
Extension: nil,
|
||||
},
|
||||
`{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":null}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for i, item := range table {
|
||||
gotEncoded, err := runtime.Encode(codec, item.obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error '%v' (%#v)", err, item.obj)
|
||||
} else if e, a := item.encoded, string(gotEncoded); e != a {
|
||||
t.Errorf("expected\n%#v\ngot\n%#v\n", e, a)
|
||||
}
|
||||
|
||||
gotDecoded, err := runtime.Decode(codec, []byte(item.encoded))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error '%v' (%v)", err, item.encoded)
|
||||
} else if e, a := item.expected, gotDecoded; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{})
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
|
||||
|
||||
codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
|
||||
|
||||
test := &runtimetesting.InternalSimple{
|
||||
TestString: "I'm the same",
|
||||
}
|
||||
obj := runtime.Object(test)
|
||||
data, err := runtime.Encode(codec, obj)
|
||||
obj2, gvk, err2 := codec.Decode(data, nil, nil)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'", err, err2)
|
||||
}
|
||||
if _, ok := obj2.(*runtimetesting.InternalSimple); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if !reflect.DeepEqual(obj2, test) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2)
|
||||
}
|
||||
if !reflect.DeepEqual(gvk, &schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) {
|
||||
t.Errorf("unexpected gvk returned by decode: %#v", gvk)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnversionedTypes(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"}
|
||||
otherGV := schema.GroupVersion{Group: "group", Version: "other"}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddUnversionedTypes(externalGV, &runtimetesting.InternalSimple{})
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{})
|
||||
scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
|
||||
scheme.AddKnownTypeWithName(otherGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
|
||||
|
||||
codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV)
|
||||
|
||||
if unv, ok := scheme.IsUnversioned(&runtimetesting.InternalSimple{}); !unv || !ok {
|
||||
t.Fatalf("type not unversioned and in scheme: %t %t", unv, ok)
|
||||
}
|
||||
|
||||
kinds, _, err := scheme.ObjectKinds(&runtimetesting.InternalSimple{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
kind := kinds[0]
|
||||
if kind != externalGV.WithKind("InternalSimple") {
|
||||
t.Fatalf("unexpected: %#v", kind)
|
||||
}
|
||||
|
||||
test := &runtimetesting.InternalSimple{
|
||||
TestString: "I'm the same",
|
||||
}
|
||||
obj := runtime.Object(test)
|
||||
data, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
obj2, gvk, err := codec.Decode(data, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := obj2.(*runtimetesting.InternalSimple); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if !reflect.DeepEqual(obj2, test) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2)
|
||||
}
|
||||
// object is serialized as an unversioned object (in the group and version it was defined in)
|
||||
if !reflect.DeepEqual(gvk, &schema.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "InternalSimple"}) {
|
||||
t.Errorf("unexpected gvk returned by decode: %#v", gvk)
|
||||
}
|
||||
|
||||
// when serialized to a different group, the object is kept in its preferred name
|
||||
codec = serializer.NewCodecFactory(scheme).LegacyCodec(otherGV)
|
||||
data, err = runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(data) != `{"apiVersion":"test.group/testExternal","kind":"InternalSimple","testString":"I'm the same"}`+"\n" {
|
||||
t.Errorf("unexpected data: %s", data)
|
||||
}
|
||||
}
|
||||
|
||||
// TestObjectFuzzer can randomly populate all the above objects.
|
||||
var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs(
|
||||
func(j *runtimetesting.MyWeirdCustomEmbeddedVersionKindField, c fuzz.Continue) {
|
||||
// We have to customize the randomization of MyWeirdCustomEmbeddedVersionKindFields because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.ObjectKind = ""
|
||||
j.ID = c.RandString()
|
||||
},
|
||||
)
|
||||
|
||||
// Returns a new Scheme set up with the test objects.
|
||||
func GetTestScheme() *runtime.Scheme {
|
||||
internalGV := schema.GroupVersion{Version: "__internal"}
|
||||
externalGV := schema.GroupVersion{Version: "v1"}
|
||||
alternateExternalGV := schema.GroupVersion{Group: "custom", Version: "v1"}
|
||||
differentExternalGV := schema.GroupVersion{Group: "other", Version: "v2"}
|
||||
|
||||
s := runtime.NewScheme()
|
||||
// Ordinarily, we wouldn't add TestType2, but because this is a test and
|
||||
// both types are from the same package, we need to get it into the system
|
||||
// so that converter will match it with ExternalType2.
|
||||
s.AddKnownTypes(internalGV, &runtimetesting.TestType1{}, &runtimetesting.TestType2{}, &runtimetesting.ExternalInternalSame{})
|
||||
s.AddKnownTypes(externalGV, &runtimetesting.ExternalInternalSame{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("TestType2"), &runtimetesting.ExternalTestType2{})
|
||||
s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &runtimetesting.TestType1{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &runtimetesting.ExternalTestType1{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("TestType4"), &runtimetesting.ExternalTestType1{})
|
||||
s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType3"), &runtimetesting.ExternalTestType1{})
|
||||
s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType5"), &runtimetesting.ExternalTestType1{})
|
||||
s.AddKnownTypeWithName(differentExternalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{})
|
||||
s.AddUnversionedTypes(externalGV, &runtimetesting.UnversionedType{})
|
||||
return s
|
||||
}
|
||||
|
||||
func TestKnownTypes(t *testing.T) {
|
||||
s := GetTestScheme()
|
||||
if len(s.KnownTypes(schema.GroupVersion{Group: "group", Version: "v2"})) != 0 {
|
||||
t.Errorf("should have no known types for v2")
|
||||
}
|
||||
|
||||
types := s.KnownTypes(schema.GroupVersion{Version: "v1"})
|
||||
for _, s := range []string{"TestType1", "TestType2", "TestType3", "ExternalInternalSame"} {
|
||||
if _, ok := types[s]; !ok {
|
||||
t.Errorf("missing type %q", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddKnownTypesIdemPotent(t *testing.T) {
|
||||
s := runtime.NewScheme()
|
||||
|
||||
gv := schema.GroupVersion{Group: "foo", Version: "v1"}
|
||||
s.AddKnownTypes(gv, &runtimetesting.InternalSimple{})
|
||||
s.AddKnownTypes(gv, &runtimetesting.InternalSimple{})
|
||||
if len(s.KnownTypes(gv)) != 1 {
|
||||
t.Errorf("expected only one %v type after double registration", gv)
|
||||
}
|
||||
if len(s.AllKnownTypes()) != 1 {
|
||||
t.Errorf("expected only one type after double registration")
|
||||
}
|
||||
|
||||
s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{})
|
||||
s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{})
|
||||
if len(s.KnownTypes(gv)) != 1 {
|
||||
t.Errorf("expected only one %v type after double registration with custom name", gv)
|
||||
}
|
||||
if len(s.AllKnownTypes()) != 1 {
|
||||
t.Errorf("expected only one type after double registration with custom name")
|
||||
}
|
||||
|
||||
s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{})
|
||||
s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{})
|
||||
if len(s.KnownTypes(gv)) != 1 {
|
||||
t.Errorf("expected only one %v type after double registration with custom name", gv)
|
||||
}
|
||||
if len(s.AllKnownTypes()) != 1 {
|
||||
t.Errorf("expected only one type after double registration with custom name")
|
||||
}
|
||||
|
||||
kinds, _, err := s.ObjectKinds(&runtimetesting.InternalSimple{})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(kinds) != 1 {
|
||||
t.Errorf("expected only one kind for InternalSimple after double registration")
|
||||
}
|
||||
}
|
||||
|
||||
// redefine InternalSimple with the same name, but obviously as a different type than in runtimetesting
|
||||
type InternalSimple struct {
|
||||
runtime.TypeMeta `json:",inline"`
|
||||
TestString string `json:"testString"`
|
||||
}
|
||||
|
||||
func (s *InternalSimple) DeepCopyObject() runtime.Object { return nil }
|
||||
|
||||
func TestConflictingAddKnownTypes(t *testing.T) {
|
||||
s := runtime.NewScheme()
|
||||
gv := schema.GroupVersion{Group: "foo", Version: "v1"}
|
||||
|
||||
panicked := make(chan bool)
|
||||
go func() {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
panicked <- true
|
||||
}
|
||||
}()
|
||||
s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{})
|
||||
s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.ExternalSimple{})
|
||||
panicked <- false
|
||||
}()
|
||||
if !<-panicked {
|
||||
t.Errorf("Expected AddKnownTypesWithName to panic with conflicting type registrations")
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
panicked <- true
|
||||
}
|
||||
}()
|
||||
|
||||
s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{})
|
||||
s.AddUnversionedTypes(gv, &InternalSimple{})
|
||||
panicked <- false
|
||||
}()
|
||||
if !<-panicked {
|
||||
t.Errorf("Expected AddUnversionedTypes to panic with conflicting type registrations")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToVersionBasic(t *testing.T) {
|
||||
s := GetTestScheme()
|
||||
tt := &runtimetesting.TestType1{A: "I'm not a pointer object"}
|
||||
other, err := s.ConvertToVersion(tt, schema.GroupVersion{Version: "v1"})
|
||||
if err != nil {
|
||||
t.Fatalf("Failure: %v", err)
|
||||
}
|
||||
converted, ok := other.(*runtimetesting.ExternalTestType1)
|
||||
if !ok {
|
||||
t.Fatalf("Got wrong type: %T", other)
|
||||
}
|
||||
if tt.A != converted.A {
|
||||
t.Fatalf("Failed to convert object correctly: %#v", converted)
|
||||
}
|
||||
}
|
||||
|
||||
type testGroupVersioner struct {
|
||||
target schema.GroupVersionKind
|
||||
ok bool
|
||||
}
|
||||
|
||||
func (m testGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersionKind) (schema.GroupVersionKind, bool) {
|
||||
return m.target, m.ok
|
||||
}
|
||||
|
||||
func TestConvertToVersion(t *testing.T) {
|
||||
testCases := []struct {
|
||||
scheme *runtime.Scheme
|
||||
in runtime.Object
|
||||
gv runtime.GroupVersioner
|
||||
same bool
|
||||
out runtime.Object
|
||||
errFn func(error) bool
|
||||
}{
|
||||
// errors if the type is not registered in the scheme
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.UnknownType{},
|
||||
errFn: func(err error) bool { return err != nil && runtime.IsNotRegisteredError(err) },
|
||||
},
|
||||
// errors if the group versioner returns no target
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: testGroupVersioner{},
|
||||
errFn: func(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "is not suitable for converting")
|
||||
},
|
||||
},
|
||||
// converts to internal
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: schema.GroupVersion{Version: "__internal"},
|
||||
out: &runtimetesting.TestType1{A: "test"},
|
||||
},
|
||||
// prefers the best match
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: schema.GroupVersions{{Version: "__internal"}, {Version: "v1"}},
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// unversioned type returned as-is
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.UnversionedType{A: "test"},
|
||||
gv: schema.GroupVersions{{Version: "v1"}},
|
||||
same: true,
|
||||
out: &runtimetesting.UnversionedType{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// unversioned type returned when not included in the target types
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.UnversionedType{A: "test"},
|
||||
gv: schema.GroupVersions{{Group: "other", Version: "v2"}},
|
||||
same: true,
|
||||
out: &runtimetesting.UnversionedType{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// detected as already being in the target version
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: schema.GroupVersions{{Version: "v1"}},
|
||||
same: true,
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// detected as already being in the first target version
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: schema.GroupVersions{{Version: "v1"}, {Version: "__internal"}},
|
||||
same: true,
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// detected as already being in the first target version
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: schema.GroupVersions{{Version: "v1"}, {Version: "__internal"}},
|
||||
same: true,
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (1/3): different kind
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType3", Version: "v1"}},
|
||||
same: true,
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (2/3): different gv
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType3", Group: "custom", Version: "v1"}},
|
||||
same: true,
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType3"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (3/3): different gvk
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Group: "custom", Version: "v1", Kind: "TestType5"}},
|
||||
same: true,
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "other", Version: "v2"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}, schema.GroupKind{Kind: "TestType1"}),
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "other", Version: "v2"}, schema.GroupKind{Kind: "TestType1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}),
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// multi group versioner is unable to find a match when kind AND group don't match (there is no TestType1 kind in group "other", and no kind "TestType5" in the default group)
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.TestType1{A: "test"},
|
||||
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "custom", Version: "v1"}, schema.GroupKind{Group: "other"}, schema.GroupKind{Kind: "TestType5"}),
|
||||
errFn: func(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), "is not suitable for converting")
|
||||
},
|
||||
},
|
||||
// multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "", Version: "v1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}, schema.GroupKind{Kind: "TestType1"}),
|
||||
same: true,
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.ExternalTestType1{A: "test"},
|
||||
gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "", Version: "v1"}, schema.GroupKind{Kind: "TestType1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}),
|
||||
same: true,
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// group versioner can choose a particular target kind for a given input when kind is the same across group versions
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.TestType1{A: "test"},
|
||||
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Version: "v1", Kind: "TestType3"}},
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
// group versioner can choose a different kind
|
||||
{
|
||||
scheme: GetTestScheme(),
|
||||
in: &runtimetesting.TestType1{A: "test"},
|
||||
gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType5", Group: "custom", Version: "v1"}},
|
||||
out: &runtimetesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"},
|
||||
A: "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, test := range testCases {
|
||||
original := test.in.DeepCopyObject()
|
||||
out, err := test.scheme.ConvertToVersion(test.in, test.gv)
|
||||
switch {
|
||||
case test.errFn != nil:
|
||||
if !test.errFn(err) {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
}
|
||||
continue
|
||||
case err != nil:
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if out == test.in {
|
||||
t.Errorf("%d: ConvertToVersion should always copy out: %#v", i, out)
|
||||
continue
|
||||
}
|
||||
|
||||
if test.same {
|
||||
if !reflect.DeepEqual(original, test.in) {
|
||||
t.Errorf("%d: unexpected mutation of input: %s", i, diff.ObjectReflectDiff(original, test.in))
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(out, test.out) {
|
||||
t.Errorf("%d: unexpected out: %s", i, diff.ObjectReflectDiff(out, test.out))
|
||||
continue
|
||||
}
|
||||
unsafe, err := test.scheme.UnsafeConvertToVersion(test.in, test.gv)
|
||||
if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(unsafe, test.out) {
|
||||
t.Errorf("%d: unexpected unsafe: %s", i, diff.ObjectReflectDiff(unsafe, test.out))
|
||||
continue
|
||||
}
|
||||
if unsafe != test.in {
|
||||
t.Errorf("%d: UnsafeConvertToVersion should return same object: %#v", i, unsafe)
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(out, test.out) {
|
||||
t.Errorf("%d: unexpected out: %s", i, diff.ObjectReflectDiff(out, test.out))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetaValues(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Group: "test.group", Version: "__internal"}
|
||||
externalGV := schema.GroupVersion{Group: "test.group", Version: "externalVersion"}
|
||||
|
||||
s := runtime.NewScheme()
|
||||
s.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{})
|
||||
|
||||
internalToExternalCalls := 0
|
||||
externalToInternalCalls := 0
|
||||
|
||||
// Register functions to verify that scope.Meta() gets set correctly.
|
||||
err := s.AddConversionFuncs(
|
||||
func(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error {
|
||||
t.Logf("internal -> external")
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
internalToExternalCalls++
|
||||
return nil
|
||||
},
|
||||
func(in *runtimetesting.ExternalSimple, out *runtimetesting.InternalSimple, scope conversion.Scope) error {
|
||||
t.Logf("external -> internal")
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
externalToInternalCalls++
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
simple := &runtimetesting.InternalSimple{
|
||||
TestString: "foo",
|
||||
}
|
||||
|
||||
s.Log(t)
|
||||
|
||||
out, err := s.ConvertToVersion(simple, externalGV)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
internal, err := s.ConvertToVersion(out, internalGV)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if e, a := simple, internal; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a)
|
||||
}
|
||||
|
||||
if e, a := 1, internalToExternalCalls; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := 1, externalToInternalCalls; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetaValuesUnregisteredConvert(t *testing.T) {
|
||||
type InternalSimple struct {
|
||||
Version string `json:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
TestString string `json:"testString"`
|
||||
}
|
||||
type ExternalSimple struct {
|
||||
Version string `json:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
TestString string `json:"testString"`
|
||||
}
|
||||
s := runtime.NewScheme()
|
||||
// We deliberately don't register the types.
|
||||
|
||||
internalToExternalCalls := 0
|
||||
|
||||
// Register functions to verify that scope.Meta() gets set correctly.
|
||||
err := s.AddConversionFuncs(
|
||||
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
|
||||
scope.Convert(&in.TestString, &out.TestString, 0)
|
||||
internalToExternalCalls++
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
simple := &InternalSimple{TestString: "foo"}
|
||||
external := &ExternalSimple{}
|
||||
err = s.Convert(simple, external, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if e, a := simple.TestString, external.TestString; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
// Verify that our conversion handler got called.
|
||||
if e, a := 1, internalToExternalCalls; e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
339
vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_test.go
generated
vendored
Normal file
339
vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
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 serializer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializertesting "k8s.io/apimachinery/pkg/runtime/serializer/testing"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/google/gofuzz"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var fuzzIters = flag.Int("fuzz-iters", 50, "How many fuzzing iterations to do.")
|
||||
|
||||
type testMetaFactory struct{}
|
||||
|
||||
func (testMetaFactory) Interpret(data []byte) (*schema.GroupVersionKind, error) {
|
||||
findKind := struct {
|
||||
APIVersion string `json:"myVersionKey,omitempty"`
|
||||
ObjectKind string `json:"myKindKey,omitempty"`
|
||||
}{}
|
||||
// yaml is a superset of json, so we use it to decode here. That way,
|
||||
// we understand both.
|
||||
if err := yaml.Unmarshal(data, &findKind); err != nil {
|
||||
return nil, fmt.Errorf("couldn't get version/kind: %v", err)
|
||||
}
|
||||
gv, err := schema.ParseGroupVersion(findKind.APIVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: findKind.ObjectKind}, nil
|
||||
}
|
||||
|
||||
// TestObjectFuzzer can randomly populate all the above objects.
|
||||
var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs(
|
||||
func(j *serializertesting.MyWeirdCustomEmbeddedVersionKindField, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j)
|
||||
j.APIVersion = ""
|
||||
j.ObjectKind = ""
|
||||
},
|
||||
)
|
||||
|
||||
// Returns a new Scheme set up with the test objects.
|
||||
func GetTestScheme() (*runtime.Scheme, runtime.Codec) {
|
||||
internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Version: "v1"}
|
||||
externalGV2 := schema.GroupVersion{Version: "v2"}
|
||||
|
||||
s := runtime.NewScheme()
|
||||
// Ordinarily, we wouldn't add TestType2, but because this is a test and
|
||||
// both types are from the same package, we need to get it into the system
|
||||
// so that converter will match it with ExternalType2.
|
||||
s.AddKnownTypes(internalGV, &serializertesting.TestType1{}, &serializertesting.TestType2{}, &serializertesting.ExternalInternalSame{})
|
||||
s.AddKnownTypes(externalGV, &serializertesting.ExternalInternalSame{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &serializertesting.ExternalTestType1{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("TestType2"), &serializertesting.ExternalTestType2{})
|
||||
s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &serializertesting.TestType1{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &serializertesting.ExternalTestType1{})
|
||||
s.AddKnownTypeWithName(externalGV2.WithKind("TestType1"), &serializertesting.ExternalTestType1{})
|
||||
|
||||
s.AddUnversionedTypes(externalGV, &metav1.Status{})
|
||||
|
||||
cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{}))
|
||||
codec := cf.LegacyCodec(schema.GroupVersion{Version: "v1"})
|
||||
return s, codec
|
||||
}
|
||||
|
||||
var semantic = conversion.EqualitiesOrDie(
|
||||
func(a, b serializertesting.MyWeirdCustomEmbeddedVersionKindField) bool {
|
||||
a.APIVersion, a.ObjectKind = "", ""
|
||||
b.APIVersion, b.ObjectKind = "", ""
|
||||
return a == b
|
||||
},
|
||||
)
|
||||
|
||||
func runTest(t *testing.T, source interface{}) {
|
||||
name := reflect.TypeOf(source).Elem().Name()
|
||||
TestObjectFuzzer.Fuzz(source)
|
||||
|
||||
_, codec := GetTestScheme()
|
||||
data, err := runtime.Encode(codec, source.(runtime.Object))
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v (%#v)", name, err, source)
|
||||
return
|
||||
}
|
||||
obj2, err := runtime.Decode(codec, data)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v (%v)", name, err, string(data))
|
||||
return
|
||||
}
|
||||
if !semantic.DeepEqual(source, obj2) {
|
||||
t.Errorf("1: %v: diff: %v", name, diff.ObjectGoPrintSideBySide(source, obj2))
|
||||
return
|
||||
}
|
||||
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface()
|
||||
if err := runtime.DecodeInto(codec, data, obj3.(runtime.Object)); err != nil {
|
||||
t.Errorf("2: %v: %v", name, err)
|
||||
return
|
||||
}
|
||||
if !semantic.DeepEqual(source, obj3) {
|
||||
t.Errorf("3: %v: diff: %v", name, diff.ObjectDiff(source, obj3))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypes(t *testing.T) {
|
||||
table := []interface{}{
|
||||
&serializertesting.TestType1{},
|
||||
&serializertesting.ExternalInternalSame{},
|
||||
}
|
||||
for _, item := range table {
|
||||
// Try a few times, since runTest uses random values.
|
||||
for i := 0; i < *fuzzIters; i++ {
|
||||
runTest(t, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionedEncoding(t *testing.T) {
|
||||
s, _ := GetTestScheme()
|
||||
cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{}))
|
||||
info, _ := runtime.SerializerInfoForMediaType(cf.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
encoder := info.Serializer
|
||||
|
||||
codec := cf.CodecForVersions(encoder, nil, schema.GroupVersion{Version: "v2"}, nil)
|
||||
out, err := runtime.Encode(codec, &serializertesting.TestType1{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(out) != `{"myVersionKey":"v2","myKindKey":"TestType1"}`+"\n" {
|
||||
t.Fatal(string(out))
|
||||
}
|
||||
|
||||
codec = cf.CodecForVersions(encoder, nil, schema.GroupVersion{Version: "v3"}, nil)
|
||||
_, err = runtime.Encode(codec, &serializertesting.TestType1{})
|
||||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// unversioned encode with no versions is written directly to wire
|
||||
codec = cf.CodecForVersions(encoder, nil, runtime.InternalGroupVersioner, nil)
|
||||
out, err = runtime.Encode(codec, &serializertesting.TestType1{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(out) != `{}`+"\n" {
|
||||
t.Fatal(string(out))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleNames(t *testing.T) {
|
||||
_, codec := GetTestScheme()
|
||||
|
||||
obj, _, err := codec.Decode([]byte(`{"myKindKey":"TestType3","myVersionKey":"v1","A":"value"}`), nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
internal := obj.(*serializertesting.TestType1)
|
||||
if internal.A != "value" {
|
||||
t.Fatalf("unexpected decoded object: %#v", internal)
|
||||
}
|
||||
|
||||
out, err := runtime.Encode(codec, internal)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(out), `"myKindKey":"TestType1"`) {
|
||||
t.Errorf("unexpected encoded output: %s", string(out))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertTypesWhenDefaultNamesMatch(t *testing.T) {
|
||||
internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Version: "v1"}
|
||||
|
||||
s := runtime.NewScheme()
|
||||
// create two names internally, with TestType1 being preferred
|
||||
s.AddKnownTypeWithName(internalGV.WithKind("TestType1"), &serializertesting.TestType1{})
|
||||
s.AddKnownTypeWithName(internalGV.WithKind("OtherType1"), &serializertesting.TestType1{})
|
||||
// create two names externally, with TestType1 being preferred
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &serializertesting.ExternalTestType1{})
|
||||
s.AddKnownTypeWithName(externalGV.WithKind("OtherType1"), &serializertesting.ExternalTestType1{})
|
||||
|
||||
ext := &serializertesting.ExternalTestType1{}
|
||||
ext.APIVersion = "v1"
|
||||
ext.ObjectKind = "OtherType1"
|
||||
ext.A = "test"
|
||||
data, err := json.Marshal(ext)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expect := &serializertesting.TestType1{A: "test"}
|
||||
|
||||
codec := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{})).LegacyCodec(schema.GroupVersion{Version: "v1"})
|
||||
|
||||
obj, err := runtime.Decode(codec, data)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !semantic.DeepEqual(expect, obj) {
|
||||
t.Errorf("unexpected object: %#v", obj)
|
||||
}
|
||||
|
||||
into := &serializertesting.TestType1{}
|
||||
if err := runtime.DecodeInto(codec, data, into); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !semantic.DeepEqual(expect, into) {
|
||||
t.Errorf("unexpected object: %#v", obj)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncode_Ptr(t *testing.T) {
|
||||
_, codec := GetTestScheme()
|
||||
tt := &serializertesting.TestType1{A: "I am a pointer object"}
|
||||
data, err := runtime.Encode(codec, tt)
|
||||
obj2, err2 := runtime.Decode(codec, data)
|
||||
if err != nil || err2 != nil {
|
||||
t.Fatalf("Failure: '%v' '%v'\n%s", err, err2, data)
|
||||
}
|
||||
if _, ok := obj2.(*serializertesting.TestType1); !ok {
|
||||
t.Fatalf("Got wrong type")
|
||||
}
|
||||
if !semantic.DeepEqual(obj2, tt) {
|
||||
t.Errorf("Expected:\n %#v,\n Got:\n %#v", tt, obj2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadJSONRejection(t *testing.T) {
|
||||
log.SetOutput(os.Stderr)
|
||||
_, codec := GetTestScheme()
|
||||
badJSONs := [][]byte{
|
||||
[]byte(`{"myVersionKey":"v1"}`), // Missing kind
|
||||
[]byte(`{"myVersionKey":"v1","myKindKey":"bar"}`), // Unknown kind
|
||||
[]byte(`{"myVersionKey":"bar","myKindKey":"TestType1"}`), // Unknown version
|
||||
[]byte(`{"myKindKey":"TestType1"}`), // Missing version
|
||||
}
|
||||
for _, b := range badJSONs {
|
||||
if _, err := runtime.Decode(codec, b); err == nil {
|
||||
t.Errorf("Did not reject bad json: %s", string(b))
|
||||
}
|
||||
}
|
||||
badJSONKindMismatch := []byte(`{"myVersionKey":"v1","myKindKey":"ExternalInternalSame"}`)
|
||||
if err := runtime.DecodeInto(codec, badJSONKindMismatch, &serializertesting.TestType1{}); err == nil {
|
||||
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
|
||||
}
|
||||
if err := runtime.DecodeInto(codec, []byte(``), &serializertesting.TestType1{}); err != nil {
|
||||
t.Errorf("Should allow empty decode: %v", err)
|
||||
}
|
||||
if _, _, err := codec.Decode([]byte(``), &schema.GroupVersionKind{Kind: "ExternalInternalSame"}, nil); err == nil {
|
||||
t.Errorf("Did not give error for empty data with only kind default")
|
||||
}
|
||||
if _, _, err := codec.Decode([]byte(`{"myVersionKey":"v1"}`), &schema.GroupVersionKind{Kind: "ExternalInternalSame"}, nil); err != nil {
|
||||
t.Errorf("Gave error for version and kind default")
|
||||
}
|
||||
if _, _, err := codec.Decode([]byte(`{"myKindKey":"ExternalInternalSame"}`), &schema.GroupVersionKind{Version: "v1"}, nil); err != nil {
|
||||
t.Errorf("Gave error for version and kind default")
|
||||
}
|
||||
if _, _, err := codec.Decode([]byte(``), &schema.GroupVersionKind{Kind: "ExternalInternalSame", Version: "v1"}, nil); err != nil {
|
||||
t.Errorf("Gave error for version and kind defaulted: %v", err)
|
||||
}
|
||||
if _, err := runtime.Decode(codec, []byte(``)); err == nil {
|
||||
t.Errorf("Did not give error for empty data")
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a new Scheme set up with the test objects needed by TestDirectCodec.
|
||||
func GetDirectCodecTestScheme() *runtime.Scheme {
|
||||
internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal}
|
||||
externalGV := schema.GroupVersion{Version: "v1"}
|
||||
|
||||
s := runtime.NewScheme()
|
||||
// Ordinarily, we wouldn't add TestType2, but because this is a test and
|
||||
// both types are from the same package, we need to get it into the system
|
||||
// so that converter will match it with ExternalType2.
|
||||
s.AddKnownTypes(internalGV, &serializertesting.TestType1{})
|
||||
s.AddKnownTypes(externalGV, &serializertesting.ExternalTestType1{})
|
||||
|
||||
s.AddUnversionedTypes(externalGV, &metav1.Status{})
|
||||
return s
|
||||
}
|
||||
|
||||
func TestDirectCodec(t *testing.T) {
|
||||
s := GetDirectCodecTestScheme()
|
||||
cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{}))
|
||||
info, _ := runtime.SerializerInfoForMediaType(cf.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
serializer := info.Serializer
|
||||
df := DirectCodecFactory{cf}
|
||||
ignoredGV, err := schema.ParseGroupVersion("ignored group/ignored version")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
directEncoder := df.EncoderForVersion(serializer, ignoredGV)
|
||||
directDecoder := df.DecoderToVersion(serializer, ignoredGV)
|
||||
out, err := runtime.Encode(directEncoder, &serializertesting.ExternalTestType1{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(out) != `{"myVersionKey":"v1","myKindKey":"ExternalTestType1"}`+"\n" {
|
||||
t.Fatal(string(out))
|
||||
}
|
||||
a, _, err := directDecoder.Decode(out, nil, nil)
|
||||
e := &serializertesting.ExternalTestType1{
|
||||
MyWeirdCustomEmbeddedVersionKindField: serializertesting.MyWeirdCustomEmbeddedVersionKindField{
|
||||
APIVersion: "v1",
|
||||
ObjectKind: "ExternalTestType1",
|
||||
},
|
||||
}
|
||||
if !semantic.DeepEqual(e, a) {
|
||||
t.Fatalf("expect %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
267
vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json_test.go
generated
vendored
Normal file
267
vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
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 json_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
|
||||
type testDecodable struct {
|
||||
Other string
|
||||
Value int `json:"value"`
|
||||
gvk schema.GroupVersionKind
|
||||
}
|
||||
|
||||
func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d }
|
||||
func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
|
||||
func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk }
|
||||
func (d *testDecodable) DeepCopyObject() runtime.Object {
|
||||
panic("testDecodable does not support DeepCopy")
|
||||
}
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
testCases := []struct {
|
||||
creater runtime.ObjectCreater
|
||||
typer runtime.ObjectTyper
|
||||
yaml bool
|
||||
pretty bool
|
||||
|
||||
data []byte
|
||||
defaultGVK *schema.GroupVersionKind
|
||||
into runtime.Object
|
||||
|
||||
errFn func(error) bool
|
||||
expectedObject runtime.Object
|
||||
expectedGVK *schema.GroupVersionKind
|
||||
}{
|
||||
{
|
||||
data: []byte("{}"),
|
||||
|
||||
expectedGVK: &schema.GroupVersionKind{},
|
||||
errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'Kind' is missing in") },
|
||||
},
|
||||
{
|
||||
data: []byte("{}"),
|
||||
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{err: fmt.Errorf("fake error")},
|
||||
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
errFn: func(err error) bool { return err.Error() == "fake error" },
|
||||
},
|
||||
{
|
||||
data: []byte("{}"),
|
||||
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
},
|
||||
|
||||
// version without group is not defaulted
|
||||
{
|
||||
data: []byte(`{"apiVersion":"blah"}`),
|
||||
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"},
|
||||
},
|
||||
// group without version is defaulted
|
||||
{
|
||||
data: []byte(`{"apiVersion":"other/"}`),
|
||||
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
expectedObject: &testDecodable{},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
},
|
||||
|
||||
// accept runtime.Unknown as into and bypass creator
|
||||
{
|
||||
data: []byte(`{}`),
|
||||
into: &runtime.Unknown{},
|
||||
|
||||
expectedGVK: &schema.GroupVersionKind{},
|
||||
expectedObject: &runtime.Unknown{
|
||||
Raw: []byte(`{}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
},
|
||||
},
|
||||
{
|
||||
data: []byte(`{"test":"object"}`),
|
||||
into: &runtime.Unknown{},
|
||||
|
||||
expectedGVK: &schema.GroupVersionKind{},
|
||||
expectedObject: &runtime.Unknown{
|
||||
Raw: []byte(`{"test":"object"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
},
|
||||
},
|
||||
{
|
||||
data: []byte(`{"test":"object"}`),
|
||||
into: &runtime.Unknown{},
|
||||
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
expectedObject: &runtime.Unknown{
|
||||
TypeMeta: runtime.TypeMeta{APIVersion: "other/blah", Kind: "Test"},
|
||||
Raw: []byte(`{"test":"object"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
},
|
||||
},
|
||||
|
||||
// unregistered objects can be decoded into directly
|
||||
{
|
||||
data: []byte(`{"kind":"Test","apiVersion":"other/blah","value":1,"Other":"test"}`),
|
||||
into: &testDecodable{},
|
||||
typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind(schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
expectedObject: &testDecodable{
|
||||
Other: "test",
|
||||
Value: 1,
|
||||
},
|
||||
},
|
||||
// registered types get defaulted by the into object kind
|
||||
{
|
||||
data: []byte(`{"value":1,"Other":"test"}`),
|
||||
into: &testDecodable{},
|
||||
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
expectedObject: &testDecodable{
|
||||
Other: "test",
|
||||
Value: 1,
|
||||
},
|
||||
},
|
||||
// registered types get defaulted by the into object kind even without version, but return an error
|
||||
{
|
||||
data: []byte(`{"value":1,"Other":"test"}`),
|
||||
into: &testDecodable{},
|
||||
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: ""}},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: ""},
|
||||
errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'apiVersion' is missing in") },
|
||||
expectedObject: &testDecodable{
|
||||
Other: "test",
|
||||
Value: 1,
|
||||
},
|
||||
},
|
||||
|
||||
// runtime.VersionedObjects are decoded
|
||||
{
|
||||
data: []byte(`{"value":1,"Other":"test"}`),
|
||||
into: &runtime.VersionedObjects{Objects: []runtime.Object{}},
|
||||
creater: &mockCreater{obj: &testDecodable{}},
|
||||
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
|
||||
defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
expectedObject: &runtime.VersionedObjects{
|
||||
Objects: []runtime.Object{
|
||||
&testDecodable{
|
||||
Other: "test",
|
||||
Value: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// runtime.VersionedObjects with an object are decoded into
|
||||
{
|
||||
data: []byte(`{"Other":"test"}`),
|
||||
into: &runtime.VersionedObjects{Objects: []runtime.Object{&testDecodable{Value: 2}}},
|
||||
typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}},
|
||||
expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
|
||||
expectedObject: &runtime.VersionedObjects{
|
||||
Objects: []runtime.Object{
|
||||
&testDecodable{
|
||||
Other: "test",
|
||||
Value: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range testCases {
|
||||
var s runtime.Serializer
|
||||
if test.yaml {
|
||||
s = json.NewYAMLSerializer(json.DefaultMetaFactory, test.creater, test.typer)
|
||||
} else {
|
||||
s = json.NewSerializer(json.DefaultMetaFactory, test.creater, test.typer, test.pretty)
|
||||
}
|
||||
obj, gvk, err := s.Decode([]byte(test.data), test.defaultGVK, test.into)
|
||||
|
||||
if !reflect.DeepEqual(test.expectedGVK, gvk) {
|
||||
t.Errorf("%d: unexpected GVK: %v", i, gvk)
|
||||
}
|
||||
|
||||
switch {
|
||||
case err == nil && test.errFn != nil:
|
||||
t.Errorf("%d: failed: %v", i, err)
|
||||
continue
|
||||
case err != nil && test.errFn == nil:
|
||||
t.Errorf("%d: failed: %v", i, err)
|
||||
continue
|
||||
case err != nil:
|
||||
if !test.errFn(err) {
|
||||
t.Errorf("%d: failed: %v", i, err)
|
||||
}
|
||||
if obj != nil {
|
||||
t.Errorf("%d: should have returned nil object", i)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if test.into != nil && test.into != obj {
|
||||
t.Errorf("%d: expected into to be returned: %v", i, obj)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(test.expectedObject, obj) {
|
||||
t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type mockCreater struct {
|
||||
apiVersion string
|
||||
kind string
|
||||
err error
|
||||
obj runtime.Object
|
||||
}
|
||||
|
||||
func (c *mockCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) {
|
||||
c.apiVersion, c.kind = kind.GroupVersion().String(), kind.Kind
|
||||
return c.obj, c.err
|
||||
}
|
||||
|
||||
type mockTyper struct {
|
||||
gvk *schema.GroupVersionKind
|
||||
err error
|
||||
}
|
||||
|
||||
func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
|
||||
if t.gvk == nil {
|
||||
return nil, false, t.err
|
||||
}
|
||||
return []schema.GroupVersionKind{*t.gvk}, false, t.err
|
||||
}
|
||||
|
||||
func (t *mockTyper) Recognizes(_ schema.GroupVersionKind) bool {
|
||||
return false
|
||||
}
|
||||
45
vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/meta_test.go
generated
vendored
Normal file
45
vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/meta_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
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 json
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSimpleMetaFactoryInterpret(t *testing.T) {
|
||||
factory := SimpleMetaFactory{}
|
||||
gvk, err := factory.Interpret([]byte(`{"apiVersion":"1","kind":"object"}`))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if gvk.Version != "1" || gvk.Kind != "object" {
|
||||
t.Errorf("unexpected interpret: %#v", gvk)
|
||||
}
|
||||
|
||||
// no kind or version
|
||||
gvk, err = factory.Interpret([]byte(`{}`))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if gvk.Version != "" || gvk.Kind != "" {
|
||||
t.Errorf("unexpected interpret: %#v", gvk)
|
||||
}
|
||||
|
||||
// unparsable
|
||||
gvk, err = factory.Interpret([]byte(`{`))
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
}
|
||||
2
vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/doc.go
generated
vendored
2
vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/doc.go
generated
vendored
|
|
@ -15,4 +15,4 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
// Package protobuf provides a Kubernetes serializer for the protobuf format.
|
||||
package protobuf
|
||||
package protobuf // import "k8s.io/apimachinery/pkg/runtime/serializer/protobuf"
|
||||
|
|
|
|||
30
vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer/testing/BUILD
generated
vendored
Normal file
30
vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer/testing/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["recognizer_test.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/json: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"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue