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