agones.dev/agones@v1.54.0/pkg/allocation/converters/converter_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 converters
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/require"
    23  	"google.golang.org/grpc/codes"
    24  	"google.golang.org/grpc/status"
    25  	"google.golang.org/protobuf/types/known/wrapperspb"
    26  	corev1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  
    29  	pb "agones.dev/agones/pkg/allocation/go"
    30  	"agones.dev/agones/pkg/apis"
    31  	agonesv1 "agones.dev/agones/pkg/apis/agones/v1"
    32  	allocationv1 "agones.dev/agones/pkg/apis/allocation/v1"
    33  	"agones.dev/agones/pkg/util/runtime"
    34  )
    35  
    36  func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) {
    37  	allocated := agonesv1.GameServerStateAllocated
    38  	ready := agonesv1.GameServerStateReady
    39  	increment := agonesv1.GameServerPriorityIncrement
    40  	decrement := agonesv1.GameServerPriorityDecrement
    41  	one := int64(1)
    42  	ten := int64(10)
    43  
    44  	tests := []struct {
    45  		name     string
    46  		features string
    47  		in       *pb.AllocationRequest
    48  		want     *allocationv1.GameServerAllocation
    49  	}{
    50  		{
    51  			name:     "all fields are set (PlayerAllocationFilter, CountsAndListsFilter)",
    52  			features: fmt.Sprintf("%s=true&%s=true", runtime.FeaturePlayerAllocationFilter, runtime.FeatureCountsAndLists),
    53  			in: &pb.AllocationRequest{
    54  				Namespace: "ns",
    55  				MultiClusterSetting: &pb.MultiClusterSetting{
    56  					Enabled: true,
    57  					PolicySelector: &pb.LabelSelector{
    58  						MatchLabels: map[string]string{
    59  							"a": "b",
    60  						},
    61  					},
    62  				},
    63  				RequiredGameServerSelector: &pb.GameServerSelector{
    64  					MatchLabels: map[string]string{
    65  						"c": "d",
    66  					},
    67  					GameServerState: pb.GameServerSelector_READY,
    68  					Players: &pb.PlayerSelector{
    69  						MinAvailable: 10,
    70  						MaxAvailable: 20,
    71  					},
    72  				},
    73  				PreferredGameServerSelectors: []*pb.GameServerSelector{
    74  					{
    75  						MatchLabels: map[string]string{
    76  							"e": "f",
    77  						},
    78  						GameServerState: pb.GameServerSelector_ALLOCATED,
    79  						Players: &pb.PlayerSelector{
    80  							MinAvailable: 5,
    81  							MaxAvailable: 10,
    82  						},
    83  					},
    84  					{
    85  						MatchLabels: map[string]string{
    86  							"g": "h",
    87  						},
    88  					},
    89  				},
    90  				GameServerSelectors: []*pb.GameServerSelector{
    91  					{
    92  						MatchLabels: map[string]string{
    93  							"m": "n",
    94  						},
    95  						GameServerState: pb.GameServerSelector_READY,
    96  						Counters: map[string]*pb.CounterSelector{
    97  							"o": {
    98  								MinCount:     0,
    99  								MaxCount:     10,
   100  								MinAvailable: 1,
   101  								MaxAvailable: 10,
   102  							},
   103  						},
   104  						Lists: map[string]*pb.ListSelector{
   105  							"p": {
   106  								ContainsValue: "abc",
   107  								MinAvailable:  1,
   108  								MaxAvailable:  10,
   109  							},
   110  						},
   111  					},
   112  				},
   113  				Priorities: []*pb.Priority{
   114  					{
   115  						Type:  pb.Priority_Counter,
   116  						Key:   "o",
   117  						Order: pb.Priority_Descending,
   118  					},
   119  					{
   120  						Type:  pb.Priority_List,
   121  						Key:   "p",
   122  						Order: pb.Priority_Ascending,
   123  					},
   124  				},
   125  				Counters: map[string]*pb.CounterAction{
   126  					"o": {
   127  						Action: wrapperspb.String("Increment"),
   128  						Amount: wrapperspb.Int64(1),
   129  					},
   130  					"q": {
   131  						Action:   wrapperspb.String("Decrement"),
   132  						Amount:   wrapperspb.Int64(1),
   133  						Capacity: wrapperspb.Int64(10),
   134  					},
   135  				},
   136  				Lists: map[string]*pb.ListAction{
   137  					"p": {
   138  						AddValues:    []string{"foo", "bar", "baz"},
   139  						Capacity:     wrapperspb.Int64(10),
   140  						DeleteValues: []string{"alice", "bob", "cat"},
   141  					},
   142  				},
   143  				Scheduling: pb.AllocationRequest_Packed,
   144  				Metadata: &pb.MetaPatch{
   145  					Labels: map[string]string{
   146  						"i": "j",
   147  					},
   148  				},
   149  				MetaPatch: &pb.MetaPatch{
   150  					Labels: map[string]string{
   151  						"i": "j",
   152  					},
   153  				},
   154  			},
   155  			want: &allocationv1.GameServerAllocation{
   156  				ObjectMeta: metav1.ObjectMeta{
   157  					Namespace: "ns",
   158  				},
   159  				Spec: allocationv1.GameServerAllocationSpec{
   160  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   161  						Enabled: true,
   162  						PolicySelector: metav1.LabelSelector{
   163  							MatchLabels: map[string]string{
   164  								"a": "b",
   165  							},
   166  						},
   167  					},
   168  					Required: allocationv1.GameServerSelector{
   169  						LabelSelector: metav1.LabelSelector{
   170  							MatchLabels: map[string]string{
   171  								"c": "d",
   172  							},
   173  						},
   174  						GameServerState: &ready,
   175  						Players:         &allocationv1.PlayerSelector{MinAvailable: 10, MaxAvailable: 20},
   176  					},
   177  					Preferred: []allocationv1.GameServerSelector{
   178  						{
   179  							LabelSelector: metav1.LabelSelector{
   180  								MatchLabels: map[string]string{
   181  									"e": "f",
   182  								},
   183  							},
   184  							GameServerState: &allocated,
   185  							Players:         &allocationv1.PlayerSelector{MinAvailable: 5, MaxAvailable: 10},
   186  						},
   187  						{
   188  							LabelSelector: metav1.LabelSelector{
   189  								MatchLabels: map[string]string{
   190  									"g": "h",
   191  								},
   192  							},
   193  							GameServerState: &ready,
   194  						},
   195  					},
   196  					Priorities: []agonesv1.Priority{
   197  						{
   198  							Type:  "Counter",
   199  							Key:   "o",
   200  							Order: "Descending",
   201  						},
   202  						{
   203  							Type:  "List",
   204  							Key:   "p",
   205  							Order: "Ascending",
   206  						},
   207  					},
   208  					Counters: map[string]allocationv1.CounterAction{
   209  						"o": {
   210  							Action: &increment,
   211  							Amount: &one,
   212  						},
   213  						"q": {
   214  							Action:   &decrement,
   215  							Amount:   &one,
   216  							Capacity: &ten,
   217  						},
   218  					},
   219  					Lists: map[string]allocationv1.ListAction{
   220  						"p": {
   221  							AddValues:    []string{"foo", "bar", "baz"},
   222  							Capacity:     &ten,
   223  							DeleteValues: []string{"alice", "bob", "cat"},
   224  						},
   225  					},
   226  					Selectors: []allocationv1.GameServerSelector{
   227  						{
   228  							LabelSelector: metav1.LabelSelector{
   229  								MatchLabels: map[string]string{
   230  									"m": "n",
   231  								},
   232  							},
   233  							GameServerState: &ready,
   234  							Counters: map[string]allocationv1.CounterSelector{
   235  								"o": {
   236  									MinCount:     0,
   237  									MaxCount:     10,
   238  									MinAvailable: 1,
   239  									MaxAvailable: 10,
   240  								},
   241  							},
   242  							Lists: map[string]allocationv1.ListSelector{
   243  								"p": {
   244  									ContainsValue: "abc",
   245  									MinAvailable:  1,
   246  									MaxAvailable:  10,
   247  								},
   248  							},
   249  						},
   250  					},
   251  					Scheduling: apis.Packed,
   252  					MetaPatch: allocationv1.MetaPatch{
   253  						Labels: map[string]string{
   254  							"i": "j",
   255  						},
   256  					},
   257  				},
   258  			},
   259  		},
   260  		{
   261  			name:     "all fields are set",
   262  			features: fmt.Sprintf("%s=false&%s=false", runtime.FeaturePlayerAllocationFilter, runtime.FeatureCountsAndLists),
   263  			in: &pb.AllocationRequest{
   264  				Namespace: "ns",
   265  				MultiClusterSetting: &pb.MultiClusterSetting{
   266  					Enabled: true,
   267  					PolicySelector: &pb.LabelSelector{
   268  						MatchLabels: map[string]string{
   269  							"a": "b",
   270  						},
   271  					},
   272  				},
   273  				RequiredGameServerSelector: &pb.GameServerSelector{
   274  					MatchLabels: map[string]string{
   275  						"c": "d",
   276  					},
   277  				},
   278  				PreferredGameServerSelectors: []*pb.GameServerSelector{
   279  					{
   280  						MatchLabels: map[string]string{
   281  							"e": "f",
   282  						},
   283  					},
   284  					{
   285  						MatchLabels: map[string]string{
   286  							"g": "h",
   287  						},
   288  					},
   289  				},
   290  				GameServerSelectors: []*pb.GameServerSelector{
   291  					{
   292  						MatchLabels: map[string]string{
   293  							"m": "n",
   294  						},
   295  					},
   296  				},
   297  				Scheduling: pb.AllocationRequest_Packed,
   298  				Metadata: &pb.MetaPatch{
   299  					Labels: map[string]string{
   300  						"i": "j",
   301  					},
   302  				},
   303  				MetaPatch: &pb.MetaPatch{
   304  					Labels: map[string]string{
   305  						"i": "j",
   306  					},
   307  				},
   308  			},
   309  			want: &allocationv1.GameServerAllocation{
   310  				ObjectMeta: metav1.ObjectMeta{
   311  					Namespace: "ns",
   312  				},
   313  				Spec: allocationv1.GameServerAllocationSpec{
   314  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   315  						Enabled: true,
   316  						PolicySelector: metav1.LabelSelector{
   317  							MatchLabels: map[string]string{
   318  								"a": "b",
   319  							},
   320  						},
   321  					},
   322  					Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{
   323  						MatchLabels: map[string]string{
   324  							"c": "d",
   325  						},
   326  					},
   327  						GameServerState: &ready,
   328  					},
   329  					Preferred: []allocationv1.GameServerSelector{
   330  						{
   331  							LabelSelector: metav1.LabelSelector{
   332  								MatchLabels: map[string]string{
   333  									"e": "f",
   334  								},
   335  							},
   336  							GameServerState: &ready,
   337  						},
   338  						{
   339  							LabelSelector: metav1.LabelSelector{
   340  								MatchLabels: map[string]string{
   341  									"g": "h",
   342  								},
   343  							},
   344  							GameServerState: &ready,
   345  						},
   346  					},
   347  					Selectors: []allocationv1.GameServerSelector{
   348  						{
   349  							LabelSelector: metav1.LabelSelector{
   350  								MatchLabels: map[string]string{
   351  									"m": "n",
   352  								},
   353  							},
   354  							GameServerState: &ready,
   355  						},
   356  					},
   357  					Scheduling: apis.Packed,
   358  					MetaPatch: allocationv1.MetaPatch{
   359  						Labels: map[string]string{
   360  							"i": "j",
   361  						},
   362  					},
   363  				},
   364  			},
   365  		},
   366  		{
   367  			name:     "empty fields to GSA",
   368  			features: fmt.Sprintf("%s=false&%s=false", runtime.FeaturePlayerAllocationFilter, runtime.FeatureCountsAndLists),
   369  			in: &pb.AllocationRequest{
   370  				Namespace:                    "",
   371  				MultiClusterSetting:          &pb.MultiClusterSetting{},
   372  				RequiredGameServerSelector:   &pb.GameServerSelector{},
   373  				PreferredGameServerSelectors: []*pb.GameServerSelector{},
   374  				Scheduling:                   pb.AllocationRequest_Distributed,
   375  				Metadata:                     &pb.MetaPatch{},
   376  			},
   377  			want: &allocationv1.GameServerAllocation{
   378  				ObjectMeta: metav1.ObjectMeta{
   379  					Namespace: "",
   380  				},
   381  				Spec: allocationv1.GameServerAllocationSpec{
   382  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   383  						Enabled: false,
   384  					},
   385  					Scheduling: apis.Distributed,
   386  					Required: allocationv1.GameServerSelector{
   387  						GameServerState: &ready,
   388  					},
   389  				},
   390  			},
   391  		},
   392  		{
   393  			name:     "empty fields to GSA (PlayerAllocationFilter, CountsAndListsFilter)",
   394  			features: fmt.Sprintf("%s=true&%s=true", runtime.FeaturePlayerAllocationFilter, runtime.FeatureCountsAndLists),
   395  			in: &pb.AllocationRequest{
   396  				Namespace:                    "",
   397  				MultiClusterSetting:          &pb.MultiClusterSetting{},
   398  				RequiredGameServerSelector:   &pb.GameServerSelector{},
   399  				PreferredGameServerSelectors: []*pb.GameServerSelector{},
   400  				Scheduling:                   pb.AllocationRequest_Distributed,
   401  				Metadata:                     &pb.MetaPatch{},
   402  			},
   403  			want: &allocationv1.GameServerAllocation{
   404  				ObjectMeta: metav1.ObjectMeta{
   405  					Namespace: "",
   406  				},
   407  				Spec: allocationv1.GameServerAllocationSpec{
   408  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   409  						Enabled: false,
   410  					},
   411  					Required: allocationv1.GameServerSelector{
   412  						GameServerState: &ready,
   413  					},
   414  					Scheduling: apis.Distributed,
   415  				},
   416  			},
   417  		},
   418  		{
   419  			name:     "empty fields to GSA with selectors fields",
   420  			features: fmt.Sprintf("%s=false&%s=false", runtime.FeaturePlayerAllocationFilter, runtime.FeatureCountsAndLists),
   421  			in: &pb.AllocationRequest{
   422  				Namespace:           "",
   423  				MultiClusterSetting: &pb.MultiClusterSetting{},
   424  				GameServerSelectors: []*pb.GameServerSelector{{}},
   425  				Scheduling:          pb.AllocationRequest_Distributed,
   426  				Metadata:            &pb.MetaPatch{},
   427  			},
   428  			want: &allocationv1.GameServerAllocation{
   429  				ObjectMeta: metav1.ObjectMeta{
   430  					Namespace: "",
   431  				},
   432  				Spec: allocationv1.GameServerAllocationSpec{
   433  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   434  						Enabled: false,
   435  					},
   436  					Selectors: []allocationv1.GameServerSelector{{
   437  						GameServerState: &ready,
   438  					}},
   439  					Scheduling: apis.Distributed,
   440  				},
   441  			},
   442  		},
   443  		{
   444  			name:     "empty fields to GSA (PlayerAllocationFilter, CountsAndListsFilter) with selectors fields",
   445  			features: fmt.Sprintf("%s=true&%s=true", runtime.FeaturePlayerAllocationFilter, runtime.FeatureCountsAndLists),
   446  			in: &pb.AllocationRequest{
   447  				Namespace:           "",
   448  				MultiClusterSetting: &pb.MultiClusterSetting{},
   449  				GameServerSelectors: []*pb.GameServerSelector{{}},
   450  				Scheduling:          pb.AllocationRequest_Distributed,
   451  				Metadata:            &pb.MetaPatch{},
   452  			},
   453  			want: &allocationv1.GameServerAllocation{
   454  				ObjectMeta: metav1.ObjectMeta{
   455  					Namespace: "",
   456  				},
   457  				Spec: allocationv1.GameServerAllocationSpec{
   458  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   459  						Enabled: false,
   460  					},
   461  					Selectors: []allocationv1.GameServerSelector{
   462  						{GameServerState: &ready},
   463  					},
   464  					Scheduling: apis.Distributed,
   465  				},
   466  			},
   467  		},
   468  		{
   469  			name: "empty object to GSA",
   470  			in:   &pb.AllocationRequest{},
   471  			want: &allocationv1.GameServerAllocation{
   472  				Spec: allocationv1.GameServerAllocationSpec{
   473  					Scheduling: apis.Packed,
   474  				},
   475  			},
   476  		},
   477  		{
   478  			name: "nil object",
   479  			in:   nil,
   480  			want: nil,
   481  		},
   482  		{
   483  			name: "accepts deprecated metapatch field",
   484  			in: &pb.AllocationRequest{
   485  				Namespace:                    "",
   486  				MultiClusterSetting:          &pb.MultiClusterSetting{},
   487  				RequiredGameServerSelector:   &pb.GameServerSelector{},
   488  				PreferredGameServerSelectors: []*pb.GameServerSelector{},
   489  				Scheduling:                   pb.AllocationRequest_Distributed,
   490  				MetaPatch: &pb.MetaPatch{
   491  					Labels: map[string]string{
   492  						"a": "b",
   493  					},
   494  				},
   495  			},
   496  			want: &allocationv1.GameServerAllocation{
   497  				ObjectMeta: metav1.ObjectMeta{
   498  					Namespace: "",
   499  				},
   500  				Spec: allocationv1.GameServerAllocationSpec{
   501  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   502  						Enabled: false,
   503  					},
   504  					Required: allocationv1.GameServerSelector{
   505  						GameServerState: &ready,
   506  					},
   507  					Scheduling: apis.Distributed,
   508  					MetaPatch: allocationv1.MetaPatch{
   509  						Labels: map[string]string{
   510  							"a": "b",
   511  						},
   512  					},
   513  				},
   514  			},
   515  		},
   516  		{
   517  			name: "Prefers metadata over metapatch field",
   518  			in: &pb.AllocationRequest{
   519  				Namespace:                    "",
   520  				MultiClusterSetting:          &pb.MultiClusterSetting{},
   521  				RequiredGameServerSelector:   &pb.GameServerSelector{},
   522  				PreferredGameServerSelectors: []*pb.GameServerSelector{},
   523  				Scheduling:                   pb.AllocationRequest_Distributed,
   524  				Metadata: &pb.MetaPatch{
   525  					Labels: map[string]string{
   526  						"a": "b",
   527  					},
   528  				},
   529  				MetaPatch: &pb.MetaPatch{
   530  					Labels: map[string]string{
   531  						"c": "d",
   532  					},
   533  				},
   534  			},
   535  			want: &allocationv1.GameServerAllocation{
   536  				ObjectMeta: metav1.ObjectMeta{
   537  					Namespace: "",
   538  				},
   539  				Spec: allocationv1.GameServerAllocationSpec{
   540  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   541  						Enabled: false,
   542  					},
   543  					Scheduling: apis.Distributed,
   544  					Required: allocationv1.GameServerSelector{
   545  						GameServerState: &ready,
   546  					},
   547  					MetaPatch: allocationv1.MetaPatch{
   548  						Labels: map[string]string{
   549  							"a": "b",
   550  						},
   551  					},
   552  				},
   553  			},
   554  		},
   555  		{
   556  			name:     "partially empty Counters and Lists fields to GSA (PlayerAllocationFilter, CountsAndListsFilter)",
   557  			features: fmt.Sprintf("%s=true&%s=true", runtime.FeaturePlayerAllocationFilter, runtime.FeatureCountsAndLists),
   558  			in: &pb.AllocationRequest{
   559  				Namespace:                    "",
   560  				MultiClusterSetting:          &pb.MultiClusterSetting{},
   561  				RequiredGameServerSelector:   &pb.GameServerSelector{},
   562  				PreferredGameServerSelectors: []*pb.GameServerSelector{},
   563  				GameServerSelectors: []*pb.GameServerSelector{
   564  					{
   565  						GameServerState: pb.GameServerSelector_READY,
   566  						Counters: map[string]*pb.CounterSelector{
   567  							"c": {
   568  								MinAvailable: 10,
   569  							},
   570  						},
   571  						Lists: map[string]*pb.ListSelector{
   572  							"d": {
   573  								ContainsValue: "abc",
   574  								MinAvailable:  1,
   575  							},
   576  						},
   577  					},
   578  				},
   579  				Lists: map[string]*pb.ListAction{
   580  					"d": {
   581  						Capacity: wrapperspb.Int64(one),
   582  					},
   583  				},
   584  				Scheduling: pb.AllocationRequest_Distributed,
   585  				Metadata:   &pb.MetaPatch{},
   586  			},
   587  			want: &allocationv1.GameServerAllocation{
   588  				ObjectMeta: metav1.ObjectMeta{
   589  					Namespace: "",
   590  				},
   591  				Spec: allocationv1.GameServerAllocationSpec{
   592  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   593  						Enabled: false,
   594  					},
   595  					Required: allocationv1.GameServerSelector{
   596  						GameServerState: &ready,
   597  					},
   598  					Selectors: []allocationv1.GameServerSelector{
   599  						{
   600  							GameServerState: &ready,
   601  							Counters: map[string]allocationv1.CounterSelector{
   602  								"c": {
   603  									MinCount:     0,
   604  									MaxCount:     0,
   605  									MinAvailable: 10,
   606  									MaxAvailable: 0,
   607  								},
   608  							},
   609  							Lists: map[string]allocationv1.ListSelector{
   610  								"d": {
   611  									ContainsValue: "abc",
   612  									MinAvailable:  1,
   613  									MaxAvailable:  0,
   614  								},
   615  							},
   616  						},
   617  					},
   618  					Lists: map[string]allocationv1.ListAction{
   619  						"d": {
   620  							Capacity: &one,
   621  						},
   622  					},
   623  					Scheduling: apis.Distributed,
   624  				},
   625  			},
   626  		},
   627  	}
   628  	for _, tc := range tests {
   629  		t.Run(tc.name, func(t *testing.T) {
   630  			t.Parallel()
   631  
   632  			runtime.FeatureTestMutex.Lock()
   633  			defer runtime.FeatureTestMutex.Unlock()
   634  			require.NoError(t, runtime.ParseFeatures(tc.features))
   635  
   636  			out := ConvertAllocationRequestToGSA(tc.in)
   637  			assert.Equal(t, tc.want, out, "mismatch with want after conversion: \"%s\"", tc.name)
   638  		})
   639  	}
   640  }
   641  
   642  func TestConvertGSAToAllocationRequest(t *testing.T) {
   643  	increment := agonesv1.GameServerPriorityIncrement
   644  	decrement := agonesv1.GameServerPriorityDecrement
   645  	two := int64(2)
   646  	twenty := int64(20)
   647  
   648  	tests := []struct {
   649  		name     string
   650  		features string
   651  		in       *allocationv1.GameServerAllocation
   652  		want     *pb.AllocationRequest
   653  	}{
   654  		{
   655  			name: "empty fields",
   656  			in: &allocationv1.GameServerAllocation{
   657  				ObjectMeta: metav1.ObjectMeta{
   658  					Namespace: "",
   659  				},
   660  				Spec: allocationv1.GameServerAllocationSpec{
   661  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   662  						Enabled: false,
   663  					},
   664  					Scheduling: apis.Distributed,
   665  				},
   666  			},
   667  			want: &pb.AllocationRequest{
   668  				Namespace:           "",
   669  				MultiClusterSetting: &pb.MultiClusterSetting{},
   670  				Scheduling:          pb.AllocationRequest_Distributed,
   671  				Metadata:            &pb.MetaPatch{},
   672  				MetaPatch:           &pb.MetaPatch{},
   673  			},
   674  		}, {
   675  			name: "empty object",
   676  			in: &allocationv1.GameServerAllocation{
   677  				Spec: allocationv1.GameServerAllocationSpec{
   678  					Scheduling: apis.Packed,
   679  				},
   680  			},
   681  			want: &pb.AllocationRequest{
   682  				MultiClusterSetting: &pb.MultiClusterSetting{},
   683  				Metadata:            &pb.MetaPatch{},
   684  				MetaPatch:           &pb.MetaPatch{},
   685  			},
   686  		}, {
   687  			name:     "partial GSA with CountsAndLists",
   688  			features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists),
   689  			in: &allocationv1.GameServerAllocation{
   690  				ObjectMeta: metav1.ObjectMeta{
   691  					Namespace: "",
   692  				},
   693  				Spec: allocationv1.GameServerAllocationSpec{
   694  					MultiClusterSetting: allocationv1.MultiClusterSetting{
   695  						Enabled: false,
   696  					},
   697  					Selectors: []allocationv1.GameServerSelector{
   698  						{
   699  							Counters: map[string]allocationv1.CounterSelector{
   700  								"a": {
   701  									MinCount:     0,
   702  									MaxCount:     0,
   703  									MinAvailable: 10,
   704  									MaxAvailable: 0,
   705  								},
   706  							},
   707  							Lists: map[string]allocationv1.ListSelector{
   708  								"b": {
   709  									ContainsValue: "abc",
   710  									MinAvailable:  1,
   711  									MaxAvailable:  0,
   712  								},
   713  							},
   714  						},
   715  					},
   716  					Priorities: []agonesv1.Priority{
   717  						{
   718  							Type:  "Counter",
   719  							Key:   "a",
   720  							Order: "Ascending",
   721  						},
   722  						{
   723  							Type:  "List",
   724  							Key:   "b",
   725  							Order: "Descending",
   726  						},
   727  					},
   728  					Counters: map[string]allocationv1.CounterAction{
   729  						"a": {
   730  							Action:   &decrement,
   731  							Amount:   &two,
   732  							Capacity: &twenty,
   733  						},
   734  						"c": {
   735  							Action: &increment,
   736  							Amount: &two,
   737  						},
   738  					},
   739  					Lists: map[string]allocationv1.ListAction{
   740  						"b": {
   741  							AddValues: []string{"hello", "world"},
   742  						},
   743  						"d": {
   744  							Capacity: &two,
   745  						},
   746  						"c": {
   747  							DeleteValues: []string{"good", "bye"},
   748  						},
   749  					},
   750  					Scheduling: apis.Distributed,
   751  				},
   752  			},
   753  			want: &pb.AllocationRequest{
   754  				Namespace:                    "",
   755  				MultiClusterSetting:          &pb.MultiClusterSetting{},
   756  				PreferredGameServerSelectors: []*pb.GameServerSelector{},
   757  				RequiredGameServerSelector: &pb.GameServerSelector{
   758  					GameServerState: pb.GameServerSelector_READY,
   759  					Counters: map[string]*pb.CounterSelector{
   760  						"a": {
   761  							MinCount:     0,
   762  							MaxCount:     0,
   763  							MinAvailable: 10,
   764  							MaxAvailable: 0,
   765  						},
   766  					},
   767  					Lists: map[string]*pb.ListSelector{
   768  						"b": {
   769  							ContainsValue: "abc",
   770  							MinAvailable:  1,
   771  							MaxAvailable:  0,
   772  						},
   773  					},
   774  				},
   775  				GameServerSelectors: []*pb.GameServerSelector{
   776  					{
   777  						GameServerState: pb.GameServerSelector_READY,
   778  						Counters: map[string]*pb.CounterSelector{
   779  							"a": {
   780  								MinCount:     0,
   781  								MaxCount:     0,
   782  								MinAvailable: 10,
   783  								MaxAvailable: 0,
   784  							},
   785  						},
   786  						Lists: map[string]*pb.ListSelector{
   787  							"b": {
   788  								ContainsValue: "abc",
   789  								MinAvailable:  1,
   790  								MaxAvailable:  0,
   791  							},
   792  						},
   793  					},
   794  				},
   795  				Scheduling: pb.AllocationRequest_Distributed,
   796  				Metadata:   &pb.MetaPatch{},
   797  				MetaPatch:  &pb.MetaPatch{},
   798  				Priorities: []*pb.Priority{
   799  					{
   800  						Type:  pb.Priority_Counter,
   801  						Key:   "a",
   802  						Order: pb.Priority_Ascending,
   803  					},
   804  					{
   805  						Type:  pb.Priority_List,
   806  						Key:   "b",
   807  						Order: pb.Priority_Descending,
   808  					},
   809  				},
   810  				Counters: map[string]*pb.CounterAction{
   811  					"a": {
   812  						Action:   wrapperspb.String(decrement),
   813  						Amount:   wrapperspb.Int64(two),
   814  						Capacity: wrapperspb.Int64(twenty),
   815  					},
   816  					"c": {
   817  						Action: wrapperspb.String(increment),
   818  						Amount: wrapperspb.Int64(two),
   819  					},
   820  				},
   821  				Lists: map[string]*pb.ListAction{
   822  					"b": {
   823  						AddValues: []string{"hello", "world"},
   824  					},
   825  					"d": {
   826  						Capacity: wrapperspb.Int64(two),
   827  					},
   828  					"c": {
   829  						DeleteValues: []string{"good", "bye"},
   830  					},
   831  				},
   832  			},
   833  		},
   834  	}
   835  	for _, tc := range tests {
   836  		t.Run(tc.name, func(t *testing.T) {
   837  			t.Parallel()
   838  
   839  			runtime.FeatureTestMutex.Lock()
   840  			defer runtime.FeatureTestMutex.Unlock()
   841  			require.NoError(t, runtime.ParseFeatures(tc.features))
   842  
   843  			ar := ConvertGSAToAllocationRequest(tc.in)
   844  			if !assert.Equal(t, tc.want, ar) {
   845  				t.Errorf("mismatch with want after conversion \"%s\"", tc.name)
   846  			}
   847  		})
   848  	}
   849  }
   850  
   851  func TestConvertGSAToAllocationResponse(t *testing.T) {
   852  	tests := []struct {
   853  		name                      string
   854  		features                  string
   855  		in                        *allocationv1.GameServerAllocation
   856  		grpcUnallocatedStatusCode codes.Code
   857  		want                      *pb.AllocationResponse
   858  		wantErrCode               codes.Code
   859  		skipConvertToGSA          bool
   860  	}{
   861  		{
   862  			name: "status state is set to allocated",
   863  			in: &allocationv1.GameServerAllocation{
   864  				TypeMeta: metav1.TypeMeta{
   865  					Kind:       "GameServerAllocation",
   866  					APIVersion: "allocation.agones.dev/v1",
   867  				},
   868  				Status: allocationv1.GameServerAllocationStatus{
   869  					State:          allocationv1.GameServerAllocationAllocated,
   870  					GameServerName: "GSN",
   871  					Ports: []agonesv1.GameServerStatusPort{
   872  						{
   873  							Port: 123,
   874  						},
   875  						{
   876  							Name: "port-name",
   877  						},
   878  					},
   879  					Address:  "address",
   880  					NodeName: "node-name",
   881  					Source:   "local",
   882  				},
   883  			},
   884  			want: &pb.AllocationResponse{
   885  				GameServerName: "GSN",
   886  				Address:        "address",
   887  				NodeName:       "node-name",
   888  				Ports: []*pb.AllocationResponse_GameServerStatusPort{
   889  					{
   890  						Port: 123,
   891  					},
   892  					{
   893  						Name: "port-name",
   894  					},
   895  				},
   896  				Source: "local",
   897  			},
   898  		},
   899  		{
   900  			name: "status field is set to unallocated",
   901  			in: &allocationv1.GameServerAllocation{
   902  				TypeMeta: metav1.TypeMeta{
   903  					Kind:       "GameServerAllocation",
   904  					APIVersion: "allocation.agones.dev/v1",
   905  				},
   906  				Status: allocationv1.GameServerAllocationStatus{
   907  					State:          allocationv1.GameServerAllocationUnAllocated,
   908  					GameServerName: "GSN",
   909  					Ports: []agonesv1.GameServerStatusPort{
   910  						{
   911  							Port: 123,
   912  						},
   913  						{
   914  							Name: "port-name",
   915  						},
   916  					},
   917  					Address:  "address",
   918  					NodeName: "node-name",
   919  				},
   920  			},
   921  			wantErrCode:      codes.ResourceExhausted,
   922  			skipConvertToGSA: true,
   923  		},
   924  		{
   925  			name: "status state is set to contention",
   926  			in: &allocationv1.GameServerAllocation{
   927  				TypeMeta: metav1.TypeMeta{
   928  					Kind:       "GameServerAllocation",
   929  					APIVersion: "allocation.agones.dev/v1",
   930  				},
   931  				Status: allocationv1.GameServerAllocationStatus{
   932  					State: allocationv1.GameServerAllocationContention,
   933  				},
   934  			},
   935  			wantErrCode:      codes.Aborted,
   936  			skipConvertToGSA: true,
   937  		},
   938  		{
   939  			name: "Empty fields",
   940  			in: &allocationv1.GameServerAllocation{
   941  				TypeMeta: metav1.TypeMeta{
   942  					Kind:       "GameServerAllocation",
   943  					APIVersion: "allocation.agones.dev/v1",
   944  				},
   945  				Status: allocationv1.GameServerAllocationStatus{
   946  					Ports: []agonesv1.GameServerStatusPort{},
   947  				},
   948  			},
   949  			wantErrCode:      codes.Unknown,
   950  			skipConvertToGSA: true,
   951  		},
   952  		{
   953  			name: "Empty objects",
   954  			in: &allocationv1.GameServerAllocation{
   955  				TypeMeta: metav1.TypeMeta{
   956  					Kind:       "GameServerAllocation",
   957  					APIVersion: "allocation.agones.dev/v1",
   958  				},
   959  				Status: allocationv1.GameServerAllocationStatus{
   960  					State: allocationv1.GameServerAllocationAllocated,
   961  				},
   962  			},
   963  			want: &pb.AllocationResponse{},
   964  		},
   965  		{
   966  			name: "nil objects",
   967  			in:   nil,
   968  			want: nil,
   969  		},
   970  		{
   971  			name: "status metadata contains labels and annotations",
   972  			in: &allocationv1.GameServerAllocation{
   973  				TypeMeta: metav1.TypeMeta{
   974  					Kind:       "GameServerAllocation",
   975  					APIVersion: "allocation.agones.dev/v1",
   976  				},
   977  				Status: allocationv1.GameServerAllocationStatus{
   978  					State:          allocationv1.GameServerAllocationAllocated,
   979  					GameServerName: "GSN",
   980  					Ports: []agonesv1.GameServerStatusPort{
   981  						{
   982  							Port: 123,
   983  						},
   984  						{
   985  							Name: "port-name",
   986  						},
   987  					},
   988  					Address:  "address",
   989  					NodeName: "node-name",
   990  					Source:   "local",
   991  					Metadata: &allocationv1.GameServerMetadata{
   992  						Labels: map[string]string{
   993  							"label-key": "label-value",
   994  							"other-key": "other-value",
   995  						},
   996  						Annotations: map[string]string{
   997  							"annotation-key": "annotation-value",
   998  							"other-key":      "other-value",
   999  						},
  1000  					},
  1001  				},
  1002  			},
  1003  			want: &pb.AllocationResponse{
  1004  				GameServerName: "GSN",
  1005  				Address:        "address",
  1006  				NodeName:       "node-name",
  1007  				Ports: []*pb.AllocationResponse_GameServerStatusPort{
  1008  					{
  1009  						Port: 123,
  1010  					},
  1011  					{
  1012  						Name: "port-name",
  1013  					},
  1014  				},
  1015  				Source: "local",
  1016  				Metadata: &pb.AllocationResponse_GameServerMetadata{
  1017  					Labels: map[string]string{
  1018  						"label-key": "label-value",
  1019  						"other-key": "other-value",
  1020  					},
  1021  					Annotations: map[string]string{
  1022  						"annotation-key": "annotation-value",
  1023  						"other-key":      "other-value",
  1024  					},
  1025  				},
  1026  			},
  1027  		},
  1028  		{
  1029  			name: "addresses convert",
  1030  			in: &allocationv1.GameServerAllocation{
  1031  				TypeMeta: metav1.TypeMeta{
  1032  					Kind:       "GameServerAllocation",
  1033  					APIVersion: "allocation.agones.dev/v1",
  1034  				},
  1035  				Status: allocationv1.GameServerAllocationStatus{
  1036  					State:          allocationv1.GameServerAllocationAllocated,
  1037  					GameServerName: "GSN",
  1038  					Ports: []agonesv1.GameServerStatusPort{
  1039  						{
  1040  							Port: 123,
  1041  						},
  1042  						{
  1043  							Name: "port-name",
  1044  						},
  1045  					},
  1046  					Address: "address",
  1047  					Addresses: []corev1.NodeAddress{
  1048  						{Type: "SomeAddressType", Address: "123.123.123.123"},
  1049  						{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1050  					},
  1051  					NodeName: "node-name",
  1052  					Source:   "local",
  1053  					Metadata: &allocationv1.GameServerMetadata{
  1054  						Labels: map[string]string{
  1055  							"label-key": "label-value",
  1056  							"other-key": "other-value",
  1057  						},
  1058  						Annotations: map[string]string{
  1059  							"annotation-key": "annotation-value",
  1060  							"other-key":      "other-value",
  1061  						},
  1062  					},
  1063  				},
  1064  			},
  1065  			want: &pb.AllocationResponse{
  1066  				GameServerName: "GSN",
  1067  				Address:        "address",
  1068  				Addresses: []*pb.AllocationResponse_GameServerStatusAddress{
  1069  					{Type: "SomeAddressType", Address: "123.123.123.123"},
  1070  					{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1071  				},
  1072  				NodeName: "node-name",
  1073  				Ports: []*pb.AllocationResponse_GameServerStatusPort{
  1074  					{
  1075  						Port: 123,
  1076  					},
  1077  					{
  1078  						Name: "port-name",
  1079  					},
  1080  				},
  1081  				Source: "local",
  1082  				Metadata: &pb.AllocationResponse_GameServerMetadata{
  1083  					Labels: map[string]string{
  1084  						"label-key": "label-value",
  1085  						"other-key": "other-value",
  1086  					},
  1087  					Annotations: map[string]string{
  1088  						"annotation-key": "annotation-value",
  1089  						"other-key":      "other-value",
  1090  					},
  1091  				},
  1092  			},
  1093  		},
  1094  		{
  1095  			name:     "all fields are set (CountsAndLists)",
  1096  			features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists),
  1097  			in: &allocationv1.GameServerAllocation{
  1098  				TypeMeta: metav1.TypeMeta{
  1099  					Kind:       "GameServerAllocation",
  1100  					APIVersion: "allocation.agones.dev/v1",
  1101  				},
  1102  				Status: allocationv1.GameServerAllocationStatus{
  1103  					State:          allocationv1.GameServerAllocationAllocated,
  1104  					GameServerName: "GSN",
  1105  					Ports: []agonesv1.GameServerStatusPort{
  1106  						{
  1107  							Port: 123,
  1108  						},
  1109  						{
  1110  							Name: "port-name",
  1111  						},
  1112  					},
  1113  					Address: "address",
  1114  					Addresses: []corev1.NodeAddress{
  1115  						{Type: "SomeAddressType", Address: "123.123.123.123"},
  1116  						{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1117  					},
  1118  					NodeName: "node-name",
  1119  					Source:   "local",
  1120  					Metadata: &allocationv1.GameServerMetadata{
  1121  						Labels: map[string]string{
  1122  							"label-key": "label-value",
  1123  							"other-key": "other-value",
  1124  						},
  1125  						Annotations: map[string]string{
  1126  							"annotation-key": "annotation-value",
  1127  							"other-key":      "other-value",
  1128  						},
  1129  					},
  1130  					Counters: map[string]agonesv1.CounterStatus{
  1131  						"p": {
  1132  							Count:    0,
  1133  							Capacity: 1,
  1134  						},
  1135  					},
  1136  					Lists: map[string]agonesv1.ListStatus{
  1137  						"p": {
  1138  							Values:   []string{"foo", "bar", "baz"},
  1139  							Capacity: 10,
  1140  						},
  1141  					},
  1142  				},
  1143  			},
  1144  			want: &pb.AllocationResponse{
  1145  				GameServerName: "GSN",
  1146  				Address:        "address",
  1147  				Addresses: []*pb.AllocationResponse_GameServerStatusAddress{
  1148  					{Type: "SomeAddressType", Address: "123.123.123.123"},
  1149  					{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1150  				},
  1151  				NodeName: "node-name",
  1152  				Ports: []*pb.AllocationResponse_GameServerStatusPort{
  1153  					{
  1154  						Port: 123,
  1155  					},
  1156  					{
  1157  						Name: "port-name",
  1158  					},
  1159  				},
  1160  				Source: "local",
  1161  				Metadata: &pb.AllocationResponse_GameServerMetadata{
  1162  					Labels: map[string]string{
  1163  						"label-key": "label-value",
  1164  						"other-key": "other-value",
  1165  					},
  1166  					Annotations: map[string]string{
  1167  						"annotation-key": "annotation-value",
  1168  						"other-key":      "other-value",
  1169  					},
  1170  				},
  1171  				Counters: map[string]*pb.AllocationResponse_CounterStatus{
  1172  					"p": {
  1173  						Count:    wrapperspb.Int64(0),
  1174  						Capacity: wrapperspb.Int64(1),
  1175  					},
  1176  				},
  1177  				Lists: map[string]*pb.AllocationResponse_ListStatus{
  1178  					"p": {
  1179  						Values:   []string{"foo", "bar", "baz"},
  1180  						Capacity: wrapperspb.Int64(10),
  1181  					},
  1182  				},
  1183  			},
  1184  		},
  1185  		{
  1186  			name:     "Counters fields are set (CountsAndLists)",
  1187  			features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists),
  1188  			in: &allocationv1.GameServerAllocation{
  1189  				TypeMeta: metav1.TypeMeta{
  1190  					Kind:       "GameServerAllocation",
  1191  					APIVersion: "allocation.agones.dev/v1",
  1192  				},
  1193  				Status: allocationv1.GameServerAllocationStatus{
  1194  					State:          allocationv1.GameServerAllocationAllocated,
  1195  					GameServerName: "GSN",
  1196  					Ports: []agonesv1.GameServerStatusPort{
  1197  						{
  1198  							Port: 123,
  1199  						},
  1200  						{
  1201  							Name: "port-name",
  1202  						},
  1203  					},
  1204  					Address: "address",
  1205  					Addresses: []corev1.NodeAddress{
  1206  						{Type: "SomeAddressType", Address: "123.123.123.123"},
  1207  						{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1208  					},
  1209  					NodeName: "node-name",
  1210  					Source:   "local",
  1211  					Metadata: &allocationv1.GameServerMetadata{
  1212  						Labels: map[string]string{
  1213  							"label-key": "label-value",
  1214  							"other-key": "other-value",
  1215  						},
  1216  						Annotations: map[string]string{
  1217  							"annotation-key": "annotation-value",
  1218  							"other-key":      "other-value",
  1219  						},
  1220  					},
  1221  					Counters: map[string]agonesv1.CounterStatus{
  1222  						"p": {
  1223  							Count:    0,
  1224  							Capacity: 1,
  1225  						},
  1226  					},
  1227  				},
  1228  			},
  1229  			want: &pb.AllocationResponse{
  1230  				GameServerName: "GSN",
  1231  				Address:        "address",
  1232  				Addresses: []*pb.AllocationResponse_GameServerStatusAddress{
  1233  					{Type: "SomeAddressType", Address: "123.123.123.123"},
  1234  					{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1235  				},
  1236  				NodeName: "node-name",
  1237  				Ports: []*pb.AllocationResponse_GameServerStatusPort{
  1238  					{
  1239  						Port: 123,
  1240  					},
  1241  					{
  1242  						Name: "port-name",
  1243  					},
  1244  				},
  1245  				Source: "local",
  1246  				Metadata: &pb.AllocationResponse_GameServerMetadata{
  1247  					Labels: map[string]string{
  1248  						"label-key": "label-value",
  1249  						"other-key": "other-value",
  1250  					},
  1251  					Annotations: map[string]string{
  1252  						"annotation-key": "annotation-value",
  1253  						"other-key":      "other-value",
  1254  					},
  1255  				},
  1256  				Counters: map[string]*pb.AllocationResponse_CounterStatus{
  1257  					"p": {
  1258  						Count:    wrapperspb.Int64(0),
  1259  						Capacity: wrapperspb.Int64(1),
  1260  					},
  1261  				},
  1262  			},
  1263  		},
  1264  		{
  1265  			name:     "Lists fields are set (CountsAndLists)",
  1266  			features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists),
  1267  			in: &allocationv1.GameServerAllocation{
  1268  				TypeMeta: metav1.TypeMeta{
  1269  					Kind:       "GameServerAllocation",
  1270  					APIVersion: "allocation.agones.dev/v1",
  1271  				},
  1272  				Status: allocationv1.GameServerAllocationStatus{
  1273  					State:          allocationv1.GameServerAllocationAllocated,
  1274  					GameServerName: "GSN",
  1275  					Ports: []agonesv1.GameServerStatusPort{
  1276  						{
  1277  							Port: 123,
  1278  						},
  1279  						{
  1280  							Name: "port-name",
  1281  						},
  1282  					},
  1283  					Address: "address",
  1284  					Addresses: []corev1.NodeAddress{
  1285  						{Type: "SomeAddressType", Address: "123.123.123.123"},
  1286  						{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1287  					},
  1288  					NodeName: "node-name",
  1289  					Source:   "local",
  1290  					Metadata: &allocationv1.GameServerMetadata{
  1291  						Labels: map[string]string{
  1292  							"label-key": "label-value",
  1293  							"other-key": "other-value",
  1294  						},
  1295  						Annotations: map[string]string{
  1296  							"annotation-key": "annotation-value",
  1297  							"other-key":      "other-value",
  1298  						},
  1299  					},
  1300  					Lists: map[string]agonesv1.ListStatus{
  1301  						"p": {
  1302  							Values:   []string{"foo", "bar", "baz"},
  1303  							Capacity: 10,
  1304  						},
  1305  					},
  1306  				},
  1307  			},
  1308  			want: &pb.AllocationResponse{
  1309  				GameServerName: "GSN",
  1310  				Address:        "address",
  1311  				Addresses: []*pb.AllocationResponse_GameServerStatusAddress{
  1312  					{Type: "SomeAddressType", Address: "123.123.123.123"},
  1313  					{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1314  				},
  1315  				NodeName: "node-name",
  1316  				Ports: []*pb.AllocationResponse_GameServerStatusPort{
  1317  					{
  1318  						Port: 123,
  1319  					},
  1320  					{
  1321  						Name: "port-name",
  1322  					},
  1323  				},
  1324  				Source: "local",
  1325  				Metadata: &pb.AllocationResponse_GameServerMetadata{
  1326  					Labels: map[string]string{
  1327  						"label-key": "label-value",
  1328  						"other-key": "other-value",
  1329  					},
  1330  					Annotations: map[string]string{
  1331  						"annotation-key": "annotation-value",
  1332  						"other-key":      "other-value",
  1333  					},
  1334  				},
  1335  				Lists: map[string]*pb.AllocationResponse_ListStatus{
  1336  					"p": {
  1337  						Values:   []string{"foo", "bar", "baz"},
  1338  						Capacity: wrapperspb.Int64(10),
  1339  					},
  1340  				},
  1341  			},
  1342  		},
  1343  		{
  1344  			name: "status field is set to unallocated, non-default unallocated",
  1345  			in: &allocationv1.GameServerAllocation{
  1346  				TypeMeta: metav1.TypeMeta{
  1347  					Kind:       "GameServerAllocation",
  1348  					APIVersion: "allocation.agones.dev/v1",
  1349  				},
  1350  				Status: allocationv1.GameServerAllocationStatus{
  1351  					State:          allocationv1.GameServerAllocationUnAllocated,
  1352  					GameServerName: "GSN",
  1353  					Ports: []agonesv1.GameServerStatusPort{
  1354  						{
  1355  							Port: 123,
  1356  						},
  1357  						{
  1358  							Name: "port-name",
  1359  						},
  1360  					},
  1361  					Address:  "address",
  1362  					NodeName: "node-name",
  1363  				},
  1364  			},
  1365  			grpcUnallocatedStatusCode: codes.Unimplemented,
  1366  			wantErrCode:               codes.Unimplemented,
  1367  			skipConvertToGSA:          true,
  1368  		},
  1369  	}
  1370  	for _, tc := range tests {
  1371  		t.Run(tc.name, func(t *testing.T) {
  1372  			t.Parallel()
  1373  			runtime.FeatureTestMutex.Lock()
  1374  			defer runtime.FeatureTestMutex.Unlock()
  1375  			require.NoError(t, runtime.ParseFeatures(tc.features))
  1376  
  1377  			grpcUnallocatedStatusCode := tc.grpcUnallocatedStatusCode
  1378  			if grpcUnallocatedStatusCode == codes.OK {
  1379  				grpcUnallocatedStatusCode = codes.ResourceExhausted
  1380  			}
  1381  
  1382  			out, err := ConvertGSAToAllocationResponse(tc.in, grpcUnallocatedStatusCode)
  1383  			if tc.wantErrCode != 0 {
  1384  				st, ok := status.FromError(err)
  1385  				if !assert.True(t, ok) {
  1386  					return
  1387  				}
  1388  				assert.Equal(t, tc.wantErrCode, st.Code())
  1389  			}
  1390  			if !assert.Equal(t, tc.want, out) {
  1391  				t.Errorf("mismatch with want after conversion: \"%s\"", tc.name)
  1392  			}
  1393  
  1394  			if !tc.skipConvertToGSA {
  1395  				source := ""
  1396  				if tc.in != nil {
  1397  					source = tc.in.Status.Source
  1398  				}
  1399  				gsa := ConvertAllocationResponseToGSA(tc.want, source)
  1400  				if !assert.Equal(t, tc.in, gsa) {
  1401  					t.Errorf("mismatch with input after double conversion \"%s\"", tc.name)
  1402  				}
  1403  			}
  1404  		})
  1405  	}
  1406  }
  1407  
  1408  func TestConvertAllocationResponseToGSA(t *testing.T) {
  1409  	tests := []struct {
  1410  		name     string
  1411  		features string
  1412  		in       *pb.AllocationResponse
  1413  		want     *allocationv1.GameServerAllocation
  1414  	}{
  1415  		{
  1416  			name: "Empty fields",
  1417  			in: &pb.AllocationResponse{
  1418  				Ports:  []*pb.AllocationResponse_GameServerStatusPort{},
  1419  				Source: "33.188.237.156:443",
  1420  			},
  1421  			want: &allocationv1.GameServerAllocation{
  1422  				TypeMeta: metav1.TypeMeta{
  1423  					Kind:       "GameServerAllocation",
  1424  					APIVersion: "allocation.agones.dev/v1",
  1425  				},
  1426  				Status: allocationv1.GameServerAllocationStatus{
  1427  					State:  allocationv1.GameServerAllocationAllocated,
  1428  					Source: "33.188.237.156:443",
  1429  				},
  1430  			},
  1431  		},
  1432  		{
  1433  			name: "Addresses convert",
  1434  			in: &pb.AllocationResponse{
  1435  				Ports:  []*pb.AllocationResponse_GameServerStatusPort{},
  1436  				Source: "33.188.237.156:443",
  1437  				Addresses: []*pb.AllocationResponse_GameServerStatusAddress{
  1438  					{Type: "SomeAddressType", Address: "123.123.123.123"},
  1439  					{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1440  				},
  1441  			},
  1442  			want: &allocationv1.GameServerAllocation{
  1443  				TypeMeta: metav1.TypeMeta{
  1444  					Kind:       "GameServerAllocation",
  1445  					APIVersion: "allocation.agones.dev/v1",
  1446  				},
  1447  				Status: allocationv1.GameServerAllocationStatus{
  1448  					State:  allocationv1.GameServerAllocationAllocated,
  1449  					Source: "33.188.237.156:443",
  1450  					Addresses: []corev1.NodeAddress{
  1451  						{Type: "SomeAddressType", Address: "123.123.123.123"},
  1452  						{Type: "AnotherAddressType", Address: "321.321.321.321"},
  1453  					},
  1454  				},
  1455  			},
  1456  		},
  1457  		{
  1458  			name:     "Counters and Lists convert",
  1459  			features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists),
  1460  			in: &pb.AllocationResponse{
  1461  				Ports:  []*pb.AllocationResponse_GameServerStatusPort{},
  1462  				Source: "33.188.237.156:443",
  1463  				Counters: map[string]*pb.AllocationResponse_CounterStatus{
  1464  					"p": {
  1465  						Count:    wrapperspb.Int64(1),
  1466  						Capacity: wrapperspb.Int64(3),
  1467  					},
  1468  				},
  1469  				Lists: map[string]*pb.AllocationResponse_ListStatus{
  1470  					"p": {
  1471  						Values:   []string{"foo", "bar", "baz"},
  1472  						Capacity: wrapperspb.Int64(3),
  1473  					},
  1474  				},
  1475  			},
  1476  			want: &allocationv1.GameServerAllocation{
  1477  				TypeMeta: metav1.TypeMeta{
  1478  					Kind:       "GameServerAllocation",
  1479  					APIVersion: "allocation.agones.dev/v1",
  1480  				},
  1481  				Status: allocationv1.GameServerAllocationStatus{
  1482  					State:  allocationv1.GameServerAllocationAllocated,
  1483  					Source: "33.188.237.156:443",
  1484  					Counters: map[string]agonesv1.CounterStatus{
  1485  						"p": {
  1486  							Count:    1,
  1487  							Capacity: 3,
  1488  						},
  1489  					},
  1490  					Lists: map[string]agonesv1.ListStatus{
  1491  						"p": {
  1492  							Values:   []string{"foo", "bar", "baz"},
  1493  							Capacity: 3,
  1494  						},
  1495  					},
  1496  				},
  1497  			},
  1498  		},
  1499  		{
  1500  			name:     "Counters convert",
  1501  			features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists),
  1502  			in: &pb.AllocationResponse{
  1503  				Ports:  []*pb.AllocationResponse_GameServerStatusPort{},
  1504  				Source: "33.188.237.156:443",
  1505  				Counters: map[string]*pb.AllocationResponse_CounterStatus{
  1506  					"p": {
  1507  						Count:    wrapperspb.Int64(1),
  1508  						Capacity: wrapperspb.Int64(3),
  1509  					},
  1510  				},
  1511  			},
  1512  			want: &allocationv1.GameServerAllocation{
  1513  				TypeMeta: metav1.TypeMeta{
  1514  					Kind:       "GameServerAllocation",
  1515  					APIVersion: "allocation.agones.dev/v1",
  1516  				},
  1517  				Status: allocationv1.GameServerAllocationStatus{
  1518  					State:  allocationv1.GameServerAllocationAllocated,
  1519  					Source: "33.188.237.156:443",
  1520  					Counters: map[string]agonesv1.CounterStatus{
  1521  						"p": {
  1522  							Count:    1,
  1523  							Capacity: 3,
  1524  						},
  1525  					},
  1526  				},
  1527  			},
  1528  		},
  1529  		{
  1530  			name:     "List convert",
  1531  			features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists),
  1532  			in: &pb.AllocationResponse{
  1533  				Ports:  []*pb.AllocationResponse_GameServerStatusPort{},
  1534  				Source: "33.188.237.156:443",
  1535  				Lists: map[string]*pb.AllocationResponse_ListStatus{
  1536  					"p": {
  1537  						Values:   []string{"foo", "bar", "baz"},
  1538  						Capacity: wrapperspb.Int64(3),
  1539  					},
  1540  				},
  1541  			},
  1542  			want: &allocationv1.GameServerAllocation{
  1543  				TypeMeta: metav1.TypeMeta{
  1544  					Kind:       "GameServerAllocation",
  1545  					APIVersion: "allocation.agones.dev/v1",
  1546  				},
  1547  				Status: allocationv1.GameServerAllocationStatus{
  1548  					State:  allocationv1.GameServerAllocationAllocated,
  1549  					Source: "33.188.237.156:443",
  1550  					Lists: map[string]agonesv1.ListStatus{
  1551  						"p": {
  1552  							Values:   []string{"foo", "bar", "baz"},
  1553  							Capacity: 3,
  1554  						},
  1555  					},
  1556  				},
  1557  			},
  1558  		},
  1559  	}
  1560  	for _, tc := range tests {
  1561  		t.Run(tc.name, func(t *testing.T) {
  1562  			t.Parallel()
  1563  			runtime.FeatureTestMutex.Lock()
  1564  			defer runtime.FeatureTestMutex.Unlock()
  1565  			require.NoError(t, runtime.ParseFeatures(tc.features))
  1566  			out := ConvertAllocationResponseToGSA(tc.in, tc.in.Source)
  1567  			if !assert.Equal(t, tc.want, out) {
  1568  				t.Errorf("mismatch with want after conversion: \"%s\"", tc.name)
  1569  			}
  1570  		})
  1571  	}
  1572  }