Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
AutopsyTestCases.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.testing;
20 
21 import java.awt.AWTException;
22 import java.awt.Rectangle;
23 import java.awt.Robot;
24 import java.awt.Toolkit;
25 import java.awt.image.BufferedImage;
26 import java.io.File;
27 import java.io.IOException;
28 import java.nio.charset.StandardCharsets;
29 import java.text.DateFormat;
30 import java.text.MessageFormat;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Comparator;
34 import java.util.Date;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Random;
39 import java.util.Set;
40 import java.util.function.Function;
41 import java.util.logging.Logger;
42 import java.util.logging.Level;
43 import java.util.regex.Matcher;
44 import java.util.regex.Pattern;
45 import java.util.stream.Collectors;
46 import java.util.stream.Stream;
47 import javax.imageio.ImageIO;
48 import javax.swing.JDialog;
49 import javax.swing.SwingUtilities;
50 import javax.swing.text.JTextComponent;
51 import javax.swing.tree.TreePath;
52 import org.apache.commons.io.IOUtils;
53 import org.apache.commons.lang3.StringUtils;
54 import org.apache.commons.lang3.tuple.Pair;
55 import org.apache.commons.lang3.tuple.Triple;
56 import org.netbeans.jellytools.MainWindowOperator;
57 import org.netbeans.jellytools.NbDialogOperator;
58 import org.netbeans.jellytools.WizardOperator;
59 import org.netbeans.jemmy.JemmyProperties;
60 import org.netbeans.jemmy.Timeout;
61 import org.netbeans.jemmy.TimeoutExpiredException;
62 import org.netbeans.jemmy.Timeouts;
63 import org.netbeans.jemmy.operators.JButtonOperator;
64 import org.netbeans.jemmy.operators.JCheckBoxOperator;
65 import org.netbeans.jemmy.operators.JComboBoxOperator;
66 import org.netbeans.jemmy.operators.JDialogOperator;
67 import org.netbeans.jemmy.operators.JFileChooserOperator;
68 import org.netbeans.jemmy.operators.JListOperator;
69 import org.netbeans.jemmy.operators.JTabbedPaneOperator;
70 import org.netbeans.jemmy.operators.JTableOperator;
71 import org.netbeans.jemmy.operators.JTextAreaOperator;
72 import org.netbeans.jemmy.operators.JTextFieldOperator;
73 import org.netbeans.jemmy.operators.JToggleButtonOperator;
74 import org.netbeans.jemmy.operators.JTreeOperator;
75 import org.netbeans.jemmy.operators.JTreeOperator.NoSuchPathException;
83 
84 public class AutopsyTestCases {
85 
86  private static final Logger logger = Logger.getLogger(AutopsyTestCases.class.getName()); // DO NOT USE AUTOPSY LOGGER
87  private long start;
88 
89  // by default, how many minutes jemmy waits for a dialog to appear (default is 1 minute).
90  private static final long DIALOG_FIND_TIMEOUT_MINUTES = 5;
91 
92  static {
93  Timeouts.setDefault("Waiter.WaitingTime", DIALOG_FIND_TIMEOUT_MINUTES * 60 * 1000);
94  }
95 
103  public static String getEscapedPath(String path) {
104  if (path.startsWith("\\\\")) { //already has escaped to \\\\NetworkLocation
105  return path;
106  }
107  if (path.startsWith("\\")) {
108  return "\\" + path;
109  } else {
110  return path;
111  }
112  }
113 
114  public AutopsyTestCases(boolean isMultiUser) {
115  start = 0;
116  if (isMultiUser) {
118  } else {
120  }
121  }
122 
123  public void testNewCaseWizardOpen(String title) {
124  try {
125  logger.info("New Case");
126  setTimeout("WindowWaiter.WaitWindowTimeout", 240000);
127  NbDialogOperator nbdo = new NbDialogOperator(title);
128  JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button
129  jbo.pushNoBlock();
130  } catch (TimeoutExpiredException ex) {
131  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
133  screenshot("TimeoutScreenshot");
134  }
135  }
136 
137  public void testNewCaseWizard() {
138  try {
139  logger.info("New Case Wizard");
140  WizardOperator wo = new WizardOperator("New Case Information");
141  JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 1);
142  jtfo0.typeText("AutopsyTestCase"); // Name the case "AutopsyTestCase"
143  JTextFieldOperator jtfo1 = new JTextFieldOperator(wo, 2);
144  jtfo1.typeText(getEscapedPath(System.getProperty("out_path")));
145  wo.btNext().clickMouse();
146  JTextFieldOperator jtfo2 = new JTextFieldOperator(wo, 0);
147  jtfo2.typeText("000"); // Set the case number
148  JTextFieldOperator jtfo3 = new JTextFieldOperator(wo, 1);
149  jtfo3.typeText("Examiner 1"); // Set the case examiner
150  start = System.currentTimeMillis();
151  wo.btFinish().clickMouse();
152  } catch (TimeoutExpiredException ex) {
153  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
155  screenshot("TimeoutScreenshot");
156  }
157  }
158 
160  try {
161  /*
162  * This time out is to give time for creating case database and
163  * opening solr index
164  */
165  new Timeout("pausing", 120000).sleep();
166  logger.info("Starting Add Image process");
167  setTimeout("WindowWaiter.WaitWindowTimeOut", 240000);
168  WizardOperator wo = new WizardOperator("Add Data Source");
169  while (!wo.btNext().isEnabled()) {
170  new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
171  }
172 
173  // pass by host menu with auto-generate host (which should already be selected)
174  wo.btNext().clickMouse();
175 
176  //select the toggle button for Disk Image or VM File it will be the first button created and proceed to next panel
177  JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 0);
178  jtbo.clickMouse();
179  wo.btNext().clickMouse();
180  new Timeout("pausing", 5000).sleep();
181  JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 0);
182  String img_path = getEscapedPath(System.getProperty("img_path"));
183  String imageDir = img_path;
184  logger.log(Level.INFO, "setting image path to " + imageDir);
185  ((JTextComponent) jtfo0.getSource()).setText(imageDir);
186  new Timeout("pausing", 5000).sleep();
187  JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo, 0);
188  logger.log(Level.INFO, "setting time zone");
189  comboBoxOperator.setSelectedItem("(GMT-5:00) America/New_York");
190  // do in invoke later to allow time for validation to happen.
191  new Thread(() -> {
192  new Timeout("pausing", 5000).sleep();
193  logger.log(Level.INFO, "clicking next button");
194  wo.btNext().clickMouse();
195  }).start();
196  new Timeout("pausing", 8000).sleep();
197  } catch (TimeoutExpiredException ex) {
198  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
200  screenshot("TimeoutScreenshot");
201  }
202  }
203 
205  try {
206  /*
207  * This time out is to give time for creating case database and
208  * opening solr index
209  */
210  new Timeout("pausing", 120000).sleep();
211  logger.info("Starting Add Logical Files process");
212  WizardOperator wo = new WizardOperator("Add Data Source");
213  wo.setTimeouts(setTimeout("WindowWaiter.WaitWindowTimeOut", 240000));
214  while (!wo.btNext().isEnabled()) {
215  new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
216  }
217 
218  // pass by host menu with auto-generate host (which should already be selected)
219  wo.btNext().clickMouse();
220 
221  //select the toggle button for Logical Files it will be the third button created and proceed to next panel
222  JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 2);
223  jtbo.clickMouse();
224  wo.btNext().clickMouse();
225  JButtonOperator addButtonOperator = new JButtonOperator(wo, "Add");
226  addButtonOperator.pushNoBlock();
227  JFileChooserOperator fileChooserOperator = new JFileChooserOperator();
228  fileChooserOperator.setCurrentDirectory(new File(getEscapedPath(System.getProperty("img_path"))));
229  // set the current directory one level above the directory containing logicalFileSet folder.
230  fileChooserOperator.goUpLevel();
231  fileChooserOperator.chooseFile(new File(getEscapedPath(System.getProperty("img_path"))).getName());
232  wo.btNext().clickMouse();
233  } catch (TimeoutExpiredException ex) {
234  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
236  screenshot("TimeoutScreenshot");
237  }
238  }
239 
240  public void testAddSourceWizard1() {
241  try {
242  WizardOperator wo = new WizardOperator("Add Data Source");
243  while (!wo.btFinish().isEnabled()) {
244  new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
245  }
246  logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start));
247  wo.btFinish().clickMouse();
248  } catch (TimeoutExpiredException ex) {
249  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
251  screenshot("TimeoutScreenshot");
252  }
253  }
254 
255  public void testConfigureIngest1() {
256  try {
257  /*
258  * This timeout is to allow the setup for the ingest job settings
259  * panel to complete.
260  */
261  new Timeout("pausing", 10000).sleep();
262 
263  logger.info("Looking for hash lookup module in ingest job settings panel");
264  WizardOperator wo = new WizardOperator("Add Data Source");
265  while (!wo.btNext().isEnabled()) {
266  new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
267  }
268  JTableOperator jto = new JTableOperator(wo, 0);
269  int row = jto.findCellRow("Hash Lookup", 2, 0);
270  jto.clickOnCell(row, 1);
271  logger.info("Selected hash lookup module in ingest job settings panel");
272  JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings");
273  jbo1.pushNoBlock();
274  logger.info("Pushed Global Settings button for hash lookup module in ingest job settings panel");
275  } catch (TimeoutExpiredException ex) {
276  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
278  screenshot("TimeoutScreenshot");
279  }
280  }
281 
282  public void testConfigureHash() {
283  try {
284  logger.info("Hash Configure");
285  JDialog hashMainDialog = JDialogOperator.waitJDialog("Global Hash Lookup Settings", false, false);
286  JDialogOperator hashMainDialogOperator = new JDialogOperator(hashMainDialog);
287  List<String> databases = new ArrayList<>();
288  databases.add(getEscapedPath(System.getProperty("nsrl_path")));
289  databases.add(getEscapedPath(System.getProperty("known_bad_path")));
290  databases.stream().map((database) -> {
291  JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import");
292  importButtonOperator.pushNoBlock();
293  JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Set", false, false);
294  JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog);
295  JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0);
296  browseButtonOperator.pushNoBlock();
297  JFileChooserOperator fileChooserOperator = new JFileChooserOperator();
298  fileChooserOperator.chooseFile(database);
299  JButtonOperator okButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "OK", 0);
300  return okButtonOperator;
301  }).map((okButtonOperator) -> {
302  okButtonOperator.pushNoBlock();
303  return okButtonOperator;
304  }).forEach((_item) -> {
305  new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
306  });
307  // Used if the database has no index
308  //JDialog jd3 = JDialogOperator.waitJDialog("No Index Exists", false, false);
309  //JDialogOperator jdo3 = new JDialogOperator(jd3);
310  //JButtonOperator jbo3 = new JButtonOperator(jdo3, "Yes", 0);
311  new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
312  //jbo3.pushNoBlock();
313  JButtonOperator jbo4 = new JButtonOperator(hashMainDialogOperator, "OK", 0);
314  jbo4.pushNoBlock();
315  } catch (TimeoutExpiredException ex) {
316  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
318  screenshot("TimeoutScreenshot");
319  }
320  }
321 
322  public void testConfigureIngest2() {
323  try {
324  logger.info("Looking for keyword search module in ingest job settings panel");
325  WizardOperator wo = new WizardOperator("Add Data Source");
326  while (!wo.btNext().isEnabled()) {
327  new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
328  }
329  JTableOperator jto = new JTableOperator(wo, 0);
330  int row = jto.findCellRow("Keyword Search", 2, 0);
331  jto.clickOnCell(row, 1);
332  logger.info("Selected keyword search module in ingest job settings panel");
333  JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings");
334  jbo1.pushNoBlock();
335  logger.info("Pushed Global Settings button for keyword search module in ingest job settings panel");
336  } catch (TimeoutExpiredException ex) {
337  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
339  screenshot("TimeoutScreenshot");
340  }
341  }
342 
343  public void testConfigureSearch() {
344  try {
345  logger.info("Search Configure");
346  JDialog jd = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false);
347  JDialogOperator jdo = new JDialogOperator(jd);
348  String words = getEscapedPath(System.getProperty("keyword_path"));
349  JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0);
350  jbo0.pushNoBlock();
351  JFileChooserOperator jfco0 = new JFileChooserOperator();
352  jfco0.chooseFile(words);
353  JTableOperator jto = new JTableOperator(jdo, 0);
354  jto.clickOnCell(0, 0);
355  new Timeout("pausing", 1000).sleep(); // give it a second to process
356  if (Boolean.parseBoolean(System.getProperty("mugen_mode"))) {
357  JTabbedPaneOperator jtpo = new JTabbedPaneOperator(jdo);
358  jtpo.selectPage("String Extraction");
359  JCheckBoxOperator jcbo0 = new JCheckBoxOperator(jtpo, "Arabic (Arabic)");
360  jcbo0.doClick();
361  JCheckBoxOperator jcbo1 = new JCheckBoxOperator(jtpo, "Han (Chinese, Japanese, Korean)");
362  jcbo1.doClick();
363  new Timeout("pausing", 1000).sleep(); // give it a second to process
364  }
365  JButtonOperator jbo2 = new JButtonOperator(jdo, "OK", 0);
366  jbo2.pushNoBlock();
367  WizardOperator wo = new WizardOperator("Add Data Source");
368  new Timeout("pausing", 10000).sleep(); // let things catch up
369  wo.btNext().clickMouse();
370  } catch (TimeoutExpiredException ex) {
371  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
373  screenshot("TimeoutScreenshot");
374  }
375  }
376 
377  public void testIngest() {
378  try {
379  logger.info("Ingest 3");
380  new Timeout("pausing", 10000).sleep(); // wait for ingest to actually start
381  long startIngest = System.currentTimeMillis();
383  while (man.isIngestRunning()) {
384  new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
385  }
386  logger.log(Level.INFO, "Ingest (including enqueue) took {0}ms", (System.currentTimeMillis() - startIngest));
387  // allow keyword search to finish saving artifacts, just in case
388  // but randomize the timing so that we don't always get the same error
389  // consistently, making it seem like default behavior
390  Random rand = new Random();
391  new Timeout("pausing", 10000 + (rand.nextInt(15000) + 5000)).sleep();
392  } catch (TimeoutExpiredException ex) {
393  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
395  screenshot("TimeoutScreenshot");
396  }
397 
398  }
399 
401  try {
402  logger.info("Data Sources Node");
403  MainWindowOperator mwo = MainWindowOperator.getDefault();
404  JTreeOperator jto = new JTreeOperator(mwo, "Data Sources");
405  String[] nodeNames = {"Data Sources"};
406  TreePath tp = jto.findPath(nodeNames);
407  expandNodes(jto, tp);
408  } catch (TimeoutExpiredException ex) {
409  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
411  screenshot("TimeoutScreenshot");
412  }
413  }
414 
416  try {
417  logger.info("Generate Report Toolbars");
418  MainWindowOperator mwo = MainWindowOperator.getDefault();
419  JButtonOperator jbo = new JButtonOperator(mwo, "Generate Report");
420  jbo.pushNoBlock();
421  } catch (TimeoutExpiredException ex) {
422  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
424  screenshot("TimeoutScreenshot");
425  }
426  }
427 
428  public void testGenerateReportButton() throws IOException {
429  try {
430  logger.info("Generate Report Button");
431  setTimeout("ComponentOperator.WaitComponentTimeout", 240000);
432  JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false);
433  JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog);
434  JListOperator listOperator = new JListOperator(reportDialogOperator);
435  JButtonOperator jbo0 = new JButtonOperator(reportDialogOperator, "Next");
436  DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss");
437  Date date = new Date();
438  String datenotime = dateFormat.format(date);
439  listOperator.clickOnItem(0, 1);
440  jbo0.pushNoBlock();
441  new Timeout("pausing", 2000).sleep();
442 
443  // Next button on the data source selection panel
444  JButtonOperator dataSourceSelectionPanelNext = new JButtonOperator(reportDialogOperator, "Next");
445  dataSourceSelectionPanelNext.pushNoBlock();
446  new Timeout("pausing", 2000).sleep();
447 
448  JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish");
449  jbo1.pushNoBlock();
450  JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false);
451  JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog);
452  JTextAreaOperator.waitJTextArea(previewDialog, "Complete", false, false);
453  JButtonOperator jbo2 = new JButtonOperator(previewDialogOperator, "Close");
454  jbo2.pushNoBlock();
455  new Timeout("pausing", 10000).sleep();
456  System.setProperty("ReportStr", datenotime);
457  } catch (TimeoutExpiredException ex) {
458  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
460  screenshot("TimeoutScreenshot");
461  }
462  }
463 
464  public void screenshot(String name) {
465  String outPath = getEscapedPath(System.getProperty("out_path"));
466  File screenShotFile = new File(outPath + "\\" + name + ".png");
467  if (!screenShotFile.exists()) {
468  logger.info("Taking screenshot.");
469  try {
470  Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
471  BufferedImage capture = new Robot().createScreenCapture(screenRect);
472  ImageIO.write(capture, "png", screenShotFile);
473  new Timeout("pausing", 1000).sleep(); // give it a second to save
474  } catch (IOException ex) {
475  logger.log(Level.WARNING, "IOException taking screenshot.", ex);
476  } catch (AWTException ex) {
477  logger.log(Level.WARNING, "AWTException taking screenshot.", ex);
478  }
479  }
480  }
481 
482  /*
483  * Nightly test failed at WindowWaiter.WaitWindowTimeOut because of
484  * TimeoutExpiredException. So we use this conveninent method to override
485  * the default Jemmy Timeouts value.
486  */
487  private Timeouts setTimeout(String name, int value) {
488  Timeouts timeouts = JemmyProperties.getCurrentTimeouts();
489  timeouts.setTimeout(name, value);
490  return timeouts;
491  }
492 
493  private void setMultiUserPerferences() {
495  //PostgreSQL database settings
496  CaseDbConnectionInfo connectionInfo = new CaseDbConnectionInfo(
497  System.getProperty("dbHost"),
498  System.getProperty("dbPort"),
499  System.getProperty("dbUserName"),
500  System.getProperty("dbPassword"),
502  try {
504  } catch (UserPreferencesException ex) {
505  logger.log(Level.SEVERE, "Error saving case database connection info", ex); //NON-NLS
507  }
508  //Solr Index settings
509  UserPreferences.setIndexingServerHost(System.getProperty("solrHost"));
510  UserPreferences.setIndexingServerPort(Integer.parseInt(System.getProperty("solrPort")));
511  //ActiveMQ Message Service Setting, username and password field are empty
513  System.getProperty("messageServiceHost"),
514  Integer.parseInt(System.getProperty("messageServicePort")),
515  "",
516  "");
517  try {
519  } catch (UserPreferencesException ex) {
520  logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS
522  }
523 
524  UserPreferences.setZkServerHost(System.getProperty("zooKeeperHost"));
525  UserPreferences.setZkServerPort(System.getProperty("zooKeeperPort"));
526  }
527 
528  private void expandNodes(JTreeOperator jto, TreePath tp) {
529  try {
530  jto.expandPath(tp);
531  for (TreePath t : jto.getChildPaths(tp)) {
532  expandNodes(jto, t);
533  }
534  } catch (NoSuchPathException ne) {
535  logger.log(Level.SEVERE, "Error expanding tree path", ne);
537  }
538  }
539 
540 
541  private void logSystemDiagnostics() {
542  logger.log(Level.INFO, getSystemDiagnostics());
543  }
544 
545  private static final String NEWLINE = System.lineSeparator();
546 
547  private static final int TOP_NUM = 10;
548 
549  private static Set<String> IGNORED_PROCESSES = Stream.of("_Total", "Idle", "Memory Compression").collect(Collectors.toSet());
550 
551 
552 
558  private static String getSystemDiagnostics() {
559  if (PlatformUtil.isWindowsOS()) {
560  try {
561  List<Map<String, String>> processPerformance = getWmicTable("wmic path Win32_PerfFormattedData_PerfProc_Process get Name,PercentProcessorTime,IOReadBytesPerSec,IOWriteBytesPerSec,WorkingSetPeak").stream()
562  .filter(obj -> !IGNORED_PROCESSES.contains(obj.get("name")))
563  .collect(Collectors.toList());
564 
565  List<Pair<String, Long>> cpuUsageProcesses = getKeyValLimited(processPerformance, "name", "percentprocessortime");
566  List<Pair<String, Long>> memUsageProcesses = getKeyValLimited(processPerformance, "name", "workingsetpeak");
567 
568  List<Triple<String, Long, Long>> ioProcesses = getFilteredLimited(
569  processPerformance,
570  obj -> {
571  String key = obj.get("name");
572  if (key == null) {
573  return null;
574  }
575 
576  try {
577  return Triple.of(key, Long.parseLong(obj.get("ioreadbytespersec")), Long.parseLong(obj.get("iowritebytespersec")));
578  } catch (NumberFormatException | NullPointerException ex) {
579  return null;
580  }
581 
582  },
583  Comparator.comparing(pr -> -(pr.getMiddle() + pr.getRight())));
584 
585  String cpuLoad = getWmicString("wmic cpu get loadpercentage", "loadpercentage");
586  String cpuCores = getWmicString("wmic cpu get numberofcores", "numberofcores");
587  String freePhysicalMemory = getWmicString("wmic OS get FreeSpaceInPagingFiles", "freespaceinpagingfiles"); // in kb
588  String totalPhysicalMemory = getWmicString("wmic ComputerSystem get TotalPhysicalMemory", "totalphysicalmemory"); // bytes
589  String memUsage;
590  try {
591  double freeMemMb = Double.parseDouble(freePhysicalMemory) / 1000;
592  double totalMemMb = Double.parseDouble(totalPhysicalMemory) / 1000 / 1000;
593  memUsage = MessageFormat.format("Free Physical Memory: {0,number,#.##}MB and total physical: {1,number,#.##}MB", freeMemMb, totalMemMb);
594  } catch (NumberFormatException ex) {
595  memUsage = MessageFormat.format("Free Physical Memory: \"{0}\" and total physical: \"{1}\"", freePhysicalMemory, totalPhysicalMemory);
596  }
597 
598  List<Triple<String, Long, String>> networkStatus = getFilteredLimited(
599  getWmicTable("wmic path win32_networkadapter where \"netconnectionstatus = 2 OR NOT errordescription IS NULL\" get netconnectionid, name, speed, maxspeed, errordescription"),
600  (Map<String, String> obj) -> {
601  String name = obj.get("netconnectionid");
602  if (StringUtils.isBlank(name)) {
603  name = obj.get("name");
604  }
605 
606  if (StringUtils.isBlank(name)) {
607  return null;
608  }
609 
610  String errorDescription = obj.get("errordescription");
611 
612  Long speed = 0L;
613  try {
614  speed = Long.parseLong(obj.get("speed"));
615  } catch (NumberFormatException | NullPointerException ex) {
616  }
617 
618  return Triple.of(name, speed, errorDescription);
619  },
620  (a, b) -> StringUtils.compareIgnoreCase(a.getLeft(), b.getRight()));
621 
622  List<Pair<String, Long>> diskStatus = getKeyValLimited(
623  getWmicTable("wmic path Win32_PerfFormattedData_PerfDisk_LogicalDisk get AvgDiskQueueLength,Name").stream()
624  .filter(obj -> !IGNORED_PROCESSES.contains(obj.get("name")))
625  .collect(Collectors.toList()),
626  "name",
627  "avgdiskqueuelength");
628 
629  return "SYSTEM DIAGNOSTICS:" + NEWLINE
630  + MessageFormat.format("CPU Load Percentage: {0}% with {1} cores", cpuLoad, cpuCores) + NEWLINE
631  + MessageFormat.format("Memory Usage: {0}", memUsage) + NEWLINE
632  + "Disk Usage (disk to average disk queue length): " + NEWLINE
633  + diskStatus.stream().map(pr -> pr.getKey() + ": " + pr.getValue()).collect(Collectors.joining(NEWLINE)) + NEWLINE
634  + NEWLINE
635  + "Network Status (of only connected or error): " + NEWLINE
636  + networkStatus.stream().map(obj -> {
637  String errorString = StringUtils.isBlank(obj.getRight()) ? "" : MessageFormat.format(" (error: {0})", obj.getRight());
638  return MessageFormat.format("{0}: {1,number,#.##}MB/S possible {2}", obj.getLeft(), ((double) obj.getMiddle()) / 1000 / 1000, errorString);
639  }).collect(Collectors.joining(NEWLINE)) + NEWLINE
640  + NEWLINE
641  + "CPU consuming processes: " + NEWLINE
642  + cpuUsageProcesses.stream().map(pr -> MessageFormat.format("{0}: {1}%", pr.getKey(), pr.getValue())).collect(Collectors.joining(NEWLINE)) + NEWLINE
643  + NEWLINE
644  + "Memory consuming processes (working set peak): " + NEWLINE
645  + memUsageProcesses.stream()
646  .map(
647  pr -> MessageFormat.format(
648  "{0}: {1,number,#.##}MB",
649  pr.getKey(),
650  ((double) pr.getValue()) / 1000 / 1000
651  )
652  )
653  .collect(Collectors.joining(NEWLINE)) + NEWLINE
654  + NEWLINE
655  + "I/O consuming processes (read/write): " + NEWLINE
656  + ioProcesses.stream()
657  .map(
658  pr -> MessageFormat.format(
659  "{0}: {1,number,#.##}MB/{2,number,#.##}MB", pr.getLeft(),
660  ((double) pr.getMiddle()) / 1000 / 1000,
661  ((double) pr.getRight()) / 1000 / 1000
662  )
663  )
664  .collect(Collectors.joining(NEWLINE)) + NEWLINE;
665  } catch (Throwable ex) {
666  return "SYSTEM DIAGNOSTICS:" + NEWLINE
667  + "Encountered IO exception: " + ex.getMessage() + NEWLINE;
668  }
669 
670  } else {
671  return "System diagnostics only implemented for windows at this time.";
672  }
673  }
674 
682  private static List<Pair<String, Long>> getKeyValLimited(List<Map<String, String>> objects, String keyId, String valId) {
683  return getFilteredLimited(
684  objects,
685  obj -> {
686  String key = obj.get(keyId);
687  if (key == null) {
688  return null;
689  }
690 
691  try {
692  return Pair.of(key, Long.parseLong(obj.get(valId)));
693  } catch (NumberFormatException | NullPointerException ex) {
694  return null;
695  }
696  },
697  Comparator.comparing(pr -> -pr.getValue()));
698  }
699 
707  private static <T> List<T> getFilteredLimited(List<Map<String, String>> objects, Function<Map<String, String>, T> keyObjMapper, Comparator<T> comparator) {
708  return objects.stream()
709  .map(keyObjMapper)
710  .filter(a -> a != null)
711  .sorted(comparator)
712  .limit(TOP_NUM)
713  .collect(Collectors.toList());
714  }
715 
722  private static String getProcStdOut(String... cmd) throws IOException {
723  ProcessBuilder pb = new ProcessBuilder(cmd);
724  String output = IOUtils.toString(pb.start().getInputStream(), StandardCharsets.UTF_8);
725  return output;
726  }
727 
728  // matches key=value
729  private static final Pattern EQUALS_PATTERN = Pattern.compile("^([^=]*)=(.*)$");
730 
741  private static List<Map<String, String>> getWmicTable(String cmd) throws IOException {
742  String stdOut = getProcStdOut("cmd", "/c", cmd + " /format:list");
743 
744  List<Map<String, String>> rows = new ArrayList<>();
745  Map<String, String> curObj = new HashMap<>();
746  for (String line : stdOut.split("\\r?\\n")) {
747  // if line, try to parse as key=value
748  if (StringUtils.isNotBlank(line)) {
749  Matcher matcher = EQUALS_PATTERN.matcher(line);
750  if (matcher.find()) {
751  String key = matcher.group(1).trim().toLowerCase();
752  String value = matcher.group(2).trim();
753  curObj.put(key, value);
754  }
755  // if no line and the object has keys, we have finished an entry, add it to the list.
756  } else if (!curObj.isEmpty()) {
757  rows.add(curObj);
758  curObj = new HashMap<>();
759  }
760  }
761 
762  if (!curObj.isEmpty()) {
763  rows.add(curObj);
764  curObj = new HashMap<>();
765  }
766 
767  return rows;
768  }
769 
777  private static String getWmicString(String wmicQuery, String key) throws IOException {
778  List<Map<String, String>> retVal = getWmicTable(wmicQuery);
779  if (retVal != null && !retVal.isEmpty() && retVal.get(0) != null && retVal.get(0).get(key) != null) {
780  return retVal.get(0).get(key);
781  } else {
782  return null;
783  }
784  }
785 }
static void setZkServerHost(String hostName)
static synchronized IngestManager getInstance()
static List< Map< String, String > > getWmicTable(String cmd)
static List< Pair< String, Long > > getKeyValLimited(List< Map< String, String >> objects, String keyId, String valId)
static void setIsMultiUserModeEnabled(boolean enabled)
static void setMessageServiceConnectionInfo(MessageServiceConnectionInfo info)
static< T > List< T > getFilteredLimited(List< Map< String, String >> objects, Function< Map< String, String >, T > keyObjMapper, Comparator< T > comparator)
void expandNodes(JTreeOperator jto, TreePath tp)
static void setDatabaseConnectionInfo(CaseDbConnectionInfo connectionInfo)
static String getWmicString(String wmicQuery, String key)
static void setIndexingServerHost(String hostName)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on: Mon Mar 17 2025
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.