github.com/anuvu/nomad@v0.8.7-atom1/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/hashicorp/nomad/client/config" 14 cstructs "github.com/hashicorp/nomad/client/structs" 15 "github.com/hashicorp/nomad/nomad/structs" 16 "github.com/hashicorp/nomad/testutil" 17 "github.com/stretchr/testify/assert" 18 19 ctestutils "github.com/hashicorp/nomad/client/testutil" 20 ) 21 22 var ( 23 osJavaDriverSupport = map[string]bool{ 24 "linux": true, 25 } 26 ) 27 28 // javaLocated checks whether java is installed so we can run java stuff. 29 func javaLocated() bool { 30 _, err := exec.Command("java", "-version").CombinedOutput() 31 return err == nil 32 } 33 34 // The fingerprinter test should always pass, even if Java is not installed. 35 func TestJavaDriver_Fingerprint(t *testing.T) { 36 if !testutil.IsTravis() { 37 t.Parallel() 38 } 39 ctestutils.JavaCompatible(t) 40 task := &structs.Task{ 41 Name: "foo", 42 Driver: "java", 43 Resources: structs.DefaultResources(), 44 } 45 ctx := testDriverContexts(t, task) 46 defer ctx.AllocDir.Destroy() 47 d := NewJavaDriver(ctx.DriverCtx) 48 node := &structs.Node{ 49 Attributes: map[string]string{ 50 "unique.cgroup.mountpoint": "/sys/fs/cgroups", 51 }, 52 } 53 54 request := &cstructs.FingerprintRequest{Config: &config.Config{}, Node: node} 55 var response cstructs.FingerprintResponse 56 err := d.Fingerprint(request, &response) 57 if err != nil { 58 t.Fatalf("err: %v", err) 59 } 60 61 if !response.Detected { 62 t.Fatalf("expected response to be applicable") 63 } 64 65 if response.Attributes["driver.java"] != "1" && javaLocated() { 66 if v, ok := osJavaDriverSupport[runtime.GOOS]; v && ok { 67 t.Fatalf("missing java driver") 68 } else { 69 t.Skipf("missing java driver, no OS support") 70 } 71 } 72 for _, key := range []string{"driver.java.version", "driver.java.runtime", "driver.java.vm"} { 73 if response.Attributes[key] == "" { 74 t.Fatalf("missing driver key (%s)", key) 75 } 76 } 77 } 78 79 func TestJavaDriver_StartOpen_Wait(t *testing.T) { 80 if !testutil.IsTravis() { 81 t.Parallel() 82 } 83 if !javaLocated() { 84 t.Skip("Java not found; skipping") 85 } 86 87 ctestutils.JavaCompatible(t) 88 task := &structs.Task{ 89 Name: "demo-app", 90 Driver: "java", 91 Config: map[string]interface{}{ 92 "jar_path": "demoapp.jar", 93 "jvm_options": []string{"-Xmx64m", "-Xms32m"}, 94 }, 95 LogConfig: &structs.LogConfig{ 96 MaxFiles: 10, 97 MaxFileSizeMB: 10, 98 }, 99 Resources: basicResources, 100 } 101 102 ctx := testDriverContexts(t, task) 103 defer ctx.AllocDir.Destroy() 104 d := NewJavaDriver(ctx.DriverCtx) 105 106 // Copy the test jar into the task's directory 107 dst := ctx.ExecCtx.TaskDir.Dir 108 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 109 110 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 111 t.Fatalf("prestart err: %v", err) 112 } 113 resp, err := d.Start(ctx.ExecCtx, task) 114 if err != nil { 115 t.Fatalf("err: %v", err) 116 } 117 118 // Attempt to open 119 handle2, err := d.Open(ctx.ExecCtx, resp.Handle.ID()) 120 if err != nil { 121 t.Fatalf("err: %v", err) 122 } 123 if handle2 == nil { 124 t.Fatalf("missing handle") 125 } 126 127 time.Sleep(2 * time.Second) 128 129 // There is a race condition between the handle waiting and killing. One 130 // will return an error. 131 resp.Handle.Kill() 132 handle2.Kill() 133 } 134 135 func TestJavaDriver_Start_Wait(t *testing.T) { 136 if !testutil.IsTravis() { 137 t.Parallel() 138 } 139 if !javaLocated() { 140 t.Skip("Java not found; skipping") 141 } 142 143 ctestutils.JavaCompatible(t) 144 task := &structs.Task{ 145 Name: "demo-app", 146 Driver: "java", 147 Config: map[string]interface{}{ 148 "jar_path": "demoapp.jar", 149 "args": []string{"1"}, 150 }, 151 LogConfig: &structs.LogConfig{ 152 MaxFiles: 10, 153 MaxFileSizeMB: 10, 154 }, 155 Resources: basicResources, 156 } 157 158 ctx := testDriverContexts(t, task) 159 defer ctx.AllocDir.Destroy() 160 d := NewJavaDriver(ctx.DriverCtx) 161 162 // Copy the test jar into the task's directory 163 dst := ctx.ExecCtx.TaskDir.Dir 164 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 165 166 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 167 t.Fatalf("prestart err: %v", err) 168 } 169 resp, err := d.Start(ctx.ExecCtx, task) 170 if err != nil { 171 t.Fatalf("err: %v", err) 172 } 173 174 // Task should terminate after 1 seconds 175 select { 176 case res := <-resp.Handle.WaitCh(): 177 if !res.Successful() { 178 t.Fatalf("err: %v", res.String()) 179 } 180 case <-time.After(5 * time.Second): 181 t.Fatalf("timeout") 182 } 183 184 // Get the stdout of the process and assert that it's not empty 185 stdout := filepath.Join(ctx.ExecCtx.TaskDir.LogDir, "demo-app.stdout.0") 186 fInfo, err := os.Stat(stdout) 187 if err != nil { 188 t.Fatalf("failed to get stdout of process: %v", err) 189 } 190 if fInfo.Size() == 0 { 191 t.Fatalf("stdout of process is empty") 192 } 193 194 // need to kill long lived process 195 err = resp.Handle.Kill() 196 if err != nil { 197 t.Fatalf("Error: %s", err) 198 } 199 } 200 201 func TestJavaDriver_Start_Kill_Wait(t *testing.T) { 202 if !testutil.IsTravis() { 203 t.Parallel() 204 } 205 if !javaLocated() { 206 t.Skip("Java not found; skipping") 207 } 208 209 ctestutils.JavaCompatible(t) 210 task := &structs.Task{ 211 Name: "demo-app", 212 Driver: "java", 213 Config: map[string]interface{}{ 214 "jar_path": "demoapp.jar", 215 "args": []string{"5"}, 216 }, 217 LogConfig: &structs.LogConfig{ 218 MaxFiles: 10, 219 MaxFileSizeMB: 10, 220 }, 221 Resources: basicResources, 222 } 223 224 ctx := testDriverContexts(t, task) 225 defer ctx.AllocDir.Destroy() 226 d := NewJavaDriver(ctx.DriverCtx) 227 228 // Copy the test jar into the task's directory 229 dst := ctx.ExecCtx.TaskDir.Dir 230 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 231 232 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 233 t.Fatalf("prestart err: %v", err) 234 } 235 resp, err := d.Start(ctx.ExecCtx, task) 236 if err != nil { 237 t.Fatalf("err: %v", err) 238 } 239 240 errCh := make(chan error, 1) 241 go func() { 242 time.Sleep(10 * time.Millisecond) 243 err := resp.Handle.Kill() 244 if err != nil { 245 errCh <- err 246 } 247 }() 248 249 // Task should terminate quickly 250 select { 251 case err := <-errCh: 252 t.Fatalf("err: %v", err) 253 case res := <-resp.Handle.WaitCh(): 254 if res.Successful() { 255 t.Fatal("should err") 256 } 257 case <-time.After(time.Duration(testutil.TestMultiplier()*10) * time.Second): 258 t.Fatalf("timeout") 259 260 // Need to kill long lived process 261 if err = resp.Handle.Kill(); err != nil { 262 t.Fatalf("Error: %s", err) 263 } 264 } 265 } 266 267 func TestJavaDriver_Signal(t *testing.T) { 268 if !testutil.IsTravis() { 269 t.Parallel() 270 } 271 if !javaLocated() { 272 t.Skip("Java not found; skipping") 273 } 274 275 ctestutils.JavaCompatible(t) 276 task := &structs.Task{ 277 Name: "demo-app", 278 Driver: "java", 279 Config: map[string]interface{}{ 280 "jar_path": "demoapp.jar", 281 "args": []string{"5"}, 282 }, 283 LogConfig: &structs.LogConfig{ 284 MaxFiles: 10, 285 MaxFileSizeMB: 10, 286 }, 287 Resources: basicResources, 288 } 289 290 ctx := testDriverContexts(t, task) 291 defer ctx.AllocDir.Destroy() 292 d := NewJavaDriver(ctx.DriverCtx) 293 294 // Copy the test jar into the task's directory 295 dst := ctx.ExecCtx.TaskDir.Dir 296 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 297 298 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 299 t.Fatalf("prestart err: %v", err) 300 } 301 resp, err := d.Start(ctx.ExecCtx, task) 302 if err != nil { 303 t.Fatalf("err: %v", err) 304 } 305 306 errCh := make(chan error, 1) 307 go func() { 308 time.Sleep(10 * time.Millisecond) 309 err := resp.Handle.Signal(syscall.SIGHUP) 310 if err != nil { 311 errCh <- err 312 } 313 }() 314 315 // Task should terminate quickly 316 select { 317 case err := <-errCh: 318 t.Fatalf("err: %v", err) 319 case res := <-resp.Handle.WaitCh(): 320 if res.Successful() { 321 t.Fatal("should err") 322 } 323 case <-time.After(time.Duration(testutil.TestMultiplier()*10) * time.Second): 324 t.Fatalf("timeout") 325 326 // Need to kill long lived process 327 if err = resp.Handle.Kill(); err != nil { 328 t.Fatalf("Error: %s", err) 329 } 330 } 331 } 332 333 func TestJavaDriver_User(t *testing.T) { 334 if !testutil.IsTravis() { 335 t.Parallel() 336 } 337 if !javaLocated() { 338 t.Skip("Java not found; skipping") 339 } 340 if runtime.GOOS != "linux" { 341 t.Skip("Linux only test") 342 } 343 344 ctestutils.JavaCompatible(t) 345 task := &structs.Task{ 346 Name: "demo-app", 347 Driver: "java", 348 User: "alice", 349 Config: map[string]interface{}{ 350 "jar_path": "demoapp.jar", 351 }, 352 LogConfig: &structs.LogConfig{ 353 MaxFiles: 10, 354 MaxFileSizeMB: 10, 355 }, 356 Resources: basicResources, 357 } 358 359 ctx := testDriverContexts(t, task) 360 defer ctx.AllocDir.Destroy() 361 d := NewJavaDriver(ctx.DriverCtx) 362 363 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 364 t.Fatalf("prestart err: %v", err) 365 } 366 resp, err := d.Start(ctx.ExecCtx, task) 367 if err == nil { 368 resp.Handle.Kill() 369 t.Fatalf("Should've failed") 370 } 371 msg := "user alice" 372 if !strings.Contains(err.Error(), msg) { 373 t.Fatalf("Expecting '%v' in '%v'", msg, err) 374 } 375 } 376 377 func TestJavaDriver_Start_Wait_Class(t *testing.T) { 378 if !testutil.IsTravis() { 379 t.Parallel() 380 } 381 if !javaLocated() { 382 t.Skip("Java not found; skipping") 383 } 384 385 ctestutils.JavaCompatible(t) 386 task := &structs.Task{ 387 Name: "demo-app", 388 Driver: "java", 389 Config: map[string]interface{}{ 390 "class_path": "${NOMAD_TASK_DIR}", 391 "class": "Hello", 392 "args": []string{"1"}, 393 }, 394 LogConfig: &structs.LogConfig{ 395 MaxFiles: 10, 396 MaxFileSizeMB: 10, 397 }, 398 Resources: basicResources, 399 } 400 401 ctx := testDriverContexts(t, task) 402 defer ctx.AllocDir.Destroy() 403 d := NewJavaDriver(ctx.DriverCtx) 404 405 // Copy the test jar into the task's directory 406 dst := ctx.ExecCtx.TaskDir.LocalDir 407 copyFile("./test-resources/java/Hello.class", filepath.Join(dst, "Hello.class"), t) 408 409 if _, err := d.Prestart(ctx.ExecCtx, task); err != nil { 410 t.Fatalf("prestart err: %v", err) 411 } 412 resp, err := d.Start(ctx.ExecCtx, task) 413 if err != nil { 414 t.Fatalf("err: %v", err) 415 } 416 417 // Task should terminate after 1 seconds 418 select { 419 case res := <-resp.Handle.WaitCh(): 420 if !res.Successful() { 421 t.Fatalf("err: %v", res.String()) 422 } 423 case <-time.After(5 * time.Second): 424 t.Fatalf("timeout") 425 } 426 427 // Get the stdout of the process and assert that it's not empty 428 stdout := filepath.Join(ctx.ExecCtx.TaskDir.LogDir, "demo-app.stdout.0") 429 fInfo, err := os.Stat(stdout) 430 if err != nil { 431 t.Fatalf("failed to get stdout of process: %v", err) 432 } 433 if fInfo.Size() == 0 { 434 t.Fatalf("stdout of process is empty") 435 } 436 437 // need to kill long lived process 438 if err := resp.Handle.Kill(); err != nil { 439 t.Fatalf("Error: %s", err) 440 } 441 } 442 443 func TestJavaDriver_Start_Kill(t *testing.T) { 444 assert := assert.New(t) 445 446 if !testutil.IsTravis() { 447 t.Parallel() 448 } 449 if !javaLocated() { 450 t.Skip("Java not found; skipping") 451 } 452 453 // Test that a valid kill signal will successfully stop the process 454 { 455 ctestutils.JavaCompatible(t) 456 task := &structs.Task{ 457 Name: "demo-app", 458 Driver: "java", 459 KillSignal: "SIGKILL", 460 Config: map[string]interface{}{ 461 "jar_path": "demoapp.jar", 462 "args": []string{"5"}, 463 }, 464 LogConfig: &structs.LogConfig{ 465 MaxFiles: 10, 466 MaxFileSizeMB: 10, 467 }, 468 Resources: basicResources, 469 } 470 471 ctx := testDriverContexts(t, task) 472 defer ctx.AllocDir.Destroy() 473 d := NewJavaDriver(ctx.DriverCtx) 474 475 // Copy the test jar into the task's directory 476 dst := ctx.ExecCtx.TaskDir.Dir 477 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 478 479 _, err := d.Prestart(ctx.ExecCtx, task) 480 assert.Nil(err) 481 482 resp, err := d.Start(ctx.ExecCtx, task) 483 assert.Nil(err) 484 485 assert.NotNil(resp.Handle) 486 err = resp.Handle.Kill() 487 assert.Nil(err) 488 } 489 490 // Test that an unsupported kill signal will return an error 491 { 492 ctestutils.JavaCompatible(t) 493 task := &structs.Task{ 494 Name: "demo-app", 495 Driver: "java", 496 KillSignal: "ABCDEF", 497 Config: map[string]interface{}{ 498 "jar_path": "demoapp.jar", 499 "args": []string{"5"}, 500 }, 501 LogConfig: &structs.LogConfig{ 502 MaxFiles: 10, 503 MaxFileSizeMB: 10, 504 }, 505 Resources: basicResources, 506 } 507 508 ctx := testDriverContexts(t, task) 509 defer ctx.AllocDir.Destroy() 510 d := NewJavaDriver(ctx.DriverCtx) 511 512 // Copy the test jar into the task's directory 513 dst := ctx.ExecCtx.TaskDir.Dir 514 copyFile("./test-resources/java/demoapp.jar", filepath.Join(dst, "demoapp.jar"), t) 515 516 _, err := d.Prestart(ctx.ExecCtx, task) 517 assert.Nil(err) 518 519 _, err = d.Start(ctx.ExecCtx, task) 520 assert.NotNil(err) 521 assert.Contains(err.Error(), "Signal ABCDEF is not supported") 522 } 523 }