From 0022496e5bc28542adbef0264f2ad7164429e9c7 Mon Sep 17 00:00:00 2001 From: Mahmood Ali Date: Wed, 31 Oct 2018 12:19:07 -0400 Subject: [PATCH] add java driver tests --- drivers/java/driver_test.go | 306 ++++++++++++++++++++++++ drivers/java/test-resources/Hello.class | Bin 0 -> 728 bytes drivers/java/test-resources/Hello.java | 14 ++ drivers/java/test-resources/demoapp.jar | Bin 0 -> 952 bytes 4 files changed, 320 insertions(+) create mode 100644 drivers/java/driver_test.go create mode 100644 drivers/java/test-resources/Hello.class create mode 100644 drivers/java/test-resources/Hello.java create mode 100644 drivers/java/test-resources/demoapp.jar diff --git a/drivers/java/driver_test.go b/drivers/java/driver_test.go new file mode 100644 index 000000000..520c9dba8 --- /dev/null +++ b/drivers/java/driver_test.go @@ -0,0 +1,306 @@ +package java + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sync" + "testing" + + "context" + "time" + + "github.com/hashicorp/hcl2/hcl" + ctestutil "github.com/hashicorp/nomad/client/testutil" + "github.com/hashicorp/nomad/helper/testlog" + "github.com/hashicorp/nomad/helper/uuid" + "github.com/hashicorp/nomad/nomad/structs" + "github.com/hashicorp/nomad/plugins/drivers" + "github.com/hashicorp/nomad/plugins/shared" + "github.com/hashicorp/nomad/plugins/shared/hclspec" + "github.com/hashicorp/nomad/testutil" + "github.com/stretchr/testify/require" +) + +func javaCompatible(t *testing.T) { + ctestutil.JavaCompatible(t) + + _, _, _, err := javaVersionInfo() + if err != nil { + t.Skipf("java not found; skipping: %v", err) + } +} + +func TestDriver_Fingerprint(t *testing.T) { + javaCompatible(t) + if !testutil.IsTravis() { + t.Parallel() + } + + d := NewDriver(testlog.HCLogger(t)) + harness := drivers.NewDriverHarness(t, d) + + fpCh, err := harness.Fingerprint(context.Background()) + require.NoError(t, err) + + select { + case fp := <-fpCh: + require.Equal(t, drivers.HealthStateHealthy, fp.Health) + require.Equal(t, "1", fp.Attributes["driver.java"]) + case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): + require.Fail(t, "timeout receiving fingerprint") + } +} + +func TestDriver_Jar_Start_Wait(t *testing.T) { + javaCompatible(t) + if !testutil.IsTravis() { + t.Parallel() + } + + require := require.New(t) + d := NewDriver(testlog.HCLogger(t)) + harness := drivers.NewDriverHarness(t, d) + + task := basicTask(t, "demo-app", map[string]interface{}{ + "jar_path": "demoapp.jar", + "args": []string{"1"}, + "jvm_options": []string{"-Xmx64m", "-Xms32m"}, + }) + + cleanup := harness.MkAllocDir(task, true) + defer cleanup() + + copyFile("./test-resources/java/demoapp.jar", filepath.Join(task.TaskDir().Dir, "demoapp.jar"), t) + + handle, _, err := harness.StartTask(task) + require.NoError(err) + + ch, err := harness.WaitTask(context.Background(), handle.Config.ID) + require.NoError(err) + result := <-ch + require.Nil(result.Err) + + require.Zero(result.ExitCode) + + // Get the stdout of the process and assert that it's not empty + stdout, err := ioutil.ReadFile(filepath.Join(task.TaskDir().LogDir, "demo-app.stdout.0")) + require.NoError(err) + require.Contains(string(stdout), "Hello") + + require.NoError(harness.DestroyTask(task.ID, true)) +} + +func TestDriver_Jar_Stop_Wait(t *testing.T) { + javaCompatible(t) + if !testutil.IsTravis() { + t.Parallel() + } + + require := require.New(t) + d := NewDriver(testlog.HCLogger(t)) + harness := drivers.NewDriverHarness(t, d) + + task := basicTask(t, "demo-app", map[string]interface{}{ + "jar_path": "demoapp.jar", + "args": "20", + "jvm_options": []string{"-Xmx64m", "-Xms32m"}, + }) + + cleanup := harness.MkAllocDir(task, true) + defer cleanup() + + copyFile("./test-resources/java/demoapp.jar", filepath.Join(task.TaskDir().Dir, "demoapp.jar"), t) + + handle, _, err := harness.StartTask(task) + require.NoError(err) + + ch, err := harness.WaitTask(context.Background(), handle.Config.ID) + require.NoError(err) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + result := <-ch + require.Equal(2, result.Signal) + }() + + require.NoError(harness.WaitUntilStarted(task.ID, 1*time.Second)) + + wg.Add(1) + go func() { + defer wg.Done() + + time.Sleep(10 * time.Millisecond) + err := harness.StopTask(task.ID, 2*time.Second, "SIGINT") + require.NoError(err) + }() + + waitCh := make(chan struct{}) + go func() { + defer close(waitCh) + wg.Wait() + }() + + select { + case <-waitCh: + status, err := harness.InspectTask(task.ID) + require.NoError(err) + require.Equal(drivers.TaskStateExited, status.State) + case <-time.After(5 * time.Second): + require.Fail("timeout waiting for task to shutdown") + } + + require.NoError(harness.DestroyTask(task.ID, true)) +} + +func TestDriver_Class_Start_Wait(t *testing.T) { + javaCompatible(t) + if !testutil.IsTravis() { + t.Parallel() + } + + require := require.New(t) + d := NewDriver(testlog.HCLogger(t)) + harness := drivers.NewDriverHarness(t, d) + + task := basicTask(t, "demo-app", map[string]interface{}{ + "class_path": "${NOMAD_TASK_DIR}", + "class": "Hello", + "args": []string{"1"}, + }) + + cleanup := harness.MkAllocDir(task, true) + defer cleanup() + + copyFile("./test-resources/Hello.class", filepath.Join(task.TaskDir().Dir, "Hello.class"), t) + + handle, _, err := harness.StartTask(task) + require.NoError(err) + + ch, err := harness.WaitTask(context.Background(), handle.Config.ID) + require.NoError(err) + result := <-ch + require.Nil(result.Err) + + require.Zero(result.ExitCode) + + // Get the stdout of the process and assert that it's not empty + stdout, err := ioutil.ReadFile(filepath.Join(task.TaskDir().LogDir, "demo-app.stdout.0")) + require.NoError(err) + require.Contains(string(stdout), "Hello") + + require.NoError(harness.DestroyTask(task.ID, true)) +} + +func TestJavaCmdArgs(t *testing.T) { + cases := []struct { + name string + cfg TaskConfig + expected []string + }{ + { + "jar_path_full", + TaskConfig{ + JvmOpts: []string{"-Xmx512m", "-Xms128m"}, + JarPath: "/jar-path.jar", + Args: []string{"hello", "world"}, + }, + []string{"-Xmx512m", "-Xms128m", "-jar", "/jar-path.jar", "hello", "world"}, + }, + { + "class_full", + TaskConfig{ + JvmOpts: []string{"-Xmx512m", "-Xms128m"}, + Class: "ClassName", + ClassPath: "/classpath", + Args: []string{"hello", "world"}, + }, + []string{"-Xmx512m", "-Xms128m", "-cp", "/classpath", "ClassName", "hello", "world"}, + }, + { + "jar_path_slim", + TaskConfig{ + JarPath: "/jar-path.jar", + }, + []string{"-jar", "/jar-path.jar"}, + }, + { + "class_slim", + TaskConfig{ + Class: "ClassName", + }, + []string{"ClassName"}, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + found := javaCmdArgs(c.cfg) + require.Equal(t, c.expected, found) + }) + } +} + +func basicTask(t *testing.T, name string, taskConfig map[string]interface{}) *drivers.TaskConfig { + task := &drivers.TaskConfig{ + ID: uuid.Generate(), + Name: name, + Resources: &drivers.Resources{ + NomadResources: &structs.Resources{ + MemoryMB: 128, + CPU: 100, + }, + LinuxResources: &drivers.LinuxResources{ + MemoryLimitBytes: 134217728, + CPUShares: 100, + }, + }, + } + + encodeDriverHelper(t, task, taskConfig) + return task +} + +func encodeDriverHelper(t *testing.T, task *drivers.TaskConfig, taskConfig map[string]interface{}) { + evalCtx := &hcl.EvalContext{ + Functions: shared.GetStdlibFuncs(), + } + spec, diag := hclspec.Convert(taskConfigSpec) + require.False(t, diag.HasErrors()) + taskConfigCtyVal, diag := shared.ParseHclInterface(taskConfig, spec, evalCtx) + if diag.HasErrors() { + fmt.Println("conversion error", diag.Error()) + } + require.False(t, diag.HasErrors()) + err := task.EncodeDriverConfig(taskConfigCtyVal) + require.Nil(t, err) + +} + +// copyFile moves an existing file to the destination +func copyFile(src, dst string, t *testing.T) { + in, err := os.Open(src) + if err != nil { + t.Fatalf("copying %v -> %v failed: %v", src, dst, err) + } + defer in.Close() + out, err := os.Create(dst) + if err != nil { + t.Fatalf("copying %v -> %v failed: %v", src, dst, err) + } + defer func() { + if err := out.Close(); err != nil { + t.Fatalf("copying %v -> %v failed: %v", src, dst, err) + } + }() + if _, err = io.Copy(out, in); err != nil { + t.Fatalf("copying %v -> %v failed: %v", src, dst, err) + } + if err := out.Sync(); err != nil { + t.Fatalf("copying %v -> %v failed: %v", src, dst, err) + } +} diff --git a/drivers/java/test-resources/Hello.class b/drivers/java/test-resources/Hello.class new file mode 100644 index 0000000000000000000000000000000000000000..d55f78e76eee1a200cdc812e4a0ae41b5a3f9874 GIT binary patch literal 728 zcmZ`%&2G~`7@Uohth05XX`4VPZRszLfd&eN8>X(AWu0S@V}qgG4&zWiWU$=kD~95uq$e3JAB3?y$_8Djj{R;#NO9nYF+;ArgExnMn)B%@2GL0}704%{(Tk@tijp0pb>N`NvFTt7 z+YF`rgyW_I7flY&!7be8xZ_|4ErylJefzPNN@b~*y~pnYnd&f!9o)q|2fL^;%uc8; zx~DSGQ&8vqP|E>Lnq+iPAI}jct(P=}rctCn*khQ_drZR&JT;_<5~#cX4xl!<+t}<& z#bBqt8cKTok8FR+-|-1q=usfUNXnEVcc10S2ANVa)_;x{+~!{n#whu&kiT&_ScCZu z%u@g}Vbgkv-j=B{swM9$*col;L(^K$LF#~6)M#(0A4qCZ^}e7mXPu*Hx4nx`5T3O= zLaAM|ek`4Q9HIOf;&24}9F;RtHn56yaMGH-+td-%#YT|~l?W>nqe2{qSOOblvPtIV Uh&2Q2CmQTI$Gow#Ku`ho-;^tw!~g&Q literal 0 HcmV?d00001 diff --git a/drivers/java/test-resources/Hello.java b/drivers/java/test-resources/Hello.java new file mode 100644 index 000000000..43ead64d5 --- /dev/null +++ b/drivers/java/test-resources/Hello.java @@ -0,0 +1,14 @@ +public class Hello { + public static void main(String[] args) { + System.out.println("Hello"); + int seconds = 5; + if (args.length != 0) { + seconds = Integer.parseInt(args[0]); + } + try { + Thread.sleep(1000*seconds); //1000 milliseconds is one second. + } catch(InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/drivers/java/test-resources/demoapp.jar b/drivers/java/test-resources/demoapp.jar new file mode 100644 index 0000000000000000000000000000000000000000..650c1de9750647a24120d5fe561b5382527d307e GIT binary patch literal 952 zcmWIWW@Zs#;Nak3xZU^7ivbC6GO#fCx`sIFdiuHP|2xINz|0Wf&CUT*!30$nfK#&w zPz7AGucM!*n`>~0p0C?y-!rFuymj?1@_OrPojY@WbCAIm;|EWR^t^m^Jbf>gu43Vg zcp-U2T1rYY$;sDC&PgmTE)6;ubU8r8wtq|QOXX0mEnOTO z8cPCKHd$Nc$;e)8Iya^8@hj8XV5ZDTp7AoW*Xvs1A4rMcNIb~?L$$8uaYg);#8(Mo z@1NbPK3DsE-jm!TZ%{SptdhK5aQE1p1H5Or?;L45pft@QZ|07iKG8nQzR=Sy(;Kbn`c;})ON*6F;vwC+y7J3*_pkw>X**Y9n$8uw48X)LbWy!f)h zt9)W`+_yr1s5ND zkhyczw(mEe*@cvdJv;K%FKPL1c3FMz^7nmSB?9hzat{_Z`-Vs?(_659SNo~!$xF|* zFAQV8WpZvs;P1`u0_O3Tg=U2X7Hv3dQ0zIgQC*GuWaF&ros3rtXVy+Ny3y&=-gW8! zg|cH`-pXHywKYnS(3(2o>AUVbk@nufqAx#xTXQ?(zqiuerw{JP=p6pT_G~7DaoXj| z)=jKkJxLdTvz7Vie_8la=c((g2F;NFPWD1q7rm%GdSpv!Q`6l~=j@y-u07*88g})U zVf}~9mP_ItcLm=FPwDTBJT4S=pfmf~x{EFsM5I}TLY72z3Zx#gXc3A~oyaR>?z_S> z!aguv-!iRd&dr$Wx8|VaTJ7X|{VpQ|!wq1X4e(}U5@A41?XaW_O6{lso_s-RA6+YQ wVgsdh1h54%;aZVWKC%g*M2YM$P@+VDYd|Ja5)JTXWdlhv1K~Cx{RZr00AAWsssI20 literal 0 HcmV?d00001