Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.testing;
20
21import java.awt.AWTException;
22import java.awt.Rectangle;
23import java.awt.Robot;
24import java.awt.Toolkit;
25import java.awt.image.BufferedImage;
26import java.io.File;
27import java.io.IOException;
28import java.nio.charset.StandardCharsets;
29import java.text.DateFormat;
30import java.text.MessageFormat;
31import java.text.SimpleDateFormat;
32import java.util.ArrayList;
33import java.util.Comparator;
34import java.util.Date;
35import java.util.HashMap;
36import java.util.List;
37import java.util.Map;
38import java.util.Random;
39import java.util.Set;
40import java.util.function.Function;
41import java.util.logging.Logger;
42import java.util.logging.Level;
43import java.util.regex.Matcher;
44import java.util.regex.Pattern;
45import java.util.stream.Collectors;
46import java.util.stream.Stream;
47import javax.imageio.ImageIO;
48import javax.swing.JDialog;
49import javax.swing.SwingUtilities;
50import javax.swing.text.JTextComponent;
51import javax.swing.tree.TreePath;
52import org.apache.commons.io.IOUtils;
53import org.apache.commons.lang3.StringUtils;
54import org.apache.commons.lang3.tuple.Pair;
55import org.apache.commons.lang3.tuple.Triple;
56import org.netbeans.jellytools.MainWindowOperator;
57import org.netbeans.jellytools.NbDialogOperator;
58import org.netbeans.jellytools.WizardOperator;
59import org.netbeans.jemmy.JemmyProperties;
60import org.netbeans.jemmy.Timeout;
61import org.netbeans.jemmy.TimeoutExpiredException;
62import org.netbeans.jemmy.Timeouts;
63import org.netbeans.jemmy.operators.JButtonOperator;
64import org.netbeans.jemmy.operators.JCheckBoxOperator;
65import org.netbeans.jemmy.operators.JComboBoxOperator;
66import org.netbeans.jemmy.operators.JDialogOperator;
67import org.netbeans.jemmy.operators.JFileChooserOperator;
68import org.netbeans.jemmy.operators.JListOperator;
69import org.netbeans.jemmy.operators.JTabbedPaneOperator;
70import org.netbeans.jemmy.operators.JTableOperator;
71import org.netbeans.jemmy.operators.JTextAreaOperator;
72import org.netbeans.jemmy.operators.JTextFieldOperator;
73import org.netbeans.jemmy.operators.JToggleButtonOperator;
74import org.netbeans.jemmy.operators.JTreeOperator;
75import org.netbeans.jemmy.operators.JTreeOperator.NoSuchPathException;
76import org.sleuthkit.autopsy.core.UserPreferences;
77import org.sleuthkit.autopsy.core.UserPreferencesException;
78import org.sleuthkit.autopsy.coreutils.PlatformUtil;
79import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
80import org.sleuthkit.autopsy.ingest.IngestManager;
81import org.sleuthkit.datamodel.CaseDbConnectionInfo;
82import org.sleuthkit.datamodel.TskData;
83
84public 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"),
501 TskData.DbType.POSTGRESQL);
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() {
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) -> a.getLeft().compareToIgnoreCase(b.getLeft()));
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 setDatabaseConnectionInfo(CaseDbConnectionInfo connectionInfo)
static void setIsMultiUserModeEnabled(boolean enabled)
static void setMessageServiceConnectionInfo(MessageServiceConnectionInfo info)
static void setZkServerHost(String hostName)
static void setIndexingServerHost(String hostName)
static synchronized IngestManager getInstance()
static List< Pair< String, Long > > getKeyValLimited(List< Map< String, String > > objects, String keyId, String valId)
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 List< Map< String, String > > getWmicTable(String cmd)
static String getWmicString(String wmicQuery, String key)

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