open-nomad/client/alloc_runner_test.go

174 lines
4.4 KiB
Go
Raw Normal View History

package client
import (
2016-02-04 03:58:39 +00:00
"fmt"
2015-09-24 21:29:53 +00:00
"os"
"testing"
2015-08-31 00:10:17 +00:00
"time"
"github.com/hashicorp/nomad/nomad/mock"
"github.com/hashicorp/nomad/nomad/structs"
2015-08-31 00:10:17 +00:00
"github.com/hashicorp/nomad/testutil"
2015-09-23 00:10:03 +00:00
2015-09-23 01:48:42 +00:00
ctestutil "github.com/hashicorp/nomad/client/testutil"
)
type MockAllocStateUpdater struct {
Count int
Allocs []*structs.Allocation
Err error
}
func (m *MockAllocStateUpdater) Update(alloc *structs.Allocation) error {
m.Count += 1
m.Allocs = append(m.Allocs, alloc)
return m.Err
}
func testAllocRunner(restarts bool) (*MockAllocStateUpdater, *AllocRunner) {
logger := testLogger()
conf := DefaultConfig()
2015-09-24 21:29:53 +00:00
conf.StateDir = os.TempDir()
conf.AllocDir = os.TempDir()
upd := &MockAllocStateUpdater{}
alloc := mock.Alloc()
consulClient, _ := NewConsulService(&consulServiceConfig{logger, "127.0.0.1:8500", "", "", false, false, &structs.Node{}})
if !restarts {
*alloc.Job.LookupTaskGroup(alloc.TaskGroup).RestartPolicy = structs.RestartPolicy{Attempts: 0}
2016-02-02 23:35:25 +00:00
alloc.Job.Type = structs.JobTypeBatch
}
ar := NewAllocRunner(logger, conf, upd.Update, alloc, consulClient)
return upd, ar
}
func TestAllocRunner_SimpleRun(t *testing.T) {
2015-09-23 01:48:42 +00:00
ctestutil.ExecCompatible(t)
upd, ar := testAllocRunner(false)
2015-08-31 00:10:17 +00:00
go ar.Run()
defer ar.Destroy()
2015-08-31 00:10:17 +00:00
testutil.WaitForResult(func() (bool, error) {
if upd.Count == 0 {
2016-02-04 03:58:39 +00:00
return false, fmt.Errorf("No updates")
2015-08-31 00:10:17 +00:00
}
last := upd.Allocs[upd.Count-1]
2016-02-04 03:58:39 +00:00
if last.ClientStatus == structs.AllocClientStatusDead {
return false, fmt.Errorf("got status %v; want %v", last.ClientStatus, structs.AllocClientStatusDead)
}
return true, nil
2015-08-31 00:10:17 +00:00
}, func(err error) {
t.Fatalf("err: %v", err)
})
}
func TestAllocRunner_Destroy(t *testing.T) {
2015-09-23 01:48:42 +00:00
ctestutil.ExecCompatible(t)
upd, ar := testAllocRunner(false)
2015-08-31 00:10:17 +00:00
// Ensure task takes some time
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
task.Config["command"] = "/bin/sleep"
task.Config["args"] = []string{"10"}
2015-08-31 00:10:17 +00:00
go ar.Run()
start := time.Now()
// Begin the tear down
go func() {
time.Sleep(100 * time.Millisecond)
ar.Destroy()
}()
testutil.WaitForResult(func() (bool, error) {
if upd.Count == 0 {
return false, nil
}
last := upd.Allocs[upd.Count-1]
return last.ClientStatus == structs.AllocClientStatusDead, nil
}, func(err error) {
t.Fatalf("err: %v %#v %#v", err, upd.Allocs[0], ar.alloc.TaskStates)
2015-08-31 00:10:17 +00:00
})
if time.Since(start) > 15*time.Second {
2015-08-31 00:10:17 +00:00
t.Fatalf("took too long to terminate")
}
}
func TestAllocRunner_Update(t *testing.T) {
2015-09-23 01:48:42 +00:00
ctestutil.ExecCompatible(t)
_, ar := testAllocRunner(false)
2015-08-31 00:10:17 +00:00
// Ensure task takes some time
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
task.Config["command"] = "/bin/sleep"
task.Config["args"] = []string{"10"}
2015-08-31 00:10:17 +00:00
go ar.Run()
defer ar.Destroy()
// Update the alloc definition
newAlloc := new(structs.Allocation)
*newAlloc = *ar.alloc
newAlloc.Name = "FOO"
newAlloc.AllocModifyIndex++
2015-08-31 00:10:17 +00:00
ar.Update(newAlloc)
// Check the alloc runner stores the update allocation.
2015-08-31 00:10:17 +00:00
testutil.WaitForResult(func() (bool, error) {
return ar.Alloc().Name == "FOO", nil
2015-08-31 00:10:17 +00:00
}, func(err error) {
t.Fatalf("err: %v %#v", err, ar.Alloc())
2015-08-31 00:10:17 +00:00
})
}
func TestAllocRunner_SaveRestoreState(t *testing.T) {
ctestutil.ExecCompatible(t)
upd, ar := testAllocRunner(false)
2015-08-31 00:10:17 +00:00
// Ensure task takes some time
task := ar.alloc.Job.TaskGroups[0].Tasks[0]
task.Config["command"] = "/bin/sleep"
task.Config["args"] = []string{"10"}
2015-08-31 00:10:17 +00:00
go ar.Run()
defer ar.Destroy()
// Snapshot state
2016-01-21 22:52:41 +00:00
testutil.WaitForResult(func() (bool, error) {
return len(ar.tasks) == 1, nil
}, func(err error) {
t.Fatalf("task never started: %v", err)
})
2015-08-31 00:10:17 +00:00
err := ar.SaveState()
if err != nil {
t.Fatalf("err: %v", err)
}
// Create a new alloc runner
consulClient, err := NewConsulService(&consulServiceConfig{ar.logger, "127.0.0.1:8500", "", "", false, false, &structs.Node{}})
2015-08-31 00:10:17 +00:00
ar2 := NewAllocRunner(ar.logger, ar.config, upd.Update,
&structs.Allocation{ID: ar.alloc.ID}, consulClient)
2015-08-31 00:10:17 +00:00
err = ar2.RestoreState()
if err != nil {
t.Fatalf("err: %v", err)
}
go ar2.Run()
// Destroy and wait
ar2.Destroy()
start := time.Now()
testutil.WaitForResult(func() (bool, error) {
if upd.Count == 0 {
return false, nil
}
last := upd.Allocs[upd.Count-1]
2016-01-22 00:05:35 +00:00
return last.ClientStatus != structs.AllocClientStatusPending, nil
2015-08-31 00:10:17 +00:00
}, func(err error) {
t.Fatalf("err: %v %#v %#v", err, upd.Allocs[0], ar.alloc.TaskStates)
2015-08-31 00:10:17 +00:00
})
2016-01-21 22:52:41 +00:00
if time.Since(start) > time.Duration(testutil.TestMultiplier()*15)*time.Second {
2015-08-31 00:10:17 +00:00
t.Fatalf("took too long to terminate")
}
}