/**
   * Tests that cumulative memory is computed only for processes older than a given age.
   *
   * @throws IOException if there was a problem setting up the fake procfs directories or files.
   */
  @Test
  public void testMemForOlderProcesses() throws IOException {
    // initial list of processes
    String[] pids = {"100", "200", "300", "400"};
    // create the fake procfs root directory.
    File procfsRootDir = new File(TEST_ROOT_DIR, "proc");

    try {
      setupProcfsRootDir(procfsRootDir);
      setupPidDirs(procfsRootDir, pids);

      // create stat objects.
      // assuming 100, 200 and 400 are in tree, 300 is not.
      ProcessStatInfo[] procInfos = new ProcessStatInfo[4];
      procInfos[0] =
          new ProcessStatInfo(new String[] {"100", "proc1", "1", "100", "100", "100000", "100"});
      procInfos[1] =
          new ProcessStatInfo(new String[] {"200", "proc2", "100", "100", "100", "200000", "200"});
      procInfos[2] =
          new ProcessStatInfo(new String[] {"300", "proc3", "1", "300", "300", "300000", "300"});
      procInfos[3] =
          new ProcessStatInfo(new String[] {"400", "proc4", "100", "100", "100", "400000", "400"});

      writeStatFiles(procfsRootDir, pids, procInfos);

      // crank up the process tree class.
      ProcfsBasedProcessTree processTree =
          createProcessTree("100", procfsRootDir.getAbsolutePath());
      // build the process tree.
      processTree.getProcessTree();

      // verify cumulative memory
      Assert.assertEquals(
          "Cumulative memory does not match", 700000L, processTree.getCumulativeVmem());

      // write one more process as child of 100.
      String[] newPids = {"500"};
      setupPidDirs(procfsRootDir, newPids);

      ProcessStatInfo[] newProcInfos = new ProcessStatInfo[1];
      newProcInfos[0] =
          new ProcessStatInfo(new String[] {"500", "proc5", "100", "100", "100", "500000", "500"});
      writeStatFiles(procfsRootDir, newPids, newProcInfos);

      // check memory includes the new process.
      processTree.getProcessTree();
      Assert.assertEquals(
          "Cumulative vmem does not include new process",
          1200000L,
          processTree.getCumulativeVmem());
      long cumuRssMem =
          ProcfsBasedProcessTree.PAGE_SIZE > 0 ? 1200L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
      Assert.assertEquals(
          "Cumulative rssmem does not include new process",
          cumuRssMem,
          processTree.getCumulativeRssmem());

      // however processes older than 1 iteration will retain the older value
      Assert.assertEquals(
          "Cumulative vmem shouldn't have included new process",
          700000L,
          processTree.getCumulativeVmem(1));
      cumuRssMem =
          ProcfsBasedProcessTree.PAGE_SIZE > 0 ? 700L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
      Assert.assertEquals(
          "Cumulative rssmem shouldn't have included new process",
          cumuRssMem,
          processTree.getCumulativeRssmem(1));

      // one more process
      newPids = new String[] {"600"};
      setupPidDirs(procfsRootDir, newPids);

      newProcInfos = new ProcessStatInfo[1];
      newProcInfos[0] =
          new ProcessStatInfo(new String[] {"600", "proc6", "100", "100", "100", "600000", "600"});
      writeStatFiles(procfsRootDir, newPids, newProcInfos);

      // refresh process tree
      processTree.getProcessTree();

      // processes older than 2 iterations should be same as before.
      Assert.assertEquals(
          "Cumulative vmem shouldn't have included new processes",
          700000L,
          processTree.getCumulativeVmem(2));
      cumuRssMem =
          ProcfsBasedProcessTree.PAGE_SIZE > 0 ? 700L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
      Assert.assertEquals(
          "Cumulative rssmem shouldn't have included new processes",
          cumuRssMem,
          processTree.getCumulativeRssmem(2));

      // processes older than 1 iteration should not include new process,
      // but include process 500
      Assert.assertEquals(
          "Cumulative vmem shouldn't have included new processes",
          1200000L,
          processTree.getCumulativeVmem(1));
      cumuRssMem =
          ProcfsBasedProcessTree.PAGE_SIZE > 0 ? 1200L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
      Assert.assertEquals(
          "Cumulative rssmem shouldn't have included new processes",
          cumuRssMem,
          processTree.getCumulativeRssmem(1));

      // no processes older than 3 iterations, this should be 0
      Assert.assertEquals(
          "Getting non-zero vmem for processes older than 3 iterations",
          0L,
          processTree.getCumulativeVmem(3));
      Assert.assertEquals(
          "Getting non-zero rssmem for processes older than 3 iterations",
          0L,
          processTree.getCumulativeRssmem(3));
    } finally {
      FileUtil.fullyDelete(procfsRootDir);
    }
  }
  /**
   * A basic test that creates a few process directories and writes stat files. Verifies that the
   * cpu time and memory is correctly computed.
   *
   * @throws IOException if there was a problem setting up the fake procfs directories or files.
   */
  @Test
  public void testCpuAndMemoryForProcessTree() throws IOException {

    // test processes
    String[] pids = {"100", "200", "300", "400"};
    // create the fake procfs root directory.
    File procfsRootDir = new File(TEST_ROOT_DIR, "proc");

    try {
      setupProcfsRootDir(procfsRootDir);
      setupPidDirs(procfsRootDir, pids);

      // create stat objects.
      // assuming processes 100, 200, 300 are in tree and 400 is not.
      ProcessStatInfo[] procInfos = new ProcessStatInfo[4];
      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", "1", "400", "400", "400000", "400", "4000", "800"});

      writeStatFiles(procfsRootDir, pids, procInfos);

      // crank up the process tree class.
      ProcfsBasedProcessTree processTree =
          createProcessTree("100", procfsRootDir.getAbsolutePath());
      // build the process tree.
      processTree.getProcessTree();

      // verify cumulative memory
      Assert.assertEquals(
          "Cumulative virtual memory does not match", 600000L, processTree.getCumulativeVmem());

      // verify rss memory
      long cumuRssMem =
          ProcfsBasedProcessTree.PAGE_SIZE > 0 ? 600L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
      Assert.assertEquals(
          "Cumulative rss memory does not match", cumuRssMem, processTree.getCumulativeRssmem());

      // verify cumulative cpu time
      long cumuCpuTime =
          ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS > 0
              ? 7200L * ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS
              : 0L;
      Assert.assertEquals(
          "Cumulative cpu time does not match", cumuCpuTime, processTree.getCumulativeCpuTime());

      // test the cpu time again to see if it cumulates
      procInfos[0] =
          new ProcessStatInfo(
              new String[] {"100", "proc1", "1", "100", "100", "100000", "100", "2000", "300"});
      procInfos[1] =
          new ProcessStatInfo(
              new String[] {"200", "proc2", "100", "100", "100", "200000", "200", "3000", "500"});
      writeStatFiles(procfsRootDir, pids, procInfos);

      // build the process tree.
      processTree.getProcessTree();

      // verify cumulative cpu time again
      cumuCpuTime =
          ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS > 0
              ? 9400L * ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS
              : 0L;
      Assert.assertEquals(
          "Cumulative cpu time does not match", cumuCpuTime, processTree.getCumulativeCpuTime());
    } finally {
      FileUtil.fullyDelete(procfsRootDir);
    }
  }