agones.dev/agones@v1.53.0/pkg/apis/agones/v1/fleet_test.go (about) 1 // Copyright 2018 Google LLC All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package v1 16 17 import ( 18 "fmt" 19 "strings" 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 appsv1 "k8s.io/api/apps/v1" 25 corev1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/util/intstr" 28 "k8s.io/apimachinery/pkg/util/validation" 29 "k8s.io/apimachinery/pkg/util/validation/field" 30 31 "agones.dev/agones/pkg" 32 "agones.dev/agones/pkg/apis" 33 "agones.dev/agones/pkg/util/runtime" 34 ) 35 36 func TestFleetGameServerSetGameServer(t *testing.T) { 37 t.Parallel() 38 39 f := Fleet{ 40 ObjectMeta: metav1.ObjectMeta{ 41 Name: "test", 42 Namespace: "namespace", 43 UID: "1234", 44 }, 45 Spec: FleetSpec{ 46 Replicas: 10, 47 Scheduling: apis.Packed, 48 Template: GameServerTemplateSpec{ 49 Spec: GameServerSpec{ 50 Ports: []GameServerPort{{ContainerPort: 1234}}, 51 Template: corev1.PodTemplateSpec{ 52 Spec: corev1.PodSpec{ 53 Containers: []corev1.Container{{Name: "container", Image: "myimage"}}, 54 }, 55 }, 56 }, 57 }, 58 }, 59 } 60 61 gsSet := f.GameServerSet() 62 assert.Equal(t, "", gsSet.ObjectMeta.Name) 63 assert.Equal(t, f.ObjectMeta.Namespace, gsSet.ObjectMeta.Namespace) 64 assert.Equal(t, f.ObjectMeta.Name+"-", gsSet.ObjectMeta.GenerateName) 65 assert.Equal(t, f.ObjectMeta.Name, gsSet.ObjectMeta.Labels[FleetNameLabel]) 66 assert.Equal(t, int32(0), gsSet.Spec.Replicas) 67 assert.Equal(t, f.Spec.Scheduling, gsSet.Spec.Scheduling) 68 assert.Equal(t, f.Spec.Template, gsSet.Spec.Template) 69 assert.True(t, metav1.IsControlledBy(gsSet, &f)) 70 71 runtime.FeatureTestMutex.Lock() 72 defer runtime.FeatureTestMutex.Unlock() 73 74 runtime.Must(runtime.ParseFeatures(fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists))) 75 gsSet = f.GameServerSet() 76 assert.Nil(t, gsSet.Spec.AllocationOverflow) 77 78 f.Spec.AllocationOverflow = &AllocationOverflow{ 79 Labels: map[string]string{"stuff": "things"}, 80 Annotations: nil, 81 } 82 83 assert.Nil(t, f.Spec.Priorities) 84 f.Spec.Priorities = []Priority{ 85 {Type: "Counter", 86 Key: "Foo", 87 Order: "Ascending"}} 88 assert.NotNil(t, f.Spec.Priorities) 89 assert.Equal(t, f.Spec.Priorities[0], Priority{Type: "Counter", Key: "Foo", Order: "Ascending"}) 90 91 gsSet = f.GameServerSet() 92 assert.NotNil(t, gsSet.Spec.AllocationOverflow) 93 assert.Equal(t, "things", gsSet.Spec.AllocationOverflow.Labels["stuff"]) 94 95 assert.Equal(t, gsSet.Spec.Priorities[0], Priority{Type: "Counter", Key: "Foo", Order: "Ascending"}) 96 } 97 98 func TestFleetApplyDefaults(t *testing.T) { 99 f := &Fleet{} 100 101 // gate 102 assert.EqualValues(t, "", f.Spec.Strategy.Type) 103 assert.EqualValues(t, "", f.Spec.Scheduling) 104 assert.EqualValues(t, 0, f.Spec.Replicas) 105 106 f.ApplyDefaults() 107 assert.Equal(t, appsv1.RollingUpdateDeploymentStrategyType, f.Spec.Strategy.Type) 108 assert.Equal(t, "25%", f.Spec.Strategy.RollingUpdate.MaxUnavailable.String()) 109 assert.Equal(t, "25%", f.Spec.Strategy.RollingUpdate.MaxSurge.String()) 110 assert.Equal(t, apis.Packed, f.Spec.Scheduling) 111 assert.Equal(t, int32(0), f.Spec.Replicas) 112 assert.Equal(t, pkg.Version, f.ObjectMeta.Annotations[VersionAnnotation]) 113 114 // Test apply defaults is idempotent -- calling ApplyDefaults more than one time does not change the original result. 115 f.ApplyDefaults() 116 assert.Equal(t, appsv1.RollingUpdateDeploymentStrategyType, f.Spec.Strategy.Type) 117 assert.Equal(t, "25%", f.Spec.Strategy.RollingUpdate.MaxUnavailable.String()) 118 assert.Equal(t, "25%", f.Spec.Strategy.RollingUpdate.MaxSurge.String()) 119 assert.Equal(t, apis.Packed, f.Spec.Scheduling) 120 assert.Equal(t, int32(0), f.Spec.Replicas) 121 assert.Equal(t, pkg.Version, f.ObjectMeta.Annotations[VersionAnnotation]) 122 } 123 124 func TestFleetUpperBoundReplicas(t *testing.T) { 125 f := &Fleet{Spec: FleetSpec{Replicas: 10}} 126 127 assert.Equal(t, int32(10), f.UpperBoundReplicas(12)) 128 assert.Equal(t, int32(10), f.UpperBoundReplicas(10)) 129 assert.Equal(t, int32(5), f.UpperBoundReplicas(5)) 130 } 131 132 func TestFleetLowerBoundReplicas(t *testing.T) { 133 f := &Fleet{Spec: FleetSpec{Replicas: 10}} 134 135 assert.Equal(t, int32(5), f.LowerBoundReplicas(5)) 136 assert.Equal(t, int32(0), f.LowerBoundReplicas(0)) 137 assert.Equal(t, int32(0), f.LowerBoundReplicas(-5)) 138 } 139 140 func TestSumStatusAllocatedReplicas(t *testing.T) { 141 f := Fleet{} 142 gsSet1 := f.GameServerSet() 143 gsSet1.Status.AllocatedReplicas = 2 144 145 gsSet2 := f.GameServerSet() 146 gsSet2.Status.AllocatedReplicas = 3 147 148 assert.Equal(t, int32(5), SumStatusAllocatedReplicas([]*GameServerSet{gsSet1, gsSet2})) 149 } 150 151 func TestFleetGameserverSpec(t *testing.T) { 152 f := defaultFleet() 153 f.ApplyDefaults() 154 errs := f.Validate(fakeAPIHooks{}) 155 assert.Len(t, errs, 0) 156 157 f.Spec.Template.Spec.Template = 158 corev1.PodTemplateSpec{ 159 Spec: corev1.PodSpec{ 160 Containers: []corev1.Container{{Name: "container", Image: "myimage"}, {Name: "container2", Image: "myimage"}}, 161 }, 162 } 163 164 errs = f.Validate(fakeAPIHooks{}) 165 assert.Len(t, errs, 1) 166 assert.Equal(t, "spec.template.spec.container", errs[0].Field) 167 168 f.Spec.Template.Spec.Container = "testing" 169 errs = f.Validate(fakeAPIHooks{}) 170 assert.Len(t, errs, 1) 171 assert.Equal(t, "Could not find a container named testing", errs[0].Detail) 172 173 f.Spec.Template.Spec.Container = "container" 174 errs = f.Validate(fakeAPIHooks{}) 175 assert.Len(t, errs, 0) 176 177 // Verify RollingUpdate parameters validation 178 percent := intstr.FromString("0%") 179 f.Spec.Strategy.RollingUpdate.MaxUnavailable = &percent 180 f.Spec.Strategy.RollingUpdate.MaxSurge = &percent 181 errs = f.Validate(fakeAPIHooks{}) 182 assert.Len(t, errs, 2) 183 184 intParam := intstr.FromInt(0) 185 f.Spec.Strategy.RollingUpdate.MaxUnavailable = &intParam 186 f.Spec.Strategy.RollingUpdate.MaxSurge = &intParam 187 errs = f.Validate(fakeAPIHooks{}) 188 assert.Len(t, errs, 2) 189 190 percent = intstr.FromString("2a") 191 f.Spec.Strategy.RollingUpdate.MaxUnavailable = &percent 192 f.Spec.Strategy.RollingUpdate.MaxSurge = &percent 193 errs = f.Validate(fakeAPIHooks{}) 194 assert.Len(t, errs, 2) 195 196 longName := strings.Repeat("f", validation.LabelValueMaxLength+1) 197 f = defaultFleet() 198 f.ApplyDefaults() 199 f.Spec.Template.ObjectMeta.Labels = make(map[string]string) 200 f.Spec.Template.ObjectMeta.Labels["label"] = longName 201 errs = f.Validate(fakeAPIHooks{}) 202 assert.Len(t, errs, 1) 203 204 f = defaultFleet() 205 f.ApplyDefaults() 206 f.Spec.Template.Spec.Template.ObjectMeta.Labels = make(map[string]string) 207 f.Spec.Template.Spec.Template.ObjectMeta.Labels["label"] = longName 208 errs = f.Validate(fakeAPIHooks{}) 209 assert.Len(t, errs, 1) 210 211 // Annotations test 212 f = defaultFleet() 213 f.ApplyDefaults() 214 f.Spec.Template.Spec.Template.ObjectMeta.Annotations = make(map[string]string) 215 f.Spec.Template.Spec.Template.ObjectMeta.Annotations[longName] = "" 216 errs = f.Validate(fakeAPIHooks{}) 217 assert.Len(t, errs, 1) 218 219 // Strategy Type validation test 220 f = defaultFleet() 221 f.ApplyDefaults() 222 f.Spec.Strategy.Type = appsv1.DeploymentStrategyType("") 223 errs = f.Validate(fakeAPIHooks{}) 224 assert.Len(t, errs, 1) 225 } 226 227 func TestFleetAllocationOverflow(t *testing.T) { 228 t.Parallel() 229 230 f := defaultFleet() 231 f.ApplyDefaults() 232 233 errs := f.Validate(fakeAPIHooks{}) 234 require.Empty(t, errs) 235 236 f.Spec.AllocationOverflow = &AllocationOverflow{ 237 Labels: map[string]string{"$$$nope": "value"}, 238 Annotations: nil, 239 } 240 241 errs = f.Validate(fakeAPIHooks{}) 242 require.Len(t, errs, 1) 243 require.Equal(t, field.ErrorTypeInvalid, errs[0].Type) 244 245 } 246 247 func TestFleetName(t *testing.T) { 248 f := defaultFleet() 249 f.ApplyDefaults() 250 251 longName := strings.Repeat("f", validation.LabelValueMaxLength+1) 252 f.Name = longName 253 errs := f.Validate(fakeAPIHooks{}) 254 assert.Len(t, errs, 1) 255 assert.Equal(t, "metadata.name", errs[0].Field) 256 257 f.Name = "" 258 f.GenerateName = longName 259 errs = f.Validate(fakeAPIHooks{}) 260 assert.Len(t, errs, 0) 261 } 262 263 func TestSumStatusReplicas(t *testing.T) { 264 fixture := []*GameServerSet{ 265 {Status: GameServerSetStatus{Replicas: 10}}, 266 {Status: GameServerSetStatus{Replicas: 15}}, 267 {Status: GameServerSetStatus{Replicas: 5}}, 268 } 269 270 assert.Equal(t, int32(30), SumStatusReplicas(fixture)) 271 } 272 273 func TestSumSpecReplicas(t *testing.T) { 274 fixture := []*GameServerSet{ 275 {Spec: GameServerSetSpec{Replicas: 11}}, 276 {Spec: GameServerSetSpec{Replicas: 14}}, 277 {Spec: GameServerSetSpec{Replicas: 100}}, 278 nil, 279 } 280 281 assert.Equal(t, int32(125), SumSpecReplicas(fixture)) 282 } 283 284 func TestGetReadyReplicaCountForGameServerSets(t *testing.T) { 285 fixture := []*GameServerSet{ 286 {Status: GameServerSetStatus{ReadyReplicas: 1000}}, 287 {Status: GameServerSetStatus{ReadyReplicas: 15}}, 288 {Status: GameServerSetStatus{ReadyReplicas: 5}}, 289 nil, 290 } 291 292 assert.Equal(t, int32(1020), GetReadyReplicaCountForGameServerSets(fixture)) 293 } 294 295 func TestSumGameServerSets(t *testing.T) { 296 fixture := []*GameServerSet{ 297 {Status: GameServerSetStatus{ReadyReplicas: 1000}}, 298 {Status: GameServerSetStatus{ReadyReplicas: 15}}, 299 {Status: GameServerSetStatus{ReadyReplicas: 5}}, 300 nil, 301 } 302 303 assert.Equal(t, int32(1020), SumGameServerSets(fixture, func(gsSet *GameServerSet) int32 { 304 return gsSet.Status.ReadyReplicas 305 })) 306 307 assert.Equal(t, int32(0), SumGameServerSets(fixture, func(gsSet *GameServerSet) int32 { 308 return gsSet.Status.Replicas 309 })) 310 } 311 312 func defaultFleet() *Fleet { 313 gs := GameServer{ 314 Spec: GameServerSpec{ 315 Template: corev1.PodTemplateSpec{ 316 Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "testing", Image: "testing/image"}}}}}, 317 } 318 return &Fleet{ 319 ObjectMeta: metav1.ObjectMeta{GenerateName: "simple-fleet-", Namespace: "defaultNs"}, 320 Spec: FleetSpec{ 321 Replicas: 2, 322 Template: GameServerTemplateSpec{ 323 Spec: gs.Spec, 324 }, 325 }, 326 } 327 }