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