1 /*
2 * Copyright (c) 2022 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
16 #include <cerrno>
17 #include <string>
18 #include <vector>
19 #include <iostream>
20 #include <memory>
21 #include <gtest/gtest.h>
22 #include <sys/stat.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <selinux/selinux.h>
26
27 #include "param_stub.h"
28 #include "ueventd.h"
29 #include "ueventd_device_handler.h"
30 #include "ueventd_socket.h"
31
32 using namespace testing::ext;
33
34 namespace UeventdUt {
35 namespace {
36 std::string g_testRoot{"/data/ueventd"};
37 int g_oldRootFd = -1;
38 }
39
40 class UeventdEventUnitTest : public testing::Test {
41 public:
SetUpTestCase(void)42 static void SetUpTestCase(void)
43 {
44 struct stat st{};
45 bool isExist = true;
46
47 if (stat(g_testRoot.c_str(), &st) < 0) {
48 if (errno != ENOENT) {
49 std::cout << "Cannot get stat of " << g_testRoot << std::endl;
50 // If we cannot get root for ueventd tests
51 // There is no reason to continue.
52 ASSERT_TRUE(false);
53 }
54 isExist = false;
55 }
56
57 if (isExist) {
58 RemoveDir(g_testRoot);
59 }
60 int ret = mkdir(g_testRoot.c_str(), S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
61 if (ret < 0) {
62 std::cout << "Cannot create directory " << g_testRoot << " err = " << errno << std::endl;
63 ASSERT_TRUE(0);
64 }
65 if (SwitchRoot() < 0) {
66 // If we cannot do this, there is not reason to continue
67 ASSERT_TRUE(0);
68 }
69 }
70
TearDownTestCase(void)71 static void TearDownTestCase(void)
72 {
73 // Switch back to old root
74 if (g_oldRootFd < 0) {
75 std::cout << "Old root directory is not valid\n";
76 return;
77 }
78
79 if (fchdir(g_oldRootFd) < 0) {
80 std::cout << "Failed to change working directory to '/', err = " << errno << std::endl;
81 }
82
83 if (chroot(".") < 0) {
84 std::cout << "Failed to change root directory to '/', err = " << errno << std::endl;
85 }
86 close(g_oldRootFd);
87 g_oldRootFd = -1;
88 std::cout << "Change root back done\n";
89 // Remove test data
90 if (RemoveDir(g_testRoot) < 0) {
91 std::cout << "Failed to remove " << g_testRoot << ", err = " << errno << std::endl;
92 }
93 }
94
RemoveDir(const std::string & path)95 static int RemoveDir(const std::string &path)
96 {
97 if (path.empty()) {
98 // Treat it as OK
99 return 0;
100 }
101 auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(path.c_str()), closedir);
102 if (dir == nullptr) {
103 std::cout << "Cannot open dir " << path << ", err = " << errno << std::endl;
104 return -1;
105 }
106
107 struct dirent *dp = nullptr;
108 while ((dp = readdir(dir.get())) != nullptr) {
109 // Skip hidden files
110 if (dp->d_name[0] == '.') {
111 continue;
112 }
113 bool endsWithSlash = (path.find_last_of("/") == path.size() - 1);
114 std::string fullPath {};
115 if (endsWithSlash) {
116 fullPath = path + dp->d_name;
117 } else {
118 fullPath = path + "/" + dp->d_name;
119 }
120 struct stat st {};
121 if (stat(fullPath.c_str(), &st) < 0) {
122 std::cout << "Failed to get stat of " << fullPath << std::endl;
123 continue; // Should we continue?
124 }
125 if (S_ISDIR(st.st_mode)) {
126 if (RemoveDir(fullPath) < 0) {
127 std::cout << "Failed to remove directory " << fullPath << std::endl;
128 return -1;
129 }
130 } else {
131 if (unlink(fullPath.c_str()) < 0) {
132 std::cout << "Failed to unlink file " << fullPath << std::endl;
133 return -1;
134 }
135 }
136 }
137 return rmdir(path.c_str());
138 }
139
SwitchRoot()140 static int SwitchRoot()
141 {
142 if (g_oldRootFd >= 0) {
143 close(g_oldRootFd);
144 g_oldRootFd = -1;
145 }
146 // Save old root
147 DIR *dir = opendir("/");
148 if (dir == nullptr) {
149 std::cout << "Failed to open root directory\n";
150 return -1;
151 }
152 g_oldRootFd = dirfd(dir);
153 if (g_oldRootFd < 0) {
154 std::cout << "Failed to pen root directory, err = " << errno << std::endl;
155 return -1;
156 }
157
158 // Changing working directory to "/data/ueventd"
159 if (chdir(g_testRoot.c_str()) < 0) {
160 std::cout << "Failed to change working directory to " << g_testRoot << ", err = " << errno << std::endl;
161 close(g_oldRootFd);
162 g_oldRootFd = -1;
163 }
164
165 if (chroot(g_testRoot.c_str()) < 0) {
166 std::cout << "Failed to change root directory to " << g_testRoot << ", err = " << errno << std::endl;
167 close(g_oldRootFd);
168 g_oldRootFd = -1;
169 }
170 std::cout << "Change root to " << g_testRoot << " done\n";
171 return 0;
172 }
173
SetUp()174 void SetUp() {};
TearDown()175 void TearDown() {};
176 };
177
178 // Generate uevent buffer from struct uevent.
179 // extra data used to break uevent buffer to check
180 // if ueventd will handle this situation correctly
GenerateUeventBuffer(struct Uevent & uevent,std::vector<std::string> & extraData)181 std::string GenerateUeventBuffer(struct Uevent &uevent, std::vector<std::string> &extraData)
182 {
183 std::string ueventdBuffer{};
184 if (uevent.syspath != nullptr) {
185 ueventdBuffer.append(std::string("DEVPATH=") + uevent.syspath + '\000');
186 }
187 if (uevent.subsystem != nullptr) {
188 ueventdBuffer.append(std::string("SUBSYSTEM=") + uevent.subsystem + '\000');
189 }
190 ueventdBuffer.append(std::string("ACTION=") + ActionString(uevent.action) + '\000');
191 if (uevent.deviceName != nullptr) {
192 ueventdBuffer.append(std::string("DEVNAME=") + uevent.deviceName + '\000');
193 }
194 if (uevent.partitionName != nullptr) {
195 ueventdBuffer.append(std::string("PARTNAME=") + uevent.partitionName + '\000');
196 }
197 ueventdBuffer.append(std::string("PARTN=") + std::to_string(uevent.partitionNum) + '\000');
198 ueventdBuffer.append(std::string("MAJOR=") + std::to_string(uevent.major) + '\000');
199 ueventdBuffer.append(std::string("MINOR=") + std::to_string(uevent.minor) + '\000');
200 ueventdBuffer.append(std::string("DEVUID=") + std::to_string(uevent.ug.uid) + '\000');
201 ueventdBuffer.append(std::string("DEVGID=") + std::to_string(uevent.ug.gid) + '\000');
202 if (uevent.firmware != nullptr) {
203 ueventdBuffer.append(std::string("FIRMWARE=") + uevent.firmware + '\000');
204 }
205 ueventdBuffer.append(std::string("BUSNUM=") + std::to_string(uevent.busNum) + '\000');
206 ueventdBuffer.append(std::string("DEVNUM=") + std::to_string(uevent.devNum) + '\000');
207
208 if (!extraData.empty()) {
209 for (const auto &data : extraData) {
210 ueventdBuffer.append(data);
211 }
212 }
213 return ueventdBuffer;
214 }
215
IsFileExist(const std::string & file)216 bool IsFileExist(const std::string &file)
217 {
218 struct stat st{};
219 if (file.empty()) {
220 return false;
221 }
222
223 if (stat(file.c_str(), &st) < 0) {
224 if (errno == ENOENT) {
225 std::cout << "File " << file << " is not exist\n";
226 }
227 return false;
228 }
229 return true;
230 }
231
232 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_ParseUeventdEvent001, TestSize.Level1)
233 {
234 struct Uevent uevent = {
235 .subsystem = "block",
236 .syspath = "/block/mmc/test",
237 .deviceName = "test",
238 .partitionName = "userdata",
239 .firmware = "",
240 .action = ACTION_ADD,
241 .partitionNum = 3,
242 .major = 1,
243 .minor = 2,
244 .ug = {
245 .uid = 0,
246 .gid = 0,
247 },
248 .busNum = 1,
249 .devNum = 2,
250 };
251
252 std::vector<std::string> extraData{};
253 auto ueventBuffer = GenerateUeventBuffer(uevent, extraData);
254 std::cout << "ueventBuffer = [" << ueventBuffer << "]. size = " << ueventBuffer.length() << std::endl;
255 struct Uevent outEvent;
256 ParseUeventMessage(ueventBuffer.data(), ueventBuffer.length(), &outEvent);
257 EXPECT_EQ(outEvent.action, ACTION_ADD);
258 EXPECT_EQ(outEvent.busNum, 1);
259 EXPECT_STREQ(outEvent.subsystem, "block");
260 EXPECT_STREQ(outEvent.deviceName, "test");
261 EXPECT_EQ(outEvent.devNum, 2);
262 EXPECT_EQ(outEvent.major, 1);
263 EXPECT_EQ(outEvent.minor, 2);
264 EXPECT_EQ(outEvent.partitionNum, 3);
265 EXPECT_STREQ(outEvent.partitionName, "userdata");
266 EXPECT_STREQ(outEvent.syspath, "/block/mmc/test");
267 EXPECT_EQ(outEvent.ug.gid, 0);
268 EXPECT_EQ(outEvent.ug.uid, 0);
269 HandleUevent(&outEvent);
270 }
271
272 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_Actions001, TestSize.Level1)
273 {
274 struct Uevent uevent = {
275 .subsystem = "block",
276 .syspath = "/block/mmc/test",
277 .deviceName = "test",
278 .partitionName = "userdata",
279 .action = ACTION_UNKNOWN,
280 };
281 std::vector<std::string> extraData {};
282 auto ueventBuffer = GenerateUeventBuffer(uevent, extraData);
283 std::cout << "ueventBuffer = [" << ueventBuffer << "]. size = " << ueventBuffer.length() << std::endl;
284 struct Uevent outEvent;
285 ParseUeventMessage(ueventBuffer.data(), ueventBuffer.length(), &outEvent);
286 EXPECT_EQ(outEvent.action, ACTION_UNKNOWN);
287 HandleUevent(&outEvent);
288 }
289
290 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleBlockDevicesInvalidParameters001, TestSize.Level1)
291 {
292 HandleBlockDeviceEvent(nullptr);
293 // Not block device
294 struct Uevent noBlockUevent = {
295 .subsystem = "char",
296 };
297 HandleBlockDeviceEvent(&noBlockUevent);
298
299 struct Uevent invalidDevNoUevent = {
300 .subsystem = "block",
301 .major = -1,
302 .minor = -1,
303 };
304 HandleBlockDeviceEvent(&invalidDevNoUevent);
305
306 struct Uevent invalidSysPathUevent = {
307 .subsystem = "block",
308 .syspath = nullptr,
309 .major = 1,
310 .minor = 1,
311 };
312 HandleBlockDeviceEvent(&invalidSysPathUevent);
313 }
314
315 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleBlockDevicesValidParameters002, TestSize.Level1)
316 {
317 struct Uevent uevent = {
318 .subsystem = "block",
319 .syspath = "/block/mmc/block_device_test",
320 .deviceName = "block_device_test",
321 .partitionName = "block_device_test",
322 .firmware = "",
323 .action = ACTION_ADD,
324 .partitionNum = 3,
325 .major = 5,
326 .minor = 15,
327 .ug = {
328 .uid = 0,
329 .gid = 0,
330 },
331 .busNum = 1,
332 .devNum = 2,
333 };
334
335 HandleBlockDeviceEvent(&uevent);
336 // Check results
337 std::string blockDevice = "/dev/block/block_device_test";
338 struct stat st{};
339 int ret = stat(blockDevice.c_str(), &st);
340 EXPECT_EQ(ret, 0);
341 bool isBlock = S_ISBLK(st.st_mode);
342 EXPECT_TRUE(isBlock);
343 }
344
345 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleBlockDevicesRemoved001, TestSize.Level1)
346 {
347 struct Uevent uevent = {
348 .subsystem = "block",
349 .syspath = "/block/mmc/block_device_test",
350 .deviceName = "block_device_test",
351 .partitionName = "block_device_test",
352 .firmware = "",
353 .action = ACTION_REMOVE,
354 .partitionNum = 3,
355 .major = 5,
356 .minor = 15,
357 .ug = {
358 .uid = 0,
359 .gid = 0,
360 },
361 .busNum = 1,
362 .devNum = 2,
363 };
364 std::string blockDevice = "/dev/block/block_device_test";
365 struct stat st{};
366 int ret = stat(blockDevice.c_str(), &st);
367 if (ret < 0) {
368 // This should not happen actually, because we've created the device node before.
369 std::cout << "Warning. Block device " << blockDevice << " is not exist.\n";
370 }
371 HandleBlockDeviceEvent(&uevent);
372 ret = stat(blockDevice.c_str(), &st);
373 EXPECT_EQ(ret, -1);
374 EXPECT_EQ(errno, ENOENT);
375 }
376
377 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleBlockDevicesChanged001, TestSize.Level1)
378 {
379 struct Uevent uevent = {
380 .subsystem = "block",
381 .syspath = "/block/mmc/block_device_test",
382 .deviceName = "block_device_test",
383 .partitionName = "block_device_test",
384 .firmware = "",
385 .action = ACTION_REMOVE,
386 .partitionNum = 3,
387 .major = 5,
388 .minor = 15,
389 .ug = {
390 .uid = 0,
391 .gid = 0,
392 },
393 .busNum = 1,
394 .devNum = 2,
395 };
396 HandleBlockDeviceEvent(&uevent);
397 }
398
399 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleOtherDevicesInvalidParameters001, TestSize.Level1)
400 {
401 HandleOtherDeviceEvent(nullptr);
402 // Not Character device
403 struct Uevent invalidDevNoUevent = {
404 .subsystem = "test",
405 .major = -1,
406 .minor = -1,
407 };
408 HandleOtherDeviceEvent(&invalidDevNoUevent);
409
410 struct Uevent invalidSysPathUevent = {
411 .subsystem = "test",
412 .syspath = nullptr,
413 .major = 5,
414 .minor = 9,
415 };
416 HandleOtherDeviceEvent(&invalidSysPathUevent);
417
418 struct Uevent invalidSubsystemUevent = {
419 .subsystem = "",
420 .syspath = "/devices/test/char",
421 .major = 5,
422 .minor = 9,
423 };
424 HandleOtherDeviceEvent(&invalidSubsystemUevent);
425 }
426
427 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleOtherDevicesValidParameters001, TestSize.Level1)
428 {
429 struct Uevent uevent = {
430 .subsystem = "extcon3",
431 .syspath = "/devices/platform/headset/extcon/extcon3",
432 .deviceName = "extcon3-1",
433 .major = 5,
434 .minor = 9,
435 };
436 HandleOtherDeviceEvent(&uevent);
437 auto exist = IsFileExist("/dev/extcon3-1");
438 EXPECT_TRUE(exist);
439 exist = IsFileExist("/dev/extcon3");
440 EXPECT_FALSE(exist);
441 }
442
443 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleUsbDevicesWithDeviceName001, TestSize.Level1)
444 {
445 struct Uevent uevent = {
446 .subsystem = "usb",
447 .syspath = "/devices/platform/headset/extcon/usb-dev",
448 .deviceName = "usb-dev",
449 .major = 8,
450 .minor = 9,
451 };
452 HandleOtherDeviceEvent(&uevent);
453 auto exist = IsFileExist("/dev/usb-dev");
454 EXPECT_TRUE(exist);
455 }
456
457 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleInvalidUsbDevices001, TestSize.Level1)
458 {
459 struct Uevent uevent = {
460 .subsystem = "usb",
461 .syspath = "/devices/platform/headset/extcon/usb-dev-1",
462 .major = 8,
463 .minor = 10,
464 .busNum = -1,
465 .devNum = -1,
466 };
467 HandleOtherDeviceEvent(&uevent);
468 auto exist = IsFileExist("/dev/usb-dev-1");
469 EXPECT_FALSE(exist);
470 }
471
472 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_HandleUsbDevicesWithBusNo001, TestSize.Level1)
473 {
474 struct Uevent uevent = {
475 .subsystem = "usb",
476 .syspath = "/devices/platform/headset/extcon/usb-dev",
477 .major = 8,
478 .minor = 9,
479 .busNum = 3,
480 .devNum = 4,
481 };
482 HandleOtherDeviceEvent(&uevent);
483 auto exist = IsFileExist("/dev/bus/usb/003/004");
484 EXPECT_TRUE(exist);
485 }
486
487 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_Handle001, TestSize.Level1)
488 {
489 char path[] = {"/data/ueventd"};
490 RetriggerUeventByPath(g_oldRootFd, path);
491 }
492
493 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_FirmwareUevent001, TestSize.Level1)
494 {
495 struct Uevent uevent = {
496 .subsystem = "firmware",
497 .syspath = "/block/mmc/test",
498 .deviceName = "test",
499 .partitionName = "userdata",
500 .firmware = "",
501 .action = ACTION_ADD,
502 .partitionNum = 3,
503 .major = 1,
504 .minor = 2,
505 .ug = {
506 .uid = 0,
507 .gid = 0,
508 },
509 .busNum = 1,
510 .devNum = 2,
511 };
512
513 std::vector<std::string> extraData{};
514 auto ueventBuffer = GenerateUeventBuffer(uevent, extraData);
515 struct Uevent outEvent;
516 ParseUeventMessage(ueventBuffer.data(), ueventBuffer.length(), &outEvent);
517 EXPECT_EQ(outEvent.action, ACTION_ADD);
518 EXPECT_EQ(outEvent.busNum, 1);
519 EXPECT_STREQ(outEvent.subsystem, "firmware");
520 EXPECT_STREQ(outEvent.deviceName, "test");
521 EXPECT_EQ(outEvent.devNum, 2);
522 EXPECT_EQ(outEvent.major, 1);
523 EXPECT_EQ(outEvent.minor, 2);
524 EXPECT_EQ(outEvent.partitionNum, 3);
525 EXPECT_STREQ(outEvent.partitionName, "userdata");
526 EXPECT_STREQ(outEvent.syspath, "/block/mmc/test");
527 EXPECT_EQ(outEvent.ug.gid, 0);
528 EXPECT_EQ(outEvent.ug.uid, 0);
529 HandleUevent(&outEvent);
530 }
531
532 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventTest_PlatformEvent001, TestSize.Level1)
533 {
534 struct Uevent uevent = {
535 .subsystem = "platform",
536 .syspath = "/block/mmc/test",
537 .deviceName = "test",
538 .partitionName = "userdata",
539 .firmware = "",
540 .action = ACTION_ADD,
541 .partitionNum = 3,
542 .major = 1,
543 .minor = 2,
544 .ug = {
545 .uid = 0,
546 .gid = 0,
547 },
548 .busNum = 1,
549 .devNum = 2,
550 };
551
552 std::vector<std::string> extraData{};
553 auto ueventBuffer = GenerateUeventBuffer(uevent, extraData);
554 struct Uevent outEvent;
555 ParseUeventMessage(ueventBuffer.data(), ueventBuffer.length(), &outEvent);
556 EXPECT_EQ(outEvent.action, ACTION_ADD);
557 EXPECT_EQ(outEvent.busNum, 1);
558 EXPECT_STREQ(outEvent.subsystem, "platform");
559 EXPECT_STREQ(outEvent.deviceName, "test");
560 EXPECT_EQ(outEvent.devNum, 2);
561 EXPECT_EQ(outEvent.major, 1);
562 EXPECT_EQ(outEvent.minor, 2);
563 EXPECT_EQ(outEvent.partitionNum, 3);
564 EXPECT_STREQ(outEvent.partitionName, "userdata");
565 EXPECT_STREQ(outEvent.syspath, "/block/mmc/test");
566 EXPECT_EQ(outEvent.ug.gid, 0);
567 EXPECT_EQ(outEvent.ug.uid, 0);
568 HandleUevent(&outEvent);
569 }
570
571 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_PlatformEventUsb001, TestSize.Level1)
572 {
573 struct Uevent uevent = {
574 .subsystem = "usb",
575 .syspath = "/block/mmc/test",
576 .deviceName = "test",
577 .partitionName = "userdata",
578 .firmware = "",
579 .action = ACTION_ADD,
580 .partitionNum = 3,
581 .major = 1,
582 .minor = 2,
583 .ug = {
584 .uid = 0,
585 .gid = 0,
586 },
587 .busNum = 1,
588 .devNum = 2,
589 };
590
591 std::vector<std::string> extraData{};
592 auto ueventBuffer = GenerateUeventBuffer(uevent, extraData);
593 struct Uevent outEvent;
594 ParseUeventMessage(ueventBuffer.data(), ueventBuffer.length(), &outEvent);
595 EXPECT_EQ(outEvent.action, ACTION_ADD);
596 EXPECT_EQ(outEvent.busNum, 1);
597 EXPECT_STREQ(outEvent.subsystem, "usb");
598 EXPECT_STREQ(outEvent.deviceName, "test");
599 EXPECT_EQ(outEvent.devNum, 2);
600 EXPECT_EQ(outEvent.major, 1);
601 EXPECT_EQ(outEvent.minor, 2);
602 EXPECT_EQ(outEvent.partitionNum, 3);
603 EXPECT_STREQ(outEvent.partitionName, "userdata");
604 EXPECT_STREQ(outEvent.syspath, "/block/mmc/test");
605 EXPECT_EQ(outEvent.ug.gid, 0);
606 EXPECT_EQ(outEvent.ug.uid, 0);
607 HandleUevent(&outEvent);
608 }
609
TestUeventAction(ACTION action)610 static void TestUeventAction(ACTION action)
611 {
612 struct Uevent uevent = {
613 .subsystem = "block",
614 .syspath = "/block/mmc/test",
615 .deviceName = "test",
616 .partitionName = "userdata",
617 .firmware = "",
618 .action = action,
619 .partitionNum = 3,
620 .major = 1,
621 .minor = 2,
622 .ug = {
623 .uid = 0,
624 .gid = 0,
625 },
626 .busNum = 1,
627 .devNum = 2,
628 };
629
630 std::vector<std::string> extraData{};
631 auto ueventBuffer = GenerateUeventBuffer(uevent, extraData);
632 struct Uevent outEvent;
633 ParseUeventMessage(ueventBuffer.data(), ueventBuffer.length(), &outEvent);
634 EXPECT_EQ(outEvent.action, action);
635 HandleUevent(&outEvent);
636 }
637
638 HWTEST_F(UeventdEventUnitTest, Init_UeventdEventUnitTest_ActionAdd001, TestSize.Level1)
639 {
640 TestUeventAction(ACTION_ADD);
641 TestUeventAction(ACTION_REMOVE);
642 TestUeventAction(ACTION_CHANGE);
643 TestUeventAction(ACTION_MOVE);
644 TestUeventAction(ACTION_ONLINE);
645
646 TestUeventAction(ACTION_OFFLINE);
647 TestUeventAction(ACTION_BIND);
648 TestUeventAction(ACTION_UNBIND);
649 TestUeventAction(ACTION_UNKNOWN);
650 }
651 } // UeventdUt