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