1 #include <cerrno> 2 #include <functional> 3 #include <gmock/gmock.h> 4 #include <gtest/gtest.h> 5 #include <memory> 6 #include <sdeventplus/event.hpp> 7 #include <sdeventplus/exception.hpp> 8 #include <sdeventplus/source/child.hpp> 9 #include <sdeventplus/test/sdevent.hpp> 10 #include <sys/wait.h> 11 #include <systemd/sd-event.h> 12 #include <type_traits> 13 #include <utility> 14 15 namespace sdeventplus 16 { 17 namespace source 18 { 19 namespace 20 { 21 22 using testing::DoAll; 23 using testing::Return; 24 using testing::ReturnPointee; 25 using testing::SaveArg; 26 using testing::SetArgPointee; 27 28 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 29 30 class ChildTest : public testing::Test 31 { 32 protected: 33 testing::StrictMock<test::SdEventMock> mock; 34 sd_event_source* const expected_source = 35 reinterpret_cast<sd_event_source*>(1234); 36 sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); 37 UniqueEvent event = make_event(expected_event); 38 39 UniqueEvent make_event(sd_event* event) 40 { 41 auto deleter = [this, event](Event* e) { 42 EXPECT_CALL(this->mock, sd_event_unref(event)) 43 .WillOnce(Return(nullptr)); 44 delete e; 45 }; 46 return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); 47 } 48 49 void expect_destruct() 50 { 51 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 52 .WillOnce(Return(nullptr)); 53 EXPECT_CALL(mock, sd_event_unref(expected_event)) 54 .WillOnce(Return(nullptr)); 55 } 56 }; 57 58 TEST_F(ChildTest, ConstructSuccess) 59 { 60 const pid_t pid = 50; 61 const int options = WEXITED; 62 63 EXPECT_CALL(mock, sd_event_ref(expected_event)) 64 .WillOnce(Return(expected_event)); 65 sd_event_child_handler_t handler; 66 EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid, 67 options, testing::_, nullptr)) 68 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<4>(&handler), 69 Return(0))); 70 sd_event_destroy_t destroy; 71 void* userdata; 72 { 73 testing::InSequence seq; 74 EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source, 75 testing::_)) 76 .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0))); 77 EXPECT_CALL(mock, 78 sd_event_source_set_userdata(expected_source, testing::_)) 79 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 80 EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source)) 81 .WillRepeatedly(ReturnPointee(&userdata)); 82 } 83 int completions = 0; 84 const siginfo_t* return_si; 85 Child::Callback callback = [&](Child&, const siginfo_t* si) { 86 return_si = si; 87 completions++; 88 }; 89 Child child(*event, pid, options, std::move(callback)); 90 EXPECT_FALSE(callback); 91 EXPECT_NE(&child, userdata); 92 EXPECT_EQ(0, completions); 93 94 const siginfo_t* expected_si = reinterpret_cast<siginfo_t*>(865); 95 EXPECT_EQ(0, handler(nullptr, expected_si, userdata)); 96 EXPECT_EQ(1, completions); 97 EXPECT_EQ(expected_si, return_si); 98 99 child.set_callback(std::bind([]() {})); 100 EXPECT_EQ(0, handler(nullptr, expected_si, userdata)); 101 EXPECT_EQ(1, completions); 102 103 expect_destruct(); 104 destroy(userdata); 105 } 106 107 TEST_F(ChildTest, ConstructError) 108 { 109 const pid_t pid = 50; 110 const int options = WEXITED; 111 112 EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid, 113 options, testing::_, nullptr)) 114 .WillOnce(Return(-EINVAL)); 115 int completions = 0; 116 Child::Callback callback = [&completions](Child&, const siginfo_t*) { 117 completions++; 118 }; 119 EXPECT_THROW(Child(*event, pid, options, std::move(callback)), 120 SdEventError); 121 EXPECT_TRUE(callback); 122 EXPECT_EQ(0, completions); 123 } 124 125 class ChildMethodTest : public ChildTest 126 { 127 protected: 128 std::unique_ptr<Child> child; 129 sd_event_destroy_t destroy; 130 void* userdata; 131 132 void SetUp() 133 { 134 const pid_t pid = 50; 135 const int options = WEXITED; 136 137 EXPECT_CALL(mock, sd_event_ref(expected_event)) 138 .WillOnce(Return(expected_event)); 139 EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid, 140 options, testing::_, nullptr)) 141 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 142 { 143 testing::InSequence seq; 144 EXPECT_CALL(mock, sd_event_source_set_destroy_callback( 145 expected_source, testing::_)) 146 .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0))); 147 EXPECT_CALL( 148 mock, sd_event_source_set_userdata(expected_source, testing::_)) 149 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 150 EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source)) 151 .WillRepeatedly(ReturnPointee(&userdata)); 152 } 153 child = std::make_unique<Child>(*event, pid, options, 154 [](Child&, const siginfo_t*) {}); 155 } 156 157 void TearDown() 158 { 159 expect_destruct(); 160 child.reset(); 161 destroy(userdata); 162 } 163 }; 164 165 TEST_F(ChildMethodTest, GetPidSuccess) 166 { 167 const pid_t pid = 32; 168 EXPECT_CALL(mock, 169 sd_event_source_get_child_pid(expected_source, testing::_)) 170 .WillOnce(DoAll(SetArgPointee<1>(pid), Return(0))); 171 EXPECT_EQ(pid, child->get_pid()); 172 } 173 174 TEST_F(ChildMethodTest, GetPidError) 175 { 176 EXPECT_CALL(mock, 177 sd_event_source_get_child_pid(expected_source, testing::_)) 178 .WillOnce(Return(-EINVAL)); 179 EXPECT_THROW(child->get_pid(), SdEventError); 180 } 181 182 } // namespace 183 } // namespace source 184 } // namespace sdeventplus 185