Unit tests for the refactor scheduler methods

This commit is contained in:
Alex Dadgar
2015-10-16 16:35:55 -07:00
parent a0d3eb7792
commit 927efaf4e0
2 changed files with 248 additions and 1 deletions

View File

@@ -341,7 +341,10 @@ func inplaceUpdate(ctx Context, eval *structs.Evaluation, job *structs.Job,
// Set the existing node as the base set
stack.SetNodes([]*structs.Node{node})
// Stage an eviction of the current allocation
// Stage an eviction of the current allocation. This is done so that
// the current allocation is discounted when checking for feasability.
// Otherwise we would be trying to fit the tasks current resources and
// updated resources. After select is called we can remove the evict.
ctx.Plan().AppendUpdate(update.Alloc, structs.AllocDesiredStatusStop,
allocInPlace)

View File

@@ -2,6 +2,7 @@ package scheduler
import (
"fmt"
"log"
"os"
"reflect"
"testing"
@@ -341,6 +342,249 @@ func TestTasksUpdated(t *testing.T) {
}
}
func TestEvictAndPlace_LimitLessThanAllocs(t *testing.T) {
_, ctx := testContext(t)
allocs := []allocTuple{
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
}
diff := &diffResult{}
limit := 2
if !evictAndPlace(ctx, diff, allocs, "", &limit) {
t.Fatal("evictAndReplace() should have returned true")
}
if limit != 0 {
t.Fatal("evictAndReplace() should decremented limit; got %v; want 0", limit)
}
if len(diff.place) != 2 {
t.Fatal("evictAndReplace() didn't insert into diffResult properly: %v", diff.place)
}
}
func TestEvictAndPlace_LimitEqualToAllocs(t *testing.T) {
_, ctx := testContext(t)
allocs := []allocTuple{
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
}
diff := &diffResult{}
limit := 4
if evictAndPlace(ctx, diff, allocs, "", &limit) {
t.Fatal("evictAndReplace() should have returned false")
}
if limit != 0 {
t.Fatal("evictAndReplace() should decremented limit; got %v; want 0", limit)
}
if len(diff.place) != 4 {
t.Fatal("evictAndReplace() didn't insert into diffResult properly: %v", diff.place)
}
}
func TestSetStatus(t *testing.T) {
h := NewHarness(t)
logger := log.New(os.Stderr, "", log.LstdFlags)
eval := mock.Eval()
status := "a"
desc := "b"
if err := setStatus(logger, h, eval, nil, status, desc); err != nil {
t.Fatalf("setStatus() failed: %v", err)
}
if len(h.Evals) != 1 {
t.Fatalf("setStatus() didn't update plan: %v", h.Evals)
}
newEval := h.Evals[0]
if newEval.ID != eval.ID || newEval.Status != status || newEval.StatusDescription != desc {
t.Fatalf("setStatus() submited invalid eval: %v", newEval)
}
h = NewHarness(t)
next := mock.Eval()
if err := setStatus(logger, h, eval, next, status, desc); err != nil {
t.Fatalf("setStatus() failed: %v", err)
}
if len(h.Evals) != 1 {
t.Fatalf("setStatus() didn't update plan: %v", h.Evals)
}
newEval = h.Evals[0]
if newEval.NextEval != next.ID {
t.Fatalf("setStatus() didn't set nextEval correctly: %v", newEval)
}
}
func TestInplaceUpdate_ChangedTaskGroup(t *testing.T) {
state, ctx := testContext(t)
eval := mock.Eval()
job := mock.Job()
node := mock.Node()
noErr(t, state.UpsertNode(1000, node))
// Register an alloc
alloc := &structs.Allocation{
ID: structs.GenerateUUID(),
EvalID: eval.ID,
NodeID: node.ID,
JobID: job.ID,
Job: job,
Resources: &structs.Resources{
CPU: 2048,
MemoryMB: 2048,
},
DesiredStatus: structs.AllocDesiredStatusRun,
}
alloc.TaskResources = map[string]*structs.Resources{"web": alloc.Resources}
noErr(t, state.UpsertAllocs(1001, []*structs.Allocation{alloc}))
// Create a new task group that prevents in-place updates.
tg := &structs.TaskGroup{}
*tg = *job.TaskGroups[0]
task := &structs.Task{Name: "FOO"}
tg.Tasks = nil
tg.Tasks = append(tg.Tasks, task)
updates := []allocTuple{{Alloc: alloc, TaskGroup: tg}}
stack := NewGenericStack(false, ctx, nil)
// Do the inplace update.
unplaced := inplaceUpdate(ctx, eval, job, stack, updates)
if len(unplaced) != 1 {
t.Fatal("inplaceUpdate incorrectly did an inplace update")
}
if len(ctx.plan.NodeAllocation) != 0 {
t.Fatal("inplaceUpdate incorrectly did an inplace update")
}
}
func TestInplaceUpdate_NoMatch(t *testing.T) {
state, ctx := testContext(t)
eval := mock.Eval()
job := mock.Job()
node := mock.Node()
noErr(t, state.UpsertNode(1000, node))
// Register an alloc
alloc := &structs.Allocation{
ID: structs.GenerateUUID(),
EvalID: eval.ID,
NodeID: node.ID,
JobID: job.ID,
Job: job,
Resources: &structs.Resources{
CPU: 2048,
MemoryMB: 2048,
},
DesiredStatus: structs.AllocDesiredStatusRun,
}
alloc.TaskResources = map[string]*structs.Resources{"web": alloc.Resources}
noErr(t, state.UpsertAllocs(1001, []*structs.Allocation{alloc}))
// Create a new task group that requires too much resources.
tg := &structs.TaskGroup{}
*tg = *job.TaskGroups[0]
resource := &structs.Resources{CPU: 9999}
tg.Tasks[0].Resources = resource
updates := []allocTuple{{Alloc: alloc, TaskGroup: tg}}
stack := NewGenericStack(false, ctx, nil)
// Do the inplace update.
unplaced := inplaceUpdate(ctx, eval, job, stack, updates)
if len(unplaced) != 1 {
t.Fatal("inplaceUpdate incorrectly did an inplace update")
}
if len(ctx.plan.NodeAllocation) != 0 {
t.Fatal("inplaceUpdate incorrectly did an inplace update")
}
}
func TestInplaceUpdate_Success(t *testing.T) {
state, ctx := testContext(t)
eval := mock.Eval()
job := mock.Job()
node := mock.Node()
noErr(t, state.UpsertNode(1000, node))
// Register an alloc
alloc := &structs.Allocation{
ID: structs.GenerateUUID(),
EvalID: eval.ID,
NodeID: node.ID,
JobID: job.ID,
Job: job,
Resources: &structs.Resources{
CPU: 2048,
MemoryMB: 2048,
},
DesiredStatus: structs.AllocDesiredStatusRun,
}
alloc.TaskResources = map[string]*structs.Resources{"web": alloc.Resources}
noErr(t, state.UpsertAllocs(1001, []*structs.Allocation{alloc}))
// Create a new task group that updates the resources.
tg := &structs.TaskGroup{}
*tg = *job.TaskGroups[0]
resource := &structs.Resources{CPU: 737}
tg.Tasks[0].Resources = resource
updates := []allocTuple{{Alloc: alloc, TaskGroup: tg}}
stack := NewGenericStack(false, ctx, nil)
// Do the inplace update.
unplaced := inplaceUpdate(ctx, eval, job, stack, updates)
if len(unplaced) != 0 {
t.Fatal("inplaceUpdate did not do an inplace update")
}
if len(ctx.plan.NodeAllocation) != 1 {
t.Fatal("inplaceUpdate did not do an inplace update")
}
}
func TestEvictAndPlace_LimitGreaterThanAllocs(t *testing.T) {
_, ctx := testContext(t)
allocs := []allocTuple{
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
allocTuple{Alloc: &structs.Allocation{ID: structs.GenerateUUID()}},
}
diff := &diffResult{}
limit := 6
if evictAndPlace(ctx, diff, allocs, "", &limit) {
t.Fatal("evictAndReplace() should have returned false")
}
if limit != 2 {
t.Fatal("evictAndReplace() should decremented limit; got %v; want 2", limit)
}
if len(diff.place) != 4 {
t.Fatal("evictAndReplace() didn't insert into diffResult properly: %v", diff.place)
}
}
func TestTaskGroupConstraints(t *testing.T) {
constr := &structs.Constraint{Hard: true}
constr2 := &structs.Constraint{LTarget: "foo"}