...

Source file src/k8s.io/apiextensions-apiserver/pkg/controller/status/naming_controller_test.go

Documentation: k8s.io/apiextensions-apiserver/pkg/controller/status

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    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