github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/drivers/java/driver_test.go (about) 1 package java 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "testing" 10 11 dtestutil "github.com/hashicorp/nomad/plugins/drivers/testutils" 12 13 "context" 14 "time" 15 16 ctestutil "github.com/hashicorp/nomad/client/testutil" 17 "github.com/hashicorp/nomad/helper/pluginutils/hclutils" 18 "github.com/hashicorp/nomad/helper/testlog" 19 "github.com/hashicorp/nomad/helper/uuid" 20 "github.com/hashicorp/nomad/nomad/structs" 21 "github.com/hashicorp/nomad/plugins/drivers" 22 "github.com/hashicorp/nomad/testutil" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func javaCompatible(t *testing.T) { 27 ctestutil.JavaCompatible(t) 28 29 _, _, _, err := javaVersionInfo() 30 if err != nil { 31 t.Skipf("java not found; skipping: %v", err) 32 } 33 } 34 35 func TestJavaDriver_Fingerprint(t *testing.T) { 36 javaCompatible(t) 37 if !testutil.IsCI() { 38 t.Parallel() 39 } 40 41 d := NewDriver(testlog.HCLogger(t)) 42 harness := dtestutil.NewDriverHarness(t, d) 43 44 fpCh, err := harness.Fingerprint(context.Background()) 45 require.NoError(t, err) 46 47 select { 48 case fp := <-fpCh: 49 require.Equal(t, drivers.HealthStateHealthy, fp.Health) 50 detected, _ := fp.Attributes["driver.java"].GetBool() 51 require.True(t, detected) 52 case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second): 53 require.Fail(t, "timeout receiving fingerprint") 54 } 55 } 56 57 func TestJavaDriver_Jar_Start_Wait(t *testing.T) { 58 javaCompatible(t) 59 if !testutil.IsCI() { 60 t.Parallel() 61 } 62 63 require := require.New(t) 64 d := NewDriver(testlog.HCLogger(t)) 65 harness := dtestutil.NewDriverHarness(t, d) 66 67 tc := &TaskConfig{ 68 JarPath: "demoapp.jar", 69 Args: []string{"1"}, 70 JvmOpts: []string{"-Xmx64m", "-Xms32m"}, 71 } 72 task := basicTask(t, "demo-app", tc) 73 74 cleanup := harness.MkAllocDir(task, true) 75 defer cleanup() 76 77 copyFile("./test-resources/demoapp.jar", filepath.Join(task.TaskDir().Dir, "demoapp.jar"), t) 78 79 handle, _, err := harness.StartTask(task) 80 require.NoError(err) 81 82 ch, err := harness.WaitTask(context.Background(), handle.Config.ID) 83 require.NoError(err) 84 result := <-ch 85 require.Nil(result.Err) 86 87 require.Zero(result.ExitCode) 88 89 // Get the stdout of the process and assert that it's not empty 90 stdout, err := ioutil.ReadFile(filepath.Join(task.TaskDir().LogDir, "demo-app.stdout.0")) 91 require.NoError(err) 92 require.Contains(string(stdout), "Hello") 93 94 require.NoError(harness.DestroyTask(task.ID, true)) 95 } 96 97 func TestJavaDriver_Jar_Stop_Wait(t *testing.T) { 98 javaCompatible(t) 99 if !testutil.IsCI() { 100 t.Parallel() 101 } 102 103 require := require.New(t) 104 d := NewDriver(testlog.HCLogger(t)) 105 harness := dtestutil.NewDriverHarness(t, d) 106 107 tc := &TaskConfig{ 108 JarPath: "demoapp.jar", 109 Args: []string{"600"}, 110 JvmOpts: []string{"-Xmx64m", "-Xms32m"}, 111 } 112 task := basicTask(t, "demo-app", tc) 113 114 cleanup := harness.MkAllocDir(task, true) 115 defer cleanup() 116 117 copyFile("./test-resources/demoapp.jar", filepath.Join(task.TaskDir().Dir, "demoapp.jar"), t) 118 119 handle, _, err := harness.StartTask(task) 120 require.NoError(err) 121 122 ch, err := harness.WaitTask(context.Background(), handle.Config.ID) 123 require.NoError(err) 124 125 require.NoError(harness.WaitUntilStarted(task.ID, 1*time.Second)) 126 127 go func() { 128 time.Sleep(10 * time.Millisecond) 129 harness.StopTask(task.ID, 2*time.Second, "SIGINT") 130 }() 131 132 select { 133 case result := <-ch: 134 require.False(result.Successful()) 135 case <-time.After(10 * time.Second): 136 require.Fail("timeout waiting for task to shutdown") 137 } 138 139 // Ensure that the task is marked as dead, but account 140 // for WaitTask() closing channel before internal state is updated 141 testutil.WaitForResult(func() (bool, error) { 142 status, err := harness.InspectTask(task.ID) 143 if err != nil { 144 return false, fmt.Errorf("inspecting task failed: %v", err) 145 } 146 if status.State != drivers.TaskStateExited { 147 return false, fmt.Errorf("task hasn't exited yet; status: %v", status.State) 148 } 149 150 return true, nil 151 }, func(err error) { 152 require.NoError(err) 153 }) 154 155 require.NoError(harness.DestroyTask(task.ID, true)) 156 } 157 158 func TestJavaDriver_Class_Start_Wait(t *testing.T) { 159 javaCompatible(t) 160 if !testutil.IsCI() { 161 t.Parallel() 162 } 163 164 require := require.New(t) 165 d := NewDriver(testlog.HCLogger(t)) 166 harness := dtestutil.NewDriverHarness(t, d) 167 168 tc := &TaskConfig{ 169 Class: "Hello", 170 Args: []string{"1"}, 171 } 172 task := basicTask(t, "demo-app", tc) 173 174 cleanup := harness.MkAllocDir(task, true) 175 defer cleanup() 176 177 copyFile("./test-resources/Hello.class", filepath.Join(task.TaskDir().Dir, "Hello.class"), t) 178 179 handle, _, err := harness.StartTask(task) 180 require.NoError(err) 181 182 ch, err := harness.WaitTask(context.Background(), handle.Config.ID) 183 require.NoError(err) 184 result := <-ch 185 require.Nil(result.Err) 186 187 require.Zero(result.ExitCode) 188 189 // Get the stdout of the process and assert that it's not empty 190 stdout, err := ioutil.ReadFile(filepath.Join(task.TaskDir().LogDir, "demo-app.stdout.0")) 191 require.NoError(err) 192 require.Contains(string(stdout), "Hello") 193 194 require.NoError(harness.DestroyTask(task.ID, true)) 195 } 196 197 func TestJavaCmdArgs(t *testing.T) { 198 cases := []struct { 199 name string 200 cfg TaskConfig 201 expected []string 202 }{ 203 { 204 "jar_path_full", 205 TaskConfig{ 206 JvmOpts: []string{"-Xmx512m", "-Xms128m"}, 207 JarPath: "/jar-path.jar", 208 Args: []string{"hello", "world"}, 209 }, 210 []string{"-Xmx512m", "-Xms128m", "-jar", "/jar-path.jar", "hello", "world"}, 211 }, 212 { 213 "class_full", 214 TaskConfig{ 215 JvmOpts: []string{"-Xmx512m", "-Xms128m"}, 216 Class: "ClassName", 217 ClassPath: "/classpath", 218 Args: []string{"hello", "world"}, 219 }, 220 []string{"-Xmx512m", "-Xms128m", "-cp", "/classpath", "ClassName", "hello", "world"}, 221 }, 222 { 223 "jar_path_slim", 224 TaskConfig{ 225 JarPath: "/jar-path.jar", 226 }, 227 []string{"-jar", "/jar-path.jar"}, 228 }, 229 { 230 "class_slim", 231 TaskConfig{ 232 Class: "ClassName", 233 }, 234 []string{"ClassName"}, 235 }, 236 } 237 238 for _, c := range cases { 239 t.Run(c.name, func(t *testing.T) { 240 found := javaCmdArgs(c.cfg) 241 require.Equal(t, c.expected, found) 242 }) 243 } 244 } 245 246 func TestJavaDriver_ExecTaskStreaming(t *testing.T) { 247 javaCompatible(t) 248 if !testutil.IsCI() { 249 t.Parallel() 250 } 251 252 require := require.New(t) 253 d := NewDriver(testlog.HCLogger(t)) 254 harness := dtestutil.NewDriverHarness(t, d) 255 defer harness.Kill() 256 257 tc := &TaskConfig{ 258 Class: "Hello", 259 Args: []string{"900"}, 260 } 261 task := basicTask(t, "demo-app", tc) 262 263 cleanup := harness.MkAllocDir(task, true) 264 defer cleanup() 265 266 copyFile("./test-resources/Hello.class", filepath.Join(task.TaskDir().Dir, "Hello.class"), t) 267 268 _, _, err := harness.StartTask(task) 269 require.NoError(err) 270 defer d.DestroyTask(task.ID, true) 271 272 dtestutil.ExecTaskStreamingConformanceTests(t, harness, task.ID) 273 274 } 275 func basicTask(t *testing.T, name string, taskConfig *TaskConfig) *drivers.TaskConfig { 276 t.Helper() 277 278 task := &drivers.TaskConfig{ 279 ID: uuid.Generate(), 280 Name: name, 281 Resources: &drivers.Resources{ 282 NomadResources: &structs.AllocatedTaskResources{ 283 Memory: structs.AllocatedMemoryResources{ 284 MemoryMB: 128, 285 }, 286 Cpu: structs.AllocatedCpuResources{ 287 CpuShares: 100, 288 }, 289 }, 290 LinuxResources: &drivers.LinuxResources{ 291 MemoryLimitBytes: 134217728, 292 CPUShares: 100, 293 }, 294 }, 295 } 296 297 require.NoError(t, task.EncodeConcreteDriverConfig(&taskConfig)) 298 return task 299 } 300 301 // copyFile moves an existing file to the destination 302 func copyFile(src, dst string, t *testing.T) { 303 in, err := os.Open(src) 304 if err != nil { 305 t.Fatalf("copying %v -> %v failed: %v", src, dst, err) 306 } 307 defer in.Close() 308 out, err := os.Create(dst) 309 if err != nil { 310 t.Fatalf("copying %v -> %v failed: %v", src, dst, err) 311 } 312 defer func() { 313 if err := out.Close(); err != nil { 314 t.Fatalf("copying %v -> %v failed: %v", src, dst, err) 315 } 316 }() 317 if _, err = io.Copy(out, in); err != nil { 318 t.Fatalf("copying %v -> %v failed: %v", src, dst, err) 319 } 320 if err := out.Sync(); err != nil { 321 t.Fatalf("copying %v -> %v failed: %v", src, dst, err) 322 } 323 } 324 325 func TestConfig_ParseAllHCL(t *testing.T) { 326 cfgStr := ` 327 config { 328 class = "java.main" 329 class_path = "/tmp/cp" 330 jar_path = "/tmp/jar.jar" 331 jvm_options = ["-Xmx600"] 332 args = ["arg1", "arg2"] 333 }` 334 335 expected := &TaskConfig{ 336 Class: "java.main", 337 ClassPath: "/tmp/cp", 338 JarPath: "/tmp/jar.jar", 339 JvmOpts: []string{"-Xmx600"}, 340 Args: []string{"arg1", "arg2"}, 341 } 342 343 var tc *TaskConfig 344 hclutils.NewConfigParser(taskConfigSpec).ParseHCL(t, cfgStr, &tc) 345 346 require.EqualValues(t, expected, tc) 347 }