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::SaveArg; 25 using testing::SetArgPointee; 26 27 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 28 29 class ChildTest : public testing::Test 30 { 31 protected: 32 testing::StrictMock<test::SdEventMock> mock; 33 sd_event_source* const expected_source = 34 reinterpret_cast<sd_event_source*>(1234); 35 sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); 36 UniqueEvent event = make_event(expected_event); 37 38 UniqueEvent make_event(sd_event* event) 39 { 40 auto deleter = [this, event](Event* e) { 41 EXPECT_CALL(this->mock, sd_event_unref(event)) 42 .WillOnce(Return(nullptr)); 43 delete e; 44 }; 45 return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); 46 } 47 48 void expect_destruct() 49 { 50 { 51 testing::InSequence sequence; 52 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, 53 SD_EVENT_OFF)) 54 .WillOnce(Return(0)); 55 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 56 .WillOnce(Return(nullptr)); 57 } 58 EXPECT_CALL(mock, sd_event_unref(expected_event)) 59 .WillOnce(Return(nullptr)); 60 } 61 }; 62 63 TEST_F(ChildTest, ConstructSuccess) 64 { 65 const pid_t pid = 50; 66 const int options = WEXITED; 67 68 EXPECT_CALL(mock, sd_event_ref(expected_event)) 69 .WillOnce(Return(expected_event)); 70 sd_event_child_handler_t handler; 71 EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid, 72 options, testing::_, nullptr)) 73 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<4>(&handler), 74 Return(0))); 75 void* userdata; 76 EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_)) 77 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 78 int completions = 0; 79 const siginfo_t* return_si; 80 Child::Callback callback = [&](Child&, const siginfo_t* si) { 81 return_si = si; 82 completions++; 83 }; 84 Child child(*event, pid, options, std::move(callback)); 85 EXPECT_FALSE(callback); 86 EXPECT_EQ(&child, userdata); 87 EXPECT_EQ(0, completions); 88 89 const siginfo_t* expected_si = reinterpret_cast<siginfo_t*>(865); 90 EXPECT_EQ(0, handler(nullptr, expected_si, &child)); 91 EXPECT_EQ(1, completions); 92 EXPECT_EQ(expected_si, return_si); 93 94 child.set_callback(std::bind([]() {})); 95 EXPECT_EQ(0, handler(nullptr, expected_si, &child)); 96 EXPECT_EQ(1, completions); 97 98 expect_destruct(); 99 } 100 101 TEST_F(ChildTest, ConstructError) 102 { 103 const pid_t pid = 50; 104 const int options = WEXITED; 105 106 EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid, 107 options, testing::_, nullptr)) 108 .WillOnce(Return(-EINVAL)); 109 int completions = 0; 110 Child::Callback callback = [&completions](Child&, const siginfo_t*) { 111 completions++; 112 }; 113 EXPECT_THROW(Child(*event, pid, options, std::move(callback)), 114 SdEventError); 115 EXPECT_TRUE(callback); 116 EXPECT_EQ(0, completions); 117 } 118 119 class ChildMethodTest : public ChildTest 120 { 121 protected: 122 std::unique_ptr<Child> child; 123 124 void SetUp() 125 { 126 const pid_t pid = 50; 127 const int options = WEXITED; 128 129 EXPECT_CALL(mock, sd_event_ref(expected_event)) 130 .WillOnce(Return(expected_event)); 131 EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid, 132 options, testing::_, nullptr)) 133 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 134 EXPECT_CALL(mock, 135 sd_event_source_set_userdata(expected_source, testing::_)) 136 .WillOnce(Return(nullptr)); 137 child = std::make_unique<Child>(*event, pid, options, 138 [](Child&, const siginfo_t*) {}); 139 } 140 141 void TearDown() 142 { 143 expect_destruct(); 144 child.reset(); 145 } 146 }; 147 148 TEST_F(ChildMethodTest, GetPidSuccess) 149 { 150 const pid_t pid = 32; 151 EXPECT_CALL(mock, 152 sd_event_source_get_child_pid(expected_source, testing::_)) 153 .WillOnce(DoAll(SetArgPointee<1>(pid), Return(0))); 154 EXPECT_EQ(pid, child->get_pid()); 155 } 156 157 TEST_F(ChildMethodTest, GetPidError) 158 { 159 EXPECT_CALL(mock, 160 sd_event_source_get_child_pid(expected_source, testing::_)) 161 .WillOnce(Return(-EINVAL)); 162 EXPECT_THROW(child->get_pid(), SdEventError); 163 } 164 165 } // namespace 166 } // namespace source 167 } // namespace sdeventplus 168