agones.dev/agones@v1.54.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  }