1 /* 2 * Copyright (C) 2021 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 17 package android.car.cts.builtin.util; 18 19 import static org.junit.Assert.fail; 20 21 import android.app.UiAutomation; 22 import android.car.cts.builtin.util.LogcatHelper.Level; 23 import android.os.ParcelFileDescriptor; 24 import android.os.SystemClock; 25 import android.util.Log; 26 27 import androidx.test.platform.app.InstrumentationRegistry; 28 29 import com.android.compatibility.common.util.SystemUtil; 30 31 import java.io.BufferedReader; 32 import java.io.FileDescriptor; 33 import java.io.FileInputStream; 34 import java.io.IOException; 35 import java.io.InputStreamReader; 36 37 public final class LogcatHelper { 38 39 private static final String TAG = LogcatHelper.class.getSimpleName(); 40 41 private static final boolean VERBOSE = false; 42 43 private static final int DEFAULT_TIMEOUT_MS = 60_000; 44 LogcatHelper()45 private LogcatHelper() {} 46 47 /** 48 * Logcat buffers to search. 49 */ 50 public enum Buffer{ 51 EVENTS, MAIN, SYSTEM, ALL; 52 } 53 54 /** 55 * Logcat levels to search. 56 */ 57 public enum Level { 58 VERBOSE("V"), DEBUG("D"), INFO("I"), WARN("W"), ERROR("E"), ASSERT("A"); 59 60 private String mValue; 61 getValue()62 public String getValue() { 63 return mValue; 64 } 65 Level(String v)66 Level(String v) { 67 mValue = v; 68 } 69 } 70 71 /** 72 * Asserts that a message appears on {@code logcat}, using a default timeout. 73 * 74 * @param buffer logcat buffer to search 75 * @param level expected log level 76 * @parma tag expected log tag 77 * @param message substring of the expected message 78 * @param timeout for waiting the message 79 */ assertLogcatMessage(Buffer buffer, Level level, String tag, String message)80 public static void assertLogcatMessage(Buffer buffer, Level level, String tag, String message) { 81 assertLogcatMessage(buffer, level, tag, message, DEFAULT_TIMEOUT_MS); 82 } 83 84 /** 85 * Asserts that a message appears on {@code logcat}. 86 * 87 * @param buffer logcat buffer to search 88 * @param level expected log level 89 * @parma tag expected log tag 90 * @param message substring of the expected message 91 * @param timeout for waiting the message 92 */ assertLogcatMessage(Buffer buffer, Level level, String tag, String message, int timeout)93 public static void assertLogcatMessage(Buffer buffer, Level level, String tag, String message, 94 int timeout) { 95 String match = String.format("%s %s: %s", level.mValue, tag, message); 96 long startTime = SystemClock.elapsedRealtime(); 97 UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 98 String command = "logcat -b " + buffer.name().toLowerCase(); 99 ParcelFileDescriptor output = automation.executeShellCommand(command); 100 Log.d(TAG, "ran '" + command + "'; will now look for '" + match + "'"); 101 FileDescriptor fd = output.getFileDescriptor(); 102 FileInputStream fileInputStream = new FileInputStream(fd); 103 try (BufferedReader bufferedReader = new BufferedReader( 104 new InputStreamReader(fileInputStream))) { 105 String line; 106 while ((line = bufferedReader.readLine()) != null) { 107 if (VERBOSE) { 108 Log.v(TAG, "Checking line '" + line + "'"); 109 } 110 if (line.contains(match)) { 111 Log.d(TAG, "Found match on line '" + line + "', returning"); 112 return; 113 } 114 if ((SystemClock.elapsedRealtime() - startTime) > timeout) { 115 fail("match '" + match + "' was not found, Timeout: " + timeout + " ms"); 116 } 117 } 118 } catch (IOException e) { 119 fail("match '" + match + "' was not found, IO exception: " + e); 120 } 121 } 122 123 /** 124 * Asserts that a message DOESN'T appears on {@code logcat}. 125 * 126 * @param buffer is logcat buffer to search 127 * @param level expected log level 128 * @parma tag expected log tag 129 * @param message substring of the message that shouldn't appeard 130 * @param timeout for waiting the message 131 */ assertNoLogcatMessage(Buffer buffer, Level level, String tag, String message, int timeout)132 public static void assertNoLogcatMessage(Buffer buffer, Level level, String tag, String message, 133 int timeout) throws Exception { 134 String match = String.format("%s %s: %s", level.mValue, tag, message); 135 long startTime = SystemClock.elapsedRealtime(); 136 UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 137 ParcelFileDescriptor output = automation.executeShellCommand("logcat -b all"); 138 FileDescriptor fd = output.getFileDescriptor(); 139 FileInputStream fileInputStream = new FileInputStream(fd); 140 try (BufferedReader bufferedReader = new BufferedReader( 141 new InputStreamReader(fileInputStream))) { 142 String line; 143 while ((line = bufferedReader.readLine()) != null) { 144 if (line.contains(match)) { 145 fail("Match was not expected, but found: " + match); 146 } 147 if ((SystemClock.elapsedRealtime() - startTime) > timeout) { 148 return; 149 } 150 } 151 } catch (IOException e) { 152 fail("match was not found, IO exception: " + e); 153 } 154 } 155 156 /** 157 * Clears all logs. 158 */ clearLog()159 public static void clearLog() { 160 if (VERBOSE) { 161 Log.d(TAG, "Clearing logcat logs"); 162 } 163 SystemUtil.runShellCommand("logcat -b all -c"); 164 } 165 166 /** 167 * Sets the log level of the given tag. 168 */ setLogLevel(String tag, Level level)169 public static void setLogLevel(String tag, Level level) { 170 SystemUtil.runShellCommand("setprop log.tag." + tag + " " + level.getValue()); 171 } 172 } 173