From b3f161729820c4bcfcea0f44e357d5d8adc05ba6 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Thu, 4 Feb 2016 15:39:29 -0800 Subject: [PATCH] Added tests for the executor --- client/driver/exec.go | 2 +- client/driver/plugins/executor_test.go | 158 +++++++++++++++++++++++++ client/driver/raw_exec.go | 2 +- 3 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 client/driver/plugins/executor_test.go diff --git a/client/driver/exec.go b/client/driver/exec.go index cb12b6cd1..8ee6b9269 100644 --- a/client/driver/exec.go +++ b/client/driver/exec.go @@ -161,7 +161,7 @@ func (d *ExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, erro if err != nil { d.logger.Println("[ERROR] error connecting to plugin so destroying plugin pid and user pid") if e := destroyPlugin(id.PluginConfig.Pid, id.UserPid); e != nil { - d.logger.Printf("[ERROR] error destrouing plugin and userpid: %v", e) + d.logger.Printf("[ERROR] error destroying plugin and userpid: %v", e) } return nil, fmt.Errorf("error connecting to plugin: %v", err) } diff --git a/client/driver/plugins/executor_test.go b/client/driver/plugins/executor_test.go new file mode 100644 index 000000000..98fd89f11 --- /dev/null +++ b/client/driver/plugins/executor_test.go @@ -0,0 +1,158 @@ +package plugins + +import ( + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/hashicorp/nomad/client/allocdir" + "github.com/hashicorp/nomad/client/driver/env" + "github.com/hashicorp/nomad/nomad/mock" + "github.com/hashicorp/nomad/nomad/structs" + "github.com/hashicorp/nomad/testutil" +) + +var ( + constraint = &structs.Resources{ + CPU: 250, + MemoryMB: 256, + Networks: []*structs.NetworkResource{ + &structs.NetworkResource{ + MBits: 50, + DynamicPorts: []structs.Port{{Label: "http"}}, + }, + }, + } +) + +func mockAllocDir(t *testing.T) (string, *allocdir.AllocDir) { + alloc := mock.Alloc() + task := alloc.Job.TaskGroups[0].Tasks[0] + + allocDir := allocdir.NewAllocDir(filepath.Join(os.TempDir(), alloc.ID)) + if err := allocDir.Build([]*structs.Task{task}); err != nil { + log.Panicf("allocDir.Build() failed: %v", err) + } + + return task.Name, allocDir +} + +func testExecutorContext(t *testing.T) *ExecutorContext { + taskEnv := env.NewTaskEnvironment(mock.Node()) + taskName, allocDir := mockAllocDir(t) + ctx := &ExecutorContext{ + TaskEnv: taskEnv, + TaskName: taskName, + AllocDir: allocDir, + TaskResources: constraint, + } + return ctx +} + +func TestExecutor_Start_Invalid(t *testing.T) { + invalid := "/bin/foobar" + execCmd := ExecCommand{Cmd: invalid, Args: []string{"1"}} + ctx := testExecutorContext(t) + executor := NewExecutor(log.New(os.Stdout, "", log.LstdFlags)) + _, err := executor.LaunchCmd(&execCmd, ctx) + if err == nil { + t.Fatalf("Expected error") + } + defer ctx.AllocDir.Destroy() +} + +func TestExecutor_Start_Wait_Failure_Code(t *testing.T) { + execCmd := ExecCommand{Cmd: "/bin/sleep", Args: []string{"fail"}} + ctx := testExecutorContext(t) + executor := NewExecutor(log.New(os.Stdout, "", log.LstdFlags)) + ps, _ := executor.LaunchCmd(&execCmd, ctx) + 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) + } + defer ctx.AllocDir.Destroy() +} + +func TestExecutor_Start_Wait(t *testing.T) { + execCmd := ExecCommand{Cmd: "/bin/echo", Args: []string{"hello world"}} + ctx := testExecutorContext(t) + executor := NewExecutor(log.New(os.Stdout, "", log.LstdFlags)) + ps, err := executor.LaunchCmd(&execCmd, ctx) + 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) + } + defer ctx.AllocDir.Destroy() + + task := "web" + taskDir, ok := ctx.AllocDir.TaskDirs[task] + if !ok { + log.Panicf("No task directory found for task %v", task) + } + + expected := "hello world" + file := filepath.Join(allocdir.TaskLocal, "web.stdout") + absFilePath := filepath.Join(taskDir, file) + output, err := ioutil.ReadFile(absFilePath) + if err != nil { + t.Fatalf("Couldn't read file %v", absFilePath) + } + + act := strings.TrimSpace(string(output)) + if act != expected { + t.Fatalf("Command output incorrectly: want %v; got %v", expected, act) + } +} + +func TestExecutor_Start_Kill(t *testing.T) { + execCmd := ExecCommand{Cmd: "/bin/sleep", Args: []string{"10 && hello world"}} + ctx := testExecutorContext(t) + executor := NewExecutor(log.New(os.Stdout, "", log.LstdFlags)) + ps, err := executor.LaunchCmd(&execCmd, ctx) + 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) + } + defer ctx.AllocDir.Destroy() + + task := "web" + taskDir, ok := ctx.AllocDir.TaskDirs[task] + if !ok { + t.Fatalf("No task directory found for task %v", task) + } + + file := filepath.Join(allocdir.TaskLocal, "web.stdout") + absFilePath := filepath.Join(taskDir, file) + + time.Sleep(time.Duration(testutil.TestMultiplier()*2) * time.Second) + + output, err := ioutil.ReadFile(absFilePath) + if err != nil { + t.Fatalf("Couldn't read file %v", absFilePath) + } + + expected := "" + act := strings.TrimSpace(string(output)) + if act != expected { + t.Fatalf("Command output incorrectly: want %v; got %v", expected, act) + } +} diff --git a/client/driver/raw_exec.go b/client/driver/raw_exec.go index fc48b5580..f3f670d25 100644 --- a/client/driver/raw_exec.go +++ b/client/driver/raw_exec.go @@ -153,7 +153,7 @@ func (d *RawExecDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, e if err != nil { d.logger.Println("[ERROR] error connecting to plugin so destroying plugin pid and user pid") if e := destroyPlugin(id.PluginConfig.Pid, id.UserPid); e != nil { - d.logger.Printf("[ERROR] error destrouing plugin and userpid: %v", e) + d.logger.Printf("[ERROR] error destroying plugin and userpid: %v", e) } return nil, fmt.Errorf("error connecting to plugin: %v", err) }