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 expect_destruct(); 95 } 96 97 TEST_F(ChildTest, ConstructError) 98 { 99 const pid_t pid = 50; 100 const int options = WEXITED; 101 102 EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid, 103 options, testing::_, nullptr)) 104 .WillOnce(Return(-EINVAL)); 105 int completions = 0; 106 Child::Callback callback = [&completions](Child&, const siginfo_t*) { 107 completions++; 108 }; 109 EXPECT_THROW(Child(*event, pid, options, std::move(callback)), 110 SdEventError); 111 EXPECT_TRUE(callback); 112 EXPECT_EQ(0, completions); 113 } 114 115 class ChildMethodTest : public ChildTest 116 { 117 protected: 118 std::unique_ptr<Child> child; 119 120 void SetUp() 121 { 122 const pid_t pid = 50; 123 const int options = WEXITED; 124 125 EXPECT_CALL(mock, sd_event_ref(expected_event)) 126 .WillOnce(Return(expected_event)); 127 EXPECT_CALL(mock, sd_event_add_child(expected_event, testing::_, pid, 128 options, testing::_, nullptr)) 129 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 130 EXPECT_CALL(mock, 131 sd_event_source_set_userdata(expected_source, testing::_)) 132 .WillOnce(Return(nullptr)); 133 child = std::make_unique<Child>(*event, pid, options, 134 [](Child&, const siginfo_t*) {}); 135 } 136 137 void TearDown() 138 { 139 expect_destruct(); 140 child.reset(); 141 } 142 }; 143 144 TEST_F(ChildMethodTest, GetPidSuccess) 145 { 146 const pid_t pid = 32; 147 EXPECT_CALL(mock, 148 sd_event_source_get_child_pid(expected_source, testing::_)) 149 .WillOnce(DoAll(SetArgPointee<1>(pid), Return(0))); 150 EXPECT_EQ(pid, child->get_pid()); 151 } 152 153 TEST_F(ChildMethodTest, GetPidError) 154 { 155 EXPECT_CALL(mock, 156 sd_event_source_get_child_pid(expected_source, testing::_)) 157 .WillOnce(Return(-EINVAL)); 158 EXPECT_THROW(child->get_pid(), SdEventError); 159 } 160 161 } // namespace 162 } // namespace source 163 } // namespace sdeventplus 164