agones.dev/agones@v1.54.0/pkg/gameservers/gameservers_test.go (about) 1 // Copyright 2020 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 gameservers 16 17 import ( 18 "testing" 19 20 agonesv1 "agones.dev/agones/pkg/apis/agones/v1" 21 agtesting "agones.dev/agones/pkg/testing" 22 "agones.dev/agones/pkg/util/runtime" 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 corev1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 ) 28 29 func TestIsGameServerPod(t *testing.T) { 30 t.Parallel() 31 32 t.Run("it is a game server pod", func(t *testing.T) { 33 gs := &agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gameserver", UID: "1234"}, Spec: newSingleContainerSpec()} 34 gs.ApplyDefaults() 35 pod, err := gs.Pod(agtesting.FakeAPIHooks{}) 36 require.NoError(t, err) 37 assert.True(t, isGameServerPod(pod)) 38 }) 39 40 t.Run("it is not a game server pod", func(t *testing.T) { 41 pod := &corev1.Pod{} 42 assert.False(t, isGameServerPod(pod)) 43 }) 44 } 45 46 func TestAddress(t *testing.T) { 47 t.Parallel() 48 49 fixture := map[string]struct { 50 node *corev1.Node 51 expectedAddress string 52 featureFlags string 53 }{ 54 "node with external ip": { 55 node: &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: nodeFixtureName}, Status: corev1.NodeStatus{Addresses: []corev1.NodeAddress{{Address: "12.12.12.12", Type: corev1.NodeExternalIP}}}}, 56 expectedAddress: "12.12.12.12", 57 }, 58 "node with an internal ip": { 59 node: &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: nodeFixtureName}, Status: corev1.NodeStatus{Addresses: []corev1.NodeAddress{{Address: "11.11.11.11", Type: corev1.NodeInternalIP}}}}, 60 expectedAddress: "11.11.11.11", 61 }, 62 "node with internal and external ip": { 63 node: &corev1.Node{ 64 ObjectMeta: metav1.ObjectMeta{Name: nodeFixtureName}, 65 Status: corev1.NodeStatus{Addresses: []corev1.NodeAddress{ 66 {Address: "9.9.9.8", Type: corev1.NodeExternalIP}, 67 {Address: "12.12.12.12", Type: corev1.NodeInternalIP}, 68 }}, 69 }, 70 expectedAddress: "9.9.9.8", 71 }, 72 "node with external and internal dns": { 73 node: &corev1.Node{ 74 ObjectMeta: metav1.ObjectMeta{Name: nodeFixtureName}, 75 Status: corev1.NodeStatus{Addresses: []corev1.NodeAddress{ 76 {Address: "external.example.com", Type: corev1.NodeExternalDNS}, 77 {Address: "internal.example.com", Type: corev1.NodeInternalDNS}, 78 }}, 79 }, 80 expectedAddress: "external.example.com", 81 }, 82 "node with external and internal dns without feature flag": { 83 node: &corev1.Node{ 84 ObjectMeta: metav1.ObjectMeta{Name: nodeFixtureName}, 85 Status: corev1.NodeStatus{Addresses: []corev1.NodeAddress{ 86 {Address: "external.example.com", Type: corev1.NodeExternalDNS}, 87 {Address: "internal.example.com", Type: corev1.NodeInternalDNS}, 88 {Address: "9.9.9.8", Type: corev1.NodeExternalIP}, 89 {Address: "12.12.12.12", Type: corev1.NodeInternalIP}, 90 }}, 91 }, 92 expectedAddress: "external.example.com", 93 }, 94 } 95 96 dummyGS := &agonesv1.GameServer{} 97 dummyGS.Name = "some-gs" 98 99 runtime.FeatureTestMutex.Lock() 100 defer runtime.FeatureTestMutex.Unlock() 101 102 for name, fixture := range fixture { 103 t.Run(name, func(t *testing.T) { 104 err := runtime.ParseFeatures(fixture.featureFlags) 105 assert.NoError(t, err) 106 107 addr, addrs, err := address(fixture.node) 108 require.NoError(t, err) 109 assert.Equal(t, fixture.expectedAddress, addr) 110 assert.Equal(t, fixture.node.Status.Addresses, addrs) 111 }) 112 } 113 } 114 115 func TestApplyGameServerAddressAndPort(t *testing.T) { 116 t.Parallel() 117 118 noopMod := func(*corev1.Pod) {} 119 noopSyncer := func(*agonesv1.GameServer, *corev1.Pod) error { return nil } 120 for name, tc := range map[string]struct { 121 podMod func(*corev1.Pod) 122 podSyncer func(*agonesv1.GameServer, *corev1.Pod) error 123 wantPort int32 124 }{ 125 "normal": {noopMod, noopSyncer, 9999}, 126 "host ports changed after create": { 127 podMod: func(pod *corev1.Pod) { 128 pod.Spec.Containers[0].Ports[0].HostPort = 9876 129 }, 130 podSyncer: func(gs *agonesv1.GameServer, pod *corev1.Pod) error { 131 gs.Spec.Ports[0].HostPort = pod.Spec.Containers[0].Ports[0].HostPort 132 return nil 133 }, 134 wantPort: 9876, 135 }, 136 "container port with PortPolicy None changed after create": { 137 podMod: func(pod *corev1.Pod) { 138 pod.Spec.Containers[0].Ports[0].ContainerPort = 9876 139 }, 140 podSyncer: func(gs *agonesv1.GameServer, pod *corev1.Pod) error { 141 gs.Spec.Ports[0].PortPolicy = agonesv1.None 142 gs.Spec.Ports[0].ContainerPort = pod.Spec.Containers[0].Ports[0].ContainerPort 143 return nil 144 }, 145 wantPort: 9876, 146 }, 147 "Pod IP changed after create": { 148 podMod: func(pod *corev1.Pod) { 149 pod.Status.PodIPs = []corev1.PodIP{ 150 {IP: ipFixture}, 151 } 152 }, 153 podSyncer: noopSyncer, 154 wantPort: 9999, 155 }, 156 } { 157 t.Run(name, func(t *testing.T) { 158 gsFixture := &agonesv1.GameServer{ 159 ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, 160 Spec: newSingleContainerSpec(), Status: agonesv1.GameServerStatus{State: agonesv1.GameServerStateRequestReady}, 161 } 162 gsFixture.ApplyDefaults() 163 node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: nodeFixtureName}, Status: corev1.NodeStatus{Addresses: []corev1.NodeAddress{{Address: ipFixture, Type: corev1.NodeExternalIP}}}} 164 pod, err := gsFixture.Pod(agtesting.FakeAPIHooks{}) 165 require.NoError(t, err) 166 pod.Spec.NodeName = node.ObjectMeta.Name 167 pod.Status.PodIPs = []corev1.PodIP{{IP: ipFixture}} 168 tc.podMod(pod) 169 170 // PortPolicy None is behind a feature flag 171 runtime.FeatureTestMutex.Lock() 172 defer runtime.FeatureTestMutex.Unlock() 173 require.NoError(t, runtime.ParseFeatures(string(runtime.FeaturePortPolicyNone)+"=true")) 174 175 gs, err := applyGameServerAddressAndPort(gsFixture, node, pod, tc.podSyncer) 176 require.NoError(t, err) 177 if assert.NotEmpty(t, gs.Spec.Ports) { 178 assert.Equal(t, tc.wantPort, gs.Status.Ports[0].Port) 179 } 180 assert.Equal(t, ipFixture, gs.Status.Address) 181 assert.Equal(t, node.ObjectMeta.Name, gs.Status.NodeName) 182 assert.Equal(t, []corev1.NodeAddress{ 183 {Address: ipFixture, Type: "ExternalIP"}, 184 {Address: ipFixture, Type: "PodIP"}, 185 }, gs.Status.Addresses) 186 }) 187 } 188 189 t.Run("No IP specified, err expected", func(t *testing.T) { 190 gsFixture := &agonesv1.GameServer{ 191 ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, 192 Spec: newSingleContainerSpec(), Status: agonesv1.GameServerStatus{State: agonesv1.GameServerStateRequestReady}, 193 } 194 gsFixture.ApplyDefaults() 195 node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: nodeFixtureName}, Status: corev1.NodeStatus{Addresses: []corev1.NodeAddress{}}} 196 pod, err := gsFixture.Pod(agtesting.FakeAPIHooks{}) 197 require.NoError(t, err) 198 pod.Spec.NodeName = node.ObjectMeta.Name 199 200 _, err = applyGameServerAddressAndPort(gsFixture, node, pod, noopSyncer) 201 if assert.Error(t, err) { 202 assert.Equal(t, "error getting external address for GameServer test: Could not find an address for Node: node1", err.Error()) 203 } 204 }) 205 } 206 207 func TestIsBeforePodCreated(t *testing.T) { 208 fixture := map[string]struct { 209 state agonesv1.GameServerState 210 expected bool 211 }{ 212 "port": {state: agonesv1.GameServerStatePortAllocation, expected: true}, 213 "creating": {state: agonesv1.GameServerStateCreating, expected: true}, 214 "starting": {state: agonesv1.GameServerStateStarting, expected: true}, 215 "allocated": {state: agonesv1.GameServerStateAllocated, expected: false}, 216 "ready": {state: agonesv1.GameServerStateReady, expected: false}, 217 } 218 219 for k, v := range fixture { 220 t.Run(k, func(t *testing.T) { 221 gs := &agonesv1.GameServer{Status: agonesv1.GameServerStatus{State: v.state}} 222 223 assert.Equal(t, v.expected, isBeforePodCreated(gs)) 224 }) 225 } 226 }