agones.dev/agones@v1.53.0/pkg/gameserversets/gameserversets_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  	"time"
    21  
    22  	agonesv1 "agones.dev/agones/pkg/apis/agones/v1"
    23  	"agones.dev/agones/pkg/gameservers"
    24  	agtesting "agones.dev/agones/pkg/testing"
    25  	utilruntime "agones.dev/agones/pkg/util/runtime"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  	k8stesting "k8s.io/client-go/testing"
    31  )
    32  
    33  func TestSortGameServersByPackedStrategy(t *testing.T) {
    34  	t.Parallel()
    35  
    36  	utilruntime.FeatureTestMutex.Lock()
    37  	defer utilruntime.FeatureTestMutex.Unlock()
    38  
    39  	require.NoError(t, utilruntime.ParseFeatures(string(utilruntime.FeatureCountsAndLists)+"=true"))
    40  
    41  	nc := map[string]gameservers.NodeCount{
    42  		"n1": {Ready: 1, Allocated: 0},
    43  		"n2": {Ready: 0, Allocated: 2},
    44  		"n3": {Ready: 2, Allocated: 2},
    45  		"n4": {Ready: 2, Allocated: 2},
    46  	}
    47  
    48  	list := []*agonesv1.GameServer{
    49  		{ObjectMeta: metav1.ObjectMeta{Name: "g1"}, Status: agonesv1.GameServerStatus{NodeName: "n2", State: agonesv1.GameServerStateReady}},
    50  		{ObjectMeta: metav1.ObjectMeta{Name: "g2"}, Status: agonesv1.GameServerStatus{NodeName: "", State: agonesv1.GameServerStateReady}},
    51  		{ObjectMeta: metav1.ObjectMeta{Name: "g3"}, Status: agonesv1.GameServerStatus{NodeName: "n1", State: agonesv1.GameServerStateReady}},
    52  		{ObjectMeta: metav1.ObjectMeta{Name: "g4"}, Status: agonesv1.GameServerStatus{NodeName: "n2", State: agonesv1.GameServerStateCreating}},
    53  		{ObjectMeta: metav1.ObjectMeta{Name: "g5"}, Status: agonesv1.GameServerStatus{NodeName: "n3", State: agonesv1.GameServerStateReady}},
    54  		{ObjectMeta: metav1.ObjectMeta{Name: "g6"}, Status: agonesv1.GameServerStatus{NodeName: "n4", State: agonesv1.GameServerStateReady}},
    55  		{ObjectMeta: metav1.ObjectMeta{Name: "g7"}, Status: agonesv1.GameServerStatus{NodeName: "n3", State: agonesv1.GameServerStateReady}},
    56  		{ObjectMeta: metav1.ObjectMeta{Name: "g8"}, Status: agonesv1.GameServerStatus{NodeName: "n4", State: agonesv1.GameServerStateReady}},
    57  		{ObjectMeta: metav1.ObjectMeta{Name: "g9"}, Status: agonesv1.GameServerStatus{
    58  			NodeName: "n3",
    59  			State:    agonesv1.GameServerStateAllocated,
    60  			Counters: map[string]agonesv1.CounterStatus{
    61  				"foo": {
    62  					Count:    0,
    63  					Capacity: 100,
    64  				}}}},
    65  		{ObjectMeta: metav1.ObjectMeta{Name: "g10"}, Status: agonesv1.GameServerStatus{
    66  			NodeName: "n3",
    67  			State:    agonesv1.GameServerStateAllocated,
    68  			Counters: map[string]agonesv1.CounterStatus{
    69  				"foo": {
    70  					Count:    99,
    71  					Capacity: 100,
    72  				}}}},
    73  		{ObjectMeta: metav1.ObjectMeta{Name: "g11"}, Status: agonesv1.GameServerStatus{
    74  			NodeName: "n4",
    75  			State:    agonesv1.GameServerStateAllocated,
    76  			Counters: map[string]agonesv1.CounterStatus{
    77  				"foo": {
    78  					Count:    0,
    79  					Capacity: 90,
    80  				}}}},
    81  		{ObjectMeta: metav1.ObjectMeta{Name: "g12"}, Status: agonesv1.GameServerStatus{
    82  			NodeName: "n4",
    83  			State:    agonesv1.GameServerStateAllocated,
    84  			Counters: map[string]agonesv1.CounterStatus{
    85  				"foo": {
    86  					Count:    89,
    87  					Capacity: 90,
    88  				}}}},
    89  	}
    90  
    91  	priorities := []agonesv1.Priority{{
    92  		Type:  "Counter",
    93  		Key:   "foo",
    94  		Order: "Descending",
    95  	}}
    96  
    97  	result := sortGameServersByPackedStrategy(list, nc, priorities)
    98  
    99  	require.Len(t, result, len(list))
   100  	assert.Equal(t, "g2", result[0].ObjectMeta.Name)
   101  	assert.Equal(t, "g3", result[1].ObjectMeta.Name)
   102  	assert.Equal(t, "g4", result[2].ObjectMeta.Name)
   103  	assert.Equal(t, "g1", result[3].ObjectMeta.Name)
   104  	assert.Equal(t, "g9", result[4].ObjectMeta.Name)
   105  	assert.Equal(t, "g10", result[5].ObjectMeta.Name)
   106  	assert.Equal(t, "g5", result[6].ObjectMeta.Name)
   107  	assert.Equal(t, "g7", result[7].ObjectMeta.Name)
   108  	assert.Equal(t, "g11", result[8].ObjectMeta.Name)
   109  	assert.Equal(t, "g12", result[9].ObjectMeta.Name)
   110  	assert.Equal(t, "g6", result[10].ObjectMeta.Name)
   111  	assert.Equal(t, "g8", result[11].ObjectMeta.Name)
   112  
   113  	priorities = []agonesv1.Priority{{
   114  		Type:  "Counter",
   115  		Key:   "foo",
   116  		Order: "Ascending",
   117  	}}
   118  
   119  	result = sortGameServersByPackedStrategy(list, nc, priorities)
   120  
   121  	require.Len(t, result, len(list))
   122  	assert.Equal(t, "g2", result[0].ObjectMeta.Name)
   123  	assert.Equal(t, "g3", result[1].ObjectMeta.Name)
   124  	assert.Equal(t, "g4", result[2].ObjectMeta.Name)
   125  	assert.Equal(t, "g1", result[3].ObjectMeta.Name)
   126  	assert.Equal(t, "g10", result[4].ObjectMeta.Name)
   127  	assert.Equal(t, "g9", result[5].ObjectMeta.Name)
   128  	assert.Equal(t, "g5", result[6].ObjectMeta.Name)
   129  	assert.Equal(t, "g7", result[7].ObjectMeta.Name)
   130  	assert.Equal(t, "g12", result[8].ObjectMeta.Name)
   131  	assert.Equal(t, "g11", result[9].ObjectMeta.Name)
   132  	assert.Equal(t, "g6", result[10].ObjectMeta.Name)
   133  	assert.Equal(t, "g8", result[11].ObjectMeta.Name)
   134  }
   135  
   136  func TestSortGameServersByDistributedStrategy(t *testing.T) {
   137  	t.Parallel()
   138  
   139  	utilruntime.FeatureTestMutex.Lock()
   140  	defer utilruntime.FeatureTestMutex.Unlock()
   141  
   142  	require.NoError(t, utilruntime.ParseFeatures(string(utilruntime.FeatureCountsAndLists)+"=true"))
   143  
   144  	now := metav1.Now()
   145  
   146  	gs1 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "g1", CreationTimestamp: metav1.Time{Time: now.Add(10 * time.Second)}}}
   147  	gs2 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "g2", CreationTimestamp: now}}
   148  	gs3 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "g3", CreationTimestamp: metav1.Time{Time: now.Add(30 * time.Second)}}}
   149  	gs4 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "g4", CreationTimestamp: metav1.Time{Time: now.Add(30 * time.Second)}},
   150  		Status: agonesv1.GameServerStatus{
   151  			Counters: map[string]agonesv1.CounterStatus{
   152  				"bar": {
   153  					Count:    0,
   154  					Capacity: 100,
   155  				}}}}
   156  	gs5 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "g5", CreationTimestamp: now},
   157  		Status: agonesv1.GameServerStatus{
   158  			Counters: map[string]agonesv1.CounterStatus{
   159  				"bar": {
   160  					Count:    0,
   161  					Capacity: 100,
   162  				}}}}
   163  	gs6 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "g6", CreationTimestamp: now},
   164  		Status: agonesv1.GameServerStatus{
   165  			Counters: map[string]agonesv1.CounterStatus{
   166  				"bar": {
   167  					Count:    0,
   168  					Capacity: 1000,
   169  				}}}}
   170  
   171  	testScenarios := map[string]struct {
   172  		list       []*agonesv1.GameServer
   173  		priorities []agonesv1.Priority
   174  		want       []*agonesv1.GameServer
   175  	}{
   176  		"No priorities, sort by creation time": {
   177  			list:       []*agonesv1.GameServer{&gs1, &gs2, &gs3},
   178  			priorities: nil,
   179  			want:       []*agonesv1.GameServer{&gs2, &gs1, &gs3},
   180  		},
   181  		"Descending priorities": {
   182  			list: []*agonesv1.GameServer{&gs4, &gs6, &gs5},
   183  			priorities: []agonesv1.Priority{{
   184  				Type:  "Counter",
   185  				Key:   "bar",
   186  				Order: "Descending",
   187  			}},
   188  			want: []*agonesv1.GameServer{&gs6, &gs5, &gs4},
   189  		},
   190  		"Ascending priorities": {
   191  			list: []*agonesv1.GameServer{&gs4, &gs5, &gs6},
   192  			priorities: []agonesv1.Priority{{
   193  				Type:  "Counter",
   194  				Key:   "bar",
   195  				Order: "Ascending",
   196  			}},
   197  			want: []*agonesv1.GameServer{&gs5, &gs4, &gs6},
   198  		},
   199  	}
   200  
   201  	for testName, testScenario := range testScenarios {
   202  		t.Run(testName, func(t *testing.T) {
   203  
   204  			result := sortGameServersByDistributedStrategy(testScenario.list, testScenario.priorities)
   205  			assert.Equal(t, testScenario.want, result)
   206  		})
   207  	}
   208  }
   209  
   210  func TestListGameServersByGameServerSetOwner(t *testing.T) {
   211  	t.Parallel()
   212  
   213  	gsSet := &agonesv1.GameServerSet{
   214  		ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "test", UID: "1234"},
   215  		Spec: agonesv1.GameServerSetSpec{
   216  			Replicas: 10,
   217  			Template: agonesv1.GameServerTemplateSpec{},
   218  		},
   219  	}
   220  
   221  	gs1 := gsSet.GameServer()
   222  	gs1.ObjectMeta.Name = "test-1"
   223  	gs2 := gsSet.GameServer()
   224  	assert.True(t, metav1.IsControlledBy(gs2, gsSet))
   225  
   226  	gs2.ObjectMeta.Name = "test-2"
   227  	gs3 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "not-included"}}
   228  	gs4 := gsSet.GameServer()
   229  	gs4.ObjectMeta.OwnerReferences = nil
   230  
   231  	m := agtesting.NewMocks()
   232  	m.AgonesClient.AddReactor("list", "gameservers", func(_ k8stesting.Action) (bool, runtime.Object, error) {
   233  		return true, &agonesv1.GameServerList{Items: []agonesv1.GameServer{*gs1, *gs2, gs3, *gs4}}, nil
   234  	})
   235  
   236  	gameServers := m.AgonesInformerFactory.Agones().V1().GameServers()
   237  	_, cancel := agtesting.StartInformers(m, gameServers.Informer().HasSynced)
   238  	defer cancel()
   239  
   240  	list, err := ListGameServersByGameServerSetOwner(gameServers.Lister(), gsSet)
   241  	require.NoError(t, err)
   242  
   243  	// sort of stable ordering
   244  	sort.SliceStable(list, func(i, j int) bool {
   245  		return list[i].ObjectMeta.Name < list[j].ObjectMeta.Name
   246  	})
   247  	assert.Equal(t, []*agonesv1.GameServer{gs1, gs2}, list)
   248  }