agones.dev/agones@v1.53.0/pkg/gameserversets/gameserver_state_cache_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 gameserversets 16 17 import ( 18 "sort" 19 "testing" 20 21 agonesv1 "agones.dev/agones/pkg/apis/agones/v1" 22 "github.com/stretchr/testify/assert" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 ) 25 26 var deletionTime = metav1.Now() 27 28 func TestGameServerStateCache(t *testing.T) { 29 var cache gameServerStateCache 30 gsSet1 := &agonesv1.GameServerSet{ 31 ObjectMeta: metav1.ObjectMeta{ 32 Name: "set-1", 33 Namespace: "ns1", 34 }, 35 } 36 gsSet1b := &agonesv1.GameServerSet{ 37 ObjectMeta: metav1.ObjectMeta{ 38 Name: "set-1", 39 Namespace: "ns2", 40 }, 41 } 42 gsSet2 := &agonesv1.GameServerSet{ 43 ObjectMeta: metav1.ObjectMeta{ 44 Name: "set-2", 45 Namespace: "ns1", 46 }, 47 } 48 49 entry1 := cache.forGameServerSet(gsSet1) 50 if got, want := entry1, cache.forGameServerSet(gsSet1); got != want { 51 t.Errorf("unexpectedly different entries for the same set") 52 } 53 if got, want := entry1, cache.forGameServerSet(gsSet1b); got == want { 54 t.Errorf("unexpectedly same entries for different sets 1 and 1b") 55 } 56 if got, want := entry1, cache.forGameServerSet(gsSet2); got == want { 57 t.Errorf("unexpectedly same entries for different sets 1 and 2") 58 } 59 if got, want := entry1, cache.forGameServerSet(gsSet1); got != want { 60 t.Errorf("unexpectedly different entries for the same set") 61 } 62 cache.deleteGameServerSet(gsSet1) 63 if got, want := entry1, cache.forGameServerSet(gsSet1); got == want { 64 t.Errorf("unexpectedly same entries for sets 1 before and after deletion") 65 } 66 } 67 68 func TestGameServerSetCacheEntry(t *testing.T) { 69 gs1 := makeGameServer("gs-1") 70 gs2 := makeGameServer("gs-2") 71 72 cases := []struct { 73 desc string 74 setup func(c *gameServerSetCacheEntry) 75 list []*agonesv1.GameServer 76 expected []*agonesv1.GameServer 77 expectedPendingCreations int 78 expectedPendingDeletions int 79 }{ 80 { 81 desc: "EmptyList", 82 setup: func(_ *gameServerSetCacheEntry) {}, 83 list: nil, 84 expected: nil, 85 }, 86 { 87 desc: "LocallyAddedGameServerNotInServerResults", 88 setup: func(c *gameServerSetCacheEntry) { c.created(gs1) }, 89 list: nil, 90 expected: []*agonesv1.GameServer{gs1}, 91 expectedPendingCreations: 1, 92 }, 93 { 94 desc: "LocallyAddedGameServerAnotherOneFoundOnServer", 95 setup: func(c *gameServerSetCacheEntry) { c.created(gs1) }, 96 list: []*agonesv1.GameServer{gs2}, 97 expected: []*agonesv1.GameServer{gs1, gs2}, 98 expectedPendingCreations: 1, 99 }, 100 { 101 desc: "LocallyAddedGameServerAlsoFoundOnServer", 102 setup: func(c *gameServerSetCacheEntry) { c.created(gs1) }, 103 list: []*agonesv1.GameServer{gs1}, 104 expected: []*agonesv1.GameServer{gs1}, 105 }, 106 { 107 desc: "LocallyDeletedStillFoundOnServer", 108 setup: func(c *gameServerSetCacheEntry) { c.deleted(gs1) }, 109 list: []*agonesv1.GameServer{gs1}, 110 expected: []*agonesv1.GameServer{deleted(gs1)}, 111 expectedPendingDeletions: 1, 112 }, 113 { 114 desc: "LocallyDeletedNotFoundOnServer", 115 setup: func(c *gameServerSetCacheEntry) { c.deleted(gs1) }, 116 list: []*agonesv1.GameServer{}, 117 expected: []*agonesv1.GameServer{}, 118 }, 119 { 120 desc: "LocallyCreatedAndDeletedFoundOnServer", 121 setup: func(c *gameServerSetCacheEntry) { 122 c.created(gs1) 123 c.deleted(gs1) 124 }, 125 list: []*agonesv1.GameServer{gs1}, 126 expected: []*agonesv1.GameServer{deleted(gs1)}, 127 expectedPendingDeletions: 1, 128 }, 129 { 130 desc: "LocallyCreatedAndDeletedFoundDeletedOnServer", 131 setup: func(c *gameServerSetCacheEntry) { 132 c.created(gs1) 133 c.deleted(gs1) 134 }, 135 list: []*agonesv1.GameServer{deleted(gs1)}, 136 expected: []*agonesv1.GameServer{deleted(gs1)}, 137 }, 138 { 139 desc: "LocallyCreatedAndDeletedNotFoundOnServer", 140 setup: func(c *gameServerSetCacheEntry) { 141 c.created(gs1) 142 c.deleted(gs1) 143 }, 144 list: []*agonesv1.GameServer{}, 145 expected: []*agonesv1.GameServer{}, 146 }, 147 } 148 149 for _, tc := range cases { 150 t.Run(tc.desc, func(t *testing.T) { 151 entry := &gameServerSetCacheEntry{} 152 153 tc.setup(entry) 154 result := entry.reconcileWithUpdatedServerList(tc.list) 155 assert.Equal(t, sortedStatusInfo(result), sortedStatusInfo(tc.expected)) 156 157 if got, want := len(entry.pendingCreation), tc.expectedPendingCreations; got != want { 158 t.Errorf("unexpected # of pending creations %v, wanted %v", got, want) 159 } 160 if got, want := len(entry.pendingDeletion), tc.expectedPendingDeletions; got != want { 161 t.Errorf("unexpected # of pending deletions %v, wanted %v", got, want) 162 } 163 164 result2 := entry.reconcileWithUpdatedServerList(result) 165 assert.Equal(t, sortedStatusInfo(result2), sortedStatusInfo(result)) 166 167 // now both pending creations and deletions must be zero 168 if got, want := len(entry.pendingCreation), 0; got != want { 169 t.Errorf("unexpected # of pending creations %v, wanted %v", got, want) 170 } 171 if got, want := len(entry.pendingDeletion), 0; got != want { 172 t.Errorf("unexpected # of pending deletions %v, wanted %v", got, want) 173 } 174 }) 175 } 176 } 177 178 func makeGameServer(s string) *agonesv1.GameServer { 179 return &agonesv1.GameServer{ 180 ObjectMeta: metav1.ObjectMeta{ 181 Name: s, 182 }, 183 } 184 } 185 186 func deleted(gs *agonesv1.GameServer) *agonesv1.GameServer { 187 gs2 := gs.DeepCopy() 188 gs2.ObjectMeta.DeletionTimestamp = &deletionTime 189 return gs2 190 } 191 192 type gameServerStatusInfo struct { 193 name string 194 status string 195 deleted bool 196 } 197 198 func sortedStatusInfo(list []*agonesv1.GameServer) []gameServerStatusInfo { 199 var result []gameServerStatusInfo 200 for _, gs := range list { 201 result = append(result, gameServerStatusInfo{ 202 gs.Name, 203 string(gs.Status.State), 204 gs.DeletionTimestamp != nil, 205 }) 206 } 207 208 sort.Slice(result, func(i, j int) bool { 209 return result[i].name < result[j].name 210 }) 211 return result 212 }