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