1 /*
2  * Copyright (C) 2019 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 com.android.protolog.tool
18 
19 import com.android.json.stream.JsonReader
20 import com.android.internal.protolog.ProtoLogMessage
21 import com.android.internal.protolog.ProtoLogFileProto
22 import org.junit.Assert.assertEquals
23 import org.junit.Before
24 import org.junit.Test
25 import org.mockito.Mockito
26 import org.mockito.Mockito.mock
27 import java.io.ByteArrayOutputStream
28 import java.io.InputStream
29 import java.io.OutputStream
30 import java.io.PrintStream
31 import java.text.SimpleDateFormat
32 import java.util.Date
33 import java.util.Locale
34 
35 class LogParserTest {
36     private val configParser: ViewerConfigParser = mock(ViewerConfigParser::class.java)
37     private val parser = LogParser(configParser)
38     private var config: MutableMap<Long, ViewerConfigParser.ConfigEntry> = mutableMapOf()
39     private var outStream: OutputStream = ByteArrayOutputStream()
40     private var printStream: PrintStream = PrintStream(outStream)
41     private val dateFormat = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
42 
43     @Before
initnull44     fun init() {
45         Mockito.`when`(configParser.parseConfig(any(JsonReader::class.java))).thenReturn(config)
46     }
47 
anynull48     private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
49 
50     private fun getConfigDummyStream(): InputStream {
51         return "".byteInputStream()
52     }
53 
buildProtoInputnull54     private fun buildProtoInput(logBuilder: ProtoLogFileProto.Builder): InputStream {
55         logBuilder.setVersion(Constants.VERSION)
56         logBuilder.magicNumber =
57                 ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_H.number.toLong() shl 32 or
58                         ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_L.number.toLong()
59         return logBuilder.build().toByteArray().inputStream()
60     }
61 
testDatenull62     private fun testDate(timeMS: Long): String {
63         return dateFormat.format(Date(timeMS))
64     }
65 
66     @Test
parsenull67     fun parse() {
68         config[70933285] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b",
69                 "ERROR", "WindowManager")
70 
71         val logBuilder = ProtoLogFileProto.newBuilder()
72         val logMessageBuilder = ProtoLogMessage.newBuilder()
73         logMessageBuilder
74                 .setMessageHash(70933285)
75                 .setElapsedRealtimeNanos(0)
76                 .addBooleanParams(true)
77         logBuilder.addLog(logMessageBuilder.build())
78 
79         parser.parse(buildProtoInput(logBuilder), getConfigDummyStream(), printStream)
80 
81         assertEquals("${testDate(0)} ERROR WindowManager: Test completed successfully: true\n",
82                 outStream.toString())
83     }
84 
85     @Test
parse_formattingnull86     fun parse_formatting() {
87         config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %%" +
88                 " %x %s %f", "ERROR", "WindowManager")
89 
90         val logBuilder = ProtoLogFileProto.newBuilder()
91         val logMessageBuilder = ProtoLogMessage.newBuilder()
92         logMessageBuilder
93                 .setMessageHash(123)
94                 .setElapsedRealtimeNanos(0)
95                 .addBooleanParams(true)
96                 .addAllSint64Params(listOf(1000, 20000))
97                 .addDoubleParams(1000.1)
98                 .addStrParams("test")
99         logBuilder.addLog(logMessageBuilder.build())
100 
101         parser.parse(buildProtoInput(logBuilder), getConfigDummyStream(), printStream)
102 
103         assertEquals("${testDate(0)} ERROR WindowManager: Test completed successfully: " +
104                 "true 1000 % 4e20 test 1000.100000\n",
105                 outStream.toString())
106     }
107 
108     @Test
parse_invalidParamsTooManynull109     fun parse_invalidParamsTooMany() {
110         config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %%",
111                 "ERROR", "WindowManager")
112 
113         val logBuilder = ProtoLogFileProto.newBuilder()
114         val logMessageBuilder = ProtoLogMessage.newBuilder()
115         logMessageBuilder
116                 .setMessageHash(123)
117                 .setElapsedRealtimeNanos(0)
118                 .addBooleanParams(true)
119                 .addAllSint64Params(listOf(1000, 20000, 300000))
120                 .addAllDoubleParams(listOf(0.1, 0.00001, 1000.1))
121                 .addStrParams("test")
122         logBuilder.addLog(logMessageBuilder.build())
123 
124         parser.parse(buildProtoInput(logBuilder), getConfigDummyStream(), printStream)
125 
126         assertEquals("${testDate(0)} INVALID: 123 - [test] [1000, 20000, 300000] " +
127                 "[0.1, 1.0E-5, 1000.1] [true]\n", outStream.toString())
128     }
129 
130     @Test
parse_invalidParamsNotEnoughnull131     fun parse_invalidParamsNotEnough() {
132         config[123] = ViewerConfigParser.ConfigEntry("Test completed successfully: %b %d %%" +
133                 " %x %s %f", "ERROR", "WindowManager")
134 
135         val logBuilder = ProtoLogFileProto.newBuilder()
136         val logMessageBuilder = ProtoLogMessage.newBuilder()
137         logMessageBuilder
138                 .setMessageHash(123)
139                 .setElapsedRealtimeNanos(0)
140                 .addBooleanParams(true)
141                 .addStrParams("test")
142         logBuilder.addLog(logMessageBuilder.build())
143 
144         parser.parse(buildProtoInput(logBuilder), getConfigDummyStream(), printStream)
145 
146         assertEquals("${testDate(0)} INVALID: 123 - [test] [] [] [true]\n",
147                 outStream.toString())
148     }
149 
150     @Test(expected = InvalidInputException::class)
parse_invalidMagicNumbernull151     fun parse_invalidMagicNumber() {
152         val logBuilder = ProtoLogFileProto.newBuilder()
153         logBuilder.setVersion(Constants.VERSION)
154         logBuilder.magicNumber = 0
155         val stream = logBuilder.build().toByteArray().inputStream()
156 
157         parser.parse(stream, getConfigDummyStream(), printStream)
158     }
159 
160     @Test(expected = InvalidInputException::class)
parse_invalidVersionnull161     fun parse_invalidVersion() {
162         val logBuilder = ProtoLogFileProto.newBuilder()
163         logBuilder.setVersion("invalid")
164         logBuilder.magicNumber =
165                 ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_H.number.toLong() shl 32 or
166                         ProtoLogFileProto.MagicNumber.MAGIC_NUMBER_L.number.toLong()
167         val stream = logBuilder.build().toByteArray().inputStream()
168 
169         parser.parse(stream, getConfigDummyStream(), printStream)
170     }
171 
172     @Test
parse_noConfignull173     fun parse_noConfig() {
174         val logBuilder = ProtoLogFileProto.newBuilder()
175         val logMessageBuilder = ProtoLogMessage.newBuilder()
176         logMessageBuilder
177                 .setMessageHash(70933285)
178                 .setElapsedRealtimeNanos(0)
179                 .addBooleanParams(true)
180         logBuilder.addLog(logMessageBuilder.build())
181 
182         parser.parse(buildProtoInput(logBuilder), getConfigDummyStream(), printStream)
183 
184         assertEquals("${testDate(0)} UNKNOWN: 70933285 - [] [] [] [true]\n",
185                 outStream.toString())
186     }
187 }
188