2016-09-08 20:21:58 +00:00
|
|
|
/*
|
|
|
|
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 master
|
|
|
|
|
|
|
|
import (
|
2016-12-22 05:47:08 +00:00
|
|
|
"encoding/json"
|
|
|
|
"reflect"
|
2016-09-08 20:21:58 +00:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2017-06-22 18:24:23 +00:00
|
|
|
"k8s.io/api/core/v1"
|
2017-01-11 14:09:48 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
2017-01-27 20:42:17 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
2017-01-11 14:09:48 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
2017-10-16 11:41:50 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
2016-09-08 20:21:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestGroupVersions(t *testing.T) {
|
|
|
|
// legacyUnsuffixedGroups contains the groups released prior to deciding that kubernetes API groups should be dns-suffixed
|
|
|
|
// new groups should be suffixed with ".k8s.io" (https://github.com/kubernetes/kubernetes/pull/31887#issuecomment-244462396)
|
|
|
|
legacyUnsuffixedGroups := sets.NewString(
|
|
|
|
"",
|
|
|
|
"apps",
|
|
|
|
"autoscaling",
|
|
|
|
"batch",
|
|
|
|
"componentconfig",
|
|
|
|
"extensions",
|
|
|
|
"policy",
|
|
|
|
)
|
|
|
|
|
|
|
|
// No new groups should be added to the legacyUnsuffixedGroups exclusion list
|
2017-10-12 17:05:49 +00:00
|
|
|
if len(legacyUnsuffixedGroups) != 7 {
|
2016-09-08 20:21:58 +00:00
|
|
|
t.Errorf("No additional unnamespaced groups should be created")
|
|
|
|
}
|
|
|
|
|
2017-10-16 11:41:50 +00:00
|
|
|
for _, gv := range legacyscheme.Registry.RegisteredGroupVersions() {
|
2016-09-08 20:21:58 +00:00
|
|
|
if !strings.HasSuffix(gv.Group, ".k8s.io") && !legacyUnsuffixedGroups.Has(gv.Group) {
|
|
|
|
t.Errorf("Group %s does not have the standard kubernetes API group suffix of .k8s.io", gv.Group)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-22 05:47:08 +00:00
|
|
|
|
|
|
|
func TestTypeTags(t *testing.T) {
|
2017-10-16 11:41:50 +00:00
|
|
|
for gvk, knownType := range legacyscheme.Scheme.AllKnownTypes() {
|
2016-12-22 05:47:08 +00:00
|
|
|
if gvk.Version == runtime.APIVersionInternal {
|
|
|
|
ensureNoTags(t, gvk, knownType, nil)
|
|
|
|
} else {
|
|
|
|
ensureTags(t, gvk, knownType, nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// These types are registered in external versions, and therefore include json tags,
|
|
|
|
// but are also registered in internal versions (or referenced from internal types),
|
|
|
|
// so we explicitly allow tags for them
|
|
|
|
var typesAllowedTags = map[reflect.Type]bool{
|
2017-05-09 16:16:12 +00:00
|
|
|
reflect.TypeOf(intstr.IntOrString{}): true,
|
|
|
|
reflect.TypeOf(metav1.Time{}): true,
|
2017-08-04 10:47:23 +00:00
|
|
|
reflect.TypeOf(metav1.MicroTime{}): true,
|
2017-05-09 16:16:12 +00:00
|
|
|
reflect.TypeOf(metav1.Duration{}): true,
|
|
|
|
reflect.TypeOf(metav1.TypeMeta{}): true,
|
|
|
|
reflect.TypeOf(metav1.ListMeta{}): true,
|
|
|
|
reflect.TypeOf(metav1.ObjectMeta{}): true,
|
|
|
|
reflect.TypeOf(metav1.OwnerReference{}): true,
|
|
|
|
reflect.TypeOf(metav1.LabelSelector{}): true,
|
|
|
|
reflect.TypeOf(metav1.GetOptions{}): true,
|
|
|
|
reflect.TypeOf(metav1.ExportOptions{}): true,
|
|
|
|
reflect.TypeOf(metav1.ListOptions{}): true,
|
|
|
|
reflect.TypeOf(metav1.DeleteOptions{}): true,
|
|
|
|
reflect.TypeOf(metav1.GroupVersionKind{}): true,
|
|
|
|
reflect.TypeOf(metav1.GroupVersionResource{}): true,
|
2017-05-24 22:31:34 +00:00
|
|
|
reflect.TypeOf(metav1.Status{}): true,
|
2016-12-22 05:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func ensureNoTags(t *testing.T, gvk schema.GroupVersionKind, tp reflect.Type, parents []reflect.Type) {
|
|
|
|
if _, ok := typesAllowedTags[tp]; ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
parents = append(parents, tp)
|
|
|
|
|
|
|
|
switch tp.Kind() {
|
|
|
|
case reflect.Map, reflect.Slice, reflect.Ptr:
|
|
|
|
ensureNoTags(t, gvk, tp.Elem(), parents)
|
|
|
|
|
2017-10-12 14:04:43 +00:00
|
|
|
case reflect.String, reflect.Bool, reflect.Float32, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uintptr, reflect.Uint32, reflect.Uint64, reflect.Interface:
|
2016-12-22 05:47:08 +00:00
|
|
|
// no-op
|
|
|
|
|
|
|
|
case reflect.Struct:
|
|
|
|
for i := 0; i < tp.NumField(); i++ {
|
|
|
|
f := tp.Field(i)
|
2017-10-03 19:53:27 +00:00
|
|
|
if f.PkgPath != "" {
|
|
|
|
continue // Ignore unexported fields
|
|
|
|
}
|
2016-12-22 05:47:08 +00:00
|
|
|
jsonTag := f.Tag.Get("json")
|
|
|
|
protoTag := f.Tag.Get("protobuf")
|
|
|
|
if len(jsonTag) > 0 || len(protoTag) > 0 {
|
|
|
|
t.Errorf("Internal types should not have json or protobuf tags. %#v has tag on field %v: %v", gvk, f.Name, f.Tag)
|
|
|
|
for i, tp := range parents {
|
|
|
|
t.Logf("%s%v:", strings.Repeat(" ", i), tp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ensureNoTags(t, gvk, f.Type, parents)
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
t.Errorf("Unexpected type %v in %#v", tp.Kind(), gvk)
|
|
|
|
for i, tp := range parents {
|
|
|
|
t.Logf("%s%v:", strings.Repeat(" ", i), tp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
|
|
|
unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
|
|
|
|
)
|
|
|
|
|
|
|
|
// These fields are limited exceptions to the standard JSON naming structure.
|
|
|
|
// Additions should only be made if a non-standard field name was released and cannot be changed for compatibility reasons.
|
|
|
|
var allowedNonstandardJSONNames = map[reflect.Type]string{
|
|
|
|
reflect.TypeOf(v1.DaemonEndpoint{}): "Port",
|
|
|
|
}
|
|
|
|
|
|
|
|
func ensureTags(t *testing.T, gvk schema.GroupVersionKind, tp reflect.Type, parents []reflect.Type) {
|
|
|
|
// This type handles its own encoding/decoding and doesn't need json tags
|
|
|
|
if tp.Implements(marshalerType) && (tp.Implements(unmarshalerType) || reflect.PtrTo(tp).Implements(unmarshalerType)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
parents = append(parents, tp)
|
|
|
|
|
|
|
|
switch tp.Kind() {
|
|
|
|
case reflect.Map, reflect.Slice, reflect.Ptr:
|
|
|
|
ensureTags(t, gvk, tp.Elem(), parents)
|
|
|
|
|
|
|
|
case reflect.String, reflect.Bool, reflect.Float32, reflect.Int, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uintptr, reflect.Uint32, reflect.Uint64, reflect.Interface:
|
|
|
|
// no-op
|
|
|
|
|
|
|
|
case reflect.Struct:
|
|
|
|
for i := 0; i < tp.NumField(); i++ {
|
|
|
|
f := tp.Field(i)
|
|
|
|
jsonTag := f.Tag.Get("json")
|
|
|
|
if len(jsonTag) == 0 {
|
|
|
|
t.Errorf("External types should have json tags. %#v tags on field %v are: %s", gvk, f.Name, f.Tag)
|
|
|
|
for i, tp := range parents {
|
|
|
|
t.Logf("%s%v", strings.Repeat(" ", i), tp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonTagName := strings.Split(jsonTag, ",")[0]
|
|
|
|
if len(jsonTagName) > 0 && (jsonTagName[0] < 'a' || jsonTagName[0] > 'z') && jsonTagName != "-" && allowedNonstandardJSONNames[tp] != jsonTagName {
|
|
|
|
t.Errorf("External types should have json names starting with lowercase letter. %#v has json tag on field %v with name %s", gvk, f.Name, jsonTagName)
|
|
|
|
t.Log(tp)
|
|
|
|
t.Log(allowedNonstandardJSONNames[tp])
|
|
|
|
for i, tp := range parents {
|
|
|
|
t.Logf("%s%v", strings.Repeat(" ", i), tp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ensureTags(t, gvk, f.Type, parents)
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
t.Errorf("Unexpected type %v in %#v", tp.Kind(), gvk)
|
|
|
|
for i, tp := range parents {
|
|
|
|
t.Logf("%s%v:", strings.Repeat(" ", i), tp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|