github.com/ncodes/nomad@v0.5.7-0.20170403112158-97adf4a74fb3/client/driver/java_test.go (about) 1 package driver 2 3 import ( 4 "os" 5 "os/exec" 6 "path/filepath" 7 "runtime" 8 "strings" 9 "syscall" 10 "testing" 11 "time" 12 13 "github.com/ncodes/nomad/client/config" 14 "github.com/ncodes/nomad/nomad/structs" 15 "github.com/ncodes/nomad/testutil" 16 17 ctestutils "github.com/ncodes/nomad/client/testutil" 18 ) 19 20 var ( 21 osJavaDriverSupport = map[string]bool{ 22 "linux": true, 23 } 24 ) 25 26 // javaLocated checks whether java is installed so we can run java stuff. 27 func javaLocated() bool { 28 _, err := exec.Command("java", "-version").CombinedOutput() 29 return err == nil 30 } 31 32 // The fingerprinter test should always pass, even if Java is not installed. 33 func TestJavaDriver_Fingerprint(t *testing.T) { 34 ctestutils.JavaCompatible(t) 35 task := &structs.Task{ 36 Name: "foo", 37 Driver: "java", 38 Resources: structs.DefaultResources(), 39 } 40 ctx := testDriverContexts(t, task) 41 defer ctx.AllocDir.Destroy() 42 d := NewJavaDriver(ctx.DriverCtx) 43 node := &structs.Node{ 44 Attributes: map[string]string{ 45 "unique.cgroup.mountpoint": "/sys/fs/cgroups", 46 }, 47 } 48 apply, err := d.Fingerprint(&config.Config{}, node) 49 if err != nil { 50 t.Fatalf("err: %v", err) 51 } 52 if apply != javaLocated() { 53 t.Fatalf("Fingerprinter should detect Java when it is installed") 54 } 55 if node.Attributes["driver.java"] != "1" { 56 if v, ok := osJavaDriverSupport[runtime.GOOS]; v && ok { 57 t.Fatalf("missing java driver") 58 } else { 59 t.Skipf("missing java driver, no OS support") 60 } 61 } 62 for _, key := range []string{"driver.java.version", "driver.java.runtime", "driver.java.vm"} { 63 if node.Attributes[key] == "" { 64 t.Fatalf("missing driver key (%s)", key) 65 } 66 } 67 } 68 69 func TestJavaDriver_StartOpen_Wait(t *testing.T) { 70 if !javaLocated() { 71 t.Skip("Java not found; skipping") 72 } 73 74 ctestutils.JavaCompatible(t) 75 task := &structs.Task{ 76 Name: "demo-app", 77 Driver: "java", 78 Config: map[string]interface{}{ 79 "jar_path": "demoapp.jar", 80 "jvm_options": []string{"-Xmx64m", "-Xms32m"}, 81 }, 82 LogConfig: &structs.LogConfig{ 83 MaxFiles: 10, 84 MaxFileSizeMB: 10, 85 }, 86 Resources: basicResources, 87 } 88 89 ctx := testDriverContexts(t, task) 90 defer ctx.AllocDir.Destroy() 91 d := NewJavaDriver(ctx.DriverCtx) 92 93 // Copy the test jar into the task's directory 94 dst := ctx.ExecCtx.TaskDir.Dir 95 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 96 97 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 98 t.Fatalf("prestart err: %v", err) 99 } 100 handle, err := d.Start(ctx.ExecCtx, task) 101 if err != nil { 102 t.Fatalf("err: %v", err) 103 } 104 if handle == nil { 105 t.Fatalf("missing handle") 106 } 107 108 // Attempt to open 109 handle2, err := d.Open(ctx.ExecCtx, handle.ID()) 110 if err != nil { 111 t.Fatalf("err: %v", err) 112 } 113 if handle2 == nil { 114 t.Fatalf("missing handle") 115 } 116 117 time.Sleep(2 * time.Second) 118 119 // There is a race condition between the handle waiting and killing. One 120 // will return an error. 121 handle.Kill() 122 handle2.Kill() 123 } 124 125 func TestJavaDriver_Start_Wait(t *testing.T) { 126 if !javaLocated() { 127 t.Skip("Java not found; skipping") 128 } 129 130 ctestutils.JavaCompatible(t) 131 task := &structs.Task{ 132 Name: "demo-app", 133 Driver: "java", 134 Config: map[string]interface{}{ 135 "jar_path": "demoapp.jar", 136 }, 137 LogConfig: &structs.LogConfig{ 138 MaxFiles: 10, 139 MaxFileSizeMB: 10, 140 }, 141 Resources: basicResources, 142 } 143 144 ctx := testDriverContexts(t, task) 145 defer ctx.AllocDir.Destroy() 146 d := NewJavaDriver(ctx.DriverCtx) 147 148 // Copy the test jar into the task's directory 149 dst := ctx.ExecCtx.TaskDir.Dir 150 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 151 152 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 153 t.Fatalf("prestart err: %v", err) 154 } 155 handle, err := d.Start(ctx.ExecCtx, task) 156 if err != nil { 157 t.Fatalf("err: %v", err) 158 } 159 if handle == nil { 160 t.Fatalf("missing handle") 161 } 162 163 // Task should terminate quickly 164 select { 165 case res := <-handle.WaitCh(): 166 if !res.Successful() { 167 t.Fatalf("err: %v", res) 168 } 169 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 170 // expect the timeout b/c it's a long lived process 171 break 172 } 173 174 // Get the stdout of the process and assrt that it's not empty 175 stdout := filepath.Join(ctx.ExecCtx.TaskDir.LogDir, "demo-app.stdout.0") 176 fInfo, err := os.Stat(stdout) 177 if err != nil { 178 t.Fatalf("failed to get stdout of process: %v", err) 179 } 180 if fInfo.Size() == 0 { 181 t.Fatalf("stdout of process is empty") 182 } 183 184 // need to kill long lived process 185 err = handle.Kill() 186 if err != nil { 187 t.Fatalf("Error: %s", err) 188 } 189 } 190 191 func TestJavaDriver_Start_Kill_Wait(t *testing.T) { 192 if !javaLocated() { 193 t.Skip("Java not found; skipping") 194 } 195 196 ctestutils.JavaCompatible(t) 197 task := &structs.Task{ 198 Name: "demo-app", 199 Driver: "java", 200 Config: map[string]interface{}{ 201 "jar_path": "demoapp.jar", 202 }, 203 LogConfig: &structs.LogConfig{ 204 MaxFiles: 10, 205 MaxFileSizeMB: 10, 206 }, 207 Resources: basicResources, 208 } 209 210 ctx := testDriverContexts(t, task) 211 defer ctx.AllocDir.Destroy() 212 d := NewJavaDriver(ctx.DriverCtx) 213 214 // Copy the test jar into the task's directory 215 dst := ctx.ExecCtx.TaskDir.Dir 216 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 217 218 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 219 t.Fatalf("prestart err: %v", err) 220 } 221 handle, err := d.Start(ctx.ExecCtx, task) 222 if err != nil { 223 t.Fatalf("err: %v", err) 224 } 225 if handle == nil { 226 t.Fatalf("missing handle") 227 } 228 229 go func() { 230 time.Sleep(100 * time.Millisecond) 231 err := handle.Kill() 232 if err != nil { 233 t.Fatalf("err: %v", err) 234 } 235 }() 236 237 // Task should terminate quickly 238 select { 239 case res := <-handle.WaitCh(): 240 if res.Successful() { 241 t.Fatal("should err") 242 } 243 case <-time.After(time.Duration(testutil.TestMultiplier()*10) * time.Second): 244 t.Fatalf("timeout") 245 246 // Need to kill long lived process 247 if err = handle.Kill(); err != nil { 248 t.Fatalf("Error: %s", err) 249 } 250 } 251 } 252 253 func TestJavaDriver_Signal(t *testing.T) { 254 if !javaLocated() { 255 t.Skip("Java not found; skipping") 256 } 257 258 ctestutils.JavaCompatible(t) 259 task := &structs.Task{ 260 Name: "demo-app", 261 Driver: "java", 262 Config: map[string]interface{}{ 263 "jar_path": "demoapp.jar", 264 }, 265 LogConfig: &structs.LogConfig{ 266 MaxFiles: 10, 267 MaxFileSizeMB: 10, 268 }, 269 Resources: basicResources, 270 } 271 272 ctx := testDriverContexts(t, task) 273 defer ctx.AllocDir.Destroy() 274 d := NewJavaDriver(ctx.DriverCtx) 275 276 // Copy the test jar into the task's directory 277 dst := ctx.ExecCtx.TaskDir.Dir 278 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 279 280 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 281 t.Fatalf("prestart err: %v", err) 282 } 283 handle, err := d.Start(ctx.ExecCtx, task) 284 if err != nil { 285 t.Fatalf("err: %v", err) 286 } 287 if handle == nil { 288 t.Fatalf("missing handle") 289 } 290 291 go func() { 292 time.Sleep(100 * time.Millisecond) 293 err := handle.Signal(syscall.SIGHUP) 294 if err != nil { 295 t.Fatalf("err: %v", err) 296 } 297 }() 298 299 // Task should terminate quickly 300 select { 301 case res := <-handle.WaitCh(): 302 if res.Successful() { 303 t.Fatal("should err") 304 } 305 case <-time.After(time.Duration(testutil.TestMultiplier()*10) * time.Second): 306 t.Fatalf("timeout") 307 308 // Need to kill long lived process 309 if err = handle.Kill(); err != nil { 310 t.Fatalf("Error: %s", err) 311 } 312 } 313 } 314 315 func TestJavaDriverUser(t *testing.T) { 316 if !javaLocated() { 317 t.Skip("Java not found; skipping") 318 } 319 320 ctestutils.JavaCompatible(t) 321 task := &structs.Task{ 322 Name: "demo-app", 323 Driver: "java", 324 User: "alice", 325 Config: map[string]interface{}{ 326 "jar_path": "demoapp.jar", 327 }, 328 LogConfig: &structs.LogConfig{ 329 MaxFiles: 10, 330 MaxFileSizeMB: 10, 331 }, 332 Resources: basicResources, 333 } 334 335 ctx := testDriverContexts(t, task) 336 defer ctx.AllocDir.Destroy() 337 d := NewJavaDriver(ctx.DriverCtx) 338 339 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 340 t.Fatalf("prestart err: %v", err) 341 } 342 handle, err := d.Start(ctx.ExecCtx, task) 343 if err == nil { 344 handle.Kill() 345 t.Fatalf("Should've failed") 346 } 347 msg := "user alice" 348 if !strings.Contains(err.Error(), msg) { 349 t.Fatalf("Expecting '%v' in '%v'", msg, err) 350 } 351 } 352 353 func TestJavaDriver_Start_Wait_Class(t *testing.T) { 354 if !javaLocated() { 355 t.Skip("Java not found; skipping") 356 } 357 358 ctestutils.JavaCompatible(t) 359 task := &structs.Task{ 360 Name: "demo-app", 361 Driver: "java", 362 Config: map[string]interface{}{ 363 "class_path": "${NOMAD_TASK_DIR}", 364 "class": "Hello", 365 }, 366 LogConfig: &structs.LogConfig{ 367 MaxFiles: 10, 368 MaxFileSizeMB: 10, 369 }, 370 Resources: basicResources, 371 } 372 373 ctx := testDriverContexts(t, task) 374 defer ctx.AllocDir.Destroy() 375 d := NewJavaDriver(ctx.DriverCtx) 376 377 // Copy the test jar into the task's directory 378 dst := ctx.ExecCtx.TaskDir.LocalDir 379 copyFile("./test-resources/java/Hello.class", filepath.Join(dst, "Hello.class"), t) 380 381 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 382 t.Fatalf("prestart err: %v", err) 383 } 384 handle, err := d.Start(ctx.ExecCtx, task) 385 if err != nil { 386 t.Fatalf("err: %v", err) 387 } 388 if handle == nil { 389 t.Fatalf("missing handle") 390 } 391 392 // Task should terminate quickly 393 select { 394 case res := <-handle.WaitCh(): 395 if !res.Successful() { 396 t.Fatalf("err: %v", res) 397 } 398 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 399 // expect the timeout b/c it's a long lived process 400 break 401 } 402 403 // Get the stdout of the process and assrt that it's not empty 404 stdout := filepath.Join(ctx.ExecCtx.TaskDir.LogDir, "demo-app.stdout.0") 405 fInfo, err := os.Stat(stdout) 406 if err != nil { 407 t.Fatalf("failed to get stdout of process: %v", err) 408 } 409 if fInfo.Size() == 0 { 410 t.Fatalf("stdout of process is empty") 411 } 412 413 // need to kill long lived process 414 err = handle.Kill() 415 if err != nil { 416 t.Fatalf("Error: %s", err) 417 } 418 }