open-nomad/client/driver/executor/executor_test.go

289 lines
6.9 KiB
Go
Raw Normal View History

2016-02-05 00:03:17 +00:00
package executor
2016-02-04 23:39:29 +00:00
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
2016-04-01 20:28:20 +00:00
"syscall"
2016-02-04 23:39:29 +00:00
"testing"
"time"
"github.com/hashicorp/nomad/client/allocdir"
"github.com/hashicorp/nomad/client/driver/env"
cstructs "github.com/hashicorp/nomad/client/structs"
2018-06-13 22:33:25 +00:00
"github.com/hashicorp/nomad/helper/testlog"
2016-02-04 23:39:29 +00:00
"github.com/hashicorp/nomad/nomad/mock"
tu "github.com/hashicorp/nomad/testutil"
"github.com/mitchellh/go-ps"
2016-02-04 23:39:29 +00:00
)
// testExecutorContext returns an ExecutorContext and AllocDir.
//
// The caller is responsible for calling AllocDir.Destroy() to cleanup.
func testExecutorContext(t *testing.T) (*ExecutorContext, *allocdir.AllocDir) {
2016-02-04 23:39:29 +00:00
alloc := mock.Alloc()
task := alloc.Job.TaskGroups[0].Tasks[0]
2017-05-26 23:46:03 +00:00
taskEnv := env.NewBuilder(mock.Node(), alloc, task, "global").Build()
2016-02-04 23:39:29 +00:00
2018-06-13 22:33:25 +00:00
allocDir := allocdir.NewAllocDir(testlog.Logger(t), filepath.Join(os.TempDir(), alloc.ID))
if err := allocDir.Build(); err != nil {
2018-06-13 22:33:25 +00:00
t.Fatalf("AllocDir.Build() failed: %v", err)
2016-02-04 23:39:29 +00:00
}
2017-03-02 23:54:12 +00:00
if err := allocDir.NewTaskDir(task.Name).Build(false, nil, cstructs.FSIsolationNone); err != nil {
allocDir.Destroy()
2018-06-13 22:33:25 +00:00
t.Fatalf("allocDir.NewTaskDir(%q) failed: %v", task.Name, err)
}
td := allocDir.TaskDirs[task.Name]
2016-02-04 23:39:29 +00:00
ctx := &ExecutorContext{
TaskEnv: taskEnv,
Task: task,
TaskDir: td.Dir,
LogDir: td.LogDir,
2016-02-04 23:39:29 +00:00
}
return ctx, allocDir
2016-02-04 23:39:29 +00:00
}
func TestExecutor_Start_Invalid(t *testing.T) {
2017-07-21 19:14:54 +00:00
t.Parallel()
2016-02-04 23:39:29 +00:00
invalid := "/bin/foobar"
execCmd := ExecCommand{Cmd: invalid, Args: []string{"1"}}
ctx, allocDir := testExecutorContext(t)
defer allocDir.Destroy()
2018-06-13 22:33:25 +00:00
executor := NewExecutor(testlog.Logger(t))
2016-10-12 18:35:29 +00:00
if err := executor.SetContext(ctx); err != nil {
t.Fatalf("Unexpected error")
}
if _, err := executor.LaunchCmd(&execCmd); err == nil {
2016-02-04 23:39:29 +00:00
t.Fatalf("Expected error")
}
}
func TestExecutor_Start_Wait_Failure_Code(t *testing.T) {
2017-07-21 19:14:54 +00:00
t.Parallel()
2017-07-23 02:27:20 +00:00
execCmd := ExecCommand{Cmd: "/bin/date", Args: []string{"fail"}}
ctx, allocDir := testExecutorContext(t)
defer allocDir.Destroy()
2018-06-13 22:33:25 +00:00
executor := NewExecutor(testlog.Logger(t))
2016-10-12 18:35:29 +00:00
if err := executor.SetContext(ctx); err != nil {
t.Fatalf("Unexpected error")
}
ps, err := executor.LaunchCmd(&execCmd)
if err != nil {
t.Fatalf("Unexpected error")
}
2016-02-04 23:39:29 +00:00
if ps.Pid == 0 {
t.Fatalf("expected process to start and have non zero pid")
}
ps, _ = executor.Wait()
if ps.ExitCode < 1 {
t.Fatalf("expected exit code to be non zero, actual: %v", ps.ExitCode)
}
if err := executor.Exit(); err != nil {
t.Fatalf("error: %v", err)
}
2016-02-04 23:39:29 +00:00
}
func TestExecutor_Start_Wait(t *testing.T) {
2017-07-21 19:14:54 +00:00
t.Parallel()
2016-02-04 23:39:29 +00:00
execCmd := ExecCommand{Cmd: "/bin/echo", Args: []string{"hello world"}}
ctx, allocDir := testExecutorContext(t)
defer allocDir.Destroy()
2018-06-13 22:33:25 +00:00
executor := NewExecutor(testlog.Logger(t))
2016-10-12 18:35:29 +00:00
if err := executor.SetContext(ctx); err != nil {
t.Fatalf("Unexpected error")
}
ps, err := executor.LaunchCmd(&execCmd)
2016-02-04 23:39:29 +00:00
if err != nil {
t.Fatalf("error in launching command: %v", err)
}
if ps.Pid == 0 {
t.Fatalf("expected process to start and have non zero pid")
}
ps, err = executor.Wait()
if err != nil {
t.Fatalf("error in waiting for command: %v", err)
}
if err := executor.Exit(); err != nil {
t.Fatalf("error: %v", err)
}
2016-02-04 23:39:29 +00:00
expected := "hello world"
file := filepath.Join(ctx.LogDir, "web.stdout.0")
2016-02-25 04:06:43 +00:00
output, err := ioutil.ReadFile(file)
2016-02-04 23:39:29 +00:00
if err != nil {
2016-02-25 04:06:43 +00:00
t.Fatalf("Couldn't read file %v", file)
2016-02-04 23:39:29 +00:00
}
act := strings.TrimSpace(string(output))
if act != expected {
t.Fatalf("Command output incorrectly: want %v; got %v", expected, act)
}
}
2016-04-01 20:28:20 +00:00
func TestExecutor_WaitExitSignal(t *testing.T) {
2017-07-21 19:14:54 +00:00
t.Parallel()
2016-04-01 20:28:20 +00:00
execCmd := ExecCommand{Cmd: "/bin/sleep", Args: []string{"10000"}}
ctx, allocDir := testExecutorContext(t)
defer allocDir.Destroy()
2018-06-13 22:33:25 +00:00
executor := NewExecutor(testlog.Logger(t))
2016-10-12 18:35:29 +00:00
if err := executor.SetContext(ctx); err != nil {
t.Fatalf("Unexpected error")
}
ps, err := executor.LaunchCmd(&execCmd)
2016-04-01 20:28:20 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
go func() {
2017-07-23 02:27:20 +00:00
time.Sleep(2 * time.Second)
ru, err := executor.Stats()
if err != nil {
t.Fatalf("err: %v", err)
}
2017-07-23 02:27:20 +00:00
if len(ru.Pids) == 0 {
t.Fatalf("expected pids")
}
2016-04-01 20:28:20 +00:00
proc, err := os.FindProcess(ps.Pid)
if err != nil {
t.Fatalf("err: %v", err)
}
if err := proc.Signal(syscall.SIGKILL); err != nil {
t.Fatalf("err: %v", err)
}
}()
ps, err = executor.Wait()
if err != nil {
t.Fatalf("err: %v", err)
}
if ps.Signal != int(syscall.SIGKILL) {
t.Fatalf("expected signal: %v, actual: %v", int(syscall.SIGKILL), ps.Signal)
}
}
2016-02-04 23:39:29 +00:00
func TestExecutor_Start_Kill(t *testing.T) {
2017-07-21 19:14:54 +00:00
t.Parallel()
2016-02-04 23:39:29 +00:00
execCmd := ExecCommand{Cmd: "/bin/sleep", Args: []string{"10 && hello world"}}
ctx, allocDir := testExecutorContext(t)
defer allocDir.Destroy()
2018-06-13 22:33:25 +00:00
executor := NewExecutor(testlog.Logger(t))
2016-10-12 18:35:29 +00:00
if err := executor.SetContext(ctx); err != nil {
t.Fatalf("Unexpected error")
}
ps, err := executor.LaunchCmd(&execCmd)
2016-02-04 23:39:29 +00:00
if err != nil {
t.Fatalf("error in launching command: %v", err)
}
if ps.Pid == 0 {
t.Fatalf("expected process to start and have non zero pid")
}
ps, err = executor.Wait()
if err != nil {
t.Fatalf("error in waiting for command: %v", err)
}
if err := executor.Exit(); err != nil {
t.Fatalf("error: %v", err)
}
2016-02-04 23:39:29 +00:00
file := filepath.Join(ctx.LogDir, "web.stdout.0")
time.Sleep(time.Duration(tu.TestMultiplier()*2) * time.Second)
2016-02-04 23:39:29 +00:00
2016-02-25 04:06:43 +00:00
output, err := ioutil.ReadFile(file)
2016-02-04 23:39:29 +00:00
if err != nil {
2016-02-25 04:06:43 +00:00
t.Fatalf("Couldn't read file %v", file)
2016-02-04 23:39:29 +00:00
}
expected := ""
act := strings.TrimSpace(string(output))
if act != expected {
t.Fatalf("Command output incorrectly: want %v; got %v", expected, act)
}
}
2016-03-19 19:18:10 +00:00
func TestExecutor_MakeExecutable(t *testing.T) {
2017-07-21 19:14:54 +00:00
t.Parallel()
2016-03-19 19:18:10 +00:00
// Create a temp file
f, err := ioutil.TempFile("", "")
if err != nil {
t.Fatal(err)
}
defer f.Close()
defer os.Remove(f.Name())
// Set its permissions to be non-executable
f.Chmod(os.FileMode(0610))
2018-03-11 18:05:31 +00:00
// Make a fake executor
2018-06-13 22:33:25 +00:00
executor := NewExecutor(testlog.Logger(t))
2016-03-19 19:18:10 +00:00
err = executor.(*UniversalExecutor).makeExecutable(f.Name())
if err != nil {
t.Fatalf("makeExecutable() failed: %v", err)
}
// Check the permissions
stat, err := f.Stat()
if err != nil {
t.Fatalf("Stat() failed: %v", err)
}
act := stat.Mode().Perm()
exp := os.FileMode(0755)
if act != exp {
t.Fatalf("expected permissions %v; got %v", exp, act)
2016-03-19 19:18:10 +00:00
}
}
2016-03-26 19:49:49 +00:00
2016-05-25 21:58:32 +00:00
func TestScanPids(t *testing.T) {
2017-07-21 19:14:54 +00:00
t.Parallel()
2016-05-25 21:58:32 +00:00
p1 := NewFakeProcess(2, 5)
p2 := NewFakeProcess(10, 2)
p3 := NewFakeProcess(15, 6)
p4 := NewFakeProcess(3, 10)
p5 := NewFakeProcess(20, 18)
2018-03-11 18:05:31 +00:00
// Make a fake executor
2018-06-13 22:33:25 +00:00
executor := NewExecutor(testlog.Logger(t)).(*UniversalExecutor)
2016-05-25 21:58:32 +00:00
nomadPids, err := executor.scanPids(5, []ps.Process{p1, p2, p3, p4, p5})
if err != nil {
t.Fatalf("error: %v", err)
}
if len(nomadPids) != 4 {
t.Fatalf("expected: 4, actual: %v", len(nomadPids))
}
}
type FakeProcess struct {
pid int
ppid int
}
func (f FakeProcess) Pid() int {
return f.pid
}
func (f FakeProcess) PPid() int {
return f.ppid
}
func (f FakeProcess) Executable() string {
return "fake"
}
func NewFakeProcess(pid int, ppid int) ps.Process {
return FakeProcess{pid: pid, ppid: ppid}
}