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