1
16
17 package status
18
19 import (
20 "reflect"
21 "strings"
22 "testing"
23 "time"
24
25 apiextensionshelpers "k8s.io/apiextensions-apiserver/pkg/apihelpers"
26 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
27 listers "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/client-go/tools/cache"
30 )
31
32 type crdBuilder struct {
33 curr apiextensionsv1.CustomResourceDefinition
34 }
35
36 func newCRD(name string) *crdBuilder {
37 tokens := strings.SplitN(name, ".", 2)
38 return &crdBuilder{
39 curr: apiextensionsv1.CustomResourceDefinition{
40 ObjectMeta: metav1.ObjectMeta{Name: name},
41 Spec: apiextensionsv1.CustomResourceDefinitionSpec{
42 Group: tokens[1],
43 Names: apiextensionsv1.CustomResourceDefinitionNames{
44 Plural: tokens[0],
45 },
46 },
47 },
48 }
49 }
50
51 func (b *crdBuilder) SpecNames(plural, singular, kind, listKind string, shortNames ...string) *crdBuilder {
52 b.curr.Spec.Names.Plural = plural
53 b.curr.Spec.Names.Singular = singular
54 b.curr.Spec.Names.Kind = kind
55 b.curr.Spec.Names.ListKind = listKind
56 b.curr.Spec.Names.ShortNames = shortNames
57
58 return b
59 }
60
61 func (b *crdBuilder) StatusNames(plural, singular, kind, listKind string, shortNames ...string) *crdBuilder {
62 b.curr.Status.AcceptedNames.Plural = plural
63 b.curr.Status.AcceptedNames.Singular = singular
64 b.curr.Status.AcceptedNames.Kind = kind
65 b.curr.Status.AcceptedNames.ListKind = listKind
66 b.curr.Status.AcceptedNames.ShortNames = shortNames
67
68 return b
69 }
70
71 func (b *crdBuilder) Condition(c apiextensionsv1.CustomResourceDefinitionCondition) *crdBuilder {
72 b.curr.Status.Conditions = append(b.curr.Status.Conditions, c)
73
74 return b
75 }
76
77 func names(plural, singular, kind, listKind string, shortNames ...string) apiextensionsv1.CustomResourceDefinitionNames {
78 ret := apiextensionsv1.CustomResourceDefinitionNames{
79 Plural: plural,
80 Singular: singular,
81 Kind: kind,
82 ListKind: listKind,
83 ShortNames: shortNames,
84 }
85 return ret
86 }
87
88 func (b *crdBuilder) NewOrDie() *apiextensionsv1.CustomResourceDefinition {
89 return &b.curr
90 }
91
92 var acceptedCondition = apiextensionsv1.CustomResourceDefinitionCondition{
93 Type: apiextensionsv1.NamesAccepted,
94 Status: apiextensionsv1.ConditionTrue,
95 Reason: "NoConflicts",
96 Message: "no conflicts found",
97 }
98
99 var notAcceptedCondition = apiextensionsv1.CustomResourceDefinitionCondition{
100 Type: apiextensionsv1.NamesAccepted,
101 Status: apiextensionsv1.ConditionFalse,
102 Reason: "NotAccepted",
103 Message: "not all names are accepted",
104 }
105
106 var installingCondition = apiextensionsv1.CustomResourceDefinitionCondition{
107 Type: apiextensionsv1.Established,
108 Status: apiextensionsv1.ConditionFalse,
109 Reason: "Installing",
110 Message: "the initial names have been accepted",
111 }
112
113 var notEstablishedCondition = apiextensionsv1.CustomResourceDefinitionCondition{
114 Type: apiextensionsv1.Established,
115 Status: apiextensionsv1.ConditionFalse,
116 Reason: "NotAccepted",
117 Message: "not all names are accepted",
118 }
119
120 func nameConflictCondition(reason, message string) apiextensionsv1.CustomResourceDefinitionCondition {
121 return apiextensionsv1.CustomResourceDefinitionCondition{
122 Type: apiextensionsv1.NamesAccepted,
123 Status: apiextensionsv1.ConditionFalse,
124 Reason: reason,
125 Message: message,
126 }
127 }
128
129 func TestSync(t *testing.T) {
130 tests := []struct {
131 name string
132
133 in *apiextensionsv1.CustomResourceDefinition
134 existing []*apiextensionsv1.CustomResourceDefinition
135 expectedNames apiextensionsv1.CustomResourceDefinitionNames
136 expectedNameConflictCondition apiextensionsv1.CustomResourceDefinitionCondition
137 expectedEstablishedCondition apiextensionsv1.CustomResourceDefinitionCondition
138 }{
139 {
140 name: "first resource",
141 in: newCRD("alfa.bravo.com").NewOrDie(),
142 existing: []*apiextensionsv1.CustomResourceDefinition{},
143 expectedNames: apiextensionsv1.CustomResourceDefinitionNames{
144 Plural: "alfa",
145 },
146 expectedNameConflictCondition: acceptedCondition,
147 expectedEstablishedCondition: installingCondition,
148 },
149 {
150 name: "different groups",
151 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
152 existing: []*apiextensionsv1.CustomResourceDefinition{
153 newCRD("alfa.charlie.com").StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
154 },
155 expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
156 expectedNameConflictCondition: acceptedCondition,
157 expectedEstablishedCondition: installingCondition,
158 },
159 {
160 name: "conflict plural to singular",
161 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
162 existing: []*apiextensionsv1.CustomResourceDefinition{
163 newCRD("india.bravo.com").StatusNames("india", "alfa", "", "").NewOrDie(),
164 },
165 expectedNames: names("", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
166 expectedNameConflictCondition: nameConflictCondition("PluralConflict", `"alfa" is already in use`),
167 expectedEstablishedCondition: notEstablishedCondition,
168 },
169 {
170 name: "conflict singular to shortName",
171 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
172 existing: []*apiextensionsv1.CustomResourceDefinition{
173 newCRD("india.bravo.com").StatusNames("india", "indias", "", "", "delta-singular").NewOrDie(),
174 },
175 expectedNames: names("alfa", "", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
176 expectedNameConflictCondition: nameConflictCondition("SingularConflict", `"delta-singular" is already in use`),
177 expectedEstablishedCondition: notEstablishedCondition,
178 },
179 {
180 name: "conflict on shortName to shortName",
181 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
182 existing: []*apiextensionsv1.CustomResourceDefinition{
183 newCRD("india.bravo.com").StatusNames("india", "indias", "", "", "hotel-shortname-2").NewOrDie(),
184 },
185 expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind"),
186 expectedNameConflictCondition: nameConflictCondition("ShortNamesConflict", `"hotel-shortname-2" is already in use`),
187 expectedEstablishedCondition: notEstablishedCondition,
188 },
189 {
190 name: "conflict on kind to listkind",
191 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
192 existing: []*apiextensionsv1.CustomResourceDefinition{
193 newCRD("india.bravo.com").StatusNames("india", "indias", "", "echo-kind").NewOrDie(),
194 },
195 expectedNames: names("alfa", "delta-singular", "", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
196 expectedNameConflictCondition: nameConflictCondition("KindConflict", `"echo-kind" is already in use`),
197 expectedEstablishedCondition: notEstablishedCondition,
198 },
199 {
200 name: "conflict on listkind to kind",
201 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
202 existing: []*apiextensionsv1.CustomResourceDefinition{
203 newCRD("india.bravo.com").StatusNames("india", "indias", "foxtrot-listkind", "").NewOrDie(),
204 },
205 expectedNames: names("alfa", "delta-singular", "echo-kind", "", "golf-shortname-1", "hotel-shortname-2"),
206 expectedNameConflictCondition: nameConflictCondition("ListKindConflict", `"foxtrot-listkind" is already in use`),
207 expectedEstablishedCondition: notEstablishedCondition,
208 },
209 {
210 name: "no conflict on resource and kind",
211 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
212 existing: []*apiextensionsv1.CustomResourceDefinition{
213 newCRD("india.bravo.com").StatusNames("india", "echo-kind", "", "").NewOrDie(),
214 },
215 expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
216 expectedNameConflictCondition: acceptedCondition,
217 expectedEstablishedCondition: installingCondition,
218 },
219 {
220 name: "merge on conflicts",
221 in: newCRD("alfa.bravo.com").
222 SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
223 StatusNames("zulu", "yankee-singular", "xray-kind", "whiskey-listkind", "victor-shortname-1", "uniform-shortname-2").
224 NewOrDie(),
225 existing: []*apiextensionsv1.CustomResourceDefinition{
226 newCRD("india.bravo.com").StatusNames("india", "indias", "foxtrot-listkind", "", "delta-singular").NewOrDie(),
227 },
228 expectedNames: names("alfa", "yankee-singular", "echo-kind", "whiskey-listkind", "golf-shortname-1", "hotel-shortname-2"),
229 expectedNameConflictCondition: nameConflictCondition("ListKindConflict", `"foxtrot-listkind" is already in use`),
230 expectedEstablishedCondition: notEstablishedCondition,
231 },
232 {
233 name: "merge on conflicts shortNames as one",
234 in: newCRD("alfa.bravo.com").
235 SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
236 StatusNames("zulu", "yankee-singular", "xray-kind", "whiskey-listkind", "victor-shortname-1", "uniform-shortname-2").
237 NewOrDie(),
238 existing: []*apiextensionsv1.CustomResourceDefinition{
239 newCRD("india.bravo.com").StatusNames("india", "indias", "foxtrot-listkind", "", "delta-singular", "golf-shortname-1").NewOrDie(),
240 },
241 expectedNames: names("alfa", "yankee-singular", "echo-kind", "whiskey-listkind", "victor-shortname-1", "uniform-shortname-2"),
242 expectedNameConflictCondition: nameConflictCondition("ListKindConflict", `"foxtrot-listkind" is already in use`),
243 expectedEstablishedCondition: notEstablishedCondition,
244 },
245 {
246 name: "no conflicts on self",
247 in: newCRD("alfa.bravo.com").
248 SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
249 StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
250 NewOrDie(),
251 existing: []*apiextensionsv1.CustomResourceDefinition{
252 newCRD("alfa.bravo.com").
253 SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
254 StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
255 NewOrDie(),
256 },
257 expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
258 expectedNameConflictCondition: acceptedCondition,
259 expectedEstablishedCondition: installingCondition,
260 },
261 {
262 name: "no conflicts on self, remove shortname",
263 in: newCRD("alfa.bravo.com").
264 SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1").
265 StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
266 NewOrDie(),
267 existing: []*apiextensionsv1.CustomResourceDefinition{
268 newCRD("alfa.bravo.com").
269 SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
270 StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
271 NewOrDie(),
272 },
273 expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1"),
274 expectedNameConflictCondition: acceptedCondition,
275 expectedEstablishedCondition: installingCondition,
276 },
277 {
278 name: "installing before with true condition",
279 in: newCRD("alfa.bravo.com").Condition(acceptedCondition).NewOrDie(),
280 existing: []*apiextensionsv1.CustomResourceDefinition{},
281 expectedNames: apiextensionsv1.CustomResourceDefinitionNames{
282 Plural: "alfa",
283 },
284 expectedNameConflictCondition: acceptedCondition,
285 expectedEstablishedCondition: installingCondition,
286 },
287 {
288 name: "not installing before with false condition",
289 in: newCRD("alfa.bravo.com").Condition(notAcceptedCondition).NewOrDie(),
290 existing: []*apiextensionsv1.CustomResourceDefinition{},
291 expectedNames: apiextensionsv1.CustomResourceDefinitionNames{
292 Plural: "alfa",
293 },
294 expectedNameConflictCondition: acceptedCondition,
295 expectedEstablishedCondition: installingCondition,
296 },
297 {
298 name: "conflicting, installing before with true condition",
299 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
300 Condition(acceptedCondition).
301 NewOrDie(),
302 existing: []*apiextensionsv1.CustomResourceDefinition{
303 newCRD("india.bravo.com").StatusNames("india", "alfa", "", "").NewOrDie(),
304 },
305 expectedNames: names("", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
306 expectedNameConflictCondition: nameConflictCondition("PluralConflict", `"alfa" is already in use`),
307 expectedEstablishedCondition: notEstablishedCondition,
308 },
309 {
310 name: "conflicting, not installing before with false condition",
311 in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
312 Condition(notAcceptedCondition).
313 NewOrDie(),
314 existing: []*apiextensionsv1.CustomResourceDefinition{
315 newCRD("india.bravo.com").StatusNames("india", "alfa", "", "").NewOrDie(),
316 },
317 expectedNames: names("", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
318 expectedNameConflictCondition: nameConflictCondition("PluralConflict", `"alfa" is already in use`),
319 expectedEstablishedCondition: notEstablishedCondition,
320 },
321 }
322
323 for _, tc := range tests {
324 crdIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
325 for _, obj := range tc.existing {
326 crdIndexer.Add(obj)
327 }
328
329 c := NamingConditionController{
330 crdLister: listers.NewCustomResourceDefinitionLister(crdIndexer),
331 crdMutationCache: cache.NewIntegerResourceVersionMutationCache(crdIndexer, crdIndexer, 60*time.Second, false),
332 }
333 actualNames, actualNameConflictCondition, establishedCondition := c.calculateNamesAndConditions(tc.in)
334
335 if e, a := tc.expectedNames, actualNames; !reflect.DeepEqual(e, a) {
336 t.Errorf("%v expected %v, got %#v", tc.name, e, a)
337 }
338 if e, a := tc.expectedNameConflictCondition, actualNameConflictCondition; !apiextensionshelpers.IsCRDConditionEquivalent(&e, &a) {
339 t.Errorf("%v expected %v, got %v", tc.name, e, a)
340 }
341 if e, a := tc.expectedEstablishedCondition, establishedCondition; !apiextensionshelpers.IsCRDConditionEquivalent(&e, &a) {
342 t.Errorf("%v expected %v, got %v", tc.name, e, a)
343 }
344 }
345 }
346
View as plain text