1
16
17 package testing
18
19 import (
20 "fmt"
21 "reflect"
22 "regexp"
23 "strings"
24
25 apinamingtest "k8s.io/apimachinery/pkg/api/apitesting/naming"
26 "k8s.io/apimachinery/pkg/runtime"
27 "k8s.io/apimachinery/pkg/runtime/schema"
28 "k8s.io/apimachinery/pkg/util/errors"
29 "k8s.io/apimachinery/pkg/util/sets"
30 )
31
32
33 var APIVersionRegexp = regexp.MustCompile(`^v\d+((alpha|beta){1}\d+)?$`)
34
35
36 type ComponentConfigPackage struct {
37 ComponentName string
38 GroupName string
39 SchemeGroupVersion schema.GroupVersion
40 AddToScheme func(*runtime.Scheme) error
41 SkipTests sets.String
42 AllowedTags map[reflect.Type]bool
43 AllowedNonstandardJSONNames map[reflect.Type]string
44 }
45
46 type testingFunc func(*runtime.Scheme, *ComponentConfigPackage) error
47
48 const (
49 verifyTagNaming = "verifyTagNaming"
50 verifyGroupNameSuffix = "verifyGroupNameSuffix"
51 verifyGroupNameMatch = "verifyGroupNameMatch"
52 verifyCorrectGroupName = "verifyCorrectGroupName"
53 verifyComponentConfigKindExists = "verifyComponentConfigKindExists"
54 verifyExternalAPIVersion = "verifyExternalAPIVersion"
55 verifyInternalAPIVersion = "verifyInternalAPIVersion"
56 )
57
58 var testingFuncs = map[string]testingFunc{
59 verifyTagNaming: verifyTagNamingFunc,
60 verifyGroupNameSuffix: verifyGroupNameSuffixFunc,
61 verifyGroupNameMatch: verifyGroupNameMatchFunc,
62 verifyCorrectGroupName: verifyCorrectGroupNameFunc,
63 }
64
65
66
67
68
69
70
71
72 func VerifyExternalTypePackage(pkginfo *ComponentConfigPackage) error {
73 scheme, err := setup(pkginfo)
74 if err != nil {
75 return fmt.Errorf("test setup error: %v", err)
76 }
77 extraFns := map[string]testingFunc{
78 verifyExternalAPIVersion: verifyExternalAPIVersionFunc,
79 }
80 return runFuncs(scheme, pkginfo, extraFns)
81 }
82
83
84
85
86
87
88
89
90 func VerifyInternalTypePackage(pkginfo *ComponentConfigPackage) error {
91 scheme, err := setup(pkginfo)
92 if err != nil {
93 return fmt.Errorf("test setup error: %v", err)
94 }
95 extraFns := map[string]testingFunc{
96 verifyInternalAPIVersion: verifyInternalAPIVersionFunc,
97 verifyComponentConfigKindExists: verifyComponentConfigKindExistsFunc,
98 }
99 return runFuncs(scheme, pkginfo, extraFns)
100 }
101
102 func setup(pkginfo *ComponentConfigPackage) (*runtime.Scheme, error) {
103 if len(pkginfo.ComponentName) == 0 ||
104 len(pkginfo.GroupName) == 0 ||
105 pkginfo.SchemeGroupVersion.Empty() ||
106 pkginfo.AddToScheme == nil {
107 return nil, fmt.Errorf("invalid argument: not all parameters were passed correctly to the function")
108 }
109
110 scheme := runtime.NewScheme()
111 if err := pkginfo.AddToScheme(scheme); err != nil {
112 return nil, fmt.Errorf("AddToScheme must not return an error: %v", err)
113 }
114 if len(scheme.AllKnownTypes()) == 0 {
115 return nil, fmt.Errorf("AddToScheme doesn't register any type")
116 }
117 return scheme, nil
118 }
119
120 func runFuncs(scheme *runtime.Scheme, pkginfo *ComponentConfigPackage, extraFns map[string]testingFunc) error {
121 verifyFns := []testingFunc{}
122 for name, fn := range testingFuncs {
123 if pkginfo.SkipTests.Has(name) {
124 continue
125 }
126 verifyFns = append(verifyFns, fn)
127 }
128 for name, fn := range extraFns {
129 if pkginfo.SkipTests.Has(name) {
130 continue
131 }
132 verifyFns = append(verifyFns, fn)
133 }
134 errs := []error{}
135 for _, fn := range verifyFns {
136 if err := fn(scheme, pkginfo); err != nil {
137 errs = append(errs, err)
138 }
139 }
140 return errors.NewAggregate(errs)
141 }
142
143 func verifyTagNamingFunc(scheme *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
144 return apinamingtest.VerifyTagNaming(scheme, pkginfo.AllowedTags, pkginfo.AllowedNonstandardJSONNames)
145 }
146
147 func verifyGroupNameSuffixFunc(scheme *runtime.Scheme, _ *ComponentConfigPackage) error {
148 return apinamingtest.VerifyGroupNames(scheme, sets.NewString())
149 }
150
151 func verifyGroupNameMatchFunc(_ *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
152 if pkginfo.GroupName != pkginfo.SchemeGroupVersion.Group {
153 return fmt.Errorf("GroupName must be equal to SchemeGroupVersion.Group, GroupName: %v,SchemeGroupVersion.Group: %v",
154 pkginfo.GroupName, pkginfo.SchemeGroupVersion.Group)
155 }
156 return nil
157 }
158
159 func verifyCorrectGroupNameFunc(_ *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
160 desiredGroupName := fmt.Sprintf("%s.config.k8s.io", lowercaseWithoutDashes(pkginfo.ComponentName))
161 if pkginfo.SchemeGroupVersion.Group != desiredGroupName {
162 return fmt.Errorf("got GroupName %q, want %q", pkginfo.SchemeGroupVersion.Group, desiredGroupName)
163
164 }
165 return nil
166 }
167
168 func verifyComponentConfigKindExistsFunc(scheme *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
169 expectedKind := fmt.Sprintf("%sConfiguration", dashesToCapitalCase(pkginfo.ComponentName))
170 expectedGVK := pkginfo.SchemeGroupVersion.WithKind(expectedKind)
171 if !scheme.Recognizes(expectedGVK) {
172 registeredKinds := sets.NewString()
173 for gvk := range scheme.AllKnownTypes() {
174 registeredKinds.Insert(gvk.Kind)
175 }
176 return fmt.Errorf("Kind %s not registered in the scheme, registered kinds are %v", expectedKind, registeredKinds.List())
177 }
178 return nil
179 }
180
181 func verifyExternalAPIVersionFunc(_ *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
182 if !APIVersionRegexp.MatchString(pkginfo.SchemeGroupVersion.Version) {
183 return fmt.Errorf("invalid API version %q, must match %q", pkginfo.SchemeGroupVersion.Version, APIVersionRegexp.String())
184 }
185 return nil
186 }
187
188 func verifyInternalAPIVersionFunc(_ *runtime.Scheme, pkginfo *ComponentConfigPackage) error {
189 if pkginfo.SchemeGroupVersion.Version != runtime.APIVersionInternal {
190 return fmt.Errorf("internal API version must be %q, got %q",
191 runtime.APIVersionInternal, pkginfo.SchemeGroupVersion.Version)
192 }
193 return nil
194 }
195
196 func lowercaseWithoutDashes(str string) string {
197 return strings.Replace(strings.ToLower(str), "-", "", -1)
198 }
199
200 func dashesToCapitalCase(str string) string {
201 segments := strings.Split(str, "-")
202 result := ""
203 for _, segment := range segments {
204 result += strings.Title(segment)
205 }
206 return result
207 }
208
View as plain text