| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.loganalysis.parser; |
| |
| import com.android.loganalysis.item.DmesgActionInfoItem; |
| import com.android.loganalysis.item.DmesgItem; |
| import com.android.loganalysis.item.DmesgServiceInfoItem; |
| import com.android.loganalysis.item.DmesgStageInfoItem; |
| import java.io.BufferedReader; |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import junit.framework.TestCase; |
| |
| /** |
| * Unit tests for {@link DmesgParser}. |
| */ |
| public class DmesgParserTest extends TestCase { |
| |
| private static final String BOOT_ANIMATION = "bootanim"; |
| private static final String NETD = "netd"; |
| private static final String[] LINES = new String[] { |
| "[ 3.786943] ueventd: Coldboot took 0.701291 seconds", |
| "[ 22.962730] init: starting service 'bootanim'...", |
| "[ 23.252321] init: starting service 'netd'...", |
| "[ 29.331069] ipa-wan ipa_wwan_ioctl:1428 dev(rmnet_data0) register to IPA", |
| "[ 32.182592] ueventd: fixup /sys/devices/virtual/input/poll_delay 0 1004 660", |
| "[ 35.642666] SELinux: initialized (dev fuse, type fuse), uses genfs_contexts", |
| "[ 39.855818] init: Service 'bootanim' (pid 588) exited with status 0", |
| "[ 41.665818] init: init first stage started!", |
| "[ 44.942872] init: processing action (early-init) from (/init.rc:13)", |
| "[ 47.233446] init: processing action (set_mmap_rnd_bits) from (<Builtin Action>:0)", |
| "[ 47.240083] init: processing action (set_kptr_restrict) from (<Builtin Action>:0)", |
| "[ 47.245778] init: processing action (keychord_init) from (<Builtin Action>:0)", |
| "[ 52.361049] init: processing action (persist.sys.usb.config=* boot) from (<Builtin Action>:0)", |
| "[ 52.361108] init: processing action (enable_property_trigger) from (<Builtin Action>:0)", |
| "[ 52.361313] init: processing action (security.perf_harden=1) from (/init.rc:677)", |
| "[ 52.361495] init: processing action (ro.debuggable=1) from (/init.rc:700)", |
| "[ 59.331069] ipa-wan ipa_wwan_ioctl:1428 dev(rmnet_data0) register to IPA", |
| "[ 62.182592] ueventd: fixup /sys/devices/virtual/input/poll_delay 0 1004 660", |
| "[ 65.642666] SELinux: initialized (dev fuse, type fuse), uses genfs_contexts", |
| "[ 69.855818] init: Service 'bootanim' (pid 588) exited with status 0"}; |
| |
| private static final Map<String, DmesgServiceInfoItem> EXPECTED_SERVICE_INFO_ITEMS = |
| getExpectedServiceInfoItems(); |
| |
| private static final List<DmesgStageInfoItem> EXPECTED_STAGE_INFO_ITEMS = |
| getExpectedStageInfoItems(); |
| |
| private static final List<DmesgActionInfoItem> EXPECTED_ACTION_INFO_ITEMS = |
| getExpectedActionInfoItems(); |
| |
| /** |
| * Test for empty dmesg logs passed to the DmesgParser |
| */ |
| public void testEmptyDmesgLog() throws IOException { |
| String[] lines = new String[] {""}; |
| try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( |
| new ByteArrayInputStream(String.join("\n", lines).getBytes())))) { |
| DmesgParser dmesgParser = new DmesgParser(); |
| dmesgParser.parseInfo(bufferedReader); |
| assertEquals("Service info items list should be empty", 0, |
| dmesgParser.getServiceInfoItems().size()); |
| } |
| } |
| |
| /** |
| * Test for complete dmesg logs passed as list of strings |
| */ |
| public void testCompleteDmesgLog_passedAsList() { |
| |
| DmesgParser dmesgParser = new DmesgParser(); |
| DmesgItem actualDmesgItem = dmesgParser.parse(Arrays.asList(LINES)); |
| |
| assertEquals("Service info items list size should be 2", 2, |
| dmesgParser.getServiceInfoItems().size()); |
| assertEquals("Stage info items list size should be 2", 2, |
| dmesgParser.getStageInfoItems().size()); |
| assertEquals("Action info items list size should be 8", 8, |
| dmesgParser.getActionInfoItems().size()); |
| |
| assertEquals(EXPECTED_SERVICE_INFO_ITEMS, actualDmesgItem.getServiceInfoItems()); |
| assertEquals(EXPECTED_STAGE_INFO_ITEMS, actualDmesgItem.getStageInfoItems()); |
| assertEquals(EXPECTED_ACTION_INFO_ITEMS, actualDmesgItem.getActionInfoItems()); |
| } |
| |
| /** |
| * Test for complete dmesg logs passed as buffered input |
| */ |
| public void testCompleteDmesgLog_passedAsBufferedInput() throws IOException { |
| try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( |
| new ByteArrayInputStream(String.join("\n", LINES).getBytes())))) { |
| DmesgParser dmesgParser = new DmesgParser(); |
| dmesgParser.parseInfo(bufferedReader); |
| assertEquals("Service info items list size should be 2", 2, |
| dmesgParser.getServiceInfoItems().size()); |
| assertEquals("Stage info items list size should be 2", 2, |
| dmesgParser.getStageInfoItems().size()); |
| assertEquals("Action info items list size should be 8", 8, |
| dmesgParser.getActionInfoItems().size()); |
| } |
| } |
| |
| /** |
| * Test service which logs both the start and end time |
| */ |
| public void testCompleteServiceInfo() { |
| DmesgParser dmesgParser = new DmesgParser(); |
| for (String line : LINES) { |
| dmesgParser.parseServiceInfo(line); |
| } |
| |
| assertEquals("There should be two service infos", 2, |
| dmesgParser.getServiceInfoItems().size()); |
| assertEquals(EXPECTED_SERVICE_INFO_ITEMS, dmesgParser.getServiceInfoItems()); |
| } |
| |
| /** |
| * Test service which logs only the start time |
| */ |
| public void testStartServiceInfo() { |
| DmesgParser dmesgParser = new DmesgParser(); |
| for (String line : LINES) { |
| dmesgParser.parseServiceInfo(line); |
| } |
| List<DmesgServiceInfoItem> serviceInfoItems = new ArrayList<>( |
| dmesgParser.getServiceInfoItems().values()); |
| assertEquals("There should be exactly two service infos", 2, serviceInfoItems.size()); |
| assertEquals("Service name is not bootanim", BOOT_ANIMATION, |
| serviceInfoItems.get(0).getServiceName()); |
| assertEquals("Service name is not netd", NETD, serviceInfoItems.get(1).getServiceName()); |
| } |
| |
| /** |
| * Test multiple service info parsed correctly and stored in the same order logged in |
| * the file. |
| */ |
| public void testMultipleServiceInfo() { |
| DmesgParser dmesgParser = new DmesgParser(); |
| for (String line : LINES) { |
| dmesgParser.parseServiceInfo(line); |
| } |
| assertEquals("There should be exactly two service info", 2, |
| dmesgParser.getServiceInfoItems().size()); |
| assertEquals(EXPECTED_SERVICE_INFO_ITEMS, dmesgParser.getServiceInfoItems()); |
| } |
| |
| /** |
| * Test invalid patterns on the start and exit service logs |
| */ |
| public void testInvalidServiceLogs() { |
| // Added space at the end of the start and exit of service logs to make it invalid |
| String[] lines = new String[] { |
| "[ 22.962730] init: starting service 'bootanim'... ", |
| "[ 23.252321] init: starting service 'netd'... ", |
| "[ 29.331069] ipa-wan ipa_wwan_ioctl:1428 dev(rmnet_data0) register to IPA", |
| "[ 32.182592] ueventd: fixup /sys/devices/virtual/input/poll_delay 0 1004 660", |
| "[ 35.642666] SELinux: initialized (dev fuse, type fuse), uses genfs_contexts", |
| "[ 39.855818] init: Service 'bootanim' (pid 588) exited with status 0 "}; |
| DmesgParser dmesgParser = new DmesgParser(); |
| for (String line : lines) { |
| dmesgParser.parseServiceInfo(line); |
| } |
| List<DmesgServiceInfoItem> serviceInfoItems = new ArrayList<>( |
| dmesgParser.getServiceInfoItems().values()); |
| assertEquals("No service info should be available", 0, serviceInfoItems.size()); |
| } |
| |
| /** |
| * Test init stages' start time logs |
| */ |
| public void testCompleteStageInfo() { |
| DmesgParser dmesgParser = new DmesgParser(); |
| for (String line : LINES) { |
| dmesgParser.parseStageInfo(line); |
| } |
| List<DmesgStageInfoItem> stageInfoItems = dmesgParser.getStageInfoItems(); |
| assertEquals(2, stageInfoItems.size()); |
| assertEquals(EXPECTED_STAGE_INFO_ITEMS, stageInfoItems); |
| } |
| |
| /** |
| * Test processing action start time logs |
| */ |
| public void testCompleteActionInfo() { |
| DmesgParser dmesgParser = new DmesgParser(); |
| for (String line : LINES) { |
| dmesgParser.parseActionInfo(line); |
| } |
| List<DmesgActionInfoItem> actualActionInfoItems = dmesgParser.getActionInfoItems(); |
| assertEquals(8, actualActionInfoItems.size()); |
| assertEquals(EXPECTED_ACTION_INFO_ITEMS, actualActionInfoItems); |
| } |
| |
| private static List<DmesgActionInfoItem> getExpectedActionInfoItems() { |
| return Arrays.asList( |
| new DmesgActionInfoItem("early-init", (long) (Double.parseDouble("44942.872"))), |
| new DmesgActionInfoItem("set_mmap_rnd_bits", |
| (long) (Double.parseDouble("47233.446"))), |
| new DmesgActionInfoItem("set_kptr_restrict", |
| (long) (Double.parseDouble("47240.083"))), |
| new DmesgActionInfoItem("keychord_init", (long) (Double.parseDouble("47245.778"))), |
| new DmesgActionInfoItem("persist.sys.usb.config=* boot", |
| (long) (Double.parseDouble("52361.049"))), |
| new DmesgActionInfoItem("enable_property_trigger", |
| (long) (Double.parseDouble("52361.108"))), |
| new DmesgActionInfoItem("security.perf_harden=1", |
| (long) (Double.parseDouble("52361.313"))), |
| new DmesgActionInfoItem("ro.debuggable=1", |
| (long) (Double.parseDouble("52361.495")))); |
| } |
| |
| private static List<DmesgStageInfoItem> getExpectedStageInfoItems() { |
| return Arrays.asList( |
| new DmesgStageInfoItem("ueventd_Coldboot", null, 701L), |
| new DmesgStageInfoItem("first", 41665L, null)); |
| } |
| |
| private static Map<String, DmesgServiceInfoItem> getExpectedServiceInfoItems() { |
| Map<String, DmesgServiceInfoItem> serviceInfoItemsMap = new HashMap<>(); |
| DmesgServiceInfoItem bootanimServiceInfoItem = new DmesgServiceInfoItem(); |
| bootanimServiceInfoItem.setServiceName(BOOT_ANIMATION); |
| bootanimServiceInfoItem.setStartTime(22962L); |
| bootanimServiceInfoItem.setEndTime(69855L); |
| |
| DmesgServiceInfoItem netdServiceInfoItem = new DmesgServiceInfoItem(); |
| netdServiceInfoItem.setServiceName(NETD); |
| netdServiceInfoItem.setStartTime(23252L); |
| |
| serviceInfoItemsMap.put(BOOT_ANIMATION, bootanimServiceInfoItem); |
| serviceInfoItemsMap.put(NETD, netdServiceInfoItem); |
| |
| return serviceInfoItemsMap; |
| } |
| |
| } |