Add first version
[ric-plt/sdl.git] / tst / hiredisclusterepolladapter_test.cpp
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
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
25 using namespace shareddatalayer;
26 using namespace shareddatalayer::redis;
27 using namespace shareddatalayer::tst;
28 using namespace testing;
29
30 namespace
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
106 TEST_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
114 TEST_F(HiredisClusterEpollAdapterTest, HasVirtualDestructor)
115 {
116     EXPECT_TRUE(std::has_virtual_destructor<HiredisClusterEpollAdapter>::value);
117 }
118
119 TEST_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
136 TEST_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
144 TEST_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
152 TEST_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
162 TEST_F(HiredisClusterEpollAdapterAttachedTest, DoesNotHandleInputEventIfNotReading)
163 {
164     InSequence dummy;
165     EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleRead(&ac))
166         .Times(0);
167     savedEventHandler(EngineMock::EVENT_IN);
168 }
169
170 TEST_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
180 TEST_F(HiredisClusterEpollAdapterAttachedTest, DoesNotHandleOutputEventIfNotWriting)
181 {
182     InSequence dummy;
183     EXPECT_CALL(hiredisClusterSystemMock, redisAsyncHandleWrite(&ac))
184         .Times(0);
185     savedEventHandler(EngineMock::EVENT_OUT);
186 }
187
188 TEST_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
207 TEST_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
231 TEST_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
240 TEST_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
249 TEST_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
263 TEST_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 }