Home | History | Annotate | Download | only in parser
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.loganalysis.parser;
     17 
     18 import com.android.loganalysis.item.JavaCrashItem;
     19 import com.android.loganalysis.item.LogcatItem;
     20 import com.android.loganalysis.item.MiscLogcatItem;
     21 import com.android.loganalysis.util.ArrayUtil;
     22 
     23 import junit.framework.TestCase;
     24 
     25 import java.text.DateFormat;
     26 import java.text.ParseException;
     27 import java.text.SimpleDateFormat;
     28 import java.util.Arrays;
     29 import java.util.Date;
     30 import java.util.List;
     31 import java.util.regex.Pattern;
     32 
     33 /**
     34  * Unit tests for {@link LogcatParserTest}.
     35  */
     36 public class LogcatParserTest extends TestCase {
     37 
     38     /**
     39      * Test that an ANR is parsed in the log.
     40      */
     41     public void testParse_anr() throws ParseException {
     42         List<String> lines = Arrays.asList(
     43                 "04-25 17:17:08.445   312   366 E ActivityManager: ANR (application not responding) in process: com.android.package",
     44                 "04-25 17:17:08.445   312   366 E ActivityManager: Reason: keyDispatchingTimedOut",
     45                 "04-25 17:17:08.445   312   366 E ActivityManager: Load: 0.71 / 0.83 / 0.51",
     46                 "04-25 17:17:08.445   312   366 E ActivityManager: 33% TOTAL: 21% user + 11% kernel + 0.3% iowait");
     47 
     48         LogcatItem logcat = new LogcatParser("2012").parse(lines);
     49         assertNotNull(logcat);
     50         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getStartTime());
     51         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getStopTime());
     52         assertEquals(1, logcat.getEvents().size());
     53         assertEquals(1, logcat.getAnrs().size());
     54         assertEquals(312, logcat.getAnrs().get(0).getPid().intValue());
     55         assertEquals(366, logcat.getAnrs().get(0).getTid().intValue());
     56         assertEquals("", logcat.getAnrs().get(0).getLastPreamble());
     57         assertEquals("", logcat.getAnrs().get(0).getProcessPreamble());
     58         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getAnrs().get(0).getEventTime());
     59     }
     60 
     61     /**
     62      * Test that an ANR is parsed in the log.
     63      */
     64     public void testParse_anr_pid() throws ParseException {
     65         List<String> lines = Arrays.asList(
     66                 "04-25 17:17:08.445   312   366 E ActivityManager: ANR (application not responding) in process: com.android.package",
     67                 "04-25 17:17:08.445   312   366 E ActivityManager: PID: 1234",
     68                 "04-25 17:17:08.445   312   366 E ActivityManager: Reason: keyDispatchingTimedOut",
     69                 "04-25 17:17:08.445   312   366 E ActivityManager: Load: 0.71 / 0.83 / 0.51",
     70                 "04-25 17:17:08.445   312   366 E ActivityManager: 33% TOTAL: 21% user + 11% kernel + 0.3% iowait");
     71 
     72         LogcatItem logcat = new LogcatParser("2012").parse(lines);
     73         assertNotNull(logcat);
     74         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getStartTime());
     75         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getStopTime());
     76         assertEquals(1, logcat.getEvents().size());
     77         assertEquals(1, logcat.getAnrs().size());
     78         assertEquals(1234, logcat.getAnrs().get(0).getPid().intValue());
     79         assertNull(logcat.getAnrs().get(0).getTid());
     80         assertEquals("", logcat.getAnrs().get(0).getLastPreamble());
     81         assertEquals("", logcat.getAnrs().get(0).getProcessPreamble());
     82         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getAnrs().get(0).getEventTime());
     83     }
     84 
     85     /**
     86      * Test that Java crashes can be parsed.
     87      */
     88     public void testParse_java_crash() throws ParseException {
     89         List<String> lines = Arrays.asList(
     90                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
     91                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
     92                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
     93                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)");
     94 
     95         LogcatItem logcat = new LogcatParser("2012").parse(lines);
     96         assertNotNull(logcat);
     97         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
     98         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
     99         assertEquals(1, logcat.getEvents().size());
    100         assertEquals(1, logcat.getJavaCrashes().size());
    101         assertEquals(3064, logcat.getJavaCrashes().get(0).getPid().intValue());
    102         assertEquals(3082, logcat.getJavaCrashes().get(0).getTid().intValue());
    103         assertEquals("", logcat.getJavaCrashes().get(0).getLastPreamble());
    104         assertEquals("", logcat.getJavaCrashes().get(0).getProcessPreamble());
    105         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    106                 logcat.getJavaCrashes().get(0).getEventTime());
    107     }
    108 
    109     public void testParse_test_exception() {
    110         List<String> lines = Arrays.asList(
    111                 "11-25 19:26:53.581  5832  7008 I TestRunner: ----- begin exception -----",
    112                 "11-25 19:26:53.589  5832  7008 I TestRunner: ",
    113                 "11-25 19:26:53.589  5832  7008 I TestRunner: java.util.concurrent.TimeoutException",
    114                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:49)",
    115                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:36)",
    116                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.support.test.uiautomator.UiDevice.wait(UiDevice.java:169)",
    117                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at com.android.test.uiautomator.common.helpers.MapsHelper.doSearch(MapsHelper.java:87)",
    118                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at com.android.test.uiautomator.aupt.MapsTest.testMaps(MapsTest.java:58)",
    119                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at java.lang.reflect.Method.invoke(Native Method)",
    120                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at java.lang.reflect.Method.invoke(Method.java:372)",
    121                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)",
    122                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)",
    123                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at junit.framework.TestCase.runBare(TestCase.java:134)",
    124                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at junit.framework.TestResult$1.protect(TestResult.java:115)",
    125                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at junit.framework.TestResult.runProtected(TestResult.java:133)",
    126                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at junit.framework.TestResult.run(TestResult.java:118)",
    127                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at junit.framework.TestCase.run(TestCase.java:124)",
    128                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.support.test.aupt.AuptTestRunner$AuptPrivateTestRunner.runTest(AuptTestRunner.java:182)",
    129                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)",
    130                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)",
    131                 "11-25 19:26:53.589  5832  7008 I TestRunner:    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1848)",
    132                 "11-25 19:26:53.589  5832  7008 I TestRunner: ----- end exception -----"
    133                 );
    134 
    135         LogcatParser logcatParser = new LogcatParser("2012");
    136         logcatParser.addJavaCrashTag("I", "TestRunner", LogcatParser.JAVA_CRASH);
    137         LogcatItem logcat = logcatParser.parse(lines);
    138         assertNotNull(logcat);
    139         assertEquals(1, logcat.getEvents().size());
    140         assertEquals(1, logcat.getJavaCrashes().size());
    141         assertEquals(5832, logcat.getJavaCrashes().get(0).getPid().intValue());
    142         assertEquals(7008, logcat.getJavaCrashes().get(0).getTid().intValue());
    143         assertEquals("", logcat.getJavaCrashes().get(0).getLastPreamble());
    144         assertEquals("", logcat.getJavaCrashes().get(0).getProcessPreamble());
    145         assertEquals(LogcatParser.JAVA_CRASH, logcat.getJavaCrashes().get(0).getCategory());
    146     }
    147 
    148     public void testParse_test_exception_with_exras() {
    149         List<String> lines = Arrays.asList(
    150                 "12-06 17:19:18.746  6598  7960 I TestRunner: failed: testYouTube(com.android.test.uiautomator.aupt.YouTubeTest)",
    151                 "12-06 17:19:18.746  6598  7960 I TestRunner: ----- begin exception -----",
    152                 "12-06 17:19:18.747  6598  7960 I TestRunner: ",
    153                 "12-06 17:19:18.747  6598  7960 I TestRunner: java.util.concurrent.TimeoutException",
    154                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:49)",
    155                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:36)",
    156                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at android.support.test.uiautomator.UiDevice.wait(UiDevice.java:169)",
    157                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at android.support.test.aupt.AppLauncher.launchApp(AppLauncher.java:127)",
    158                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at com.android.test.uiautomator.common.helpers.YouTubeHelper.open(YouTubeHelper.java:49)",
    159                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at com.android.test.uiautomator.aupt.YouTubeTest.setUp(YouTubeTest.java:44)",
    160                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at junit.framework.TestCase.runBare(TestCase.java:132)",
    161                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at junit.framework.TestResult$1.protect(TestResult.java:115)",
    162                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at junit.framework.TestResult.runProtected(TestResult.java:133)",
    163                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at junit.framework.TestResult.run(TestResult.java:118)",
    164                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at junit.framework.TestCase.run(TestCase.java:124)",
    165                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at android.support.test.aupt.AuptTestRunner$AuptPrivateTestRunner.runTest(AuptTestRunner.java:182)",
    166                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)",
    167                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)",
    168                 "12-06 17:19:18.747  6598  7960 I TestRunner:    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1851)",
    169                 "12-06 17:19:18.747  6598  7960 I TestRunner: ----- end exception -----"
    170                 );
    171 
    172         LogcatParser logcatParser = new LogcatParser("2012");
    173         logcatParser.addJavaCrashTag("I", "TestRunner", LogcatParser.JAVA_CRASH);
    174         LogcatItem logcat = logcatParser.parse(lines);
    175         assertNotNull(logcat);
    176         assertEquals(1, logcat.getEvents().size());
    177         assertEquals(1, logcat.getJavaCrashes().size());
    178         assertEquals(6598, logcat.getJavaCrashes().get(0).getPid().intValue());
    179         assertEquals(7960, logcat.getJavaCrashes().get(0).getTid().intValue());
    180         assertEquals("", logcat.getJavaCrashes().get(0).getLastPreamble());
    181         assertEquals("", logcat.getJavaCrashes().get(0).getProcessPreamble());
    182         // Check that lines not related to java crash are absent
    183         assertFalse(logcat.getJavaCrashes().get(0).getStack().contains("begin exception"));
    184         assertFalse(logcat.getJavaCrashes().get(0).getStack().contains("end exception"));
    185         assertFalse(logcat.getJavaCrashes().get(0).getStack().contains("failed: testYouTube"));
    186         //System.out.println(logcat.getJavaCrashes().get(0).getStack());
    187     }
    188 
    189     /**
    190      * Test that Java crashes from system server can be parsed.
    191      */
    192     public void testParse_java_crash_system_server() throws ParseException {
    193         List<String> lines = Arrays.asList(
    194                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: message",
    195                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    196                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    197                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    198                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)");
    199 
    200         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    201         assertNotNull(logcat);
    202         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
    203         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
    204         assertEquals(1, logcat.getEvents().size());
    205         assertEquals(1, logcat.getJavaCrashes().size());
    206         assertEquals("system_server", logcat.getJavaCrashes().get(0).getApp());
    207         assertEquals(3064, logcat.getJavaCrashes().get(0).getPid().intValue());
    208         assertEquals(3082, logcat.getJavaCrashes().get(0).getTid().intValue());
    209         assertEquals("", logcat.getJavaCrashes().get(0).getLastPreamble());
    210         assertEquals("", logcat.getJavaCrashes().get(0).getProcessPreamble());
    211         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    212                 logcat.getJavaCrashes().get(0).getEventTime());
    213     }
    214 
    215     /**
    216      * Test that Java crashes with process and pid can be parsed.
    217      */
    218     public void testParse_java_crash_process_pid() throws ParseException {
    219         List<String> lines = Arrays.asList(
    220                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: FATAL EXCEPTION: main",
    221                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: Process: com.android.package, PID: 1234",
    222                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    223                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    224                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    225                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)");
    226 
    227         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    228         assertNotNull(logcat);
    229         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
    230         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
    231         assertEquals(1, logcat.getEvents().size());
    232         assertEquals(1, logcat.getJavaCrashes().size());
    233         assertEquals("com.android.package", logcat.getJavaCrashes().get(0).getApp());
    234         assertEquals(1234, logcat.getJavaCrashes().get(0).getPid().intValue());
    235         assertNull(logcat.getJavaCrashes().get(0).getTid());
    236         assertEquals("", logcat.getJavaCrashes().get(0).getLastPreamble());
    237         assertEquals("", logcat.getJavaCrashes().get(0).getProcessPreamble());
    238         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    239                 logcat.getJavaCrashes().get(0).getEventTime());
    240     }
    241 
    242     /**
    243      * Test that Java crashes with pid can be parsed.
    244      */
    245     public void testParse_java_crash_pid() throws ParseException {
    246         List<String> lines = Arrays.asList(
    247                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: FATAL EXCEPTION: main",
    248                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: PID: 1234",
    249                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    250                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    251                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    252                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)");
    253 
    254         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    255         assertNotNull(logcat);
    256         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
    257         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
    258         assertEquals(1, logcat.getEvents().size());
    259         assertEquals(1, logcat.getJavaCrashes().size());
    260         assertNull(logcat.getJavaCrashes().get(0).getApp());
    261         assertEquals(1234, logcat.getJavaCrashes().get(0).getPid().intValue());
    262         assertNull(logcat.getJavaCrashes().get(0).getTid());
    263         assertEquals("", logcat.getJavaCrashes().get(0).getLastPreamble());
    264         assertEquals("", logcat.getJavaCrashes().get(0).getProcessPreamble());
    265         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    266                 logcat.getJavaCrashes().get(0).getEventTime());
    267     }
    268 
    269     /**
    270      * Test that Java crashes with process and pid without stack can be parsed.
    271      */
    272     public void testParse_java_crash_empty() throws ParseException {
    273         List<String> lines = Arrays.asList(
    274                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: FATAL EXCEPTION: main",
    275                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: PID: 1234");
    276 
    277         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    278         assertNotNull(logcat);
    279         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
    280         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
    281         assertEquals(0, logcat.getEvents().size());
    282         assertEquals(0, logcat.getJavaCrashes().size());
    283     }
    284 
    285     /**
    286      * Test that native crashes can be parsed from the info log level.
    287      */
    288     public void testParse_native_crash_info() throws ParseException {
    289         List<String> lines = Arrays.asList(
    290                 "04-25 18:33:27.273   115   115 I DEBUG   : Build fingerprint: 'product:build:target'",
    291                 "04-25 18:33:27.273   115   115 I DEBUG   : pid: 3112, tid: 3112  >>> com.google.android.browser <<<",
    292                 "04-25 18:33:27.273   115   115 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000");
    293 
    294         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    295         assertNotNull(logcat);
    296         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStartTime());
    297         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStopTime());
    298         assertEquals(1, logcat.getEvents().size());
    299         assertEquals(1, logcat.getNativeCrashes().size());
    300         assertEquals(3112, logcat.getNativeCrashes().get(0).getPid().intValue());
    301         assertEquals(3112, logcat.getNativeCrashes().get(0).getTid().intValue());
    302         assertEquals("com.google.android.browser", logcat.getNativeCrashes().get(0).getApp());
    303         assertEquals("", logcat.getNativeCrashes().get(0).getLastPreamble());
    304         assertEquals("", logcat.getNativeCrashes().get(0).getProcessPreamble());
    305         assertEquals(parseTime("2012-04-25 18:33:27.273"),
    306                 logcat.getNativeCrashes().get(0).getEventTime());
    307     }
    308 
    309     /**
    310      * Test that native crashes can be parsed from the fatal log level.
    311      */
    312     public void testParse_native_crash_fatal() throws ParseException {
    313         List<String> lines = Arrays.asList(
    314                 "04-25 18:33:27.273   115   115 F DEBUG   : Build fingerprint: 'product:build:target'",
    315                 "04-25 18:33:27.273   115   115 F DEBUG   : pid: 3112, tid: 3112, name: Name  >>> com.google.android.browser <<<",
    316                 "04-25 18:33:27.273   115   115 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000");
    317 
    318         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    319         assertNotNull(logcat);
    320         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStartTime());
    321         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStopTime());
    322         assertEquals(1, logcat.getEvents().size());
    323         assertEquals(1, logcat.getNativeCrashes().size());
    324         assertEquals(3112, logcat.getNativeCrashes().get(0).getPid().intValue());
    325         assertEquals(3112, logcat.getNativeCrashes().get(0).getTid().intValue());
    326         assertEquals("com.google.android.browser", logcat.getNativeCrashes().get(0).getApp());
    327         assertEquals("", logcat.getNativeCrashes().get(0).getLastPreamble());
    328         assertEquals("", logcat.getNativeCrashes().get(0).getProcessPreamble());
    329         assertEquals(parseTime("2012-04-25 18:33:27.273"),
    330                 logcat.getNativeCrashes().get(0).getEventTime());
    331     }
    332 
    333     /**
    334      * Test that native crashes can be parsed if they have the same pid/tid.
    335      */
    336     public void testParse_native_crash_same_pid() throws ParseException {
    337         List<String> lines = Arrays.asList(
    338                 "04-25 18:33:27.273   115   115 I DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***",
    339                 "04-25 18:33:27.273   115   115 I DEBUG   : Build fingerprint: 'product:build:target'",
    340                 "04-25 18:33:27.273   115   115 I DEBUG   : pid: 3112, tid: 3112  >>> com.google.android.browser <<<",
    341                 "04-25 18:33:27.273   115   115 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000",
    342                 "04-25 18:33:27.273   115   115 I DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***",
    343                 "04-25 18:33:27.273   115   115 I DEBUG   : Build fingerprint: 'product:build:target'",
    344                 "04-25 18:33:27.273   115   115 I DEBUG   : pid: 3113, tid: 3113  >>> com.google.android.browser2 <<<",
    345                 "04-25 18:33:27.273   115   115 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000");
    346 
    347         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    348         assertNotNull(logcat);
    349         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStartTime());
    350         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStopTime());
    351         assertEquals(2, logcat.getEvents().size());
    352         assertEquals(2, logcat.getNativeCrashes().size());
    353         assertEquals(3112, logcat.getNativeCrashes().get(0).getPid().intValue());
    354         assertEquals(3112, logcat.getNativeCrashes().get(0).getTid().intValue());
    355         assertEquals("com.google.android.browser", logcat.getNativeCrashes().get(0).getApp());
    356         assertEquals(3113, logcat.getNativeCrashes().get(1).getPid().intValue());
    357         assertEquals(3113, logcat.getNativeCrashes().get(1).getTid().intValue());
    358         assertEquals("com.google.android.browser2", logcat.getNativeCrashes().get(1).getApp());
    359     }
    360 
    361     public void testParse_misc_events() throws ParseException {
    362         List<String> lines = Arrays.asList(
    363                 "04-25 18:33:27.273  1676  1821 W AudioTrack: obtainBuffer timed out (is the CPU pegged?) 0x361378 user=0000116a, server=00000000",
    364                 "04-25 18:33:28.273  7813  7813 E gralloc : GetBufferLock timed out for thread 7813 buffer 0x61 usage 0x200 LockState 1",
    365                 "04-25 18:33:29.273   395   637 W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: null");
    366 
    367         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    368         assertNotNull(logcat);
    369         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStartTime());
    370         assertEquals(parseTime("2012-04-25 18:33:29.273"), logcat.getStopTime());
    371         assertEquals(3, logcat.getEvents().size());
    372         assertEquals(1, logcat.getMiscEvents(LogcatParser.HIGH_CPU_USAGE).size());
    373         assertEquals(1, logcat.getMiscEvents(LogcatParser.HIGH_MEMORY_USAGE).size());
    374         assertEquals(1, logcat.getMiscEvents(LogcatParser.RUNTIME_RESTART).size());
    375 
    376         MiscLogcatItem item = logcat.getMiscEvents(LogcatParser.HIGH_CPU_USAGE).get(0);
    377 
    378         assertEquals(1676, item.getPid().intValue());
    379         assertEquals(1821, item.getTid().intValue());
    380         assertEquals(parseTime("2012-04-25 18:33:27.273"), item.getEventTime());
    381 
    382         item = logcat.getMiscEvents(LogcatParser.HIGH_MEMORY_USAGE).get(0);
    383 
    384         assertEquals(7813, item.getPid().intValue());
    385         assertEquals(7813, item.getTid().intValue());
    386         assertEquals(parseTime("2012-04-25 18:33:28.273"), item.getEventTime());
    387 
    388         item = logcat.getMiscEvents(LogcatParser.RUNTIME_RESTART).get(0);
    389 
    390         assertEquals(395, item.getPid().intValue());
    391         assertEquals(637, item.getTid().intValue());
    392         assertEquals(parseTime("2012-04-25 18:33:29.273"), item.getEventTime());
    393     }
    394 
    395     /**
    396      * Test that multiple events can be parsed.
    397      */
    398     public void testParse_multiple_events() throws ParseException {
    399         List<String> lines = Arrays.asList(
    400                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    401                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    402                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    403                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)",
    404                 "04-25 09:55:47.799  3065  3090 E AndroidRuntime: java.lang.Exception",
    405                 "04-25 09:55:47.799  3065  3090 E AndroidRuntime: \tat class.method1(Class.java:1)",
    406                 "04-25 09:55:47.799  3065  3090 E AndroidRuntime: \tat class.method2(Class.java:2)",
    407                 "04-25 09:55:47.799  3065  3090 E AndroidRuntime: \tat class.method3(Class.java:3)",
    408                 "04-25 17:17:08.445   312   366 E ActivityManager: ANR (application not responding) in process: com.android.package",
    409                 "04-25 17:17:08.445   312   366 E ActivityManager: Reason: keyDispatchingTimedOut",
    410                 "04-25 17:17:08.445   312   366 E ActivityManager: Load: 0.71 / 0.83 / 0.51",
    411                 "04-25 17:17:08.445   312   366 E ActivityManager: 33% TOTAL: 21% user + 11% kernel + 0.3% iowait",
    412                 "04-25 17:17:08.445   312   366 E ActivityManager: ANR (application not responding) in process: com.android.package",
    413                 "04-25 17:17:08.445   312   366 E ActivityManager: Reason: keyDispatchingTimedOut",
    414                 "04-25 17:17:08.445   312   366 E ActivityManager: Load: 0.71 / 0.83 / 0.51",
    415                 "04-25 17:17:08.445   312   366 E ActivityManager: 33% TOTAL: 21% user + 11% kernel + 0.3% iowait",
    416                 "04-25 18:33:27.273   115   115 I DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***",
    417                 "04-25 18:33:27.273   115   115 I DEBUG   : Build fingerprint: 'product:build:target'",
    418                 "04-25 18:33:27.273   115   115 I DEBUG   : pid: 3112, tid: 3112  >>> com.google.android.browser <<<",
    419                 "04-25 18:33:27.273   115   115 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000",
    420                 "04-25 18:33:27.273   117   117 I DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***",
    421                 "04-25 18:33:27.273   117   117 I DEBUG   : Build fingerprint: 'product:build:target'",
    422                 "04-25 18:33:27.273   117   117 I DEBUG   : pid: 3113, tid: 3113  >>> com.google.android.browser <<<",
    423                 "04-25 18:33:27.273   117   117 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000");
    424 
    425 
    426         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    427         assertNotNull(logcat);
    428         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
    429         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStopTime());
    430         assertEquals(6, logcat.getEvents().size());
    431         assertEquals(2, logcat.getAnrs().size());
    432         assertEquals(2, logcat.getJavaCrashes().size());
    433         assertEquals(2, logcat.getNativeCrashes().size());
    434 
    435         assertEquals(312, logcat.getAnrs().get(0).getPid().intValue());
    436         assertEquals(366, logcat.getAnrs().get(0).getTid().intValue());
    437         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getAnrs().get(0).getEventTime());
    438 
    439         assertEquals(312, logcat.getAnrs().get(1).getPid().intValue());
    440         assertEquals(366, logcat.getAnrs().get(1).getTid().intValue());
    441         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getAnrs().get(1).getEventTime());
    442 
    443         assertEquals(3064, logcat.getJavaCrashes().get(0).getPid().intValue());
    444         assertEquals(3082, logcat.getJavaCrashes().get(0).getTid().intValue());
    445         assertEquals(
    446                 parseTime("2012-04-25 09:55:47.799"),
    447                 logcat.getJavaCrashes().get(0).getEventTime());
    448 
    449         assertEquals(3065, logcat.getJavaCrashes().get(1).getPid().intValue());
    450         assertEquals(3090, logcat.getJavaCrashes().get(1).getTid().intValue());
    451         assertEquals(
    452                 parseTime("2012-04-25 09:55:47.799"),
    453                 logcat.getJavaCrashes().get(1).getEventTime());
    454 
    455         assertEquals(3112, logcat.getNativeCrashes().get(0).getPid().intValue());
    456         assertEquals(3112, logcat.getNativeCrashes().get(0).getTid().intValue());
    457         assertEquals(
    458                 parseTime("2012-04-25 18:33:27.273"),
    459                 logcat.getNativeCrashes().get(0).getEventTime());
    460 
    461         assertEquals(3113, logcat.getNativeCrashes().get(1).getPid().intValue());
    462         assertEquals(3113, logcat.getNativeCrashes().get(1).getTid().intValue());
    463         assertEquals(
    464                 parseTime("2012-04-25 18:33:27.273"),
    465                 logcat.getNativeCrashes().get(1).getEventTime());
    466     }
    467 
    468     /** Test that including extra uid column still parses the logs. */
    469     public void testParse_uid() throws ParseException {
    470         List<String> lines =
    471                 Arrays.asList(
    472                         "04-25 09:55:47.799  wifi  3064  3082 E AndroidRuntime: java.lang.Exception",
    473                         "04-25 09:55:47.799  wifi  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    474                         "04-25 09:55:47.799  wifi  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    475                         "04-25 09:55:47.799  wifi  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)",
    476                         "04-25 09:55:47.799  wifi  3065  3090 E AndroidRuntime: java.lang.Exception",
    477                         "04-25 09:55:47.799  wifi  3065  3090 E AndroidRuntime: \tat class.method1(Class.java:1)",
    478                         "04-25 09:55:47.799  wifi  3065  3090 E AndroidRuntime: \tat class.method2(Class.java:2)",
    479                         "04-25 09:55:47.799  wifi  3065  3090 E AndroidRuntime: \tat class.method3(Class.java:3)",
    480                         "04-25 17:17:08.445  1337  312   366 E ActivityManager: ANR (application not responding) in process: com.android.package",
    481                         "04-25 17:17:08.445  1337  312   366 E ActivityManager: Reason: keyDispatchingTimedOut",
    482                         "04-25 17:17:08.445  1337  312   366 E ActivityManager: Load: 0.71 / 0.83 / 0.51",
    483                         "04-25 17:17:08.445  1337  312   366 E ActivityManager: 33% TOTAL: 21% user + 11% kernel + 0.3% iowait",
    484                         "04-25 17:17:08.445  1337  312   366 E ActivityManager: ANR (application not responding) in process: com.android.package",
    485                         "04-25 17:17:08.445  1337  312   366 E ActivityManager: Reason: keyDispatchingTimedOut",
    486                         "04-25 17:17:08.445  1337  312   366 E ActivityManager: Load: 0.71 / 0.83 / 0.51",
    487                         "04-25 17:17:08.445  1337  312   366 E ActivityManager: 33% TOTAL: 21% user + 11% kernel + 0.3% iowait",
    488                         "04-25 18:33:27.273  wifi123  115   115 I DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***",
    489                         "04-25 18:33:27.273  wifi123  115   115 I DEBUG   : Build fingerprint: 'product:build:target'",
    490                         "04-25 18:33:27.273  wifi123  115   115 I DEBUG   : pid: 3112, tid: 3112  >>> com.google.android.browser <<<",
    491                         "04-25 18:33:27.273  wifi123  115   115 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000",
    492                         "04-25 18:33:27.273  wifi123  117   117 I DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***",
    493                         "04-25 18:33:27.273  wifi123  117   117 I DEBUG   : Build fingerprint: 'product:build:target'",
    494                         "04-25 18:33:27.273  wifi123  117   117 I DEBUG   : pid: 3113, tid: 3113  >>> com.google.android.browser <<<",
    495                         "04-25 18:33:27.273  wifi123  117   117 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000");
    496 
    497 
    498         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    499         assertNotNull(logcat);
    500         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
    501         assertEquals(parseTime("2012-04-25 18:33:27.273"), logcat.getStopTime());
    502         assertEquals(6, logcat.getEvents().size());
    503         assertEquals(2, logcat.getAnrs().size());
    504         assertEquals(2, logcat.getJavaCrashes().size());
    505         assertEquals(2, logcat.getNativeCrashes().size());
    506 
    507         assertEquals(312, logcat.getAnrs().get(0).getPid().intValue());
    508         assertEquals(366, logcat.getAnrs().get(0).getTid().intValue());
    509         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getAnrs().get(0).getEventTime());
    510 
    511         assertEquals(312, logcat.getAnrs().get(1).getPid().intValue());
    512         assertEquals(366, logcat.getAnrs().get(1).getTid().intValue());
    513         assertEquals(parseTime("2012-04-25 17:17:08.445"), logcat.getAnrs().get(1).getEventTime());
    514 
    515         assertEquals(3064, logcat.getJavaCrashes().get(0).getPid().intValue());
    516         assertEquals(3082, logcat.getJavaCrashes().get(0).getTid().intValue());
    517         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    518                 logcat.getJavaCrashes().get(0).getEventTime());
    519 
    520         assertEquals(3065, logcat.getJavaCrashes().get(1).getPid().intValue());
    521         assertEquals(3090, logcat.getJavaCrashes().get(1).getTid().intValue());
    522         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    523                 logcat.getJavaCrashes().get(1).getEventTime());
    524 
    525         assertEquals(3112, logcat.getNativeCrashes().get(0).getPid().intValue());
    526         assertEquals(3112, logcat.getNativeCrashes().get(0).getTid().intValue());
    527         assertEquals(parseTime("2012-04-25 18:33:27.273"),
    528                 logcat.getNativeCrashes().get(0).getEventTime());
    529 
    530         assertEquals(3113, logcat.getNativeCrashes().get(1).getPid().intValue());
    531         assertEquals(3113, logcat.getNativeCrashes().get(1).getTid().intValue());
    532         assertEquals(parseTime("2012-04-25 18:33:27.273"),
    533                 logcat.getNativeCrashes().get(1).getEventTime());
    534     }
    535 
    536     /**
    537      * Test that multiple java crashes and native crashes can be parsed even when interleaved.
    538      */
    539     public void testParse_multiple_events_interleaved() throws ParseException {
    540         List<String> lines = Arrays.asList(
    541                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    542                 "04-25 09:55:47.799  3065  3090 E AndroidRuntime: java.lang.Exception",
    543                 "04-25 09:55:47.799   115   115 I DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***",
    544                 "04-25 09:55:47.799   117   117 I DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***",
    545                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    546                 "04-25 09:55:47.799  3065  3090 E AndroidRuntime: \tat class.method1(Class.java:1)",
    547                 "04-25 09:55:47.799   115   115 I DEBUG   : Build fingerprint: 'product:build:target'",
    548                 "04-25 09:55:47.799   117   117 I DEBUG   : Build fingerprint: 'product:build:target'",
    549                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    550                 "04-25 09:55:47.799  3065  3090 E AndroidRuntime: \tat class.method2(Class.java:2)",
    551                 "04-25 09:55:47.799   115   115 I DEBUG   : pid: 3112, tid: 3112  >>> com.google.android.browser <<<",
    552                 "04-25 09:55:47.799   117   117 I DEBUG   : pid: 3113, tid: 3113  >>> com.google.android.browser <<<",
    553                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)",
    554                 "04-25 09:55:47.799  3065  3090 E AndroidRuntime: \tat class.method3(Class.java:3)",
    555                 "04-25 09:55:47.799   115   115 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000",
    556                 "04-25 09:55:47.799   117   117 I DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000");
    557 
    558         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    559         assertNotNull(logcat);
    560         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
    561         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
    562         assertEquals(4, logcat.getEvents().size());
    563         assertEquals(0, logcat.getAnrs().size());
    564         assertEquals(2, logcat.getJavaCrashes().size());
    565         assertEquals(2, logcat.getNativeCrashes().size());
    566 
    567         assertEquals(3064, logcat.getJavaCrashes().get(0).getPid().intValue());
    568         assertEquals(3082, logcat.getJavaCrashes().get(0).getTid().intValue());
    569         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    570                 logcat.getJavaCrashes().get(0).getEventTime());
    571 
    572         assertEquals(3065, logcat.getJavaCrashes().get(1).getPid().intValue());
    573         assertEquals(3090, logcat.getJavaCrashes().get(1).getTid().intValue());
    574         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    575                 logcat.getJavaCrashes().get(1).getEventTime());
    576 
    577         assertEquals(3112, logcat.getNativeCrashes().get(0).getPid().intValue());
    578         assertEquals(3112, logcat.getNativeCrashes().get(0).getTid().intValue());
    579         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    580                 logcat.getNativeCrashes().get(0).getEventTime());
    581 
    582         assertEquals(3113, logcat.getNativeCrashes().get(1).getPid().intValue());
    583         assertEquals(3113, logcat.getNativeCrashes().get(1).getTid().intValue());
    584         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    585                 logcat.getNativeCrashes().get(1).getEventTime());
    586     }
    587 
    588     /**
    589      * Test that the preambles are set correctly.
    590      */
    591     public void testParse_preambles() throws ParseException {
    592         List<String> lines = Arrays.asList(
    593                 "04-25 09:15:47.799   123  3082 I tag: message 1",
    594                 "04-25 09:20:47.799  3064  3082 I tag: message 2",
    595                 "04-25 09:25:47.799   345  3082 I tag: message 3",
    596                 "04-25 09:30:47.799  3064  3082 I tag: message 4",
    597                 "04-25 09:35:47.799   456  3082 I tag: message 5",
    598                 "04-25 09:40:47.799  3064  3082 I tag: message 6",
    599                 "04-25 09:45:47.799   567  3082 I tag: message 7",
    600                 "04-25 09:50:47.799  3064  3082 I tag: message 8",
    601                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    602                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    603                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    604                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)");
    605 
    606         List<String> expectedLastPreamble = Arrays.asList(
    607                 "04-25 09:15:47.799   123  3082 I tag: message 1",
    608                 "04-25 09:20:47.799  3064  3082 I tag: message 2",
    609                 "04-25 09:25:47.799   345  3082 I tag: message 3",
    610                 "04-25 09:30:47.799  3064  3082 I tag: message 4",
    611                 "04-25 09:35:47.799   456  3082 I tag: message 5",
    612                 "04-25 09:40:47.799  3064  3082 I tag: message 6",
    613                 "04-25 09:45:47.799   567  3082 I tag: message 7",
    614                 "04-25 09:50:47.799  3064  3082 I tag: message 8");
    615 
    616         List<String> expectedProcPreamble = Arrays.asList(
    617                 "04-25 09:20:47.799  3064  3082 I tag: message 2",
    618                 "04-25 09:30:47.799  3064  3082 I tag: message 4",
    619                 "04-25 09:40:47.799  3064  3082 I tag: message 6",
    620                 "04-25 09:50:47.799  3064  3082 I tag: message 8");
    621 
    622         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    623         assertNotNull(logcat);
    624         assertEquals(parseTime("2012-04-25 09:15:47.799"), logcat.getStartTime());
    625         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
    626         assertEquals(1, logcat.getEvents().size());
    627         assertEquals(1, logcat.getJavaCrashes().size());
    628         assertEquals(3064, logcat.getJavaCrashes().get(0).getPid().intValue());
    629         assertEquals(3082, logcat.getJavaCrashes().get(0).getTid().intValue());
    630         assertEquals(ArrayUtil.join("\n", expectedLastPreamble),
    631                 logcat.getJavaCrashes().get(0).getLastPreamble());
    632         assertEquals(ArrayUtil.join("\n", expectedProcPreamble),
    633                 logcat.getJavaCrashes().get(0).getProcessPreamble());
    634         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    635                 logcat.getJavaCrashes().get(0).getEventTime());
    636     }
    637 
    638     /**
    639      * Test that events while the device is rebooting are ignored.
    640      */
    641     public void testParse_reboot() throws ParseException {
    642         List<String> lines = Arrays.asList(
    643                 "04-25 09:15:47.799   123  3082 I ShutdownThread: Rebooting, reason: null",
    644                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    645                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    646                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    647                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)");
    648 
    649         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    650         assertNotNull(logcat);
    651         assertEquals(parseTime("2012-04-25 09:15:47.799"), logcat.getStartTime());
    652         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
    653         assertEquals(0, logcat.getEvents().size());
    654     }
    655 
    656     /**
    657      * Test that events while the device is rebooting are ignored, but devices after the reboot are
    658      * captured.
    659      */
    660     public void testParse_reboot_resume() throws ParseException {
    661         List<String> lines = Arrays.asList(
    662                 "04-25 09:15:47.799   123  3082 I ShutdownThread: Rebooting, reason: null",
    663                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    664                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    665                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    666                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)",
    667                 "logcat interrupted. May see duplicated content in log.--------- beginning of /dev/log/main",
    668                 "04-25 09:59:47.799  3064  3082 E AndroidRuntime: java.lang.Exception2",
    669                 "04-25 09:59:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    670                 "04-25 09:59:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    671                 "04-25 09:59:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)");
    672 
    673 
    674         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    675         assertNotNull(logcat);
    676         assertEquals(parseTime("2012-04-25 09:15:47.799"), logcat.getStartTime());
    677         assertEquals(parseTime("2012-04-25 09:59:47.799"), logcat.getStopTime());
    678         assertEquals(1, logcat.getEvents().size());
    679         assertEquals("java.lang.Exception2", logcat.getJavaCrashes().get(0).getException());
    680 
    681         lines = Arrays.asList(
    682                 "04-25 09:15:47.799   123  3082 I ShutdownThread: Rebooting, reason: null",
    683                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: java.lang.Exception",
    684                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    685                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    686                 "04-25 09:55:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)",
    687                 "logcat interrupted. May see duplicated content in log.--------- beginning of main",
    688                 "04-25 09:59:47.799  3064  3082 E AndroidRuntime: java.lang.Exception2",
    689                 "04-25 09:59:47.799  3064  3082 E AndroidRuntime: \tat class.method1(Class.java:1)",
    690                 "04-25 09:59:47.799  3064  3082 E AndroidRuntime: \tat class.method2(Class.java:2)",
    691                 "04-25 09:59:47.799  3064  3082 E AndroidRuntime: \tat class.method3(Class.java:3)");
    692 
    693 
    694         logcat = new LogcatParser("2012").parse(lines);
    695         assertNotNull(logcat);
    696         assertEquals(parseTime("2012-04-25 09:15:47.799"), logcat.getStartTime());
    697         assertEquals(parseTime("2012-04-25 09:59:47.799"), logcat.getStopTime());
    698         assertEquals(1, logcat.getEvents().size());
    699         assertEquals("java.lang.Exception2", logcat.getJavaCrashes().get(0).getException());
    700     }
    701 
    702     /**
    703      * Test that the time logcat format can be parsed.
    704      */
    705     public void testParse_time() throws ParseException {
    706         List<String> lines = Arrays.asList(
    707                 "04-25 09:55:47.799  E/AndroidRuntime(3064): java.lang.Exception",
    708                 "04-25 09:55:47.799  E/AndroidRuntime(3064): \tat class.method1(Class.java:1)",
    709                 "04-25 09:55:47.799  E/AndroidRuntime(3064): \tat class.method2(Class.java:2)",
    710                 "04-25 09:55:47.799  E/AndroidRuntime(3064): \tat class.method3(Class.java:3)");
    711 
    712         LogcatItem logcat = new LogcatParser("2012").parse(lines);
    713         assertNotNull(logcat);
    714         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStartTime());
    715         assertEquals(parseTime("2012-04-25 09:55:47.799"), logcat.getStopTime());
    716         assertEquals(1, logcat.getEvents().size());
    717         assertEquals(1, logcat.getJavaCrashes().size());
    718         assertEquals(3064, logcat.getJavaCrashes().get(0).getPid().intValue());
    719         assertNull(logcat.getJavaCrashes().get(0).getTid());
    720         assertEquals(parseTime("2012-04-25 09:55:47.799"),
    721                 logcat.getJavaCrashes().get(0).getEventTime());
    722     }
    723 
    724     /**
    725      * Test that we can add and find custom patterns that match based on logcat Tags only.
    726      */
    727     public void testAddPattern_byTagOnly() {
    728         List<String> lines = Arrays.asList(
    729                 "04-25 18:33:28.273  7813  7813 E HelloTag: Hello everyone!!!1",
    730                 "04-25 18:33:29.273   395   637 I Watchdog: find me!",
    731                 "04-25 18:33:39.273   395   637 W Watchdog: find me!");
    732 
    733         LogcatParser parser = new LogcatParser("2012");
    734         assertNotNull(parser);
    735         parser.addPattern(null, null, "HelloTag", "HelloCategory");
    736         parser.addPattern(null, null, "Watchdog", "WatchdogCategory");
    737         LogcatItem logcat = parser.parse(lines);
    738         assertNotNull(logcat);
    739 
    740         /* verify that we find the HelloTag entry */
    741         List<MiscLogcatItem> matchedEvents = logcat.getMiscEvents("HelloCategory");
    742         assertEquals(1, matchedEvents.size());
    743         assertEquals("HelloTag", matchedEvents.get(0).getTag());
    744 
    745         /* verify that we find both Watchdog entries */
    746         matchedEvents = logcat.getMiscEvents("WatchdogCategory");
    747         assertEquals(2, matchedEvents.size());
    748         assertEquals("Watchdog", matchedEvents.get(0).getTag());
    749     }
    750 
    751     /**
    752      * Test that we can add and find custom patterns that match based on Level AND Tag.
    753      */
    754     public void testAddPattern_byLevelAndTagOnly() {
    755         List<String> lines = Arrays.asList(
    756                 "04-25 18:33:28.273  7813  7813 E HelloTag: GetBufferLock timed out for thread 7813 buffer 0x61 usage 0x200 LockState 1",
    757                 "04-25 18:33:29.273   395   637 I Watchdog: Info",
    758                 "04-25 18:33:29.273   395   637 W Watchdog: Warning");
    759 
    760         LogcatParser parser = new LogcatParser("2012");
    761         assertNotNull(parser);
    762         parser.addPattern(null, "I", "Watchdog", "WatchdogCategory");
    763         LogcatItem logcat = parser.parse(lines);
    764         assertNotNull(logcat);
    765 
    766         List<MiscLogcatItem> matchedEvents = logcat.getMiscEvents("WatchdogCategory");
    767         assertEquals(1, matchedEvents.size());
    768         assertEquals("Watchdog", matchedEvents.get(0).getTag());
    769         assertEquals("Info", matchedEvents.get(0).getStack());
    770     }
    771 
    772     /**
    773      * Test that we can add and find custom patterns that match based on Level, Tag, AND Message.
    774      */
    775     public void testAddPattern_byLevelTagAndMessageOnly() {
    776         List<String> lines = Arrays.asList(
    777                 "04-25 18:33:29.273   395   637 W Watchdog: I'm the one you need to find!",
    778                 "04-25 18:33:29.273   395   637 W Watchdog: my message doesn't match.",
    779                 "04-25 18:33:29.273   395   637 I Watchdog: my Level doesn't match, try and find me!",
    780                 "04-25 18:33:29.273   395   637 W NotMe: my Tag doesn't match, try and find me!");
    781 
    782         LogcatParser parser = new LogcatParser("2012");
    783         assertNotNull(parser);
    784         parser.addPattern(Pattern.compile(".*find*."), "W", "Watchdog", "WatchdogCategory");
    785         LogcatItem logcat = parser.parse(lines);
    786         assertNotNull(logcat);
    787 
    788         /* verify that we find the only entry that matches based on Level, Tag, AND Message */
    789         List<MiscLogcatItem> matchedEvents = logcat.getMiscEvents("WatchdogCategory");
    790         assertEquals(1, matchedEvents.size());
    791         assertEquals("Watchdog", matchedEvents.get(0).getTag());
    792         assertEquals("I'm the one you need to find!", matchedEvents.get(0).getStack());
    793     }
    794 
    795     public void testFatalException() {
    796         List<String> lines = Arrays.asList(
    797                 "06-05 06:14:51.529  1712  1712 D AndroidRuntime: Calling main entry com.android.commands.input.Input",
    798                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: main",
    799                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: java.lang.NullPointerException",
    800                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat android.hardware.input.InputManager.injectInputEvent(InputManager.java:641)",
    801                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.commands.input.Input.injectKeyEvent(Input.java:233)",
    802                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.commands.input.Input.sendKeyEvent(Input.java:184)",
    803                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.commands.input.Input.run(Input.java:96)",
    804                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.commands.input.Input.main(Input.java:59)",
    805                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)",
    806                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat com.android.internal.os.RuntimeInit.main(RuntimeInit.java:243)",
    807                 "06-05 06:14:51.709  1712  1712 E AndroidRuntime: \tat dalvik.system.NativeStart.main(Native Method)");
    808         LogcatParser parser = new LogcatParser("2014");
    809         LogcatItem logcat = parser.parse(lines);
    810         assertEquals(1, logcat.getJavaCrashes().size());
    811         JavaCrashItem crash = logcat.getJavaCrashes().get(0);
    812         assertEquals("com.android.commands.input.Input", crash.getApp());
    813     }
    814 
    815     /**
    816      * Test that an empty input returns {@code null}.
    817      */
    818     public void testEmptyInput() {
    819         LogcatItem item = new LogcatParser().parse(Arrays.asList(""));
    820         assertNull(item);
    821     }
    822 
    823     /**
    824      * Test that after clearing a parser, reusing it produces a new LogcatItem instead of
    825      * appending to the previous one.
    826      */
    827     public void testClear() {
    828         List<String> lines = Arrays.asList(
    829                 "04-25 18:33:28.273  7813  7813 E HelloTag: GetBufferLock timed out for thread 7813 buffer 0x61 usage 0x200 LockState 1",
    830                 "04-25 18:33:28.273  7813  7813 E GoodbyeTag: GetBufferLock timed out for thread 7813 buffer 0x61 usage 0x200 LockState 1"
    831                 );
    832         LogcatParser parser = new LogcatParser();
    833         LogcatItem l1 = parser.parse(lines.subList(0, 1));
    834         parser.clear();
    835         LogcatItem l2 = parser.parse(lines.subList(1, 2));
    836         assertEquals(l1.getEvents().size(), 1);
    837         assertEquals(l2.getEvents().size(), 1);
    838         assertFalse(l1.getEvents().get(0).getTag().equals(l2.getEvents().get(0).getTag()));
    839     }
    840 
    841     private Date parseTime(String timeStr) throws ParseException {
    842         DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    843         return formatter.parse(timeStr);
    844     }
    845 }
    846