Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Counter FleetAutoScaler e2e Test #3418

Merged
merged 6 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/counterfleetautoscaler.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ spec:
# Required.
bufferSize: 5
# Minimum aggregate counter capacity that can be provided by this FleetAutoscaler.
# If minCapacity is not specified, the actual minimum capacity will be bufferSize.
# If minCapacity is not specified, the effective minimum capacity will be bufferSize.
# When bufferSize in percentage format is used, minCapacity should be set and more than 0.
minCapacity: 10
# Maximum aggregate counter capacity that can be provided by this FleetAutoscaler.
# Required.
Expand Down
3 changes: 2 additions & 1 deletion examples/listfleetautoscaler.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ spec:
# Required.
bufferSize: 5
# Minimum aggregate list capacity that can be provided by this FleetAutoscaler.
# If minCapacity is not specified, the actual minimum capacity will be bufferSize.
# If minCapacity is not specified, the effective minimum capacity will be bufferSize.
# When bufferSize in percentage format is used, minCapacity should be set and more than 0.
minCapacity: 10
# Maximum aggregate list capacity that can be provided by this FleetAutoscaler.
# Required.
Expand Down
8 changes: 8 additions & 0 deletions pkg/apis/autoscaling/v1/fleetautoscaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@ func (c *CounterPolicy) ValidateCounterPolicy(fldPath *field.Path) field.ErrorLi
if err != nil || r < 1 || r > 99 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("bufferSize"), c.BufferSize.String(), "bufferSize should be between 1% and 99%"))
}
// When bufferSize in percentage format is used, minCapacity should be more than 0.
if c.MinCapacity < 1 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("minCapacity"), c.BufferSize.String(), " when bufferSize in percentage format is used, minCapacity should be more than 0"))
}
}

