k8s.io/kubernetes@v1.29.3/pkg/registry/core/replicationcontroller/strategy_test.go (about) 1 /* 2 Copyright 2015 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 replicationcontroller 18 19 import ( 20 "strings" 21 "testing" 22 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 25 apitesting "k8s.io/kubernetes/pkg/api/testing" 26 api "k8s.io/kubernetes/pkg/apis/core" 27 28 // ensure types are installed 29 _ "k8s.io/kubernetes/pkg/apis/core/install" 30 ) 31 32 func TestControllerStrategy(t *testing.T) { 33 ctx := genericapirequest.NewDefaultContext() 34 if !Strategy.NamespaceScoped() { 35 t.Errorf("ReplicationController must be namespace scoped") 36 } 37 if Strategy.AllowCreateOnUpdate() { 38 t.Errorf("ReplicationController should not allow create on update") 39 } 40 41 validSelector := map[string]string{"a": "b"} 42 validPodTemplate := api.PodTemplate{ 43 Template: api.PodTemplateSpec{ 44 ObjectMeta: metav1.ObjectMeta{ 45 Labels: validSelector, 46 }, 47 Spec: api.PodSpec{ 48 RestartPolicy: api.RestartPolicyAlways, 49 DNSPolicy: api.DNSClusterFirst, 50 Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, 51 }, 52 }, 53 } 54 rc := &api.ReplicationController{ 55 ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, 56 Spec: api.ReplicationControllerSpec{ 57 Selector: validSelector, 58 Template: &validPodTemplate.Template, 59 }, 60 Status: api.ReplicationControllerStatus{ 61 Replicas: 1, 62 ObservedGeneration: int64(10), 63 }, 64 } 65 66 Strategy.PrepareForCreate(ctx, rc) 67 if rc.Status.Replicas != 0 { 68 t.Error("ReplicationController should not allow setting status.replicas on create") 69 } 70 if rc.Status.ObservedGeneration != int64(0) { 71 t.Error("ReplicationController should not allow setting status.observedGeneration on create") 72 } 73 errs := Strategy.Validate(ctx, rc) 74 if len(errs) != 0 { 75 t.Errorf("Unexpected error validating %v", errs) 76 } 77 78 invalidRc := &api.ReplicationController{ 79 ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "4"}, 80 } 81 Strategy.PrepareForUpdate(ctx, invalidRc, rc) 82 errs = Strategy.ValidateUpdate(ctx, invalidRc, rc) 83 if len(errs) == 0 { 84 t.Errorf("Expected a validation error") 85 } 86 if invalidRc.ResourceVersion != "4" { 87 t.Errorf("Incoming resource version on update should not be mutated") 88 } 89 } 90 91 func TestControllerStatusStrategy(t *testing.T) { 92 ctx := genericapirequest.NewDefaultContext() 93 if !StatusStrategy.NamespaceScoped() { 94 t.Errorf("ReplicationController must be namespace scoped") 95 } 96 if StatusStrategy.AllowCreateOnUpdate() { 97 t.Errorf("ReplicationController should not allow create on update") 98 } 99 validSelector := map[string]string{"a": "b"} 100 validPodTemplate := api.PodTemplate{ 101 Template: api.PodTemplateSpec{ 102 ObjectMeta: metav1.ObjectMeta{ 103 Labels: validSelector, 104 }, 105 Spec: api.PodSpec{ 106 RestartPolicy: api.RestartPolicyAlways, 107 DNSPolicy: api.DNSClusterFirst, 108 Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, 109 }, 110 }, 111 } 112 oldController := &api.ReplicationController{ 113 ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault, ResourceVersion: "10"}, 114 Spec: api.ReplicationControllerSpec{ 115 Replicas: 3, 116 Selector: validSelector, 117 Template: &validPodTemplate.Template, 118 }, 119 Status: api.ReplicationControllerStatus{ 120 Replicas: 1, 121 ObservedGeneration: int64(10), 122 }, 123 } 124 newController := &api.ReplicationController{ 125 ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault, ResourceVersion: "9"}, 126 Spec: api.ReplicationControllerSpec{ 127 Replicas: 1, 128 Selector: validSelector, 129 Template: &validPodTemplate.Template, 130 }, 131 Status: api.ReplicationControllerStatus{ 132 Replicas: 3, 133 ObservedGeneration: int64(11), 134 }, 135 } 136 StatusStrategy.PrepareForUpdate(ctx, newController, oldController) 137 if newController.Status.Replicas != 3 { 138 t.Errorf("Replication controller status updates should allow change of replicas: %v", newController.Status.Replicas) 139 } 140 if newController.Spec.Replicas != 3 { 141 t.Errorf("PrepareForUpdate should have preferred spec") 142 } 143 errs := StatusStrategy.ValidateUpdate(ctx, newController, oldController) 144 if len(errs) != 0 { 145 t.Errorf("Unexpected error %v", errs) 146 } 147 } 148 149 func TestSelectableFieldLabelConversions(t *testing.T) { 150 apitesting.TestSelectableFieldLabelConversionsOfKind(t, 151 "v1", 152 "ReplicationController", 153 ControllerToSelectableFields(&api.ReplicationController{}), 154 nil, 155 ) 156 } 157 158 func TestValidateUpdate(t *testing.T) { 159 ctx := genericapirequest.NewDefaultContext() 160 validSelector := map[string]string{"a": "b"} 161 validPodTemplate := api.PodTemplate{ 162 Template: api.PodTemplateSpec{ 163 ObjectMeta: metav1.ObjectMeta{ 164 Labels: validSelector, 165 }, 166 Spec: api.PodSpec{ 167 RestartPolicy: api.RestartPolicyAlways, 168 DNSPolicy: api.DNSClusterFirst, 169 Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, 170 }, 171 }, 172 } 173 oldController := &api.ReplicationController{ 174 ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault, ResourceVersion: "10", Annotations: make(map[string]string)}, 175 Spec: api.ReplicationControllerSpec{ 176 Replicas: 3, 177 Selector: validSelector, 178 Template: &validPodTemplate.Template, 179 }, 180 Status: api.ReplicationControllerStatus{ 181 Replicas: 1, 182 ObservedGeneration: int64(10), 183 }, 184 } 185 // Conversion sets this annotation 186 oldController.Annotations[api.NonConvertibleAnnotationPrefix+"/"+"spec.selector"] = "no way" 187 188 // Deep-copy so we won't mutate both selectors. 189 newController := oldController.DeepCopy() 190 191 // Irrelevant (to the selector) update for the replication controller. 192 newController.Spec.Replicas = 5 193 194 // If they didn't try to update the selector then we should not return any error. 195 errs := Strategy.ValidateUpdate(ctx, newController, oldController) 196 if len(errs) > 0 { 197 t.Fatalf("unexpected errors: %v", errs) 198 } 199 200 // Update the selector - validation should return an error. 201 newController.Spec.Selector["shiny"] = "newlabel" 202 newController.Spec.Template.Labels["shiny"] = "newlabel" 203 204 errs = Strategy.ValidateUpdate(ctx, newController, oldController) 205 for _, err := range errs { 206 t.Logf("%#v\n", err) 207 } 208 if len(errs) != 1 { 209 t.Fatalf("expected a validation error") 210 } 211 if !strings.Contains(errs[0].Error(), "selector") { 212 t.Fatalf("expected error related to the selector") 213 } 214 }