1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "event_loop_test.h"
16
17 #include <cinttypes>
18 #include <ctime>
19 #include <fstream>
20 #include <iostream>
21 #include <limits>
22 #include <thread>
23
24 #include <gtest/gtest.h>
25 #include <sys/inotify.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 #include "audit.h"
31 #include "event_loop.h"
32 #include "pipeline.h"
33
34 using namespace testing::ext;
35 using namespace OHOS::HiviewDFX;
36 namespace OHOS {
37 namespace HiviewDFX {
SetUp()38 void EventLoopTest::SetUp()
39 {
40 /**
41 * @tc.setup: create an event loop and multiple event handlers
42 */
43 if (currentLooper_ != nullptr) {
44 currentLooper_->StopLoop();
45 currentLooper_.reset();
46 }
47
48 mkdir("/data/log", S_IRWXU | S_IRWXG);
49 const ::testing::TestInfo * const info = ::testing::UnitTest::GetInstance()->current_test_info();
50 printf("We are in test %s of test case %s.\n", info->name(), info->test_case_name());
51 currentLooper_ = std::make_shared<EventLoop>(info->test_case_name());
52 currentLooper_->StartLoop();
53 }
54
TearDown()55 void EventLoopTest::TearDown()
56 {
57 /**
58 * @tc.teardown: destroy the event loop we have created
59 */
60 if (currentLooper_ != nullptr) {
61 currentLooper_->StopLoop();
62 currentLooper_.reset();
63 }
64 }
65
OnEvent(std::shared_ptr<Event> & event)66 bool RealEventHandler::OnEvent(std::shared_ptr<Event>& event)
67 {
68 printf("OnEvent id:%d sender:%s pid:%d time:%" PRId64 ". index:%d\n", event->eventId_, event->sender_.c_str(),
69 gettid(), static_cast<int64_t>(time(nullptr)), event->what_);
70 lastProcessId_ = event->eventId_;
71 if ((event->what_ % 10) == 0) { // 10 : add delay in processing some event
72 usleep(100); // 100 : 100us
73 }
74 processedEventCount_++;
75 pid_ = getpid();
76 receivedEventNo_.push_back(event->what_);
77 return true;
78 }
79
DoTask()80 void RealEventHandler::DoTask()
81 {
82 printf("RealEventHandler::DoTask pid:%d time:%" PRId64 ".\n", gettid(), static_cast<int64_t>(time(nullptr)));
83 processedEventCount_++;
84 }
85
OnEvent(std::shared_ptr<Event> & event)86 bool OverheadCalculateEventHandler::OnEvent(std::shared_ptr<Event>& event)
87 {
88 auto cost = clock() - event->createTime_;
89 totalDeliverOverHead_ += cost;
90 processedEventCount_++;
91 return true;
92 }
93
OnFileDescriptorEvent(int fd,int type)94 bool DataFileEventReader::OnFileDescriptorEvent(int fd, int type)
95 {
96 printf("DataFileEventReader::OnEvent id:%d inotifyFd_:%d\n", fd, inotifyFd_);
97 const int bufSize = 2048;
98 char buffer[bufSize] = {0};
99 char *offset = nullptr;
100 struct inotify_event *event = nullptr;
101 if (inotifyFd_ <= 0) {
102 printf("Invalid inotify fd:%d", inotifyFd_);
103 return false;
104 }
105
106 int len = read(inotifyFd_, buffer, bufSize);
107 if (len <= 0) {
108 printf("failed to read event");
109 return false;
110 }
111 offset = buffer;
112 event = reinterpret_cast<struct inotify_event *>(buffer);
113 while ((reinterpret_cast<char *>(event) - buffer) < len) {
114 for (const auto &it : fileMap_) {
115 if (it.second != event->wd) {
116 printf("fail to find check point: %d", event->wd);
117 continue;
118 }
119
120 std::string filePath = it.first;
121 printf("handle file event in %s \n", filePath.c_str());
122 }
123
124 int tmpLen = sizeof(struct inotify_event) + event->len;
125 event = reinterpret_cast<struct inotify_event *>(offset + tmpLen);
126 offset += tmpLen;
127 }
128 return false;
129 }
130
GetPollFd()131 int32_t DataFileEventReader::GetPollFd()
132 {
133 if (inotifyFd_ > 0) {
134 return inotifyFd_;
135 }
136
137 inotifyFd_ = inotify_init();
138 if (inotifyFd_ == -1) {
139 printf("failed to init inotify: %s \n", strerror(errno));
140 return -1;
141 }
142
143 // create file
144 FILE *targetLogFile = fopen(EVENT_LOG_PATH.c_str(), "w+");
145 if (targetLogFile != nullptr) {
146 fclose(targetLogFile);
147 }
148
149 int wd = inotify_add_watch(inotifyFd_, EVENT_LOG_PATH.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO);
150 if (wd < 0) {
151 printf("failed to add watch entry : %s \n", strerror(errno));
152 close(inotifyFd_);
153 inotifyFd_ = -1;
154 return -1;
155 }
156 fileMap_[EVENT_LOG_PATH] = wd;
157 return inotifyFd_;
158 }
159
GetPollType()160 int32_t DataFileEventReader::GetPollType()
161 {
162 return EPOLLIN;
163 }
164
165 /**
166 * @tc.name: EventLoopStartAndStopTest001
167 * @tc.desc: start the event loop and stop the event loop
168 * @tc.type: FUNC
169 * @tc.require: AR000DPTSU
170 */
171 HWTEST_F(EventLoopTest, StartAndStopTest001, TestSize.Level3)
172 {
173 /**
174 * @tc.steps: step1. create event handler
175 */
176 auto eventhandler1 = std::make_shared<RealEventHandler>();
177 auto event1 = std::make_shared<Event>("test1");
178 currentLooper_->AddEvent(eventhandler1, event1, nullptr);
179 /**
180 * @tc.expected: step1. fetch the thread id of the event loop
181 */
182 int curPid = getpid();
183 EXPECT_NE(curPid, eventhandler1->pid_);
184 }
185
186 /**
187 * @tc.name: EventLoopEventProcessTest001
188 * @tc.desc: send multiple events to event loop
189 * @tc.type: FUNC
190 * @tc.require: AR000DPTSU
191 */
192 HWTEST_F(EventLoopTest, EventLoopEventProcessTest001, TestSize.Level3)
193 {
194 /**
195 * @tc.steps: step1. create event handler and events
196 */
197 auto eventhandler1 = std::make_shared<RealEventHandler>();
198 auto eventhandler2 = std::make_shared<RealEventHandler>();
199 auto eventhandler3 = std::make_shared<RealEventHandler>();
200 auto eventhandler4 = std::make_shared<RealEventHandler>();
201
202 auto event1 = std::make_shared<Event>("test1");
203 auto event2 = std::make_shared<Event>("test2");
204 auto event3 = std::make_shared<Event>("test3");
205 auto event4 = std::make_shared<Event>("test4");
206 auto event5 = std::make_shared<Event>("test5");
207 auto event6 = std::make_shared<Event>("test6");
208 auto event7 = std::make_shared<Event>("test7");
209
210 currentLooper_->AddEvent(eventhandler1, event1, nullptr);
211 currentLooper_->AddEvent(eventhandler2, event2, nullptr);
212 currentLooper_->AddEvent(eventhandler3, event3, nullptr);
213 currentLooper_->AddEvent(eventhandler4, event4, nullptr);
214 currentLooper_->AddEvent(eventhandler1, event5, nullptr);
215 currentLooper_->AddEvent(eventhandler4, event6, nullptr);
216 currentLooper_->AddEvent(eventhandler1, event7, nullptr);
217 sleep(2);
218
219 /**
220 * @tc.expected: step1. the event has been processed
221 */
222 EXPECT_EQ(3, eventhandler1->processedEventCount_);
223 EXPECT_EQ(1, eventhandler2->processedEventCount_);
224 EXPECT_EQ(1, eventhandler3->processedEventCount_);
225 EXPECT_EQ(2, eventhandler4->processedEventCount_);
226 }
227
228 /**
229 * @tc.name: EventLoopEventProcessTest002
230 * @tc.desc: Add Fd callback and check the result from fd
231 * @tc.type: FUNC
232 * @tc.require: AR000DPTSU
233 */
234 HWTEST_F(EventLoopTest, EventLoopEventProcessTest002, TestSize.Level3)
235 {
236 /**
237 * @tc.steps: step1. create a timer event and send to target
238 */
239 auto eventReader = std::make_shared<DataFileEventReader>();
240 auto res = currentLooper_->AddFileDescriptorEventCallback("test1", eventReader);
241 EXPECT_TRUE(res);
242
243 auto eventhandler1 = std::make_shared<RealEventHandler>();
244 auto event1 = std::make_shared<Event>("test1");
245 auto event2 = std::make_shared<Event>("test2");
246 auto event3 = std::make_shared<Event>("test3");
247
248 currentLooper_->AddEvent(eventhandler1, event1, nullptr);
249 currentLooper_->AddEvent(eventhandler1, event2, nullptr);
250 currentLooper_->AddEvent(eventhandler1, event3, nullptr);
251
252 std::ofstream testFile;
253 testFile.open(DataFileEventReader::EVENT_LOG_PATH);
254 testFile << "Writing this to a file.\n";
255 testFile.close();
256
257 sleep(1);
258 testFile.open(DataFileEventReader::EVENT_LOG_PATH);
259 testFile << "Writing this to a file.\n";
260 testFile.close();
261 sleep(1);
262 testFile.open(DataFileEventReader::EVENT_LOG_PATH);
263 testFile << "Writing this to a file.\n";
264 testFile.close();
265 sleep(1);
266
267 /**
268 * @tc.expected: step1. the event has been processed
269 */
270 EXPECT_EQ(3, eventhandler1->processedEventCount_);
271
272 res = currentLooper_->RemoveFileDescriptorEventCallback("test1");
273 EXPECT_TRUE(res);
274 res = currentLooper_->RemoveFileDescriptorEventCallback("invalid");
275 EXPECT_FALSE(res);
276
277 currentLooper_->StopLoop();
278 res = currentLooper_->AddFileDescriptorEventCallback("test1", eventReader);
279 EXPECT_FALSE(res);
280 }
281
282 /**
283 * @tc.name: EventLoopEventProcessTest003
284 * @tc.desc: Exec period event
285 * @tc.type: FUNC
286 * @tc.require: AR000DPTSU
287 */
288 HWTEST_F(EventLoopTest, EventLoopEventProcessTest003, TestSize.Level3)
289 {
290 /**
291 * @tc.steps: step1. create a timer event and send to target
292 */
293 auto eventhandler1 = std::make_shared<RealEventHandler>();
294 auto event1 = std::make_shared<Event>("test1");
295 currentLooper_->AddTimerEvent(eventhandler1, event1, nullptr, 2, true);
296 sleep(9); // 9 = 4(num of event) * 2(delay) + 1(free)
297 /**
298 * @tc.expected: step1. the event has been processed
299 */
300 EXPECT_EQ(4, eventhandler1->processedEventCount_);
301 }
302
303 /**
304 * @tc.name: EventLoopEventProcessTest004
305 * @tc.desc: Exec period task
306 * @tc.type: FUNC
307 * @tc.require: AR000DPTSU
308 */
309 HWTEST_F(EventLoopTest, EventLoopEventProcessTest004, TestSize.Level3)
310 {
311 /**
312 * @tc.steps: step1. create a timer event and send to target
313 */
314 auto eventhandler1 = std::make_shared<RealEventHandler>();
315 auto task = std::bind(&RealEventHandler::DoTask, eventhandler1.get());
316 currentLooper_->AddTimerEvent(nullptr, nullptr, task, 2, true);
317 printf("On Main Thread:%d \n", gettid());
318 sleep(9);
319 /**
320 * @tc.expected: step1. the event has been processed
321 */
322 EXPECT_EQ(4, eventhandler1->processedEventCount_);
323 }
324
325 /**
326 * @tc.name: EventLoopEventProcessTest005
327 * @tc.desc: Exec period task and remove it
328 * @tc.type: FUNC
329 * @tc.require: AR000DPTSU
330 */
331 HWTEST_F(EventLoopTest, EventLoopEventProcessTest005, TestSize.Level3)
332 {
333 /**
334 * @tc.steps: step1. create a timer event and send to target
335 */
336 auto eventhandler1 = std::make_shared<RealEventHandler>();
337 auto task = std::bind(&RealEventHandler::DoTask, eventhandler1.get());
338 auto seqId = currentLooper_->AddTimerEvent(nullptr, nullptr, task, 2, true);
339 printf("On Main Thread:%d \n", gettid());
340 sleep(5);
341 currentLooper_->RemoveEvent(seqId);
342 sleep(5);
343 /**
344 * @tc.expected: step1. the event has been processed
345 */
346 EXPECT_EQ(2, eventhandler1->processedEventCount_);
347 }
348
349 /**
350 * @tc.name: EventLoopEventProcessTest006
351 * @tc.desc: Exec timer event and remove it
352 * @tc.type: FUNC
353 * @tc.require: AR000DPTSU
354 */
355 HWTEST_F(EventLoopTest, EventLoopEventProcessTest006, TestSize.Level3)
356 {
357 /**
358 * @tc.steps: step1. create a timer event and send to target
359 */
360 auto eventhandler1 = std::make_shared<RealEventHandler>();
361 auto event1 = std::make_shared<Event>("test1");
362 currentLooper_->AddTimerEvent(eventhandler1, event1, nullptr, 2, false);
363 sleep(3);
364 EXPECT_EQ(1, eventhandler1->processedEventCount_);
365 auto event2 = std::make_shared<Event>("test2");
366 auto seq = currentLooper_->AddTimerEvent(eventhandler1, event2, nullptr, 2, false);
367 sleep(1);
368 currentLooper_->RemoveEvent(seq);
369 sleep(2);
370 EXPECT_EQ(1, eventhandler1->processedEventCount_);
371
372 // invalid interval
373 uint64_t interval = std::numeric_limits<uint64_t>::max() - 1;
374 auto event3 = std::make_shared<Event>("test3");
375 auto res = currentLooper_->AddTimerEvent(eventhandler1, event3, nullptr, interval, false);
376 EXPECT_EQ(res, -1);
377 }
378
379 /**
380 * @tc.name: EventLoopOverheadTest001
381 * @tc.desc: send an event and check the deliver cost
382 * @tc.type: FUNC
383 * @tc.require: AR000DPTSU
384 */
385 HWTEST_F(EventLoopTest, EventLoopOverheadTest001, TestSize.Level3)
386 {
387 /**
388 * @tc.steps: step1. create a handler and event
389 * @tc.steps: step2. calculate event deliver overhead
390 */
391 auto overheadCounter = std::make_shared<OverheadCalculateEventHandler>();
392 const int totalTestCount = 100;
393 for (int i = 0; i < totalTestCount; i++) {
394 auto event = std::make_shared<Event>("test");
395 event->createTime_ = clock();
396 currentLooper_->AddEvent(overheadCounter, event, nullptr);
397 }
398 sleep(10);
399 printf("TotalDeliverOverHeadCost:%" PRIu64 ".\n", overheadCounter->totalDeliverOverHead_);
400 printf("TotalProcessEventCount:%" PRIu64 ".\n", overheadCounter->processedEventCount_);
401 printf("EventTransferOverhead:%" PRIu64 ".\n",
402 overheadCounter->totalDeliverOverHead_/overheadCounter->processedEventCount_);
403 }
404
405 /**
406 * @tc.name: EventLoopEventOrderTest001
407 * @tc.desc: send 1000 events and check the receiving order
408 * @tc.type: FUNC
409 * @tc.require: AR000DPTSU
410 */
411 HWTEST_F(EventLoopTest, EventLoopEventOrderTest001, TestSize.Level3)
412 {
413 /**
414 * @tc.steps: step1. create a handler and 1000 events in a loop
415 * @tc.steps: step2. check the received order
416 */
417 auto eventhandler = std::make_shared<RealEventHandler>();
418 const uint16_t totalTestCount = 1000;
419 for (uint16_t i = 0; i < totalTestCount; i++) {
420 auto event = std::make_shared<Event>("testevent");
421 event->what_ = i;
422 currentLooper_->AddEvent(eventhandler, event, nullptr);
423 }
424 sleep(10); // 10: sleep 10 seconds
425 ASSERT_EQ(eventhandler->receivedEventNo_.size(), totalTestCount);
426 for (uint16_t i = 0; i < totalTestCount; i++) {
427 ASSERT_EQ(eventhandler->receivedEventNo_[i], i);
428 }
429 }
430
431 /**
432 * @tc.name: EventLoopWrongInputParamsTest001
433 * @tc.desc: pass invalid params to add event interface
434 * @tc.type: FUNC
435 * @tc.require: AR000DPTSU
436 */
437 HWTEST_F(EventLoopTest, EventLoopWrongInputParamsTest001, TestSize.Level3)
438 {
439 /**
440 * @tc.steps: step1. pass invalid params to add event interface
441 * @tc.steps: step2. check the return future
442 */
443 auto result0 = currentLooper_->AddEventForResult(nullptr, nullptr);
444 ASSERT_EQ(result0.get(), false);
445
446 auto eventhandler = std::make_shared<RealEventHandler>();
447 auto result1 = currentLooper_->AddEventForResult(eventhandler, nullptr);
448 ASSERT_EQ(result1.get(), false);
449
450 auto event = std::make_shared<Event>("testevent");
451 auto result2 = currentLooper_->AddEventForResult(eventhandler, event);
452 ASSERT_EQ(result2.get(), true);
453 }
454
455 /**
456 * @tc.name: EventLoopEventAuditTest001
457 * @tc.desc: Test audit function.
458 * @tc.type: FUNC
459 * @tc.require: issueI642OH
460 */
461 HWTEST_F(EventLoopTest, EventLoopEventAuditTest001, TestSize.Level3)
462 {
463 /**
464 * @tc.steps: step1. open the audit function.
465 * @tc.steps: step2. create pipeline event.
466 * @tc.steps: step3. add event to the handler.
467 */
468 Audit::GetInstance().Init(true);
469 EXPECT_TRUE(Audit::GetInstance().IsEnabled());
470 Event event("test");
471 auto pipelineEvent = std::make_shared<PipelineEvent>(event);
472 EXPECT_TRUE(pipelineEvent->isPipeline_);
473 auto eventhandler = std::make_shared<RealEventHandler>();
474 auto res1 = currentLooper_->AddEvent(eventhandler, pipelineEvent, nullptr);
475 sleep(2);
476 EXPECT_NE(0, res1);
477 EXPECT_EQ(1, eventhandler->processedEventCount_);
478
479 auto res2 = currentLooper_->AddEventForResult(eventhandler, pipelineEvent);
480 sleep(2);
481 ASSERT_EQ(res2.get(), true);
482 EXPECT_EQ(2, eventhandler->processedEventCount_);
483
484 res1 = currentLooper_->AddTimerEvent(eventhandler, pipelineEvent, nullptr, 1, false);
485 sleep(3);
486 EXPECT_NE(0, res1);
487 EXPECT_EQ(3, eventhandler->processedEventCount_);
488
489 currentLooper_->StopLoop();
490 res1 = currentLooper_->AddEvent(eventhandler, pipelineEvent, nullptr);
491 EXPECT_EQ(0, res1);
492 res2 = currentLooper_->AddEventForResult(eventhandler, nullptr);
493 ASSERT_EQ(res2.get(), false);
494 res1 = currentLooper_->AddTimerEvent(eventhandler, pipelineEvent, nullptr, 2, false);
495 sleep(3);
496 EXPECT_EQ(0, res1);
497
498 const std::string loopName = "restart_loop";
499 currentLooper_ = std::make_shared<EventLoop>(loopName);
500 EXPECT_TRUE(currentLooper_ != nullptr);
501 EXPECT_EQ(currentLooper_->GetName(), loopName);
502 currentLooper_->StartLoop();
503 res1 = currentLooper_->AddEvent(eventhandler, pipelineEvent, nullptr);
504 sleep(2);
505 EXPECT_NE(0, res1);
506 EXPECT_EQ(4, eventhandler->processedEventCount_);
507
508 EXPECT_NE(currentLooper_->GetName(), loopName); // name: loopName@xxx
509 EXPECT_EQ(currentLooper_->GetRawName(), loopName);
510 }
511 }
512 }
513