blob: b74a4022848087a2366e5ec05eeac02212b5d198 [file] [log] [blame]
Rolf Badorekef2bf512019-08-20 11:17:15 +03001/*
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 Tietavainena0745d22019-11-28 09:55:22 +020017/*
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
20*/
21
Rolf Badorekef2bf512019-08-20 11:17:15 +030022#include <type_traits>
23#include <memory>
24#include <sys/epoll.h>
25#include <gtest/gtest.h>
26#include "private/redis/hiredisclusterepolladapter.hpp"
27#include "private/tst/enginemock.hpp"
28#include "private/tst/hiredisclustersystemmock.hpp"
29
30using namespace shareddatalayer;
31using namespace shareddatalayer::redis;
32using namespace shareddatalayer::tst;
33using namespace testing;
34
35namespace
36{
37 class HiredisClusterEpollAdapterTest: public testing::Test
38 {
39 public:
40 StrictMock<EngineMock> engineMock;
41 StrictMock<HiredisClusterSystemMock> hiredisClusterSystemMock;
42 redisClusterAsyncContext acc;
43 std::unique_ptr<HiredisClusterEpollAdapter> adapter;
44 redisAsyncContext ac;
45 redisAsyncContext secondAc;
46 int acFd;
47 int secondAcFd;
48 Engine::EventHandler savedEventHandler;
49 Engine::EventHandler anotherSavedEventHandler;
50
51 HiredisClusterEpollAdapterTest():
52 acc { },
53 adapter(new HiredisClusterEpollAdapter(engineMock, hiredisClusterSystemMock)),
54 ac { },
55 secondAc { },
56 acFd(20),
57 secondAcFd(30)
58 {
59 InSequence dummy;
60 ac.c.fd = acFd;
61 adapter->setup(&acc);
62 }
63
64 ~HiredisClusterEpollAdapterTest()
65 {
66 }
67
68 void expectAddMonitoredFD(int fd, unsigned int events)
69 {
70 EXPECT_CALL(engineMock, addMonitoredFD(fd,events,_))
71 .Times(1)
72 .WillOnce(SaveArg<2>(&savedEventHandler));
73 }
74
75 void expectAddMonitoredFD2(int fd, unsigned int events)
76 {
77 EXPECT_CALL(engineMock, addMonitoredFD(fd,events,_))
78 .Times(1)
79 .WillOnce(SaveArg<2>(&anotherSavedEventHandler));
80 }
81
82 void expectModifyMonitoredFD(int fd, unsigned int events)
83 {
84 EXPECT_CALL(engineMock, modifyMonitoredFD(fd,events))
85 .Times(1);
86 }
87
88 void expectDeleteMonitoredFD(int fd)
89 {
90 EXPECT_CALL(engineMock, deleteMonitoredFD(fd))
91 .Times(1);
92 }
93 };
94
95 class HiredisClusterEpollAdapterAttachedTest: public HiredisClusterEpollAdapterTest
96 {
97 public:
98 HiredisClusterEpollAdapterAttachedTest()
99 {
100 expectAddMonitoredFD(ac.c.fd, 0);
101 acc.attach_fn(&ac, adapter.get());
102 }
103
104 ~HiredisClusterEpollAdapterAttachedTest()
105 {
106 expectDeleteMonitoredFD(ac.c.fd);
107 }
108 };
109}
110
111TEST_F(HiredisClusterEpollAdapterTest, IsNotCopyableAndIsNotMovable)
112{
113 EXPECT_FALSE(std::is_copy_constructible<HiredisClusterEpollAdapter>::value);
114 EXPECT_FALSE(std::is_copy_assignable<HiredisClusterEpollAdapter>::value);
115 EXPECT_FALSE(std::is_move_constructible<HiredisClusterEpollAdapter>::value);
116 EXPECT_FALSE(std::is_move_assignable<HiredisClusterEpollAdapter>::value);
117}
118
119TEST_F(HiredisClusterEpollAdapterTest, HasVirtualDestructor)
120{
121 EXPECT_TRUE(std::has_virtual_destructor<HiredisClusterEpollAdapter>::value);
122}
123
124TEST_F(HiredisClusterEpollAdapterAttachedTest, EventStateChangedIdempotently)
125{
126 InSequence dummy;
127 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN);
128 ac.ev.addRead(ac.ev.data);
129 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN | EngineMock::EVENT_OUT);
130 ac.ev.addWrite(ac.ev.data);
131 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_OUT);
132 ac.ev.delRead(ac.ev.data);
133 expectModifyMonitoredFD(ac.c.fd, 0);
134 ac.ev.delWrite(ac.ev.data);
135 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN);
136 ac.ev.addRead(ac.ev.data);
137 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN | EngineMock::EVENT_OUT);
138 ac.ev.addWrite(ac.ev.data);
139}
140
141TEST_F(HiredisClusterEpollAdapterAttachedTest, InputEventIsSetOnce)
142{
143 InSequence dummy;
144 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN);
145 ac.ev.addRead(ac.ev.data);
146 ac.ev.addRead(ac.ev.data);
147}
148
149TEST_F(HiredisClusterEpollAdapterAttachedTest, OutputEventIsSetOnce)
150{
151 InSequence dummy;
152 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_OUT);
153 ac.ev.addWrite(ac.ev.data);
154 ac.ev.addWrite(ac.ev.data);
155}
156
157TEST_F(HiredisClusterEpollAdapterAttachedTest, CanHandleInputEvent)
158{
159 InSequence dummy;
160 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN);
161 ac.ev.addRead(ac.ev.data);
162 EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleRead(&ac))
163 .Times(1);
164 savedEventHandler(EngineMock::EVENT_IN);
165}
166
167TEST_F(HiredisClusterEpollAdapterAttachedTest, DoesNotHandleInputEventIfNotReading)
168{
169 InSequence dummy;
170 EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleRead(&ac))
171 .Times(0);
172 savedEventHandler(EngineMock::EVENT_IN);
173}
174
175TEST_F(HiredisClusterEpollAdapterAttachedTest, CanHandleOutputEvent)
176{
177 InSequence dummy;
178 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_OUT);
179 ac.ev.addWrite(ac.ev.data);
180 EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleWrite(&ac))
181 .Times(1);
182 savedEventHandler(EngineMock::EVENT_OUT);
183}
184
185TEST_F(HiredisClusterEpollAdapterAttachedTest, DoesNotHandleOutputEventIfNotWriting)
186{
187 InSequence dummy;
188 EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleWrite(&ac))
189 .Times(0);
190 savedEventHandler(EngineMock::EVENT_OUT);
191}
192
193TEST_F(HiredisClusterEpollAdapterAttachedTest, FurtherAttachementsResetEventStateAndWritingAndReading)
194{
195 InSequence dummy;
196 expectDeleteMonitoredFD(ac.c.fd);
197 expectAddMonitoredFD(ac.c.fd, 0);
198 acc.attach_fn(&ac, adapter.get());
199 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN);
200 ac.ev.addRead(ac.ev.data);
201 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN | EngineMock::EVENT_OUT);
202 ac.ev.addWrite(ac.ev.data);
203 expectDeleteMonitoredFD(ac.c.fd);
204 expectAddMonitoredFD(ac.c.fd, 0);
205 acc.attach_fn(&ac, adapter.get());
206 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN);
207 ac.ev.addRead(ac.ev.data);
208 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN | EngineMock::EVENT_OUT);
209 ac.ev.addWrite(ac.ev.data);
210}
211
212TEST_F(HiredisClusterEpollAdapterAttachedTest, CanHandleTwoConnections)
213{
214 InSequence dummy;
215 expectAddMonitoredFD2(secondAc.c.fd, 0);
216 acc.attach_fn(&secondAc, adapter.get());
217 // Read event in first fd:
218 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN);
219 ac.ev.addRead(ac.ev.data);
220 EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleRead(&ac))
221 .Times(1);
222 savedEventHandler(EngineMock::EVENT_IN);
223
224 // Read event in second fd:
225 expectModifyMonitoredFD(secondAc.c.fd, EngineMock::EVENT_IN);
226 ac.ev.addRead(secondAc.ev.data);
227 EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleRead(&secondAc))
228 .Times(1);
229 anotherSavedEventHandler(EngineMock::EVENT_IN);
230
231 // Cleanup for extra ac
232 expectDeleteMonitoredFD(secondAc.c.fd);
233 adapter->detach(&secondAc);
234}
235
236TEST_F(HiredisClusterEpollAdapterAttachedTest, CleanupWillRemoveOngoingEventsAndDeregisterFdFromEpoll)
237{
238 InSequence dummy;
239 expectDeleteMonitoredFD(acFd);
240 ac.ev.cleanup(ac.ev.data);
241 expectAddMonitoredFD(ac.c.fd, 0);
242 acc.attach_fn(&ac, adapter.get());
243}
244
245TEST_F(HiredisClusterEpollAdapterAttachedTest, DetachMakesCleanupIfNotYetDone)
246{
247 InSequence dummy;
248 expectDeleteMonitoredFD(ac.c.fd);
249 adapter->detach(&ac);
250 expectAddMonitoredFD(ac.c.fd, 0);
251 acc.attach_fn(&ac, adapter.get());
252}
253
254TEST_F(HiredisClusterEpollAdapterAttachedTest, InputEventRemovedByCleanupIsNotHandled)
255{
256 InSequence dummy;
257 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_IN);
258 ac.ev.addRead(ac.ev.data);
259 expectDeleteMonitoredFD(ac.c.fd);
260 ac.ev.cleanup(ac.ev.data);
261 EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleRead(&ac))
262 .Times(0);
263 savedEventHandler(EngineMock::EVENT_IN);
264 expectAddMonitoredFD(ac.c.fd, 0);
265 acc.attach_fn(&ac, adapter.get());
266}
267
268TEST_F(HiredisClusterEpollAdapterAttachedTest, OutputEventRemovedByCleanupIsNotHandled)
269{
270 InSequence dummy;
271 expectModifyMonitoredFD(ac.c.fd, EngineMock::EVENT_OUT);
272 ac.ev.addWrite(ac.ev.data);
273 // Read is deleted first during cleanup handling so write (EPOLLOUT) still exists for the first EPOLL_CTL_MOD
274 expectDeleteMonitoredFD(ac.c.fd);
275 ac.ev.cleanup(ac.ev.data);
276 EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleWrite(&ac))
277 .Times(0);
278 savedEventHandler(EngineMock::EVENT_OUT);
279 expectAddMonitoredFD(ac.c.fd, 0);
280 acc.attach_fn(&ac, adapter.get());
281}