Autopsy  4.19.3
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.text.JTextComponent;
50 import javax.swing.tree.TreePath;
51 import org.apache.commons.io.IOUtils;
52 import org.apache.commons.lang3.StringUtils;
53 import org.apache.commons.lang3.tuple.Pair;
54 import org.apache.commons.lang3.tuple.Triple;
55 import org.netbeans.jellytools.MainWindowOperator;
56 import org.netbeans.jellytools.NbDialogOperator;
57 import org.netbeans.jellytools.WizardOperator;
58 import org.netbeans.jemmy.JemmyProperties;
59 import org.netbeans.jemmy.Timeout;
60 import org.netbeans.jemmy.TimeoutExpiredException;
61 import org.netbeans.jemmy.Timeouts;
62 import org.netbeans.jemmy.operators.JButtonOperator;
63 import org.netbeans.jemmy.operators.JCheckBoxOperator;
64 import org.netbeans.jemmy.operators.JComboBoxOperator;
65 import org.netbeans.jemmy.operators.JDialogOperator;
66 import org.netbeans.jemmy.operators.JFileChooserOperator;
67 import org.netbeans.jemmy.operators.JLabelOperator;
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;
81 import org.sleuthkit.datamodel.CaseDbConnectionInfo;
82 import org.sleuthkit.datamodel.TskData;
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  JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 0);
181  String img_path = getEscapedPath(System.getProperty("img_path"));
182  String imageDir = img_path;
183  ((JTextComponent) jtfo0.getSource()).setText(imageDir);
184  JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo, 0);
185  comboBoxOperator.setSelectedItem("(GMT-5:00) America/New_York");
186  wo.btNext().clickMouse();
187  } catch (TimeoutExpiredException ex) {
188  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
190  screenshot("TimeoutScreenshot");
191  }
192  }
193 
195  try {
196  /*
197  * This time out is to give time for creating case database and
198  * opening solr index
199  */
200  new Timeout("pausing", 120000).sleep();
201  logger.info("Starting Add Logical Files process");
202  WizardOperator wo = new WizardOperator("Add Data Source");
203  wo.setTimeouts(setTimeout("WindowWaiter.WaitWindowTimeOut", 240000));
204  while (!wo.btNext().isEnabled()) {
205  new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
206  }
207 
208  // pass by host menu with auto-generate host (which should already be selected)
209  wo.btNext().clickMouse();
210 
211  //select the toggle button for Logical Files it will be the third button created and proceed to next panel
212  JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 2);
213  jtbo.clickMouse();
214  wo.btNext().clickMouse();
215  JButtonOperator addButtonOperator = new JButtonOperator(wo, "Add");
216  addButtonOperator.pushNoBlock();
217  JFileChooserOperator fileChooserOperator = new JFileChooserOperator();
218  fileChooserOperator.setCurrentDirectory(new File(getEscapedPath(System.getProperty("img_path"))));
219  // set the current directory one level above the directory containing logicalFileSet folder.
220  fileChooserOperator.goUpLevel();
221  fileChooserOperator.chooseFile(new File(getEscapedPath(System.getProperty("img_path"))).getName());
222  wo.btNext().clickMouse();
223  } catch (TimeoutExpiredException ex) {
224  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
226  screenshot("TimeoutScreenshot");
227  }
228  }
229 
230  public void testAddSourceWizard1() {
231  try {
232  WizardOperator wo = new WizardOperator("Add Data Source");
233  while (!wo.btFinish().isEnabled()) {
234  new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
235  }
236  logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start));
237  wo.btFinish().clickMouse();
238  } catch (TimeoutExpiredException ex) {
239  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
241  screenshot("TimeoutScreenshot");
242  }
243  }
244 
245  public void testConfigureIngest1() {
246  try {
247  /*
248  * This timeout is to allow the setup for the ingest job settings
249  * panel to complete.
250  */
251  new Timeout("pausing", 10000).sleep();
252 
253  logger.info("Looking for hash lookup module in ingest job settings panel");
254  WizardOperator wo = new WizardOperator("Add Data Source");
255  while (!wo.btNext().isEnabled()) {
256  new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
257  }
258  JTableOperator jto = new JTableOperator(wo, 0);
259  int row = jto.findCellRow("Hash Lookup", 2, 0);
260  jto.clickOnCell(row, 1);
261  logger.info("Selected hash lookup module in ingest job settings panel");
262  JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings");
263  jbo1.pushNoBlock();
264  logger.info("Pushed Global Settings button for hash lookup module in ingest job settings panel");
265  } catch (TimeoutExpiredException ex) {
266  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
268  screenshot("TimeoutScreenshot");
269  }
270  }
271 
272  public void testConfigureHash() {
273  try {
274  logger.info("Hash Configure");
275  JDialog hashMainDialog = JDialogOperator.waitJDialog("Global Hash Lookup Settings", false, false);
276  JDialogOperator hashMainDialogOperator = new JDialogOperator(hashMainDialog);
277  List<String> databases = new ArrayList<>();
278  databases.add(getEscapedPath(System.getProperty("nsrl_path")));
279  databases.add(getEscapedPath(System.getProperty("known_bad_path")));
280  databases.stream().map((database) -> {
281  JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import");
282  importButtonOperator.pushNoBlock();
283  JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Set", false, false);
284  JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog);
285  JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0);
286  browseButtonOperator.pushNoBlock();
287  JFileChooserOperator fileChooserOperator = new JFileChooserOperator();
288  fileChooserOperator.chooseFile(database);
289  JButtonOperator okButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "OK", 0);
290  return okButtonOperator;
291  }).map((okButtonOperator) -> {
292  okButtonOperator.pushNoBlock();
293  return okButtonOperator;
294  }).forEach((_item) -> {
295  new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
296  });
297  // Used if the database has no index
298  //JDialog jd3 = JDialogOperator.waitJDialog("No Index Exists", false, false);
299  //JDialogOperator jdo3 = new JDialogOperator(jd3);
300  //JButtonOperator jbo3 = new JButtonOperator(jdo3, "Yes", 0);
301  new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
302  //jbo3.pushNoBlock();
303  JButtonOperator jbo4 = new JButtonOperator(hashMainDialogOperator, "OK", 0);
304  jbo4.pushNoBlock();
305  } catch (TimeoutExpiredException ex) {
306  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
308  screenshot("TimeoutScreenshot");
309  }
310  }
311 
312  public void testConfigureIngest2() {
313  try {
314  logger.info("Looking for keyword search module in ingest job settings panel");
315  WizardOperator wo = new WizardOperator("Add Data Source");
316  while (!wo.btNext().isEnabled()) {
317  new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
318  }
319  JTableOperator jto = new JTableOperator(wo, 0);
320  int row = jto.findCellRow("Keyword Search", 2, 0);
321  jto.clickOnCell(row, 1);
322  logger.info("Selected keyword search module in ingest job settings panel");
323  JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings");
324  jbo1.pushNoBlock();
325  logger.info("Pushed Global Settings button for keyword search module in ingest job settings panel");
326  } catch (TimeoutExpiredException ex) {
327  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
329  screenshot("TimeoutScreenshot");
330  }
331  }
332 
333  public void testConfigureSearch() {
334  try {
335  logger.info("Search Configure");
336  JDialog jd = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false);
337  JDialogOperator jdo = new JDialogOperator(jd);
338  String words = getEscapedPath(System.getProperty("keyword_path"));
339  JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0);
340  jbo0.pushNoBlock();
341  JFileChooserOperator jfco0 = new JFileChooserOperator();
342  jfco0.chooseFile(words);
343  JTableOperator jto = new JTableOperator(jdo, 0);
344  jto.clickOnCell(0, 0);
345  new Timeout("pausing", 1000).sleep(); // give it a second to process
346  if (Boolean.parseBoolean(System.getProperty("mugen_mode"))) {
347  JTabbedPaneOperator jtpo = new JTabbedPaneOperator(jdo);
348  jtpo.selectPage("String Extraction");
349  JCheckBoxOperator jcbo0 = new JCheckBoxOperator(jtpo, "Arabic (Arabic)");
350  jcbo0.doClick();
351  JCheckBoxOperator jcbo1 = new JCheckBoxOperator(jtpo, "Han (Chinese, Japanese, Korean)");
352  jcbo1.doClick();
353  new Timeout("pausing", 1000).sleep(); // give it a second to process
354  }
355  JButtonOperator jbo2 = new JButtonOperator(jdo, "OK", 0);
356  jbo2.pushNoBlock();
357  WizardOperator wo = new WizardOperator("Add Data Source");
358  new Timeout("pausing", 10000).sleep(); // let things catch up
359  wo.btNext().clickMouse();
360  } catch (TimeoutExpiredException ex) {
361  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
363  screenshot("TimeoutScreenshot");
364  }
365  }
366 
367  public void testIngest() {
368  try {
369  logger.info("Ingest 3");
370  new Timeout("pausing", 10000).sleep(); // wait for ingest to actually start
371  long startIngest = System.currentTimeMillis();
373  while (man.isIngestRunning()) {
374  new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
375  }
376  logger.log(Level.INFO, "Ingest (including enqueue) took {0}ms", (System.currentTimeMillis() - startIngest));
377  // allow keyword search to finish saving artifacts, just in case
378  // but randomize the timing so that we don't always get the same error
379  // consistently, making it seem like default behavior
380  Random rand = new Random();
381  new Timeout("pausing", 10000 + (rand.nextInt(15000) + 5000)).sleep();
382  } catch (TimeoutExpiredException ex) {
383  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
385  screenshot("TimeoutScreenshot");
386  }
387 
388  }
389 
391  try {
392  logger.info("Data Sources Node");
393  MainWindowOperator mwo = MainWindowOperator.getDefault();
394  JTreeOperator jto = new JTreeOperator(mwo, "Data Sources");
395  String[] nodeNames = {"Data Sources"};
396  TreePath tp = jto.findPath(nodeNames);
397  expandNodes(jto, tp);
398  } catch (TimeoutExpiredException ex) {
399  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
401  screenshot("TimeoutScreenshot");
402  }
403  }
404 
406  try {
407  logger.info("Generate Report Toolbars");
408  MainWindowOperator mwo = MainWindowOperator.getDefault();
409  JButtonOperator jbo = new JButtonOperator(mwo, "Generate Report");
410  jbo.pushNoBlock();
411  } catch (TimeoutExpiredException ex) {
412  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
414  screenshot("TimeoutScreenshot");
415  }
416  }
417 
418  public void testGenerateReportButton() throws IOException {
419  try {
420  logger.info("Generate Report Button");
421  setTimeout("ComponentOperator.WaitComponentTimeout", 240000);
422  JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false);
423  JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog);
424  JListOperator listOperator = new JListOperator(reportDialogOperator);
425  JButtonOperator jbo0 = new JButtonOperator(reportDialogOperator, "Next");
426  DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss");
427  Date date = new Date();
428  String datenotime = dateFormat.format(date);
429  listOperator.clickOnItem(0, 1);
430  jbo0.pushNoBlock();
431  new Timeout("pausing", 2000).sleep();
432 
433  // Next button on the data source selection panel
434  JButtonOperator dataSourceSelectionPanelNext = new JButtonOperator(reportDialogOperator, "Next");
435  dataSourceSelectionPanelNext.pushNoBlock();
436  new Timeout("pausing", 2000).sleep();
437 
438  JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish");
439  jbo1.pushNoBlock();
440  JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false);
441  JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog);
442  JTextAreaOperator.waitJTextArea(previewDialog, "Complete", false, false);
443  JButtonOperator jbo2 = new JButtonOperator(previewDialogOperator, "Close");
444  jbo2.pushNoBlock();
445  new Timeout("pausing", 10000).sleep();
446  System.setProperty("ReportStr", datenotime);
447  } catch (TimeoutExpiredException ex) {
448  logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
450  screenshot("TimeoutScreenshot");
451  }
452  }
453 
454  public void screenshot(String name) {
455  String outPath = getEscapedPath(System.getProperty("out_path"));
456  File screenShotFile = new File(outPath + "\\" + name + ".png");
457  if (!screenShotFile.exists()) {
458  logger.info("Taking screenshot.");
459  try {
460  Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
461  BufferedImage capture = new Robot().createScreenCapture(screenRect);
462  ImageIO.write(capture, "png", screenShotFile);
463  new Timeout("pausing", 1000).sleep(); // give it a second to save
464  } catch (IOException ex) {
465  logger.log(Level.WARNING, "IOException taking screenshot.", ex);
466  } catch (AWTException ex) {
467  logger.log(Level.WARNING, "AWTException taking screenshot.", ex);
468  }
469  }
470  }
471 
472  /*
473  * Nightly test failed at WindowWaiter.WaitWindowTimeOut because of
474  * TimeoutExpiredException. So we use this conveninent method to override
475  * the default Jemmy Timeouts value.
476  */
477  private Timeouts setTimeout(String name, int value) {
478  Timeouts timeouts = JemmyProperties.getCurrentTimeouts();
479  timeouts.setTimeout(name, value);
480  return timeouts;
481  }
482 
483  private void setMultiUserPerferences() {
485  //PostgreSQL database settings
486  CaseDbConnectionInfo connectionInfo = new CaseDbConnectionInfo(
487  System.getProperty("dbHost"),
488  System.getProperty("dbPort"),
489  System.getProperty("dbUserName"),
490  System.getProperty("dbPassword"),
491  TskData.DbType.POSTGRESQL);
492  try {
494  } catch (UserPreferencesException ex) {
495  logger.log(Level.SEVERE, "Error saving case database connection info", ex); //NON-NLS
497  }
498  //Solr Index settings
499  UserPreferences.setIndexingServerHost(System.getProperty("solrHost"));
500  UserPreferences.setIndexingServerPort(Integer.parseInt(System.getProperty("solrPort")));
501  //ActiveMQ Message Service Setting, username and password field are empty
503  System.getProperty("messageServiceHost"),
504  Integer.parseInt(System.getProperty("messageServicePort")),
505  "",
506  "");
507  try {
509  } catch (UserPreferencesException ex) {
510  logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS
512  }
513 
514  UserPreferences.setZkServerHost(System.getProperty("zooKeeperHost"));
515  UserPreferences.setZkServerPort(System.getProperty("zooKeeperPort"));
516  }
517 
518  private void expandNodes(JTreeOperator jto, TreePath tp) {
519  try {
520  jto.expandPath(tp);
521  for (TreePath t : jto.getChildPaths(tp)) {
522  expandNodes(jto, t);
523  }
524  } catch (NoSuchPathException ne) {
525  logger.log(Level.SEVERE, "Error expanding tree path", ne);
527  }
528  }
529 
530 
531  private void logSystemDiagnostics() {
532  logger.log(Level.INFO, getSystemDiagnostics());
533  }
534 
535  private static final String NEWLINE = System.lineSeparator();
536 
537  private static final int TOP_NUM = 10;
538 
539  private static Set<String> IGNORED_PROCESSES = Stream.of("_Total", "Idle", "Memory Compression").collect(Collectors.toSet());
540 
541 
542 
548  private static String getSystemDiagnostics() {
549  if (PlatformUtil.isWindowsOS()) {
550  try {
551  List<Map<String, String>> processPerformance = getWmicTable("wmic path Win32_PerfFormattedData_PerfProc_Process get Name,PercentProcessorTime,IOReadBytesPerSec,IOWriteBytesPerSec,WorkingSetPeak").stream()
552  .filter(obj -> !IGNORED_PROCESSES.contains(obj.get("name")))
553  .collect(Collectors.toList());
554 
555  List<Pair<String, Long>> cpuUsageProcesses = getKeyValLimited(processPerformance, "name", "percentprocessortime");
556  List<Pair<String, Long>> memUsageProcesses = getKeyValLimited(processPerformance, "name", "workingsetpeak");
557 
558  List<Triple<String, Long, Long>> ioProcesses = getFilteredLimited(
559  processPerformance,
560  obj -> {
561  String key = obj.get("name");
562  if (key == null) {
563  return null;
564  }
565 
566  try {
567  return Triple.of(key, Long.parseLong(obj.get("ioreadbytespersec")), Long.parseLong(obj.get("iowritebytespersec")));
568  } catch (NumberFormatException | NullPointerException ex) {
569  return null;
570  }
571 
572  },
573  Comparator.comparing(pr -> -(pr.getMiddle() + pr.getRight())));
574 
575  String cpuLoad = getWmicString("wmic cpu get loadpercentage", "loadpercentage");
576  String cpuCores = getWmicString("wmic cpu get numberofcores", "numberofcores");
577  String freePhysicalMemory = getWmicString("wmic OS get FreeSpaceInPagingFiles", "freespaceinpagingfiles"); // in kb
578  String totalPhysicalMemory = getWmicString("wmic ComputerSystem get TotalPhysicalMemory", "totalphysicalmemory"); // bytes
579  String memUsage;
580  try {
581  double freeMemMb = Double.parseDouble(freePhysicalMemory) / 1000;
582  double totalMemMb = Double.parseDouble(totalPhysicalMemory) / 1000 / 1000;
583  memUsage = MessageFormat.format("Free Physical Memory: {0,number,#.##}MB and total physical: {1,number,#.##}MB", freeMemMb, totalMemMb);
584  } catch (NumberFormatException ex) {
585  memUsage = MessageFormat.format("Free Physical Memory: \"{0}\" and total physical: \"{1}\"", freePhysicalMemory, totalPhysicalMemory);
586  }
587 
588  List<Triple<String, Long, String>> networkStatus = getFilteredLimited(
589  getWmicTable("wmic path win32_networkadapter where \"netconnectionstatus = 2 OR NOT errordescription IS NULL\" get netconnectionid, name, speed, maxspeed, errordescription"),
590  (Map<String, String> obj) -> {
591  String name = obj.get("netconnectionid");
592  if (StringUtils.isBlank(name)) {
593  name = obj.get("name");
594  }
595 
596  if (StringUtils.isBlank(name)) {
597  return null;
598  }
599 
600  String errorDescription = obj.get("errordescription");
601 
602  Long speed = 0L;
603  try {
604  speed = Long.parseLong(obj.get("speed"));
605  } catch (NumberFormatException | NullPointerException ex) {
606  }
607 
608  return Triple.of(name, speed, errorDescription);
609  },
610  (a, b) -> StringUtils.compareIgnoreCase(a.getLeft(), b.getRight()));
611 
612  List<Pair<String, Long>> diskStatus = getKeyValLimited(
613  getWmicTable("wmic path Win32_PerfFormattedData_PerfDisk_LogicalDisk get AvgDiskQueueLength,Name").stream()
614  .filter(obj -> !IGNORED_PROCESSES.contains(obj.get("name")))
615  .collect(Collectors.toList()),
616  "name",
617  "avgdiskqueuelength");
618 
619  return "SYSTEM DIAGNOSTICS:" + NEWLINE
620  + MessageFormat.format("CPU Load Percentage: {0}% with {1} cores", cpuLoad, cpuCores) + NEWLINE
621  + MessageFormat.format("Memory Usage: {0}", memUsage) + NEWLINE
622  + "Disk Usage (disk to average disk queue length): " + NEWLINE
623  + diskStatus.stream().map(pr -> pr.getKey() + ": " + pr.getValue()).collect(Collectors.joining(NEWLINE)) + NEWLINE
624  + NEWLINE
625  + "Network Status (of only connected or error): " + NEWLINE
626  + networkStatus.stream().map(obj -> {
627  String errorString = StringUtils.isBlank(obj.getRight()) ? "" : MessageFormat.format(" (error: {0})", obj.getRight());
628  return MessageFormat.format("{0}: {1,number,#.##}MB/S possible {2}", obj.getLeft(), ((double) obj.getMiddle()) / 1000 / 1000, errorString);
629  }).collect(Collectors.joining(NEWLINE)) + NEWLINE
630  + NEWLINE
631  + "CPU consuming processes: " + NEWLINE
632  + cpuUsageProcesses.stream().map(pr -> MessageFormat.format("{0}: {1}%", pr.getKey(), pr.getValue())).collect(Collectors.joining(NEWLINE)) + NEWLINE
633  + NEWLINE
634  + "Memory consuming processes (working set peak): " + NEWLINE
635  + memUsageProcesses.stream()
636  .map(
637  pr -> MessageFormat.format(
638  "{0}: {1,number,#.##}MB",
639  pr.getKey(),
640  ((double) pr.getValue()) / 1000 / 1000
641  )
642  )
643  .collect(Collectors.joining(NEWLINE)) + NEWLINE
644  + NEWLINE
645  + "I/O consuming processes (read/write): " + NEWLINE
646  + ioProcesses.stream()
647  .map(
648  pr -> MessageFormat.format(
649  "{0}: {1,number,#.##}MB/{2,number,#.##}MB", pr.getLeft(),
650  ((double) pr.getMiddle()) / 1000 / 1000,
651  ((double) pr.getRight()) / 1000 / 1000
652  )
653  )
654  .collect(Collectors.joining(NEWLINE)) + NEWLINE;
655  } catch (Throwable ex) {
656  return "SYSTEM DIAGNOSTICS:" + NEWLINE
657  + "Encountered IO exception: " + ex.getMessage() + NEWLINE;
658  }
659 
660  } else {
661  return "System diagnostics only implemented for windows at this time.";
662  }
663  }
664 
672  private static List<Pair<String, Long>> getKeyValLimited(List<Map<String, String>> objects, String keyId, String valId) {
673  return getFilteredLimited(
674  objects,
675  obj -> {
676  String key = obj.get(keyId);
677  if (key == null) {
678  return null;
679  }
680 
681  try {
682  return Pair.of(key, Long.parseLong(obj.get(valId)));
683  } catch (NumberFormatException | NullPointerException ex) {
684  return null;
685  }
686  },
687  Comparator.comparing(pr -> -pr.getValue()));
688  }
689 
697  private static <T> List<T> getFilteredLimited(List<Map<String, String>> objects, Function<Map<String, String>, T> keyObjMapper, Comparator<T> comparator) {
698  return objects.stream()
699  .map(keyObjMapper)
700  .filter(a -> a != null)
701  .sorted(comparator)
702  .limit(TOP_NUM)
703  .collect(Collectors.toList());
704  }
705 
712  private static String getProcStdOut(String... cmd) throws IOException {
713  ProcessBuilder pb = new ProcessBuilder(cmd);
714  String output = IOUtils.toString(pb.start().getInputStream(), StandardCharsets.UTF_8);
715  return output;
716  }
717 
718  // matches key=value
719  private static final Pattern EQUALS_PATTERN = Pattern.compile("^([^=]*)=(.*)$");
720 
731  private static List<Map<String, String>> getWmicTable(String cmd) throws IOException {
732  String stdOut = getProcStdOut("cmd", "/c", cmd + " /format:list");
733 
734  List<Map<String, String>> rows = new ArrayList<>();
735  Map<String, String> curObj = new HashMap<>();
736  for (String line : stdOut.split("\\r?\\n")) {
737  // if line, try to parse as key=value
738  if (StringUtils.isNotBlank(line)) {
739  Matcher matcher = EQUALS_PATTERN.matcher(line);
740  if (matcher.find()) {
741  String key = matcher.group(1).trim().toLowerCase();
742  String value = matcher.group(2).trim();
743  curObj.put(key, value);
744  }
745  // if no line and the object has keys, we have finished an entry, add it to the list.
746  } else if (!curObj.isEmpty()) {
747  rows.add(curObj);
748  curObj = new HashMap<>();
749  }
750  }
751 
752  if (!curObj.isEmpty()) {
753  rows.add(curObj);
754  curObj = new HashMap<>();
755  }
756 
757  return rows;
758  }
759 
767  private static String getWmicString(String wmicQuery, String key) throws IOException {
768  List<Map<String, String>> retVal = getWmicTable(wmicQuery);
769  if (retVal != null && !retVal.isEmpty() && retVal.get(0) != null && retVal.get(0).get(key) != null) {
770  return retVal.get(0).get(key);
771  } else {
772  return null;
773  }
774  }
775 }
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)
Timeouts setTimeout(String name, int value)
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-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.