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 }