Files
kubevela/pkg/controller/common/rollout/workloads/common_test.go
wyike 0a4c20c999 fix empty rolloutBatch will panic whole controller bug (#1646)
* add webhook for app and avoid controller panic

neat imports

* add test for rollout verify
2021-05-12 19:00:55 +08:00

400 lines
11 KiB
Go

/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package workloads
import (
"testing"
"k8s.io/utils/pointer"
"k8s.io/apimachinery/pkg/util/intstr"
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
)
var (
rolloutPercentSpec = &v1alpha1.RolloutPlan{
RolloutBatches: []v1alpha1.RolloutBatch{
{
Replicas: intstr.FromString("20%"),
},
{
Replicas: intstr.FromString("40%"),
},
{
Replicas: intstr.FromString("30%"),
},
{
Replicas: intstr.FromString("10%"),
},
},
}
rolloutNumericSpec = &v1alpha1.RolloutPlan{
RolloutBatches: []v1alpha1.RolloutBatch{
{
Replicas: intstr.FromInt(1),
},
{
Replicas: intstr.FromInt(2),
},
{
Replicas: intstr.FromInt(4),
},
{
Replicas: intstr.FromInt(3),
},
},
}
rolloutMixedSpec = &v1alpha1.RolloutPlan{
RolloutBatches: []v1alpha1.RolloutBatch{
{
Replicas: intstr.FromInt(1),
},
{
Replicas: intstr.FromString("20%"),
},
{
Replicas: intstr.FromString("50%"),
},
{
Replicas: intstr.FromInt(2),
},
},
}
rolloutRelaxSpec = &v1alpha1.RolloutPlan{
RolloutBatches: []v1alpha1.RolloutBatch{
{
Replicas: intstr.FromString("20%"),
},
{
Replicas: intstr.FromInt(2),
},
{
Replicas: intstr.FromInt(2),
},
{
Replicas: intstr.FromString("50%"),
},
},
}
rolloutOverFlowSpec = &v1alpha1.RolloutPlan{
RolloutBatches: []v1alpha1.RolloutBatch{
{
Replicas: intstr.FromString("140%"),
},
{
Replicas: intstr.FromInt(1),
},
{
Replicas: intstr.FromString("40%"),
},
},
}
)
func TestCalculateNewBatchTarget(t *testing.T) {
// test common rollout
if got := calculateNewBatchTarget(rolloutMixedSpec, 0, 10, 0); got != 1 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 1)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 0, 10, 1); got != 3 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 3)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 0, 10, 2); got != 8 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 8)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 0, 10, 3); got != 10 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 10)
}
// test scale up
if got := calculateNewBatchTarget(rolloutMixedSpec, 2, 12, 0); got != 3 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 3)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 3, 13, 1); got != 6 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 6)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 4, 14, 2); got != 12 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 12)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 5, 15, 3); got != 15 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 15)
}
// test scale down
if got := calculateNewBatchTarget(rolloutMixedSpec, 10, 0, 0); got != 9 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 9)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 20, 5, 1); got != 16 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 16)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 30, 15, 2); got != 18 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 18)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 40, 10, 3); got != 10 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 10)
}
}
func TestCalculateNewBatchTargetCornerCases(t *testing.T) {
// test current batch overflow
if got := calculateNewBatchTarget(rolloutMixedSpec, 2, 12, 4); got != 12 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 12)
}
if got := calculateNewBatchTarget(rolloutMixedSpec, 13, 3, 5); got != 3 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 3)
}
// numeric value doesn't match the range
if got := calculateNewBatchTarget(rolloutNumericSpec, 16, 10, 0); got != 15 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 15)
}
if got := calculateNewBatchTarget(rolloutPercentSpec, 10, 10, 2); got != 10 {
t.Errorf("calculateNewBatchTarget() = %v, want %v", got, 10)
}
}
func TestVerifyBatchesWithRolloutNormal(t *testing.T) {
if err := verifyBatchesWithRollout(rolloutMixedSpec, 10); err != nil {
t.Errorf("verifyBatchesWithRollout() = %v, want nil", err)
}
if err := verifyBatchesWithRollout(rolloutMixedSpec, 12); err != nil {
t.Errorf("verifyBatchesWithRollout() = %v, want nil", err)
}
if err := verifyBatchesWithRollout(rolloutMixedSpec, 13); err != nil {
t.Errorf("verifyBatchesWithRollout() = %v, want nil", err)
}
if err := verifyBatchesWithRollout(rolloutMixedSpec, 20); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
if err := verifyBatchesWithRollout(rolloutMixedSpec, 6); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
}
func TestVerifyBatchesWithRolloutRelaxed(t *testing.T) {
// last batch as a percentage always succeeds
if err := verifyBatchesWithRollout(rolloutRelaxSpec, 10); err != nil {
t.Errorf("verifyBatchesWithRollout() = %v, want nil", err)
}
if err := verifyBatchesWithRollout(rolloutRelaxSpec, 100); err != nil {
t.Errorf("verifyBatchesWithRollout() = %v, want nil", err)
}
if err := verifyBatchesWithRollout(rolloutRelaxSpec, 31); err != nil {
t.Errorf("verifyBatchesWithRollout() = %v, want nil", err)
}
// last can't be zero
if err := verifyBatchesWithRollout(rolloutRelaxSpec, 6); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
// overflow always fail
if err := verifyBatchesWithRollout(rolloutOverFlowSpec, 10); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
if err := verifyBatchesWithRollout(rolloutOverFlowSpec, 100); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
if err := verifyBatchesWithRollout(rolloutOverFlowSpec, 1); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
if err := verifyBatchesWithRollout(rolloutOverFlowSpec, 0); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
}
func TestVerifyEmptyRolloutBatches(t *testing.T) {
plan := &v1alpha1.RolloutPlan{
TargetSize: pointer.Int32Ptr(2),
}
if err := verifyBatchesWithRollout(plan, 3); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
}
func TestVerifyBatchesWithRolloutNumeric(t *testing.T) {
// test hard number
if err := verifyBatchesWithRollout(rolloutNumericSpec, 6); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
if err := verifyBatchesWithRollout(rolloutNumericSpec, 11); err == nil {
t.Errorf("verifyBatchesWithRollout() = %v, want error", nil)
}
if err := verifyBatchesWithRollout(rolloutNumericSpec, 10); err != nil {
t.Errorf("verifyBatchesWithRollout() = %v, want nil", err)
}
}
func Test_VerifyBatchesWithScalePassCases(t *testing.T) {
tests := map[string]struct {
rolloutSpec *v1alpha1.RolloutPlan
originalSize int
targetSize int
}{
"percent equal case 1": {
rolloutSpec: rolloutPercentSpec,
originalSize: 12,
targetSize: 12,
},
"percent equal case 2": {
rolloutSpec: rolloutPercentSpec,
originalSize: 0,
targetSize: 0,
},
"percent increase case": {
rolloutSpec: rolloutPercentSpec,
originalSize: 12,
targetSize: 22,
},
"percent decrease case 1": {
rolloutSpec: rolloutPercentSpec,
originalSize: 27,
targetSize: 7,
},
"percent decrease case 2": {
rolloutSpec: rolloutPercentSpec,
originalSize: 27,
targetSize: 0,
},
"relax increase 1": {
rolloutSpec: rolloutRelaxSpec,
originalSize: 12,
targetSize: 32,
},
"relax increase 2": {
rolloutSpec: rolloutRelaxSpec,
originalSize: 12,
targetSize: 22,
},
"mix increase 1": {
rolloutSpec: rolloutMixedSpec,
originalSize: 13,
targetSize: 26,
},
"mix increase 2": {
rolloutSpec: rolloutMixedSpec,
originalSize: 30,
targetSize: 42,
},
"mix decrease 1": {
rolloutSpec: rolloutMixedSpec,
originalSize: 32,
targetSize: 20,
},
"mix decrease 2": {
rolloutSpec: rolloutMixedSpec,
originalSize: 12,
targetSize: 0,
},
"numeric increase": {
rolloutSpec: rolloutNumericSpec,
originalSize: 16,
targetSize: 26,
},
"numeric decrease": {
rolloutSpec: rolloutNumericSpec,
originalSize: 13,
targetSize: 3,
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
if err := verifyBatchesWithScale(tt.rolloutSpec, tt.originalSize, tt.targetSize); err != nil {
t.Errorf("verifyBatchesWithScale() error = %v, want pass", err)
}
})
}
}
func Test_VerifyBatchesWithScaleFailCases(t *testing.T) {
tests := map[string]struct {
rolloutSpec *v1alpha1.RolloutPlan
originalSize int
targetSize int
}{
"total percent more than 100 increase": {
rolloutSpec: rolloutOverFlowSpec,
originalSize: 12,
targetSize: 115,
},
"total percent more than 100 decrease": {
rolloutSpec: rolloutOverFlowSpec,
originalSize: 312,
targetSize: 15,
},
"total percent more than 100 equal": {
rolloutSpec: rolloutOverFlowSpec,
originalSize: 12,
targetSize: 12,
},
"percent increase case less than batch number": {
rolloutSpec: rolloutPercentSpec,
originalSize: 12,
targetSize: 15,
},
"percent decrease case": {
rolloutSpec: rolloutPercentSpec,
originalSize: 10,
targetSize: 7,
},
"relax increase too little": {
rolloutSpec: rolloutRelaxSpec,
originalSize: 12,
targetSize: 17,
},
"mix increase": {
rolloutSpec: rolloutMixedSpec,
originalSize: 13,
targetSize: 20,
},
"mix decrease": {
rolloutSpec: rolloutMixedSpec,
originalSize: 42,
targetSize: 33,
},
"numeric increase": {
rolloutSpec: rolloutNumericSpec,
originalSize: 16,
targetSize: 32,
},
"numeric decrease 1": {
rolloutSpec: rolloutNumericSpec,
originalSize: 13,
targetSize: 10,
},
"numeric decrease 2": {
rolloutSpec: rolloutNumericSpec,
originalSize: 16,
targetSize: 10,
},
"empty rollingBatches": {
rolloutSpec: &v1alpha1.RolloutPlan{},
targetSize: 3,
originalSize: 2,
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
if err := verifyBatchesWithScale(tt.rolloutSpec, tt.originalSize, tt.targetSize); err == nil {
t.Errorf("verifyBatchesWithScale passed, want fail")
}
})
}
}