github.com/ryanslade/nomad@v0.2.4-0.20160128061903-fc95782f2089/scheduler/context_test.go (about)

     1  package scheduler
     2  
     3  import (
     4  	"log"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/hashicorp/nomad/nomad/mock"
     9  	"github.com/hashicorp/nomad/nomad/state"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  )
    12  
    13  func testContext(t testing.TB) (*state.StateStore, *EvalContext) {
    14  	state, err := state.NewStateStore(os.Stderr)
    15  	if err != nil {
    16  		t.Fatalf("err: %v", err)
    17  	}
    18  	plan := &structs.Plan{
    19  		NodeUpdate:     make(map[string][]*structs.Allocation),
    20  		NodeAllocation: make(map[string][]*structs.Allocation),
    21  	}
    22  
    23  	logger := log.New(os.Stderr, "", log.LstdFlags)
    24  
    25  	ctx := NewEvalContext(state, plan, logger)
    26  	return state, ctx
    27  }
    28  
    29  func TestEvalContext_ProposedAlloc(t *testing.T) {
    30  	state, ctx := testContext(t)
    31  	nodes := []*RankedNode{
    32  		&RankedNode{
    33  			Node: &structs.Node{
    34  				// Perfect fit
    35  				ID: structs.GenerateUUID(),
    36  				Resources: &structs.Resources{
    37  					CPU:      2048,
    38  					MemoryMB: 2048,
    39  				},
    40  			},
    41  		},
    42  		&RankedNode{
    43  			Node: &structs.Node{
    44  				// Perfect fit
    45  				ID: structs.GenerateUUID(),
    46  				Resources: &structs.Resources{
    47  					CPU:      2048,
    48  					MemoryMB: 2048,
    49  				},
    50  			},
    51  		},
    52  	}
    53  
    54  	// Add existing allocations
    55  	alloc1 := &structs.Allocation{
    56  		ID:     structs.GenerateUUID(),
    57  		EvalID: structs.GenerateUUID(),
    58  		NodeID: nodes[0].Node.ID,
    59  		JobID:  structs.GenerateUUID(),
    60  		Resources: &structs.Resources{
    61  			CPU:      2048,
    62  			MemoryMB: 2048,
    63  		},
    64  		DesiredStatus: structs.AllocDesiredStatusRun,
    65  		ClientStatus:  structs.AllocClientStatusPending,
    66  	}
    67  	alloc2 := &structs.Allocation{
    68  		ID:     structs.GenerateUUID(),
    69  		EvalID: structs.GenerateUUID(),
    70  		NodeID: nodes[1].Node.ID,
    71  		JobID:  structs.GenerateUUID(),
    72  		Resources: &structs.Resources{
    73  			CPU:      1024,
    74  			MemoryMB: 1024,
    75  		},
    76  		DesiredStatus: structs.AllocDesiredStatusRun,
    77  		ClientStatus:  structs.AllocClientStatusPending,
    78  	}
    79  	noErr(t, state.UpsertAllocs(1000, []*structs.Allocation{alloc1, alloc2}))
    80  
    81  	// Add a planned eviction to alloc1
    82  	plan := ctx.Plan()
    83  	plan.NodeUpdate[nodes[0].Node.ID] = []*structs.Allocation{alloc1}
    84  
    85  	// Add a planned placement to node1
    86  	plan.NodeAllocation[nodes[1].Node.ID] = []*structs.Allocation{
    87  		&structs.Allocation{
    88  			Resources: &structs.Resources{
    89  				CPU:      1024,
    90  				MemoryMB: 1024,
    91  			},
    92  		},
    93  	}
    94  
    95  	proposed, err := ctx.ProposedAllocs(nodes[0].Node.ID)
    96  	if err != nil {
    97  		t.Fatalf("err: %v", err)
    98  	}
    99  	if len(proposed) != 0 {
   100  		t.Fatalf("bad: %#v", proposed)
   101  	}
   102  
   103  	proposed, err = ctx.ProposedAllocs(nodes[1].Node.ID)
   104  	if err != nil {
   105  		t.Fatalf("err: %v", err)
   106  	}
   107  	if len(proposed) != 2 {
   108  		t.Fatalf("bad: %#v", proposed)
   109  	}
   110  }
   111  
   112  func TestEvalEligibility_JobStatus(t *testing.T) {
   113  	e := NewEvalEligibility()
   114  	cc := uint64(100)
   115  
   116  	// Get the job before its been set.
   117  	if status := e.JobStatus(cc); status != EvalComputedClassUnknown {
   118  		t.Fatalf("JobStatus() returned %v; want %v", status, EvalComputedClassUnknown)
   119  	}
   120  
   121  	// Set the job and get its status.
   122  	e.SetJobEligibility(false, cc)
   123  	if status := e.JobStatus(cc); status != EvalComputedClassIneligible {
   124  		t.Fatalf("JobStatus() returned %v; want %v", status, EvalComputedClassIneligible)
   125  	}
   126  
   127  	e.SetJobEligibility(true, cc)
   128  	if status := e.JobStatus(cc); status != EvalComputedClassEligible {
   129  		t.Fatalf("JobStatus() returned %v; want %v", status, EvalComputedClassEligible)
   130  	}
   131  
   132  	// Check that if I pass class zero it returns escaped
   133  	if status := e.JobStatus(0); status != EvalComputedClassEscaped {
   134  		t.Fatalf("JobStatus() returned %v; want %v", status, EvalComputedClassEscaped)
   135  	}
   136  }
   137  
   138  func TestEvalEligibility_TaskGroupStatus(t *testing.T) {
   139  	e := NewEvalEligibility()
   140  	cc := uint64(100)
   141  	tg := "foo"
   142  
   143  	// Get the tg before its been set.
   144  	if status := e.TaskGroupStatus(tg, cc); status != EvalComputedClassUnknown {
   145  		t.Fatalf("TaskGroupStatus() returned %v; want %v", status, EvalComputedClassUnknown)
   146  	}
   147  
   148  	// Set the tg and get its status.
   149  	e.SetTaskGroupEligibility(false, tg, cc)
   150  	if status := e.TaskGroupStatus(tg, cc); status != EvalComputedClassIneligible {
   151  		t.Fatalf("TaskGroupStatus() returned %v; want %v", status, EvalComputedClassIneligible)
   152  	}
   153  
   154  	e.SetTaskGroupEligibility(true, tg, cc)
   155  	if status := e.TaskGroupStatus(tg, cc); status != EvalComputedClassEligible {
   156  		t.Fatalf("TaskGroupStatus() returned %v; want %v", status, EvalComputedClassEligible)
   157  	}
   158  
   159  	// Check that if I pass class zero it returns escaped
   160  	if status := e.TaskGroupStatus(tg, 0); status != EvalComputedClassEscaped {
   161  		t.Fatalf("TaskGroupStatus() returned %v; want %v", status, EvalComputedClassEscaped)
   162  	}
   163  }
   164  
   165  func TestEvalEligibility_SetJob(t *testing.T) {
   166  	e := NewEvalEligibility()
   167  	ne1 := &structs.Constraint{
   168  		LTarget: "$attr.kernel.name",
   169  		RTarget: "linux",
   170  		Operand: "=",
   171  	}
   172  	e1 := &structs.Constraint{
   173  		LTarget: "$attr.unique.kernel.name",
   174  		RTarget: "linux",
   175  		Operand: "=",
   176  	}
   177  	e2 := &structs.Constraint{
   178  		LTarget: "$meta.unique.key_foo",
   179  		RTarget: "linux",
   180  		Operand: "<",
   181  	}
   182  	e3 := &structs.Constraint{
   183  		LTarget: "$meta.unique.key_foo",
   184  		RTarget: "Windows",
   185  		Operand: "<",
   186  	}
   187  
   188  	job := mock.Job()
   189  	jobCon := []*structs.Constraint{ne1, e1, e2}
   190  	job.Constraints = jobCon
   191  
   192  	// Set the task constraints
   193  	tg := job.TaskGroups[0]
   194  	tg.Constraints = []*structs.Constraint{e1}
   195  	tg.Tasks[0].Constraints = []*structs.Constraint{e3}
   196  
   197  	e.SetJob(job)
   198  	if !e.HasEscaped() {
   199  		t.Fatalf("HasEscaped() should be true")
   200  	}
   201  
   202  	if !e.jobEscaped {
   203  		t.Fatalf("SetJob() should mark job as escaped")
   204  	}
   205  	if escaped, ok := e.tgEscapedConstraints[tg.Name]; !ok || !escaped {
   206  		t.Fatalf("SetJob() should mark task group as escaped")
   207  	}
   208  }