1 /*
2 * Copyright (C) 2020 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 #include <gtest/gtest.h>
18 #include <string>
19
20 #include "chre/platform/atomic.h"
21 #include "chre/platform/condition_variable.h"
22 #include "chre/platform/mutex.h"
23 #include "chre/platform/shared/log_buffer.h"
24
25 namespace chre {
26
27 // TODO(b/146164384): Test that the onLogsReady callback is called
28 // asynchronously
29
30 class TestLogBufferCallback : public LogBufferCallbackInterface {
31 public:
onLogsReady()32 void onLogsReady() {
33 // Do nothing
34 }
35 };
36
37 static constexpr size_t kDefaultBufferSize = 1024;
38
39 // Helpers
copyStringWithOffset(char * destination,const char * source,size_t sourceOffset)40 void copyStringWithOffset(char *destination, const char *source,
41 size_t sourceOffset) {
42 size_t strlength = strlen(source + sourceOffset);
43 // +1 to copy nullbyte on the end
44 memcpy(destination, source + sourceOffset, strlength + 1);
45 }
46
TEST(LogBuffer,HandleOneLogAndCopy)47 TEST(LogBuffer, HandleOneLogAndCopy) {
48 char buffer[kDefaultBufferSize];
49 constexpr size_t kOutBufferSize = 20;
50 char outBuffer[kOutBufferSize];
51 const char *testLogStr = "test";
52 char testedBuffer[kOutBufferSize];
53 TestLogBufferCallback callback;
54
55 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
56 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
57 size_t numLogsDropped;
58 size_t bytesCopied =
59 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
60
61 EXPECT_EQ(bytesCopied, strlen(testLogStr) + LogBuffer::kLogDataOffset + 1);
62 copyStringWithOffset(testedBuffer, outBuffer, LogBuffer::kLogDataOffset);
63 EXPECT_TRUE(strcmp(testedBuffer, testLogStr) == 0);
64 }
65
TEST(LogBuffer,HandleTwoLogsAndCopy)66 TEST(LogBuffer, HandleTwoLogsAndCopy) {
67 char buffer[kDefaultBufferSize];
68 constexpr size_t kOutBufferSize = 30;
69 char outBuffer[kOutBufferSize];
70 const char *testLogStr = "test";
71 const char *testLogStr2 = "test2";
72 char testedBuffer[kOutBufferSize];
73 TestLogBufferCallback callback;
74
75 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
76 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
77 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr2);
78 size_t numLogsDropped;
79 size_t bytesCopied =
80 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
81
82 EXPECT_EQ(bytesCopied, strlen(testLogStr) + strlen(testLogStr2) +
83 2 * LogBuffer::kLogDataOffset + 2);
84 copyStringWithOffset(testedBuffer, outBuffer, LogBuffer::kLogDataOffset);
85 EXPECT_TRUE(strcmp(testedBuffer, testLogStr) == 0);
86 copyStringWithOffset(testedBuffer, outBuffer,
87 2 * LogBuffer::kLogDataOffset + strlen(testLogStr) + 1);
88 EXPECT_TRUE(strcmp(testedBuffer, testLogStr2) == 0);
89 }
90
TEST(LogBuffer,FailOnMoreCopyThanHandle)91 TEST(LogBuffer, FailOnMoreCopyThanHandle) {
92 char buffer[kDefaultBufferSize];
93 constexpr size_t kOutBufferSize = 20;
94 char outBuffer[kOutBufferSize];
95 const char *testLogStr = "test";
96 TestLogBufferCallback callback;
97
98 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
99 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
100 size_t numLogsDropped;
101 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
102 size_t bytesCopied =
103 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
104
105 EXPECT_EQ(bytesCopied, 0);
106 }
107
TEST(LogBuffer,FailOnHandleLargerLogThanBufferSize)108 TEST(LogBuffer, FailOnHandleLargerLogThanBufferSize) {
109 char buffer[kDefaultBufferSize];
110 constexpr size_t kOutBufferSize = 20;
111 char outBuffer[kOutBufferSize];
112 // Note the size of this log is too big to fit in the buffer that we are
113 // using for the LogBuffer object
114 std::string testLogStrStr(1025, 'a');
115 TestLogBufferCallback callback;
116
117 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
118 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStrStr.c_str());
119 size_t numLogsDropped;
120 size_t bytesCopied =
121 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
122
123 // Should not be able to read this log out because there should be no log in
124 // the first place
125 EXPECT_EQ(bytesCopied, 0);
126 }
127
TEST(LogBuffer,LogOverwritten)128 TEST(LogBuffer, LogOverwritten) {
129 char buffer[kDefaultBufferSize];
130 constexpr size_t kOutBufferSize = 200;
131 char outBuffer[kOutBufferSize];
132 char testedBuffer[kOutBufferSize];
133 TestLogBufferCallback callback;
134 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
135
136 // This for loop adds 1060 bytes of data through the buffer which is > than
137 // 1024
138 for (size_t i = 0; i < 10; i++) {
139 std::string testLogStrStr(100, 'a' + i);
140 const char *testLogStr = testLogStrStr.c_str();
141 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
142 }
143 size_t numLogsDropped;
144 size_t bytesCopied =
145 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
146 memcpy(testedBuffer, outBuffer + LogBuffer::kLogDataOffset, 101);
147
148 // Should have read out the second from front test log string which is 'a' + 1
149 // = 'b'
150 EXPECT_TRUE(strcmp(testedBuffer, std::string(100, 'b').c_str()) == 0);
151 EXPECT_EQ(bytesCopied, LogBuffer::kLogDataOffset + 100 + 1);
152 // Should have dropped the first log
153 EXPECT_EQ(numLogsDropped, 1);
154 }
155
TEST(LogBuffer,CopyIntoEmptyBuffer)156 TEST(LogBuffer, CopyIntoEmptyBuffer) {
157 char buffer[kDefaultBufferSize];
158 constexpr size_t kOutBufferSize = 0;
159 char outBuffer[kOutBufferSize];
160 TestLogBufferCallback callback;
161 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
162
163 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, "test");
164 size_t numLogsDropped;
165 size_t bytesCopied =
166 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
167
168 EXPECT_EQ(bytesCopied, 0);
169 }
170
TEST(LogBuffer,NoCopyInfoBufferAfterHandleEmptyLog)171 TEST(LogBuffer, NoCopyInfoBufferAfterHandleEmptyLog) {
172 char buffer[kDefaultBufferSize];
173 constexpr size_t kOutBufferSize = 200;
174 char outBuffer[kOutBufferSize];
175 TestLogBufferCallback callback;
176 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
177
178 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, "");
179 size_t numLogsDropped;
180 size_t bytesCopied =
181 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
182
183 EXPECT_EQ(bytesCopied, 0);
184 }
185
TEST(LogBuffer,HandleLogOfNullBytes)186 TEST(LogBuffer, HandleLogOfNullBytes) {
187 char buffer[kDefaultBufferSize];
188 constexpr size_t kOutBufferSize = 200;
189 char outBuffer[kOutBufferSize];
190 TestLogBufferCallback callback;
191 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
192
193 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, "\0\0\0");
194 size_t numLogsDropped;
195 size_t bytesCopied =
196 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
197
198 EXPECT_EQ(bytesCopied, 0);
199 }
200
TEST(LogBuffer,TruncateLongLog)201 TEST(LogBuffer, TruncateLongLog) {
202 char buffer[kDefaultBufferSize];
203 constexpr size_t kOutBufferSize = 500;
204 char outBuffer[kOutBufferSize];
205 TestLogBufferCallback callback;
206 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
207 std::string testStr(256, 'a');
208
209 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testStr.c_str());
210 size_t numLogsDropped;
211 size_t bytesCopied =
212 logBuffer.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
213
214 // Should truncate the logs down to the kLogMaxSize value of 255 by the time
215 // it is copied out.
216 EXPECT_EQ(bytesCopied, 255);
217 }
218
TEST(LogBuffer,WouldCauseOverflowTest)219 TEST(LogBuffer, WouldCauseOverflowTest) {
220 char buffer[kDefaultBufferSize];
221 TestLogBufferCallback callback;
222 LogBuffer logBuffer(&callback, buffer, kDefaultBufferSize);
223
224 // With an empty buffer inerting one character should not overflow
225 // ASSERT because if this fails the next ASSERT statement is undefined most
226 // likely.
227 ASSERT_FALSE(logBuffer.logWouldCauseOverflow(1));
228
229 // This for loop adds 1000 bytes of data. There is 24 bytes of space left in
230 // the buffer after this loop.
231 for (size_t i = 0; i < 10; i++) {
232 std::string testLogStrStr(94, 'a');
233 const char *testLogStr = testLogStrStr.c_str();
234 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
235 }
236
237 std::string testLogStrStr(11, 'a');
238 const char *testLogStr = testLogStrStr.c_str();
239 // After this log entry there is room enough for a log of character size 1.
240 logBuffer.handleLog(LogBufferLogLevel::INFO, 0, testLogStr);
241
242 // There should be just enough space for this log
243 ASSERT_FALSE(logBuffer.logWouldCauseOverflow(1));
244
245 // Inserting any more than a one char log should cause overflow
246 ASSERT_TRUE(logBuffer.logWouldCauseOverflow(2));
247 }
248
TEST(LogBuffer,TransferTest)249 TEST(LogBuffer, TransferTest) {
250 char buffer[kDefaultBufferSize];
251 const size_t kOutBufferSize = 10;
252 char outBuffer[kOutBufferSize];
253 size_t numLogsDropped;
254 TestLogBufferCallback callback;
255 LogBuffer logBufferFrom(&callback, buffer, kDefaultBufferSize);
256 LogBuffer logBufferTo(&callback, buffer, kDefaultBufferSize);
257
258 const char *str1 = "str1";
259 const char *str2 = "str2";
260 const char *str3 = "str3";
261
262 logBufferFrom.handleLog(LogBufferLogLevel::INFO, 0, str1);
263 logBufferFrom.handleLog(LogBufferLogLevel::INFO, 0, str2);
264 logBufferFrom.handleLog(LogBufferLogLevel::INFO, 0, str3);
265
266 logBufferFrom.transferTo(logBufferTo);
267
268 // The logs should have the text of each of the logs pushed onto the From
269 // buffer in FIFO ordering.
270 logBufferTo.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
271 ASSERT_TRUE(strcmp(outBuffer + LogBuffer::kLogDataOffset, str1) == 0);
272 logBufferTo.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
273 ASSERT_TRUE(strcmp(outBuffer + LogBuffer::kLogDataOffset, str2) == 0);
274 logBufferTo.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
275 ASSERT_TRUE(strcmp(outBuffer + LogBuffer::kLogDataOffset, str3) == 0);
276
277 size_t bytesCopied =
278 logBufferTo.copyLogs(outBuffer, kOutBufferSize, &numLogsDropped);
279 // There should have been no logs left in the To buffer for that last copyLogs
280 ASSERT_EQ(bytesCopied, 0);
281 }
282
283 // TODO(srok): Add multithreaded tests
284
285 } // namespace chre
286