1 package com.android.systemui.log 2 3 import androidx.test.filters.SmallTest 4 import com.android.systemui.SysuiTestCase 5 import com.android.systemui.log.core.Logger 6 import com.google.common.truth.Truth.assertThat 7 import java.io.PrintWriter 8 import java.io.StringWriter 9 import org.junit.Before 10 import org.junit.Test 11 import org.junit.runner.RunWith 12 import org.mockito.Mock 13 import org.mockito.junit.MockitoJUnitRunner 14 15 @SmallTest 16 @RunWith(MockitoJUnitRunner::class) 17 class LogBufferTest : SysuiTestCase() { 18 private lateinit var buffer: LogBuffer 19 20 private lateinit var outputWriter: StringWriter 21 22 @Mock private lateinit var logcatEchoTracker: LogcatEchoTracker 23 24 @Before 25 fun setup() { 26 outputWriter = StringWriter() 27 buffer = createBuffer() 28 } 29 30 private fun createBuffer(): LogBuffer { 31 return LogBuffer("TestBuffer", 1, logcatEchoTracker, false) 32 } 33 34 @Test 35 fun log_shouldSaveLogToBuffer() { 36 val logger = Logger(buffer, "Test") 37 logger.i("Some test message") 38 39 val dumpedString = dumpBuffer() 40 41 assertThat(dumpedString).contains("Some test message") 42 } 43 44 @Test 45 fun log_shouldRotateIfLogBufferIsFull() { 46 val logger = Logger(buffer, "Test") 47 logger.i("This should be rotated") 48 logger.i("New test message") 49 50 val dumpedString = dumpBuffer() 51 52 assertThat(dumpedString).contains("New test message") 53 } 54 55 @Test 56 fun dump_writesExceptionAndStacktrace() { 57 buffer = createBuffer() 58 val exception = createTestException("Exception message", "TestClass") 59 val logger = Logger(buffer, "Test") 60 logger.e("Extra message", exception) 61 62 val dumpedString = dumpBuffer() 63 64 assertThat(dumpedString).contains("Extra message") 65 assertThat(dumpedString).contains("java.lang.RuntimeException: Exception message") 66 assertThat(dumpedString).contains("at TestClass.TestMethod(TestClass.java:1)") 67 assertThat(dumpedString).contains("at TestClass.TestMethod(TestClass.java:2)") 68 } 69 70 @Test 71 fun dump_writesCauseAndStacktrace() { 72 buffer = createBuffer() 73 val exception = 74 createTestException( 75 "Exception message", 76 "TestClass", 77 cause = createTestException("The real cause!", "TestClass") 78 ) 79 val logger = Logger(buffer, "Test") 80 logger.e("Extra message", exception) 81 82 val dumpedString = dumpBuffer() 83 84 assertThat(dumpedString).contains("Caused by: java.lang.RuntimeException: The real cause!") 85 assertThat(dumpedString).contains("at TestClass.TestMethod(TestClass.java:1)") 86 assertThat(dumpedString).contains("at TestClass.TestMethod(TestClass.java:2)") 87 } 88 89 @Test 90 fun dump_writesSuppressedExceptionAndStacktrace() { 91 buffer = createBuffer() 92 val exception = RuntimeException("Root exception message") 93 exception.addSuppressed( 94 createTestException( 95 "First suppressed exception", 96 "FirstClass", 97 createTestException("Cause of suppressed exp", "ThirdClass") 98 ) 99 ) 100 exception.addSuppressed(createTestException("Second suppressed exception", "SecondClass")) 101 val logger = Logger(buffer, "Test") 102 logger.e("Extra message", exception) 103 104 val dumpedStr = dumpBuffer() 105 106 // first suppressed exception 107 assertThat(dumpedStr) 108 .contains("Suppressed: " + "java.lang.RuntimeException: First suppressed exception") 109 assertThat(dumpedStr).contains("at FirstClass.TestMethod(FirstClass.java:1)") 110 assertThat(dumpedStr).contains("at FirstClass.TestMethod(FirstClass.java:2)") 111 112 assertThat(dumpedStr) 113 .contains("Caused by: java.lang.RuntimeException: Cause of suppressed exp") 114 assertThat(dumpedStr).contains("at ThirdClass.TestMethod(ThirdClass.java:1)") 115 assertThat(dumpedStr).contains("at ThirdClass.TestMethod(ThirdClass.java:2)") 116 117 // second suppressed exception 118 assertThat(dumpedStr) 119 .contains("Suppressed: " + "java.lang.RuntimeException: Second suppressed exception") 120 assertThat(dumpedStr).contains("at SecondClass.TestMethod(SecondClass.java:1)") 121 assertThat(dumpedStr).contains("at SecondClass.TestMethod(SecondClass.java:2)") 122 } 123 124 private fun createTestException( 125 message: String, 126 errorClass: String, 127 cause: Throwable? = null, 128 ): Exception { 129 val exception = RuntimeException(message, cause) 130 exception.stackTrace = 131 (1..5) 132 .map { lineNumber -> 133 StackTraceElement(errorClass, "TestMethod", "$errorClass.java", lineNumber) 134 } 135 .toTypedArray() 136 return exception 137 } 138 139 private fun dumpBuffer(): String { 140 buffer.dump(PrintWriter(outputWriter), tailLength = 100) 141 return outputWriter.toString() 142 } 143 } 144