Rolf Badorek | ef2bf51 | 2019-08-20 11:17:15 +0300 | [diff] [blame] | 1 | /* |
| 2 | Copyright (c) 2018-2019 Nokia. |
| 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 | |
Timo Tietavainen | a0745d2 | 2019-11-28 09:55:22 +0200 | [diff] [blame^] | 17 | /* |
| 18 | * This source code is part of the near-RT RIC (RAN Intelligent Controller) |
| 19 | * platform project (RICP). |
| 20 | */ |
| 21 | |
Rolf Badorek | ef2bf51 | 2019-08-20 11:17:15 +0300 | [diff] [blame] | 22 | #include <memory> |
| 23 | #include <sys/epoll.h> |
| 24 | #include <gmock/gmock.h> |
| 25 | #include "private/filedescriptor.hpp" |
| 26 | #include "private/engineimpl.hpp" |
| 27 | #include "private/tst/systemmock.hpp" |
| 28 | |
| 29 | using namespace shareddatalayer; |
| 30 | using namespace shareddatalayer::tst; |
| 31 | using namespace testing; |
| 32 | |
| 33 | namespace |
| 34 | { |
| 35 | class EventHandlerMock |
| 36 | { |
| 37 | public: |
| 38 | MOCK_METHOD1(handleEvents, void(unsigned int events)); |
| 39 | }; |
| 40 | |
| 41 | class EngineImplTest: public testing::Test |
| 42 | { |
| 43 | public: |
| 44 | const int fd1; |
| 45 | const int fd2; |
| 46 | const int epfd; |
| 47 | NiceMock<SystemMock> systemMock; |
| 48 | std::shared_ptr<EngineImpl> services; |
| 49 | EventHandlerMock eventHandlerMock1; |
| 50 | EventHandlerMock eventHandlerMock2; |
| 51 | |
| 52 | EngineImplTest(): fd1(100), fd2(200), epfd(300) |
| 53 | { |
| 54 | EXPECT_CALL(systemMock, epoll_create1(EPOLL_CLOEXEC)) |
| 55 | .Times(1) |
| 56 | .WillOnce(Return(epfd)); |
| 57 | services.reset(new EngineImpl(systemMock)); |
| 58 | Mock::VerifyAndClear(&systemMock); |
| 59 | } |
| 60 | |
| 61 | ~EngineImplTest() |
| 62 | { |
| 63 | stopEngineImpl(); |
| 64 | } |
| 65 | |
| 66 | void addMonitoredFD(int fd, unsigned int events) |
| 67 | { |
| 68 | services->addMonitoredFD(fd, events, [] (unsigned int) { }); |
| 69 | } |
| 70 | |
| 71 | void addMonitoredFD(int fd, unsigned int events, EventHandlerMock& eventHandlerMock) |
| 72 | { |
| 73 | services->addMonitoredFD(fd, events, std::bind(&EventHandlerMock::handleEvents, &eventHandlerMock, std::placeholders::_1)); |
| 74 | } |
| 75 | |
| 76 | void modifyMonitoredFD(int fd, unsigned int events) |
| 77 | { |
| 78 | services->modifyMonitoredFD(fd, events); |
| 79 | } |
| 80 | |
| 81 | void deleteMonitoredFD(int fd) |
| 82 | { |
| 83 | services->deleteMonitoredFD(fd); |
| 84 | } |
| 85 | |
| 86 | void expectEpollCtl(int epfd, int op, int fd, unsigned int events) |
| 87 | { |
| 88 | EXPECT_CALL(systemMock, epoll_ctl(epfd, op, fd, NotNull())) |
| 89 | .Times(1) |
| 90 | .WillOnce(Invoke([fd, events] (int, int, int, epoll_event* event) |
| 91 | { |
| 92 | epoll_data data = { }; |
| 93 | data.fd = fd; |
| 94 | EXPECT_EQ(data.fd, event->data.fd); |
| 95 | EXPECT_EQ(data.u64, event->data.u64); |
| 96 | EXPECT_EQ(data.ptr, event->data.ptr); |
| 97 | EXPECT_EQ(events, event->events); |
| 98 | })); |
| 99 | } |
| 100 | |
| 101 | void expectAtLeastOneEpollCtl(int epfd, int op, int fd, unsigned int events) |
| 102 | { |
| 103 | EXPECT_CALL(systemMock, epoll_ctl(epfd, op, fd, NotNull())) |
| 104 | .Times(AtLeast(1)) |
| 105 | .WillOnce(Invoke([fd, events] (int, int, int, epoll_event* event) |
| 106 | { |
| 107 | EXPECT_EQ(fd, event->data.fd); |
| 108 | EXPECT_EQ(events, event->events); |
| 109 | })); |
| 110 | } |
| 111 | |
| 112 | void stopEngineImpl() |
| 113 | { |
| 114 | if (!services) |
| 115 | return; |
| 116 | |
| 117 | EXPECT_CALL(systemMock, close(epfd)).Times(1); |
| 118 | services.reset(); |
| 119 | Mock::VerifyAndClear(&systemMock); |
| 120 | } |
| 121 | }; |
| 122 | |
| 123 | using EngineImplDeathTest = EngineImplTest; |
| 124 | } |
| 125 | |
| 126 | TEST_F(EngineImplTest, HandleEventsWithoutAnyAddedFDsDoesNothing) |
| 127 | { |
| 128 | EXPECT_CALL(systemMock, epoll_wait(_, _, _, _)) |
| 129 | .Times(0); |
| 130 | services->handleEvents(); |
| 131 | } |
| 132 | |
| 133 | TEST_F(EngineImplTest, FDReturnsTheEpollFD) |
| 134 | { |
| 135 | EXPECT_EQ(epfd, services->fd()); |
| 136 | } |
| 137 | |
| 138 | TEST_F(EngineImplTest, AddingFDAddsTheFDToEpoll) |
| 139 | { |
| 140 | expectEpollCtl(epfd, EPOLL_CTL_ADD, fd1, Engine::EVENT_IN); |
| 141 | addMonitoredFD(fd1, Engine::EVENT_IN); |
| 142 | } |
| 143 | |
| 144 | TEST_F(EngineImplTest, AddingFileDescriptorSetsAtCloseCallback) |
| 145 | { |
| 146 | FileDescriptor fd(systemMock, fd1); |
| 147 | expectEpollCtl(epfd, EPOLL_CTL_ADD, fd1, Engine::EVENT_IN); |
| 148 | services->addMonitoredFD(fd, Engine::EVENT_IN, Engine::EventHandler()); |
| 149 | |
| 150 | InSequence dummy; |
| 151 | EXPECT_CALL(systemMock, epoll_ctl(epfd, EPOLL_CTL_DEL, fd1, nullptr)) |
| 152 | .Times(1); |
| 153 | EXPECT_CALL(systemMock, close(fd1)).Times(1); |
| 154 | } |
| 155 | |
| 156 | TEST_F(EngineImplDeathTest, AddingAlreadyAddedFDCallsSHAREDDATALAYER_ABORT) |
| 157 | { |
| 158 | expectAtLeastOneEpollCtl(epfd, EPOLL_CTL_ADD, fd1, Engine::EVENT_IN); |
| 159 | addMonitoredFD(fd1, Engine::EVENT_IN); |
| 160 | EXPECT_EXIT(addMonitoredFD(fd1, Engine::EVENT_IN), |
| 161 | KilledBySignal(SIGABRT), "ABORT.*engineimpl\\.cpp"); |
| 162 | } |
| 163 | |
| 164 | TEST_F(EngineImplTest, ModifyingFDModifiesTheFDInEpoll) |
| 165 | { |
| 166 | addMonitoredFD(fd1, Engine::EVENT_IN); |
| 167 | expectEpollCtl(epfd, EPOLL_CTL_MOD, fd1, Engine::EVENT_OUT); |
| 168 | modifyMonitoredFD(fd1, Engine::EVENT_OUT); |
| 169 | } |
| 170 | |
| 171 | TEST_F(EngineImplDeathTest, ModifyingNonExistingFDCallsSHAREDDATALAYER_ABORT) |
| 172 | { |
| 173 | EXPECT_EXIT(modifyMonitoredFD(fd1, 0U), |
| 174 | KilledBySignal(SIGABRT), "ABORT.*engineimpl\\.cpp"); |
| 175 | } |
| 176 | |
| 177 | TEST_F(EngineImplDeathTest, DellingFDDelsTheFDFromEpollAndFromTheMap) |
| 178 | { |
| 179 | addMonitoredFD(fd1, Engine::EVENT_IN); |
| 180 | EXPECT_CALL(systemMock, epoll_ctl(epfd, EPOLL_CTL_DEL, fd1, nullptr)) |
| 181 | .Times(1); |
| 182 | deleteMonitoredFD(fd1); |
| 183 | EXPECT_EXIT(modifyMonitoredFD(fd1, 0U), |
| 184 | KilledBySignal(SIGABRT), "ABORT.*engineimpl\\.cpp"); |
| 185 | } |
| 186 | |
| 187 | TEST_F(EngineImplDeathTest, DellingNonExistingFDCallsSHAREDDATALAYER_ABORT) |
| 188 | { |
| 189 | EXPECT_EXIT(deleteMonitoredFD(fd1), |
| 190 | KilledBySignal(SIGABRT), "ABORT.*engineimpl\\.cpp"); |
| 191 | } |
| 192 | |
| 193 | TEST_F(EngineImplTest, HandleEventsCallsAddedEventHandlersAccordingToEpollReturnValue) |
| 194 | { |
| 195 | addMonitoredFD(fd1, Engine::EVENT_IN, eventHandlerMock1); |
| 196 | addMonitoredFD(fd2, Engine::EVENT_IN, eventHandlerMock2); |
| 197 | InSequence dummy; |
| 198 | EXPECT_CALL(systemMock, epoll_wait(epfd, NotNull(), 2, 0)) |
| 199 | .Times(1) |
| 200 | .WillOnce(Invoke([this] (int, epoll_event* events, int, int) -> int |
| 201 | { |
| 202 | events[0].events = EPOLLIN; |
| 203 | events[0].data.fd = fd1; |
| 204 | events[1].events = EPOLLOUT; |
| 205 | events[1].data.fd = fd2; |
| 206 | return 2; |
| 207 | })); |
| 208 | EXPECT_CALL(eventHandlerMock1, handleEvents(Engine::EVENT_IN)) |
| 209 | .Times(1); |
| 210 | EXPECT_CALL(eventHandlerMock2, handleEvents(Engine::EVENT_OUT)) |
| 211 | .Times(1); |
| 212 | services->handleEvents(); |
| 213 | } |
| 214 | |
| 215 | TEST_F(EngineImplTest, PendingEventsOfDeletedFileDescriptorAreForgotten) |
| 216 | { |
| 217 | addMonitoredFD(fd1, Engine::EVENT_IN, eventHandlerMock1); |
| 218 | addMonitoredFD(fd2, Engine::EVENT_IN, eventHandlerMock2); |
| 219 | InSequence dummy; |
| 220 | EXPECT_CALL(eventHandlerMock2, handleEvents(_)) |
| 221 | .Times(0); |
| 222 | EXPECT_CALL(systemMock, epoll_wait(epfd, NotNull(), 2, 0)) |
| 223 | .Times(1) |
| 224 | .WillOnce(Invoke([this] (int, epoll_event* events, int, int) -> int |
| 225 | { |
| 226 | events[0].events = EPOLLIN; |
| 227 | events[0].data.fd = fd1; |
| 228 | events[1].events = EPOLLIN; |
| 229 | events[1].data.fd = fd2; |
| 230 | return 2; |
| 231 | })); |
| 232 | EXPECT_CALL(eventHandlerMock1, handleEvents(_)) |
| 233 | .Times(1) |
| 234 | .WillOnce(Invoke([this](unsigned int) |
| 235 | { |
| 236 | deleteMonitoredFD(fd2); |
| 237 | addMonitoredFD(fd2, Engine::EVENT_IN, eventHandlerMock2); |
| 238 | })); |
| 239 | services->handleEvents(); |
| 240 | } |