open-nomad/scheduler/select_test.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

371 lines
6.1 KiB
Go
Raw Permalink Normal View History

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2015-08-13 17:05:54 +00:00
package scheduler
import (
"testing"
"github.com/hashicorp/nomad/ci"
2015-08-13 17:05:54 +00:00
"github.com/hashicorp/nomad/nomad/mock"
"github.com/hashicorp/nomad/nomad/structs"
"github.com/stretchr/testify/require"
2015-08-13 17:05:54 +00:00
)
func TestLimitIterator(t *testing.T) {
ci.Parallel(t)
2015-08-13 18:33:58 +00:00
_, ctx := testContext(t)
2015-08-13 17:05:54 +00:00
nodes := []*RankedNode{
2017-09-26 22:26:33 +00:00
{
Node: mock.Node(),
FinalScore: 1,
2015-08-13 17:05:54 +00:00
},
2017-09-26 22:26:33 +00:00
{
Node: mock.Node(),
FinalScore: 2,
2015-08-13 17:05:54 +00:00
},
2017-09-26 22:26:33 +00:00
{
Node: mock.Node(),
FinalScore: 3,
2015-08-13 17:05:54 +00:00
},
}
static := NewStaticRankIterator(ctx, nodes)
limit := NewLimitIterator(ctx, static, 1, 0, 2)
limit.SetLimit(2)
2015-08-13 17:05:54 +00:00
2015-08-13 19:02:42 +00:00
out := collectRanked(limit)
2015-08-13 17:05:54 +00:00
if len(out) != 2 {
t.Fatalf("bad: %v", out)
}
if out[0] != nodes[0] && out[1] != nodes[1] {
t.Fatalf("bad: %v", out)
}
2015-08-13 22:01:02 +00:00
out = collectRanked(limit)
if len(out) != 0 {
t.Fatalf("bad: %v", out)
}
limit.Reset()
out = collectRanked(limit)
if len(out) != 2 {
t.Fatalf("bad: %v", out)
}
if out[0] != nodes[2] && out[1] != nodes[0] {
t.Fatalf("bad: %v", out)
}
2015-08-13 17:05:54 +00:00
}
func TestLimitIterator_ScoreThreshold(t *testing.T) {
ci.Parallel(t)
_, ctx := testContext(t)
type testCase struct {
desc string
nodes []*RankedNode
expectedOut []*RankedNode
threshold float64
limit int
maxSkip int
}
var nodes []*structs.Node
2018-01-23 22:12:45 +00:00
for i := 0; i < 5; i++ {
nodes = append(nodes, mock.Node())
}
testCases := []testCase{
{
desc: "Skips one low scoring node",
nodes: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
{
Node: nodes[1],
FinalScore: 2,
},
{
Node: nodes[2],
FinalScore: 3,
},
},
expectedOut: []*RankedNode{
{
Node: nodes[1],
FinalScore: 2,
},
{
Node: nodes[2],
FinalScore: 3,
},
},
threshold: -1,
limit: 2,
maxSkip: 2,
},
{
desc: "Skips maxSkip scoring nodes",
nodes: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
{
Node: nodes[1],
FinalScore: -2,
},
{
Node: nodes[2],
FinalScore: 3,
},
{
Node: nodes[3],
FinalScore: 4,
},
},
expectedOut: []*RankedNode{
{
Node: nodes[2],
FinalScore: 3,
},
{
Node: nodes[3],
FinalScore: 4,
},
},
threshold: -1,
limit: 2,
maxSkip: 2,
},
{
desc: "maxSkip limit reached",
nodes: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
{
Node: nodes[1],
FinalScore: -6,
},
{
Node: nodes[2],
FinalScore: -3,
},
{
Node: nodes[3],
FinalScore: -4,
},
},
expectedOut: []*RankedNode{
{
Node: nodes[2],
FinalScore: -3,
},
{
Node: nodes[3],
FinalScore: -4,
},
},
threshold: -1,
limit: 2,
maxSkip: 2,
},
{
desc: "draw both from skipped nodes",
nodes: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
{
Node: nodes[1],
FinalScore: -6,
},
},
expectedOut: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
{
Node: nodes[1],
FinalScore: -6,
},
},
threshold: -1,
limit: 2,
maxSkip: 2,
}, {
desc: "one node above threshold, one skipped node",
nodes: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
{
Node: nodes[1],
FinalScore: 5,
},
},
expectedOut: []*RankedNode{
{
Node: nodes[1],
FinalScore: 5,
},
{
Node: nodes[0],
FinalScore: -1,
},
},
threshold: -1,
limit: 2,
maxSkip: 2,
},
{
desc: "low scoring nodes interspersed",
nodes: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
{
Node: nodes[1],
FinalScore: 5,
},
{
Node: nodes[2],
FinalScore: -2,
},
{
Node: nodes[3],
FinalScore: 2,
},
},
expectedOut: []*RankedNode{
{
Node: nodes[1],
FinalScore: 5,
},
{
Node: nodes[3],
FinalScore: 2,
},
},
threshold: -1,
limit: 2,
maxSkip: 2,
},
{
desc: "only one node, score below threshold",
nodes: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
},
expectedOut: []*RankedNode{
{
Node: nodes[0],
FinalScore: -1,
},
},
threshold: -1,
limit: 2,
maxSkip: 2,
},
2018-01-23 22:12:45 +00:00
{
desc: "maxSkip is more than available nodes",
nodes: []*RankedNode{
{
Node: nodes[0],
FinalScore: -2,
2018-01-23 22:12:45 +00:00
},
{
Node: nodes[1],
FinalScore: 1,
2018-01-23 22:12:45 +00:00
},
},
expectedOut: []*RankedNode{
{
Node: nodes[1],
FinalScore: 1,
2018-01-23 22:12:45 +00:00
},
{
Node: nodes[0],
FinalScore: -2,
2018-01-23 22:12:45 +00:00
},
},
threshold: -1,
limit: 2,
maxSkip: 10,
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
static := NewStaticRankIterator(ctx, tc.nodes)
limit := NewLimitIterator(ctx, static, 1, 0, 2)
limit.SetLimit(2)
out := collectRanked(limit)
require := require.New(t)
require.Equal(tc.expectedOut, out)
limit.Reset()
require.Equal(0, limit.skippedNodeIndex)
require.Equal(0, len(limit.skippedNodes))
})
}
}
2015-08-13 17:05:54 +00:00
func TestMaxScoreIterator(t *testing.T) {
ci.Parallel(t)
2015-08-13 18:33:58 +00:00
_, ctx := testContext(t)
2015-08-13 17:05:54 +00:00
nodes := []*RankedNode{
2017-09-26 22:26:33 +00:00
{
Node: mock.Node(),
FinalScore: 1,
2015-08-13 17:05:54 +00:00
},
2017-09-26 22:26:33 +00:00
{
Node: mock.Node(),
FinalScore: 2,
2015-08-13 17:05:54 +00:00
},
2017-09-26 22:26:33 +00:00
{
Node: mock.Node(),
FinalScore: 3,
2015-08-13 17:05:54 +00:00
},
}
static := NewStaticRankIterator(ctx, nodes)
max := NewMaxScoreIterator(ctx, static)
2015-08-13 19:02:42 +00:00
out := collectRanked(max)
2015-08-13 17:05:54 +00:00
if len(out) != 1 {
t.Fatalf("bad: %v", out)
}
if out[0] != nodes[2] {
t.Fatalf("bad: %v", out)
}
2015-08-13 22:01:02 +00:00
out = collectRanked(max)
if len(out) != 0 {
t.Fatalf("bad: %v", out)
}
max.Reset()
out = collectRanked(max)
if len(out) != 1 {
t.Fatalf("bad: %v", out)
}
if out[0] != nodes[2] {
t.Fatalf("bad: %v", out)
}
2015-08-13 17:05:54 +00:00
}