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