return allErrs
Expand Down Expand Up @@ -411,6 +415,10 @@ func (l *ListPolicy) ValidateListPolicy(fldPath *field.Path) field.ErrorList {
if err != nil || r < 1 || r > 99 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("bufferSize"), l.BufferSize.String(), "bufferSize should be between 1% and 99%"))
}
// When bufferSize in percentage format is used, minCapacity should be more than 0.
if l.MinCapacity < 1 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("minCapacity"), l.BufferSize.String(), " when bufferSize in percentage format is used, minCapacity should be more than 0"))
}
}
return allErrs
}
Expand Down
14 changes: 10 additions & 4 deletions pkg/apis/autoscaling/v1/fleetautoscaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ func TestFleetAutoscalerCounterValidateUpdate(t *testing.T) {
fas: modifiedFAS(func(fap *FleetAutoscalerPolicy) {
fap.Counter.BufferSize.Type = intstr.String
fap.Counter.BufferSize = intstr.FromString("99%")
fap.Counter.MinCapacity = 10
}),
featureFlags: string(runtime.FeatureCountsAndLists) + "=true",
wantLength: 0,
Expand All @@ -290,24 +291,26 @@ func TestFleetAutoscalerCounterValidateUpdate(t *testing.T) {
fas: modifiedFAS(func(fap *FleetAutoscalerPolicy) {
fap.Counter.BufferSize.Type = intstr.String
fap.Counter.BufferSize = intstr.FromString("99.0%")
fap.Counter.MinCapacity = 1
}),
featureFlags: string(runtime.FeatureCountsAndLists) + "=true",
wantLength: 1,
wantField: "spec.policy.counter.bufferSize",
},
"bufferSize percentage too small": {
"bufferSize percentage and MinCapacity too small": {
fas: modifiedFAS(func(fap *FleetAutoscalerPolicy) {
fap.Counter.BufferSize.Type = intstr.String
fap.Counter.BufferSize = intstr.FromString("0%")
}),
featureFlags: string(runtime.FeatureCountsAndLists) + "=true",
wantLength: 1,
wantLength: 2,
wantField: "spec.policy.counter.bufferSize",
},
"bufferSize percentage too large": {
fas: modifiedFAS(func(fap *FleetAutoscalerPolicy) {
fap.Counter.BufferSize.Type = intstr.String
fap.Counter.BufferSize = intstr.FromString("100%")
fap.Counter.MinCapacity = 10
}),
featureFlags: string(runtime.FeatureCountsAndLists) + "=true",
wantLength: 1,
Expand Down Expand Up @@ -399,6 +402,7 @@ func TestFleetAutoscalerListValidateUpdate(t *testing.T) {
fas: modifiedFAS(func(fap *FleetAutoscalerPolicy) {
fap.List.BufferSize.Type = intstr.String
fap.List.BufferSize = intstr.FromString("99%")
fap.List.MinCapacity = 1
}),
featureFlags: string(runtime.FeatureCountsAndLists) + "=true",
wantLength: 0,
Expand All @@ -407,24 +411,26 @@ func TestFleetAutoscalerListValidateUpdate(t *testing.T) {
fas: modifiedFAS(func(fap *FleetAutoscalerPolicy) {
fap.List.BufferSize.Type = intstr.String
fap.List.BufferSize = intstr.FromString("99.0%")
fap.List.MinCapacity = 1
}),
featureFlags: string(runtime.FeatureCountsAndLists) + "=true",
wantLength: 1,
wantField: "spec.policy.list.bufferSize",
},
"bufferSize percentage too small": {
"bufferSize percentage and MinCapacity too small": {
fas: modifiedFAS(func(fap *FleetAutoscalerPolicy) {
fap.List.BufferSize.Type = intstr.String
fap.List.BufferSize = intstr.FromString("0%")
}),
featureFlags: string(runtime.FeatureCountsAndLists) + "=true",
wantLength: 1,
wantLength: 2,
wantField: "spec.policy.list.bufferSize",
},
"bufferSize percentage too large": {
fas: modifiedFAS(func(fap *FleetAutoscalerPolicy) {
fap.List.BufferSize.Type = intstr.String
fap.List.BufferSize = intstr.FromString("100%")
fap.List.MinCapacity = 1
}),
featureFlags: string(runtime.FeatureCountsAndLists) + "=true",
wantLength: 1,
Expand Down
18 changes: 10 additions & 8 deletions pkg/fleetautoscalers/fleetautoscalers.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,9 @@ func scaleDownLimited(f *agonesv1.Fleet, gameServerLister listeragonesv1.GameSer
replicas--
}

if replicas < 0 { // This shouldn't ever happen, but putting it here just in case.
replicas = 0
// We are not currently able to scale down to zero replicas, so one replica is the minimum allowed
if replicas < 1 {
replicas = 1
}

return replicas, true, nil
Expand Down Expand Up @@ -502,6 +503,10 @@ func scaleDown(f *agonesv1.Fleet, gameServerLister listeragonesv1.GameServerList
}
}
availableCapacity = aggCapacity - aggCount
// Check if we've overshot our buffer
if availableCapacity < buffer {
return replicas + 1, false, nil
}
// Check if we're Limited (Below MinCapacity)
if aggCapacity < minCapacity {
return replicas + 1, true, nil
Expand All @@ -514,14 +519,11 @@ func scaleDown(f *agonesv1.Fleet, gameServerLister listeragonesv1.GameServerList
if aggCapacity == minCapacity {
return replicas, true, nil
}
// Check if we've overshot our buffer
if availableCapacity < buffer {
return replicas + 1, false, nil
}
}

if replicas < 0 { // This shouldn't ever happen, but putting it here just in case.
replicas = 0
// We are not currently able to scale down to zero replicas, so one replica is the minimum allowed.
if replicas < 1 {
replicas = 1
}

return replicas, false, nil
Expand Down
149 changes: 148 additions & 1 deletion pkg/fleetautoscalers/fleetautoscalers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,33 @@ func TestApplyCounterPolicy(t *testing.T) {
wantErr: false,
},
},
"scale up integer": {
fleet: modifiedFleet(func(f *agonesv1.Fleet) {
f.Spec.Template.Spec.Counters = make(map[string]agonesv1.CounterStatus)
f.Spec.Template.Spec.Counters["rooms"] = agonesv1.CounterStatus{
Count: 7,
Capacity: 10}
f.Status.Replicas = 3
f.Status.ReadyReplicas = 3
f.Status.AllocatedReplicas = 0
f.Status.Counters = make(map[string]agonesv1.AggregatedCounterStatus)
f.Status.Counters["rooms"] = agonesv1.AggregatedCounterStatus{
Count: 21,
Capacity: 30}
}),
featureFlags: string(utilruntime.FeatureCountsAndLists) + "=true",
cp: &autoscalingv1.CounterPolicy{
Key: "rooms",
MaxCapacity: 100,
MinCapacity: 10,
BufferSize: intstr.FromInt(25),
},
want: expected{
replicas: 9,
limited: false,
wantErr: false,
},
},
"scale same": {
fleet: modifiedFleet(func(f *agonesv1.Fleet) {
f.Spec.Template.Spec.Counters = make(map[string]agonesv1.CounterStatus)
Expand Down Expand Up @@ -1180,11 +1207,71 @@ func TestApplyCounterPolicy(t *testing.T) {
Capacity: 7,
}}}}},
want: expected{
replicas: 0,
replicas: 1,
limited: true,
wantErr: false,
},
},
"scale down to max capacity": {
fleet: modifiedFleet(func(f *agonesv1.Fleet) {
f.Spec.Template.Spec.Counters = make(map[string]agonesv1.CounterStatus)
f.Spec.Template.Spec.Counters["rooms"] = agonesv1.CounterStatus{
Count: 0,
Capacity: 5}
f.Spec.Priorities = []agonesv1.Priority{{Type: "Counter", Key: "rooms", Order: "Descending"}}
f.Status.Replicas = 3
f.Status.ReadyReplicas = 3
f.Status.AllocatedReplicas = 0
f.Status.Counters = make(map[string]agonesv1.AggregatedCounterStatus)
f.Status.Counters["rooms"] = agonesv1.AggregatedCounterStatus{
Count: 0,
Capacity: 15}
}),
featureFlags: string(utilruntime.FeatureCountsAndLists) + "=true",
cp: &autoscalingv1.CounterPolicy{
Key: "rooms",
MaxCapacity: 5,
MinCapacity: 1,
BufferSize: intstr.FromInt(5),
},
gsList: []agonesv1.GameServer{
{ObjectMeta: metav1.ObjectMeta{
Name: "gs1",
Labels: map[string]string{"agones.dev/fleet": "fleet-1"}},
Status: agonesv1.GameServerStatus{
NodeName: "n1",
Counters: map[string]agonesv1.CounterStatus{
"rooms": {
Count: 0,
Capacity: 5,
}}}},
{ObjectMeta: metav1.ObjectMeta{
Name: "gs2",
Labels: map[string]string{"agones.dev/fleet": "fleet-1"}},
Status: agonesv1.GameServerStatus{
NodeName: "n1",
Counters: map[string]agonesv1.CounterStatus{
"rooms": {
Count: 0,
Capacity: 5,
}}}},
{ObjectMeta: metav1.ObjectMeta{
Name: "gs3",
Labels: map[string]string{"agones.dev/fleet": "fleet-1"}},
Status: agonesv1.GameServerStatus{
NodeName: "n1",
Counters: map[string]agonesv1.CounterStatus{
"rooms": {
Count: 0,
Capacity: 5,
}}}},
},
want: expected{
replicas: 1,
limited: false,
wantErr: false,
},
},
"scale up to MinCapacity": {
fleet: modifiedFleet(func(f *agonesv1.Fleet) {
f.Spec.Template.Spec.Counters = make(map[string]agonesv1.CounterStatus)
Expand Down Expand Up @@ -1274,6 +1361,66 @@ func TestApplyCounterPolicy(t *testing.T) {
wantErr: false,
},
},
"scale down by integer buffer": {
fleet: modifiedFleet(func(f *agonesv1.Fleet) {
f.Spec.Template.Spec.Counters = make(map[string]agonesv1.CounterStatus)
f.Spec.Template.Spec.Counters["players"] = agonesv1.CounterStatus{
Count: 7,
Capacity: 10}
f.Status.Replicas = 3
f.Status.ReadyReplicas = 0
f.Status.AllocatedReplicas = 3
f.Status.Counters = make(map[string]agonesv1.AggregatedCounterStatus)
f.Status.Counters["players"] = agonesv1.AggregatedCounterStatus{
Count: 21,
Capacity: 30,
}
}),
featureFlags: string(utilruntime.FeatureCountsAndLists) + "=true",
cp: &autoscalingv1.CounterPolicy{
Key: "players",
MaxCapacity: 100,
MinCapacity: 10,
BufferSize: intstr.FromInt(5),
},
gsList: []agonesv1.GameServer{
{ObjectMeta: metav1.ObjectMeta{
Name: "gs1",
Labels: map[string]string{"agones.dev/fleet": "fleet-1"}},
Status: agonesv1.GameServerStatus{
NodeName: "n1",
Counters: map[string]agonesv1.CounterStatus{
"players": {
Count: 7,
Capacity: 10,
}}}},
{ObjectMeta: metav1.ObjectMeta{
Name: "gs2",
Labels: map[string]string{"agones.dev/fleet": "fleet-1"}},
Status: agonesv1.GameServerStatus{
NodeName: "n1",
Counters: map[string]agonesv1.CounterStatus{
"players": {
Count: 7,
Capacity: 10,
}}}},
{ObjectMeta: metav1.ObjectMeta{
Name: "gs3",
Labels: map[string]string{"agones.dev/fleet": "fleet-1"}},
Status: agonesv1.GameServerStatus{
NodeName: "n1",
Counters: map[string]agonesv1.CounterStatus{
"players": {
Count: 7,
Capacity: 10,
}}}},
},
want: expected{
replicas: 2,
limited: false,
wantErr: false,
},
},
}

utilruntime.FeatureTestMutex.Lock()
Expand Down
9 changes: 8 additions & 1 deletion test/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,21 @@ Prerequisites:
- (optional) set the `IMAGE_PULL_SECRET` env var to the secret name needed to pull the gameserver and/or Agones SDK images, if needed

e2e tests are written as Go test. All go test techniques apply, e.g. picking
what to run, timeout length.
what to run, timeout length.

To run e2e tests on your kubectl configured cluster:

```
make test-e2e
```

To run a single test on your kubectl configured cluster you can optionally include any flags listed
in e2e test args in the agones/build/Makefile such as `FEATURE_GATES="CountsAndLists=true"`:

```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

FEATURE_GATES="CountsAndLists=true" go test -race -run ^TestCounterAutoscaler$
```

To run on minikube use the special target:

```
Expand Down
Loading