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  }