Skip to content

Commit 6c5ab88

Browse files
authored
Merge pull request #1300 from openshift-kni/unsched-cleanup
e2e: serial: rewrite tests for reliability
2 parents 036eb12 + e5f633f commit 6c5ab88

13 files changed

Lines changed: 538 additions & 178 deletions

File tree

internal/baseload/baseload.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,13 @@ func (nl Load) String() string {
8989
// Apply adjust the given ResourceList with the current node load by mutating
9090
// the parameter in place
9191
func (nl Load) Apply(res corev1.ResourceList) {
92-
resourcelist.AddCoreResources(res, nl.Resources)
92+
resourcelist.AddInPlace(res, nl.Resources)
9393
}
9494

9595
// Deduct subtract the current node load from the given ResourceList by mutating
9696
// the parameter in place
9797
func (nl Load) Deduct(res corev1.ResourceList) error {
98-
return resourcelist.SubCoreResources(res, nl.Resources)
98+
return resourcelist.SubInPlace(res, nl.Resources)
9999
}
100100

101101
func (nl Load) CPU() resource.Quantity {

internal/resourcelist/resourcelist.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package resourcelist
1818

1919
import (
2020
"fmt"
21+
"math"
2122
"sort"
2223
"strings"
2324

@@ -87,15 +88,15 @@ func FromContainerRequests(containers []corev1.Container) corev1.ResourceList {
8788
return res
8889
}
8990

90-
func AddCoreResources(res, resToAdd corev1.ResourceList) {
91+
func AddInPlace(res, resToAdd corev1.ResourceList) {
9192
for resName, resQty := range resToAdd {
9293
qty := res[resName]
9394
qty.Add(resQty)
9495
res[resName] = qty
9596
}
9697
}
9798

98-
func SubCoreResources(res, resToSub corev1.ResourceList) error {
99+
func SubInPlace(res, resToSub corev1.ResourceList) error {
99100
for resName, resQty := range resToSub {
100101
if resQty.Cmp(res[resName]) > 0 {
101102
return fmt.Errorf("cannot subtract resource %q because it is not found in the current resources", resName)
@@ -166,3 +167,45 @@ func RoundUpCoreResources(cpu, mem resource.Quantity) (resource.Quantity, resour
166167
func roundUp(num, multiple int64) int64 {
167168
return ((num + multiple - 1) / multiple) * multiple
168169
}
170+
171+
func Highest(rls ...corev1.ResourceList) corev1.ResourceList {
172+
if len(rls) == 0 {
173+
return make(corev1.ResourceList)
174+
}
175+
ret := rls[0].DeepCopy()
176+
if len(rls) == 1 {
177+
return ret
178+
}
179+
for _, rl := range rls[1:] {
180+
tmp := ret.DeepCopy()
181+
for resName, resQty := range ret {
182+
curQty := rl[resName]
183+
if curQty.Cmp(resQty) > 0 {
184+
tmp[resName] = curQty
185+
}
186+
}
187+
ret = tmp
188+
}
189+
return ret
190+
}
191+
192+
func ScaleCoreResources(rl corev1.ResourceList, scaleNum, scaleDen int) corev1.ResourceList {
193+
ret := rl.DeepCopy()
194+
if cpuQty, ok := rl[corev1.ResourceCPU]; ok {
195+
newVal := scaleQuantity(cpuQty, scaleNum, scaleDen)
196+
ret[corev1.ResourceCPU] = *resource.NewQuantity(newVal, resource.DecimalSI)
197+
}
198+
if memQty, ok := rl[corev1.ResourceMemory]; ok {
199+
// rounding up is unnecessary but unharmful either, and makes testing and inspection easier
200+
newVal := scaleQuantity(memQty, scaleNum, scaleDen)
201+
newVal = roundUp(newVal, 1024)
202+
ret[corev1.ResourceMemory] = *resource.NewQuantity(newVal, resource.DecimalSI)
203+
}
204+
return ret
205+
}
206+
207+
func scaleQuantity(qty resource.Quantity, scaleNum, scaleDen int) int64 {
208+
val, _ := qty.AsInt64() // TODO: handle !ok?
209+
// we use Ceil, not Round, to make sure to include the fractional amounts
210+
return int64(math.Ceil(float64(val*int64(scaleNum)) / float64(scaleDen)))
211+
}

internal/resourcelist/resourcelist_test.go

Lines changed: 172 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func TestToString(t *testing.T) {
7676
}
7777
}
7878

79-
func TestAddCoreResources(t *testing.T) {
79+
func TestAddInPlace(t *testing.T) {
8080
type testCase struct {
8181
res corev1.ResourceList
8282
resToAdd corev1.ResourceList
@@ -108,7 +108,7 @@ func TestAddCoreResources(t *testing.T) {
108108
for _, tc := range testCases {
109109
t.Run(ToString(tc.expected), func(t *testing.T) {
110110
res := tc.res.DeepCopy()
111-
AddCoreResources(res, tc.resToAdd)
111+
AddInPlace(res, tc.resToAdd)
112112
// comparing strings it just easier
113113
got := ToString(res)
114114
expected := ToString(tc.expected)
@@ -119,7 +119,7 @@ func TestAddCoreResources(t *testing.T) {
119119
}
120120
}
121121

122-
func TestSubCoreResources(t *testing.T) {
122+
func TestSubInPlace(t *testing.T) {
123123
type testCase struct {
124124
res corev1.ResourceList
125125
resToSub corev1.ResourceList
@@ -168,7 +168,7 @@ func TestSubCoreResources(t *testing.T) {
168168
for _, tc := range testCases {
169169
t.Run(ToString(tc.expected), func(t *testing.T) {
170170
res := tc.res.DeepCopy()
171-
err := SubCoreResources(res, tc.resToSub)
171+
err := SubInPlace(res, tc.resToSub)
172172
if err != nil {
173173
t.Errorf("Error while calculating resources: %s", err.Error())
174174
}
@@ -430,3 +430,171 @@ func TestAccumulate(t *testing.T) {
430430
})
431431
}
432432
}
433+
434+
func TestHighest(t *testing.T) {
435+
type testCase struct {
436+
name string
437+
ress []corev1.ResourceList
438+
expected corev1.ResourceList
439+
}
440+
441+
testCases := []testCase{
442+
{
443+
name: "empty",
444+
},
445+
{
446+
name: "one entry only",
447+
ress: []corev1.ResourceList{
448+
{
449+
corev1.ResourceCPU: resource.MustParse("1"),
450+
corev1.ResourceMemory: resource.MustParse("1Gi"),
451+
},
452+
},
453+
expected: corev1.ResourceList{
454+
corev1.ResourceCPU: resource.MustParse("1"),
455+
corev1.ResourceMemory: resource.MustParse("1Gi"),
456+
},
457+
},
458+
{
459+
name: "two identical entries",
460+
ress: []corev1.ResourceList{
461+
{
462+
corev1.ResourceCPU: resource.MustParse("2"),
463+
corev1.ResourceMemory: resource.MustParse("4Gi"),
464+
},
465+
{
466+
corev1.ResourceCPU: resource.MustParse("2"),
467+
corev1.ResourceMemory: resource.MustParse("4Gi"),
468+
},
469+
},
470+
expected: corev1.ResourceList{
471+
corev1.ResourceCPU: resource.MustParse("2"),
472+
corev1.ResourceMemory: resource.MustParse("4Gi"),
473+
},
474+
},
475+
{
476+
name: "biggest everything",
477+
ress: []corev1.ResourceList{
478+
{
479+
corev1.ResourceCPU: resource.MustParse("2"),
480+
corev1.ResourceMemory: resource.MustParse("4Gi"),
481+
},
482+
{
483+
corev1.ResourceCPU: resource.MustParse("5"),
484+
corev1.ResourceMemory: resource.MustParse("11Gi"),
485+
},
486+
},
487+
expected: corev1.ResourceList{
488+
corev1.ResourceCPU: resource.MustParse("5"),
489+
corev1.ResourceMemory: resource.MustParse("11Gi"),
490+
},
491+
},
492+
{
493+
name: "sparse peaks",
494+
ress: []corev1.ResourceList{
495+
{
496+
corev1.ResourceCPU: resource.MustParse("12"),
497+
corev1.ResourceMemory: resource.MustParse("4Gi"),
498+
},
499+
{
500+
corev1.ResourceCPU: resource.MustParse("5"),
501+
corev1.ResourceMemory: resource.MustParse("16Gi"),
502+
},
503+
{
504+
corev1.ResourceCPU: resource.MustParse("8"),
505+
corev1.ResourceMemory: resource.MustParse("8Gi"),
506+
},
507+
},
508+
expected: corev1.ResourceList{
509+
corev1.ResourceCPU: resource.MustParse("12"),
510+
corev1.ResourceMemory: resource.MustParse("16Gi"),
511+
},
512+
},
513+
}
514+
515+
for _, tc := range testCases {
516+
t.Run(tc.name, func(t *testing.T) {
517+
got := Highest(tc.ress...)
518+
if !Equal(got, tc.expected) {
519+
t.Errorf("expected %v got %v", tc.expected, got)
520+
}
521+
})
522+
}
523+
}
524+
525+
func TestScaleCoreResources(t *testing.T) {
526+
type testCase struct {
527+
name string
528+
res corev1.ResourceList
529+
scaleNum int
530+
scaleDen int
531+
expected corev1.ResourceList
532+
}
533+
534+
testCases := []testCase{
535+
{
536+
name: "empty",
537+
},
538+
{
539+
name: "scale 1",
540+
res: corev1.ResourceList{
541+
corev1.ResourceCPU: resource.MustParse("1"),
542+
corev1.ResourceMemory: resource.MustParse("1Gi"),
543+
},
544+
scaleNum: 1,
545+
scaleDen: 1,
546+
expected: corev1.ResourceList{
547+
corev1.ResourceCPU: resource.MustParse("1"),
548+
corev1.ResourceMemory: resource.MustParse("1Gi"),
549+
},
550+
},
551+
{
552+
name: "scale 4",
553+
res: corev1.ResourceList{
554+
corev1.ResourceCPU: resource.MustParse("1"),
555+
corev1.ResourceMemory: resource.MustParse("1Gi"),
556+
},
557+
scaleNum: 4,
558+
scaleDen: 1,
559+
expected: corev1.ResourceList{
560+
corev1.ResourceCPU: resource.MustParse("4"),
561+
corev1.ResourceMemory: resource.MustParse("4Gi"),
562+
},
563+
},
564+
{
565+
name: "scale 3/2",
566+
res: corev1.ResourceList{
567+
corev1.ResourceCPU: resource.MustParse("1"),
568+
corev1.ResourceMemory: resource.MustParse("1Gi"),
569+
},
570+
scaleNum: 3,
571+
scaleDen: 2,
572+
expected: corev1.ResourceList{
573+
corev1.ResourceCPU: resource.MustParse("2"),
574+
corev1.ResourceMemory: resource.MustParse("1610612736"),
575+
},
576+
},
577+
{
578+
name: "scale 7/3",
579+
res: corev1.ResourceList{
580+
corev1.ResourceCPU: resource.MustParse("1"),
581+
corev1.ResourceMemory: resource.MustParse("1Gi"),
582+
},
583+
scaleNum: 7,
584+
scaleDen: 3,
585+
expected: corev1.ResourceList{
586+
corev1.ResourceCPU: resource.MustParse("3"),
587+
corev1.ResourceMemory: resource.MustParse("2505398272"),
588+
},
589+
},
590+
}
591+
592+
for _, tc := range testCases {
593+
t.Run(tc.name, func(t *testing.T) {
594+
got := ScaleCoreResources(tc.res, tc.scaleNum, tc.scaleDen)
595+
if !Equal(got, tc.expected) {
596+
t.Errorf("expected %v got %v", ToString(tc.expected), ToString(got))
597+
}
598+
})
599+
}
600+
}

internal/wait/deployment.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,26 @@ func (wt Waiter) ForDeploymentReplicasCreation(ctx context.Context, dp *appsv1.D
8282
})
8383
return updatedDp, err
8484
}
85+
86+
func (wt Waiter) ForDeploymentReplicasReadiness(ctx context.Context, dp *appsv1.Deployment, expectedReplicas int32) (*appsv1.Deployment, error) {
87+
key := ObjectKeyFromObject(dp)
88+
updatedDp := &appsv1.Deployment{}
89+
immediate := true
90+
err := k8swait.PollUntilContextTimeout(ctx, wt.PollInterval, wt.PollTimeout, immediate, func(aContext context.Context) (bool, error) {
91+
err := wt.Cli.Get(aContext, key.AsKey(), updatedDp)
92+
if err != nil {
93+
klog.Warningf("failed to get the deployment %s: %v", key.String(), err)
94+
return false, err
95+
}
96+
97+
if updatedDp.Status.ReadyReplicas != expectedReplicas {
98+
klog.Warningf("Waiting for deployment: %q to have %d replicas, current number of: %d/%d/%d (ready/updated/total)",
99+
key.String(), expectedReplicas, updatedDp.Status.ReadyReplicas, updatedDp.Status.UpdatedReplicas, updatedDp.Status.Replicas)
100+
return false, nil
101+
}
102+
103+
klog.Infof("replicas of deployment %q are all created", key.String())
104+
return true, nil
105+
})
106+
return updatedDp, err
107+
}

0 commit comments

Comments
 (0)