| Ken Chen | d27d6c9 | 2021-10-21 22:18:59 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2019 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 <string> | 
|  | 18 |  | 
|  | 19 | #include <android-base/expected.h> | 
|  | 20 | #include <gtest/gtest.h> | 
|  | 21 | #include <netdutils/ThreadUtil.h> | 
|  | 22 |  | 
|  | 23 | namespace android::netdutils { | 
|  | 24 |  | 
|  | 25 | namespace { | 
|  | 26 |  | 
|  | 27 | android::base::expected<std::string, int> getThreadName() { | 
|  | 28 | char name[16] = {}; | 
|  | 29 | if (const int ret = pthread_getname_np(pthread_self(), name, sizeof(name)); ret != 0) { | 
|  | 30 | return android::base::unexpected(ret); | 
|  | 31 | } | 
|  | 32 | return std::string(name); | 
|  | 33 | } | 
|  | 34 |  | 
|  | 35 | class NoopRun { | 
|  | 36 | public: | 
|  | 37 | explicit NoopRun(const std::string& name = "") : mName(name) { instanceNum++; } | 
|  | 38 |  | 
|  | 39 | // Destructor happens in the thread. | 
|  | 40 | ~NoopRun() { | 
|  | 41 | if (checkName) { | 
|  | 42 | auto expected = getThreadName(); | 
|  | 43 | EXPECT_TRUE(expected.has_value()); | 
|  | 44 | EXPECT_EQ(mExpectedName, expected.value()); | 
|  | 45 | } | 
|  | 46 | instanceNum--; | 
|  | 47 | } | 
|  | 48 |  | 
|  | 49 | void run() {} | 
|  | 50 |  | 
|  | 51 | std::string threadName() { return mName; } | 
|  | 52 |  | 
|  | 53 | // Set the expected thread name which will be used to check if it matches the actual thread | 
|  | 54 | // name which is returned from the system call. The check will happen in the destructor. | 
|  | 55 | void setExpectedName(const std::string& expectedName) { | 
|  | 56 | checkName = true; | 
|  | 57 | mExpectedName = expectedName; | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | static bool waitForAllReleased(int timeoutMs) { | 
|  | 61 | constexpr int intervalMs = 20; | 
|  | 62 | int limit = timeoutMs / intervalMs; | 
|  | 63 | for (int i = 1; i < limit; i++) { | 
|  | 64 | if (instanceNum == 0) { | 
|  | 65 | return true; | 
|  | 66 | } | 
|  | 67 | usleep(intervalMs * 1000); | 
|  | 68 | } | 
|  | 69 | return false; | 
|  | 70 | } | 
|  | 71 |  | 
|  | 72 | // To track how many instances are alive. | 
|  | 73 | static std::atomic<int> instanceNum; | 
|  | 74 |  | 
|  | 75 | private: | 
|  | 76 | std::string mName; | 
|  | 77 | std::string mExpectedName; | 
|  | 78 | bool checkName = false; | 
|  | 79 | }; | 
|  | 80 |  | 
|  | 81 | std::atomic<int> NoopRun::instanceNum; | 
|  | 82 |  | 
|  | 83 | }  // namespace | 
|  | 84 |  | 
|  | 85 | TEST(ThreadUtilTest, objectReleased) { | 
|  | 86 | NoopRun::instanceNum = 0; | 
|  | 87 | NoopRun* obj = new NoopRun(); | 
|  | 88 | EXPECT_EQ(1, NoopRun::instanceNum); | 
|  | 89 | threadLaunch(obj); | 
|  | 90 |  | 
|  | 91 | // Wait for the object released along with the thread exited. | 
|  | 92 | EXPECT_TRUE(NoopRun::waitForAllReleased(1000)); | 
|  | 93 | EXPECT_EQ(0, NoopRun::instanceNum); | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | TEST(ThreadUtilTest, SetThreadName) { | 
|  | 97 | NoopRun::instanceNum = 0; | 
|  | 98 |  | 
|  | 99 | // Test thread name empty. | 
|  | 100 | NoopRun* obj1 = new NoopRun(); | 
|  | 101 | obj1->setExpectedName(""); | 
|  | 102 |  | 
|  | 103 | // Test normal case. | 
|  | 104 | NoopRun* obj2 = new NoopRun("TestName"); | 
|  | 105 | obj2->setExpectedName("TestName"); | 
|  | 106 |  | 
|  | 107 | // Test thread name too long. | 
|  | 108 | std::string name("TestNameTooooLong"); | 
|  | 109 | NoopRun* obj3 = new NoopRun(name); | 
|  | 110 | obj3->setExpectedName(name.substr(0, 15)); | 
|  | 111 |  | 
|  | 112 | // Thread names are examined in their destructors. | 
|  | 113 | EXPECT_EQ(3, NoopRun::instanceNum); | 
|  | 114 | threadLaunch(obj1); | 
|  | 115 | threadLaunch(obj2); | 
|  | 116 | threadLaunch(obj3); | 
|  | 117 |  | 
|  | 118 | EXPECT_TRUE(NoopRun::waitForAllReleased(1000)); | 
|  | 119 | EXPECT_EQ(0, NoopRun::instanceNum); | 
|  | 120 | } | 
|  | 121 |  | 
|  | 122 | }  // namespace android::netdutils |