@Test public void testProcessTree() throws Exception { try { if (!ProcfsBasedProcessTree.isAvailable()) { System.out.println("ProcfsBasedProcessTree is not available on this system. Not testing"); return; } } catch (Exception e) { LOG.info(StringUtils.stringifyException(e)); return; } // create shell script Random rm = new Random(); File tempFile = new File(TEST_ROOT_DIR, getClass().getName() + "_shellScript_" + rm.nextInt() + ".sh"); tempFile.deleteOnExit(); shellScript = TEST_ROOT_DIR + File.separator + tempFile.getName(); // create pid file tempFile = new File(TEST_ROOT_DIR, getClass().getName() + "_pidFile_" + rm.nextInt() + ".pid"); tempFile.deleteOnExit(); pidFile = TEST_ROOT_DIR + File.separator + tempFile.getName(); lowestDescendant = TEST_ROOT_DIR + File.separator + "lowestDescendantPidFile"; // write to shell-script try { FileWriter fWriter = new FileWriter(shellScript); fWriter.write( "# rogue task\n" + "sleep 1\n" + "echo hello\n" + "if [ $1 -ne 0 ]\n" + "then\n" + " sh " + shellScript + " $(($1-1))\n" + "else\n" + " echo $$ > " + lowestDescendant + "\n" + " while true\n do\n" + " sleep 5\n" + " done\n" + "fi"); fWriter.close(); } catch (IOException ioe) { LOG.info("Error: " + ioe); return; } Thread t = new RogueTaskThread(); t.start(); String pid = getRogueTaskPID(); LOG.info("Root process pid: " + pid); ProcfsBasedProcessTree p = createProcessTree(pid); p.getProcessTree(); // initialize LOG.info("ProcessTree: " + p.toString()); File leaf = new File(lowestDescendant); // wait till lowest descendant process of Rougue Task starts execution while (!leaf.exists()) { try { Thread.sleep(500); } catch (InterruptedException ie) { break; } } p.getProcessTree(); // reconstruct LOG.info("ProcessTree: " + p.toString()); // Get the process-tree dump String processTreeDump = p.getProcessTreeDump(); // destroy the process and all its subprocesses destroyProcessTree(pid); if (isSetsidAvailable()) { // whole processtree should be gone Assert.assertFalse("Proceesses in process group live", isAnyProcessInTreeAlive(p)); } else { // process should be gone Assert.assertFalse("ProcessTree must have been gone", isAlive(pid)); } LOG.info("Process-tree dump follows: \n" + processTreeDump); Assert.assertTrue( "Process-tree dump doesn't start with a proper header", processTreeDump.startsWith( "\t|- PID PPID PGRPID SESSID CMD_NAME " + "USER_MODE_TIME(MILLIS) SYSTEM_TIME(MILLIS) VMEM_USAGE(BYTES) " + "RSSMEM_USAGE(PAGES) FULL_CMD_LINE\n")); for (int i = N; i >= 0; i--) { String cmdLineDump = "\\|- [0-9]+ [0-9]+ [0-9]+ [0-9]+ \\(sh\\)" + " [0-9]+ [0-9]+ [0-9]+ [0-9]+ sh " + shellScript + " " + i; Pattern pat = Pattern.compile(cmdLineDump); Matcher mat = pat.matcher(processTreeDump); Assert.assertTrue( "Process-tree dump doesn't contain the cmdLineDump of " + i + "th process!", mat.find()); } // Not able to join thread sometimes when forking with large N. try { t.join(2000); LOG.info("RogueTaskThread successfully joined."); } catch (InterruptedException ie) { LOG.info("Interrupted while joining RogueTaskThread."); } // ProcessTree is gone now. Any further calls should be sane. p.getProcessTree(); Assert.assertFalse("ProcessTree must have been gone", isAlive(pid)); Assert.assertTrue( "Cumulative vmem for the gone-process is " + p.getCumulativeVmem() + " . It should be zero.", p.getCumulativeVmem() == 0); Assert.assertTrue(p.toString().equals("[ ]")); }
/** * Test the correctness of process-tree dump. * * @throws IOException */ @Test public void testProcessTreeDump() throws IOException { String[] pids = {"100", "200", "300", "400", "500", "600"}; File procfsRootDir = new File(TEST_ROOT_DIR, "proc"); try { setupProcfsRootDir(procfsRootDir); setupPidDirs(procfsRootDir, pids); int numProcesses = pids.length; // Processes 200, 300, 400 and 500 are descendants of 100. 600 is not. ProcessStatInfo[] procInfos = new ProcessStatInfo[numProcesses]; procInfos[0] = new ProcessStatInfo( new String[] {"100", "proc1", "1", "100", "100", "100000", "100", "1000", "200"}); procInfos[1] = new ProcessStatInfo( new String[] {"200", "proc2", "100", "100", "100", "200000", "200", "2000", "400"}); procInfos[2] = new ProcessStatInfo( new String[] {"300", "proc3", "200", "100", "100", "300000", "300", "3000", "600"}); procInfos[3] = new ProcessStatInfo( new String[] {"400", "proc4", "200", "100", "100", "400000", "400", "4000", "800"}); procInfos[4] = new ProcessStatInfo( new String[] {"500", "proc5", "400", "100", "100", "400000", "400", "4000", "800"}); procInfos[5] = new ProcessStatInfo( new String[] {"600", "proc6", "1", "1", "1", "400000", "400", "4000", "800"}); String[] cmdLines = new String[numProcesses]; cmdLines[0] = "proc1 arg1 arg2"; cmdLines[1] = "proc2 arg3 arg4"; cmdLines[2] = "proc3 arg5 arg6"; cmdLines[3] = "proc4 arg7 arg8"; cmdLines[4] = "proc5 arg9 arg10"; cmdLines[5] = "proc6 arg11 arg12"; writeStatFiles(procfsRootDir, pids, procInfos); writeCmdLineFiles(procfsRootDir, pids, cmdLines); ProcfsBasedProcessTree processTree = createProcessTree("100", procfsRootDir.getAbsolutePath()); // build the process tree. processTree.getProcessTree(); // Get the process-tree dump String processTreeDump = processTree.getProcessTreeDump(); LOG.info("Process-tree dump follows: \n" + processTreeDump); Assert.assertTrue( "Process-tree dump doesn't start with a proper header", processTreeDump.startsWith( "\t|- PID PPID PGRPID SESSID CMD_NAME " + "USER_MODE_TIME(MILLIS) SYSTEM_TIME(MILLIS) VMEM_USAGE(BYTES) " + "RSSMEM_USAGE(PAGES) FULL_CMD_LINE\n")); for (int i = 0; i < 5; i++) { ProcessStatInfo p = procInfos[i]; Assert.assertTrue( "Process-tree dump doesn't contain the cmdLineDump of process " + p.pid, processTreeDump.contains( "\t|- " + p.pid + " " + p.ppid + " " + p.pgrpId + " " + p.session + " (" + p.name + ") " + p.utime + " " + p.stime + " " + p.vmem + " " + p.rssmemPage + " " + cmdLines[i])); } // 600 should not be in the dump ProcessStatInfo p = procInfos[5]; Assert.assertFalse( "Process-tree dump shouldn't contain the cmdLineDump of process " + p.pid, processTreeDump.contains( "\t|- " + p.pid + " " + p.ppid + " " + p.pgrpId + " " + p.session + " (" + p.name + ") " + p.utime + " " + p.stime + " " + p.vmem + " " + cmdLines[5])); } finally { FileUtil.fullyDelete(procfsRootDir); } }