blob: 717e52884843bdb8251ad4da09429ad668441170 [file] [log] [blame]
/*
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 status
import (
"reflect"
"strings"
"testing"
"time"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
listers "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
)
type crdBuilder struct {
curr apiextensions.CustomResourceDefinition
}
func newCRD(name string) *crdBuilder {
tokens := strings.SplitN(name, ".", 2)
return &crdBuilder{
curr: apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: name},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: tokens[1],
Names: apiextensions.CustomResourceDefinitionNames{
Plural: tokens[0],
},
},
},
}
}
func (b *crdBuilder) SpecNames(plural, singular, kind, listKind string, shortNames ...string) *crdBuilder {
b.curr.Spec.Names.Plural = plural
b.curr.Spec.Names.Singular = singular
b.curr.Spec.Names.Kind = kind
b.curr.Spec.Names.ListKind = listKind
b.curr.Spec.Names.ShortNames = shortNames
return b
}
func (b *crdBuilder) StatusNames(plural, singular, kind, listKind string, shortNames ...string) *crdBuilder {
b.curr.Status.AcceptedNames.Plural = plural
b.curr.Status.AcceptedNames.Singular = singular
b.curr.Status.AcceptedNames.Kind = kind
b.curr.Status.AcceptedNames.ListKind = listKind
b.curr.Status.AcceptedNames.ShortNames = shortNames
return b
}
func (b *crdBuilder) Condition(c apiextensions.CustomResourceDefinitionCondition) *crdBuilder {
b.curr.Status.Conditions = append(b.curr.Status.Conditions, c)
return b
}
func names(plural, singular, kind, listKind string, shortNames ...string) apiextensions.CustomResourceDefinitionNames {
ret := apiextensions.CustomResourceDefinitionNames{
Plural: plural,
Singular: singular,
Kind: kind,
ListKind: listKind,
ShortNames: shortNames,
}
return ret
}
func (b *crdBuilder) NewOrDie() *apiextensions.CustomResourceDefinition {
return &b.curr
}
var acceptedCondition = apiextensions.CustomResourceDefinitionCondition{
Type: apiextensions.NamesAccepted,
Status: apiextensions.ConditionTrue,
Reason: "NoConflicts",
Message: "no conflicts found",
}
var notAcceptedCondition = apiextensions.CustomResourceDefinitionCondition{
Type: apiextensions.NamesAccepted,
Status: apiextensions.ConditionFalse,
Reason: "NotAccepted",
Message: "not all names are accepted",
}
var installingCondition = apiextensions.CustomResourceDefinitionCondition{
Type: apiextensions.Established,
Status: apiextensions.ConditionFalse,
Reason: "Installing",
Message: "the initial names have been accepted",
}
var notEstablishedCondition = apiextensions.CustomResourceDefinitionCondition{
Type: apiextensions.Established,
Status: apiextensions.ConditionFalse,
Reason: "NotAccepted",
Message: "not all names are accepted",
}
func nameConflictCondition(reason, message string) apiextensions.CustomResourceDefinitionCondition {
return apiextensions.CustomResourceDefinitionCondition{
Type: apiextensions.NamesAccepted,
Status: apiextensions.ConditionFalse,
Reason: reason,
Message: message,
}
}
func TestSync(t *testing.T) {
tests := []struct {
name string
in *apiextensions.CustomResourceDefinition
existing []*apiextensions.CustomResourceDefinition
expectedNames apiextensions.CustomResourceDefinitionNames
expectedNameConflictCondition apiextensions.CustomResourceDefinitionCondition
expectedEstablishedCondition apiextensions.CustomResourceDefinitionCondition
}{
{
name: "first resource",
in: newCRD("alfa.bravo.com").NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{},
expectedNames: apiextensions.CustomResourceDefinitionNames{
Plural: "alfa",
},
expectedNameConflictCondition: acceptedCondition,
expectedEstablishedCondition: installingCondition,
},
{
name: "different groups",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("alfa.charlie.com").StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
},
expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: acceptedCondition,
expectedEstablishedCondition: installingCondition,
},
{
name: "conflict plural to singular",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "alfa", "", "").NewOrDie(),
},
expectedNames: names("", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: nameConflictCondition("PluralConflict", `"alfa" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
{
name: "conflict singular to shortName",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "indias", "", "", "delta-singular").NewOrDie(),
},
expectedNames: names("alfa", "", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: nameConflictCondition("SingularConflict", `"delta-singular" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
{
name: "conflict on shortName to shortName",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "indias", "", "", "hotel-shortname-2").NewOrDie(),
},
expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind"),
expectedNameConflictCondition: nameConflictCondition("ShortNamesConflict", `"hotel-shortname-2" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
{
name: "conflict on kind to listkind",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "indias", "", "echo-kind").NewOrDie(),
},
expectedNames: names("alfa", "delta-singular", "", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: nameConflictCondition("KindConflict", `"echo-kind" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
{
name: "conflict on listkind to kind",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "indias", "foxtrot-listkind", "").NewOrDie(),
},
expectedNames: names("alfa", "delta-singular", "echo-kind", "", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: nameConflictCondition("ListKindConflict", `"foxtrot-listkind" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
{
name: "no conflict on resource and kind",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "echo-kind", "", "").NewOrDie(),
},
expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: acceptedCondition,
expectedEstablishedCondition: installingCondition,
},
{
name: "merge on conflicts",
in: newCRD("alfa.bravo.com").
SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
StatusNames("zulu", "yankee-singular", "xray-kind", "whiskey-listkind", "victor-shortname-1", "uniform-shortname-2").
NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "indias", "foxtrot-listkind", "", "delta-singular").NewOrDie(),
},
expectedNames: names("alfa", "yankee-singular", "echo-kind", "whiskey-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: nameConflictCondition("ListKindConflict", `"foxtrot-listkind" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
{
name: "merge on conflicts shortNames as one",
in: newCRD("alfa.bravo.com").
SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
StatusNames("zulu", "yankee-singular", "xray-kind", "whiskey-listkind", "victor-shortname-1", "uniform-shortname-2").
NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "indias", "foxtrot-listkind", "", "delta-singular", "golf-shortname-1").NewOrDie(),
},
expectedNames: names("alfa", "yankee-singular", "echo-kind", "whiskey-listkind", "victor-shortname-1", "uniform-shortname-2"),
expectedNameConflictCondition: nameConflictCondition("ListKindConflict", `"foxtrot-listkind" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
{
name: "no conflicts on self",
in: newCRD("alfa.bravo.com").
SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("alfa.bravo.com").
SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
NewOrDie(),
},
expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: acceptedCondition,
expectedEstablishedCondition: installingCondition,
},
{
name: "no conflicts on self, remove shortname",
in: newCRD("alfa.bravo.com").
SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1").
StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("alfa.bravo.com").
SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
StatusNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
NewOrDie(),
},
expectedNames: names("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1"),
expectedNameConflictCondition: acceptedCondition,
expectedEstablishedCondition: installingCondition,
},
{
name: "installing before with true condition",
in: newCRD("alfa.bravo.com").Condition(acceptedCondition).NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{},
expectedNames: apiextensions.CustomResourceDefinitionNames{
Plural: "alfa",
},
expectedNameConflictCondition: acceptedCondition,
expectedEstablishedCondition: installingCondition,
},
{
name: "not installing before with false condition",
in: newCRD("alfa.bravo.com").Condition(notAcceptedCondition).NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{},
expectedNames: apiextensions.CustomResourceDefinitionNames{
Plural: "alfa",
},
expectedNameConflictCondition: acceptedCondition,
expectedEstablishedCondition: installingCondition,
},
{
name: "conflicting, installing before with true condition",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
Condition(acceptedCondition).
NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "alfa", "", "").NewOrDie(),
},
expectedNames: names("", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: nameConflictCondition("PluralConflict", `"alfa" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
{
name: "conflicting, not installing before with false condition",
in: newCRD("alfa.bravo.com").SpecNames("alfa", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2").
Condition(notAcceptedCondition).
NewOrDie(),
existing: []*apiextensions.CustomResourceDefinition{
newCRD("india.bravo.com").StatusNames("india", "alfa", "", "").NewOrDie(),
},
expectedNames: names("", "delta-singular", "echo-kind", "foxtrot-listkind", "golf-shortname-1", "hotel-shortname-2"),
expectedNameConflictCondition: nameConflictCondition("PluralConflict", `"alfa" is already in use`),
expectedEstablishedCondition: notEstablishedCondition,
},
}
for _, tc := range tests {
crdIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
for _, obj := range tc.existing {
crdIndexer.Add(obj)
}
c := NamingConditionController{
crdLister: listers.NewCustomResourceDefinitionLister(crdIndexer),
crdMutationCache: cache.NewIntegerResourceVersionMutationCache(crdIndexer, crdIndexer, 60*time.Second, false),
}
actualNames, actualNameConflictCondition, establishedCondition := c.calculateNamesAndConditions(tc.in)
if e, a := tc.expectedNames, actualNames; !reflect.DeepEqual(e, a) {
t.Errorf("%v expected %v, got %#v", tc.name, e, a)
}
if e, a := tc.expectedNameConflictCondition, actualNameConflictCondition; !apiextensions.IsCRDConditionEquivalent(&e, &a) {
t.Errorf("%v expected %v, got %v", tc.name, e, a)
}
if e, a := tc.expectedEstablishedCondition, establishedCondition; !apiextensions.IsCRDConditionEquivalent(&e, &a) {
t.Errorf("%v expected %v, got %v", tc.name, e, a)
}
}
}