github.com/huiliang/nomad@v0.2.1-0.20151124023127-7a8b664699ff/client/driver/executor/test_harness_test.go (about)

     1  package executor
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"log"
     7  	"os"
     8  	"path/filepath"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/hashicorp/nomad/client/allocdir"
    13  	"github.com/hashicorp/nomad/nomad/mock"
    14  	"github.com/hashicorp/nomad/nomad/structs"
    15  )
    16  
    17  var (
    18  	constraint = &structs.Resources{
    19  		CPU:      250,
    20  		MemoryMB: 256,
    21  		Networks: []*structs.NetworkResource{
    22  			&structs.NetworkResource{
    23  				MBits:        50,
    24  				DynamicPorts: []structs.Port{{Label: "http"}},
    25  			},
    26  		},
    27  	}
    28  )
    29  
    30  func mockAllocDir(t *testing.T) (string, *allocdir.AllocDir) {
    31  	alloc := mock.Alloc()
    32  	task := alloc.Job.TaskGroups[0].Tasks[0]
    33  
    34  	allocDir := allocdir.NewAllocDir(filepath.Join(os.TempDir(), alloc.ID))
    35  	if err := allocDir.Build([]*structs.Task{task}); err != nil {
    36  		log.Panicf("allocDir.Build() failed: %v", err)
    37  	}
    38  
    39  	return task.Name, allocDir
    40  }
    41  
    42  func testExecutor(t *testing.T, buildExecutor func() Executor, compatible func(*testing.T)) {
    43  	if compatible != nil {
    44  		compatible(t)
    45  	}
    46  
    47  	command := func(name string, args ...string) Executor {
    48  		b := buildExecutor()
    49  		SetCommand(b, name, args)
    50  		return b
    51  	}
    52  
    53  	Executor_Start_Invalid(t, command)
    54  	Executor_Start_Wait_Failure_Code(t, command)
    55  	Executor_Start_Wait(t, command)
    56  	Executor_Start_Kill(t, command)
    57  	Executor_Open(t, command, buildExecutor)
    58  }
    59  
    60  type buildExecCommand func(name string, args ...string) Executor
    61  
    62  func Executor_Start_Invalid(t *testing.T, command buildExecCommand) {
    63  	invalid := "/bin/foobar"
    64  	e := command(invalid, "1")
    65  
    66  	if err := e.Limit(constraint); err != nil {
    67  		log.Panicf("Limit() failed: %v", err)
    68  	}
    69  
    70  	task, alloc := mockAllocDir(t)
    71  	defer alloc.Destroy()
    72  	if err := e.ConfigureTaskDir(task, alloc); err != nil {
    73  		log.Panicf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
    74  	}
    75  
    76  	if err := e.Start(); err == nil {
    77  		log.Panicf("Start(%v) should have failed", invalid)
    78  	}
    79  }
    80  
    81  func Executor_Start_Wait_Failure_Code(t *testing.T, command buildExecCommand) {
    82  	e := command("/bin/date", "-invalid")
    83  
    84  	if err := e.Limit(constraint); err != nil {
    85  		log.Panicf("Limit() failed: %v", err)
    86  	}
    87  
    88  	task, alloc := mockAllocDir(t)
    89  	defer alloc.Destroy()
    90  	if err := e.ConfigureTaskDir(task, alloc); err != nil {
    91  		log.Panicf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
    92  	}
    93  
    94  	if err := e.Start(); err != nil {
    95  		log.Panicf("Start() failed: %v", err)
    96  	}
    97  
    98  	if err := e.Wait(); err == nil {
    99  		log.Panicf("Wait() should have failed")
   100  	}
   101  }
   102  
   103  func Executor_Start_Wait(t *testing.T, command buildExecCommand) {
   104  	task, alloc := mockAllocDir(t)
   105  	defer alloc.Destroy()
   106  
   107  	taskDir, ok := alloc.TaskDirs[task]
   108  	if !ok {
   109  		log.Panicf("No task directory found for task %v", task)
   110  	}
   111  
   112  	expected := "hello world"
   113  	file := filepath.Join(allocdir.TaskLocal, "output.txt")
   114  	absFilePath := filepath.Join(taskDir, file)
   115  	cmd := fmt.Sprintf(`/bin/sleep 1 ; echo -n %v > %v`, expected, file)
   116  	e := command("/bin/bash", "-c", cmd)
   117  
   118  	if err := e.Limit(constraint); err != nil {
   119  		log.Panicf("Limit() failed: %v", err)
   120  	}
   121  
   122  	if err := e.ConfigureTaskDir(task, alloc); err != nil {
   123  		log.Panicf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
   124  	}
   125  
   126  	if err := e.Start(); err != nil {
   127  		log.Panicf("Start() failed: %v", err)
   128  	}
   129  
   130  	if res := e.Wait(); !res.Successful() {
   131  		log.Panicf("Wait() failed: %v", res)
   132  	}
   133  
   134  	output, err := ioutil.ReadFile(absFilePath)
   135  	if err != nil {
   136  		log.Panicf("Couldn't read file %v", absFilePath)
   137  	}
   138  
   139  	act := string(output)
   140  	if act != expected {
   141  		log.Panicf("Command output incorrectly: want %v; got %v", expected, act)
   142  	}
   143  }
   144  
   145  func Executor_Start_Kill(t *testing.T, command buildExecCommand) {
   146  	task, alloc := mockAllocDir(t)
   147  	defer alloc.Destroy()
   148  
   149  	taskDir, ok := alloc.TaskDirs[task]
   150  	if !ok {
   151  		log.Panicf("No task directory found for task %v", task)
   152  	}
   153  
   154  	filePath := filepath.Join(taskDir, "output")
   155  	e := command("/bin/bash", "-c", "sleep 1 ; echo \"failure\" > "+filePath)
   156  
   157  	if err := e.Limit(constraint); err != nil {
   158  		log.Panicf("Limit() failed: %v", err)
   159  	}
   160  
   161  	if err := e.ConfigureTaskDir(task, alloc); err != nil {
   162  		log.Panicf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
   163  	}
   164  
   165  	if err := e.Start(); err != nil {
   166  		log.Panicf("Start() failed: %v", err)
   167  	}
   168  
   169  	if err := e.Shutdown(); err != nil {
   170  		log.Panicf("Shutdown() failed: %v", err)
   171  	}
   172  
   173  	time.Sleep(1500 * time.Millisecond)
   174  
   175  	// Check that the file doesn't exist.
   176  	if _, err := os.Stat(filePath); err == nil {
   177  		log.Panicf("Stat(%v) should have failed: task not killed", filePath)
   178  	}
   179  }
   180  
   181  func Executor_Open(t *testing.T, command buildExecCommand, newExecutor func() Executor) {
   182  	task, alloc := mockAllocDir(t)
   183  	defer alloc.Destroy()
   184  
   185  	taskDir, ok := alloc.TaskDirs[task]
   186  	if !ok {
   187  		log.Panicf("No task directory found for task %v", task)
   188  	}
   189  
   190  	expected := "hello world"
   191  	file := filepath.Join(allocdir.TaskLocal, "output.txt")
   192  	absFilePath := filepath.Join(taskDir, file)
   193  	cmd := fmt.Sprintf(`/bin/sleep 1 ; echo -n %v > %v`, expected, file)
   194  	e := command("/bin/bash", "-c", cmd)
   195  
   196  	if err := e.Limit(constraint); err != nil {
   197  		log.Panicf("Limit() failed: %v", err)
   198  	}
   199  
   200  	if err := e.ConfigureTaskDir(task, alloc); err != nil {
   201  		log.Panicf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
   202  	}
   203  
   204  	if err := e.Start(); err != nil {
   205  		log.Panicf("Start() failed: %v", err)
   206  	}
   207  
   208  	id, err := e.ID()
   209  	if err != nil {
   210  		log.Panicf("ID() failed: %v", err)
   211  	}
   212  
   213  	e2 := newExecutor()
   214  	if err := e2.Open(id); err != nil {
   215  		log.Panicf("Open(%v) failed: %v", id, err)
   216  	}
   217  
   218  	if res := e2.Wait(); !res.Successful() {
   219  		log.Panicf("Wait() failed: %v", res)
   220  	}
   221  
   222  	output, err := ioutil.ReadFile(absFilePath)
   223  	if err != nil {
   224  		log.Panicf("Couldn't read file %v", absFilePath)
   225  	}
   226  
   227  	act := string(output)
   228  	if act != expected {
   229  		log.Panicf("Command output incorrectly: want %v; got %v", expected, act)
   230  	}
   231  }
   232  
   233  func Executor_Open_Invalid(t *testing.T, command buildExecCommand, newExecutor func() Executor) {
   234  	task, alloc := mockAllocDir(t)
   235  	e := command("echo", "foo")
   236  
   237  	if err := e.Limit(constraint); err != nil {
   238  		log.Panicf("Limit() failed: %v", err)
   239  	}
   240  
   241  	if err := e.ConfigureTaskDir(task, alloc); err != nil {
   242  		log.Panicf("ConfigureTaskDir(%v, %v) failed: %v", task, alloc, err)
   243  	}
   244  
   245  	if err := e.Start(); err != nil {
   246  		log.Panicf("Start() failed: %v", err)
   247  	}
   248  
   249  	id, err := e.ID()
   250  	if err != nil {
   251  		log.Panicf("ID() failed: %v", err)
   252  	}
   253  
   254  	// Destroy the allocdir which removes the exit code.
   255  	alloc.Destroy()
   256  
   257  	e2 := newExecutor()
   258  	if err := e2.Open(id); err == nil {
   259  		log.Panicf("Open(%v) should have failed", id)
   260  	}
   261  }