agones.dev/agones@v1.53.0/pkg/gameservers/pernodecounter_test.go (about) 1 // Copyright 2019 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 "time" 20 21 agonesv1 "agones.dev/agones/pkg/apis/agones/v1" 22 agtesting "agones.dev/agones/pkg/testing" 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 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/apimachinery/pkg/watch" 29 k8stesting "k8s.io/client-go/testing" 30 ) 31 32 const ( 33 defaultNs = "default" 34 name1 = "node1" 35 name2 = "node2" 36 ) 37 38 func TestPerNodeCounterGameServerEvents(t *testing.T) { 39 t.Parallel() 40 41 pnc, m := newFakePerNodeCounter() 42 43 fakeWatch := watch.NewFake() 44 m.AgonesClient.AddWatchReactor("gameservers", k8stesting.DefaultWatchReactor(fakeWatch, nil)) 45 46 _, cancel := agtesting.StartInformers(m) 47 defer cancel() 48 49 assert.Empty(t, pnc.Counts()) 50 51 gs := &agonesv1.GameServer{ 52 ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs}, 53 Status: agonesv1.GameServerStatus{ 54 State: agonesv1.GameServerStateStarting, NodeName: name1, 55 }, 56 } 57 58 fakeWatch.Add(gs.DeepCopy()) 59 require.Eventuallyf(t, func() bool { 60 return len(pnc.Counts()) == 0 61 }, 5*time.Second, time.Second, "Should be empty, instead has %v elements", len(pnc.Counts())) 62 63 gs.Status.State = agonesv1.GameServerStateReady 64 fakeWatch.Add(gs.DeepCopy()) 65 66 var counts map[string]NodeCount 67 require.Eventuallyf(t, func() bool { 68 counts = pnc.Counts() 69 return len(counts) == 1 70 }, 5*time.Second, time.Second, "len should be 1, instead: %v", len(counts)) 71 assert.Equal(t, int64(1), counts[name1].Ready) 72 assert.Equal(t, int64(0), counts[name1].Allocated) 73 74 gs.Status.State = agonesv1.GameServerStateAllocated 75 fakeWatch.Add(gs.DeepCopy()) 76 77 require.Eventuallyf(t, func() bool { 78 counts = pnc.Counts() 79 return len(counts) == 1 && int64(0) == counts[name1].Ready 80 }, 5*time.Second, time.Second, "Ready should be 0, but is instead", counts[name1].Ready) 81 assert.Equal(t, int64(1), counts[name1].Allocated) 82 83 gs.Status.State = agonesv1.GameServerStateShutdown 84 fakeWatch.Add(gs.DeepCopy()) 85 require.Eventuallyf(t, func() bool { 86 counts = pnc.Counts() 87 return len(counts) == 1 && int64(0) == counts[name1].Allocated 88 }, 5*time.Second, time.Second, "Allocated should be 0, but is instead", counts[name1].Allocated) 89 assert.Equal(t, int64(0), counts[name1].Ready) 90 91 gs.ObjectMeta.Name = "gs2" 92 gs.Status.State = agonesv1.GameServerStateReady 93 gs.Status.NodeName = name2 94 95 fakeWatch.Add(gs.DeepCopy()) 96 require.Eventuallyf(t, func() bool { 97 counts = pnc.Counts() 98 return len(counts) == 2 99 }, 5*time.Second, time.Second, "len should be 2, instead: %v", len(counts)) 100 assert.Equal(t, int64(0), counts[name1].Ready) 101 assert.Equal(t, int64(0), counts[name1].Allocated) 102 assert.Equal(t, int64(1), counts[name2].Ready) 103 assert.Equal(t, int64(0), counts[name2].Allocated) 104 105 gs.ObjectMeta.Name = "gs3" 106 // not likely, but to test the flow 107 gs.Status.State = agonesv1.GameServerStateAllocated 108 gs.Status.NodeName = name2 109 110 fakeWatch.Add(gs.DeepCopy()) 111 require.Eventuallyf(t, func() bool { 112 counts = pnc.Counts() 113 return len(counts) == 2 && int64(1) == counts[name2].Allocated 114 }, 5*time.Second, time.Second, "Allocated should be 1, but is instead", counts[name2].Allocated) 115 assert.Equal(t, int64(0), counts[name1].Ready) 116 assert.Equal(t, int64(0), counts[name1].Allocated) 117 assert.Equal(t, int64(1), counts[name2].Ready) 118 } 119 120 func TestPerNodeCounterNodeEvents(t *testing.T) { 121 t.Parallel() 122 123 pnc, m := newFakePerNodeCounter() 124 125 gsWatch := watch.NewFake() 126 nodeWatch := watch.NewFake() 127 m.AgonesClient.AddWatchReactor("gameservers", k8stesting.DefaultWatchReactor(gsWatch, nil)) 128 m.KubeClient.AddWatchReactor("nodes", k8stesting.DefaultWatchReactor(nodeWatch, nil)) 129 130 _, cancel := agtesting.StartInformers(m) 131 defer cancel() 132 133 require.Empty(t, pnc.Counts()) 134 135 gs := &agonesv1.GameServer{ 136 ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs}, 137 Status: agonesv1.GameServerStatus{ 138 State: agonesv1.GameServerStateReady, NodeName: name1}} 139 node := &corev1.Node{ObjectMeta: metav1.ObjectMeta{Namespace: defaultNs, Name: name1}} 140 141 gsWatch.Add(gs.DeepCopy()) 142 nodeWatch.Add(node.DeepCopy()) 143 require.Eventuallyf(t, func() bool { 144 return len(pnc.Counts()) == 1 145 }, 5*time.Second, time.Second, "Should be 1 element, not %v", len(pnc.Counts())) 146 147 nodeWatch.Delete(node.DeepCopy()) 148 require.Eventually(t, func() bool { 149 return len(pnc.Counts()) == 0 150 }, 5*time.Second, time.Second, "pnc.Counts() should be empty, but is instead has %v element", len(pnc.Counts())) 151 } 152 153 func TestPerNodeCounterRun(t *testing.T) { 154 t.Parallel() 155 pnc, m := newFakePerNodeCounter() 156 157 gs1 := &agonesv1.GameServer{ 158 ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs}, 159 Status: agonesv1.GameServerStatus{ 160 State: agonesv1.GameServerStateReady, NodeName: name1}} 161 162 gs2 := gs1.DeepCopy() 163 gs2.ObjectMeta.Name = "gs2" 164 gs2.Status.State = agonesv1.GameServerStateAllocated 165 166 gs3 := gs1.DeepCopy() 167 gs3.ObjectMeta.Name = "gs3" 168 gs3.Status.State = agonesv1.GameServerStateStarting 169 gs3.Status.NodeName = name2 170 171 gs4 := gs1.DeepCopy() 172 gs4.ObjectMeta.Name = "gs4" 173 gs4.Status.State = agonesv1.GameServerStateAllocated 174 175 m.AgonesClient.AddReactor("list", "gameservers", func(_ k8stesting.Action) (bool, runtime.Object, error) { 176 return true, &agonesv1.GameServerList{Items: []agonesv1.GameServer{*gs1, *gs2, *gs3, *gs4}}, nil 177 }) 178 179 ctx, cancel := agtesting.StartInformers(m, pnc.gameServerSynced) 180 defer cancel() 181 182 err := pnc.Run(ctx, 0) 183 assert.Nil(t, err) 184 185 counts := pnc.Counts() 186 187 require.Len(t, counts, 2) 188 assert.Equal(t, int64(1), counts[name1].Ready) 189 assert.Equal(t, int64(2), counts[name1].Allocated) 190 assert.Equal(t, int64(0), counts[name2].Ready) 191 assert.Equal(t, int64(0), counts[name2].Allocated) 192 } 193 194 // newFakeController returns a controller, backed by the fake Clientset 195 func newFakePerNodeCounter() (*PerNodeCounter, agtesting.Mocks) { 196 m := agtesting.NewMocks() 197 c := NewPerNodeCounter(m.KubeInformerFactory, m.AgonesInformerFactory) 198 return c, m 199 }