IPC unit tests and testing framework improvements
[platform/core/security/vasum.git] / tests / unit_tests / ipc / ut-ipc.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Jan Olszak <j.olszak@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19
20 /**
21  * @file
22  * @author  Jan Olszak (j.olszak@samsung.com)
23  * @brief   Tests of the IPC
24  */
25
26 // TODO: Test connection limit
27 // TODO: Refactor tests - function for setting up env
28
29
30 #include "config.hpp"
31 #include "ut.hpp"
32
33 #include "ipc/service.hpp"
34 #include "ipc/client.hpp"
35 #include "ipc/types.hpp"
36 #include "ipc/unique-id.hpp"
37 #include "ipc/result.hpp"
38 #include "ipc/epoll/thread-dispatcher.hpp"
39 #include "ipc/epoll/glib-dispatcher.hpp"
40 #include "utils/channel.hpp"
41 #include "utils/glib-loop.hpp"
42 #include "utils/latch.hpp"
43 #include "utils/value-latch.hpp"
44 #include "utils/scoped-dir.hpp"
45
46 #include "config/fields.hpp"
47 #include "logger/logger.hpp"
48
49 #include <boost/filesystem.hpp>
50 #include <fstream>
51 #include <atomic>
52 #include <string>
53 #include <thread>
54 #include <chrono>
55 #include <utility>
56 #include <future>
57 #include <semaphore.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <sys/wait.h>
61 #include <fcntl.h>
62
63
64 using namespace ipc;
65 using namespace epoll;
66 using namespace utils;
67 using namespace std::placeholders;
68 namespace fs = boost::filesystem;
69
70 // Timeout for sending one message
71 const int TIMEOUT = 1000 /*ms*/;
72
73 // Time that won't cause "TIMEOUT" methods to throw
74 const int SHORT_OPERATION_TIME = TIMEOUT / 100;
75
76 // Time that will cause "TIMEOUT" methods to throw
77 const int LONG_OPERATION_TIME = 1000 + TIMEOUT;
78
79 const std::string TEST_DIR = "/tmp/ut-ipc";
80 const std::string SOCKET_PATH = TEST_DIR + "/test.socket";
81 const std::string TEST_FILE = TEST_DIR + "/file.txt";
82
83 struct FixtureBase {
84     ScopedDir mTestPathGuard;
85
86     FixtureBase()
87         : mTestPathGuard(TEST_DIR)
88     {
89     }
90 };
91
92 struct ThreadedFixture : FixtureBase {
93     ThreadDispatcher dispatcher;
94
95     EventPoll& getPoll() {
96         return dispatcher.getPoll();
97     }
98 };
99
100 struct GlibFixture : FixtureBase {
101     ScopedGlibLoop glibLoop;
102     GlibDispatcher dispatcher;
103
104     EventPoll& getPoll() {
105         return dispatcher.getPoll();
106     }
107 };
108
109 struct SendData {
110     int intVal;
111     SendData(int i): intVal(i) {}
112
113     CONFIG_REGISTER
114     (
115         intVal
116     )
117 };
118
119 struct RecvData {
120     int intVal;
121     RecvData(): intVal(-1) {}
122
123     CONFIG_REGISTER
124     (
125         intVal
126     )
127 };
128
129 struct FDData {
130     config::FileDescriptor fd;
131     FDData(int fd = -1): fd(fd) {}
132
133     CONFIG_REGISTER
134     (
135         fd
136     )
137 };
138
139 struct LongSendData {
140     LongSendData(int i, int waitTime): mSendData(i), mWaitTime(waitTime), intVal(i) {}
141
142     template<typename Visitor>
143     void accept(Visitor visitor)
144     {
145         std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTime));
146         mSendData.accept(visitor);
147     }
148     template<typename Visitor>
149     void accept(Visitor visitor) const
150     {
151         std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTime));
152         mSendData.accept(visitor);
153     }
154
155     SendData mSendData;
156     int mWaitTime;
157     int intVal;
158 };
159
160 struct EmptyData {
161     CONFIG_REGISTER_EMPTY
162 };
163
164 struct ThrowOnAcceptData {
165     template<typename Visitor>
166     static void accept(Visitor)
167     {
168         throw std::runtime_error("intentional failure in accept");
169     }
170 };
171
172 void returnEmptyCallback(const PeerID,
173                          std::shared_ptr<EmptyData>&,
174                          MethodResult::Pointer methodResult)
175 {
176     methodResult->setVoid();
177 }
178
179 void returnDataCallback(const PeerID,
180                         std::shared_ptr<RecvData>&,
181                         MethodResult::Pointer methodResult)
182 {
183     auto returnData = std::make_shared<SendData>(1);
184     methodResult->set(returnData);
185 }
186
187 void echoCallback(const PeerID,
188                   std::shared_ptr<RecvData>& data,
189                   MethodResult::Pointer methodResult)
190 {
191     auto returnData = std::make_shared<SendData>(data->intVal);
192     methodResult->set(returnData);
193 }
194
195 void longEchoCallback(const PeerID,
196                       std::shared_ptr<RecvData>& data,
197                       MethodResult::Pointer methodResult)
198 {
199     std::this_thread::sleep_for(std::chrono::milliseconds(LONG_OPERATION_TIME));
200     auto returnData = std::make_shared<SendData>(data->intVal);
201     methodResult->set(returnData);
202 }
203
204 void shortEchoCallback(const PeerID,
205                        std::shared_ptr<RecvData>& data,
206                        MethodResult::Pointer methodResult)
207 {
208     std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME));
209     auto returnData = std::make_shared<SendData>(data->intVal);
210     methodResult->set(returnData);
211 }
212
213 PeerID connectPeer(Service& s, Client& c)
214 {
215     // Connects the Client to the Service and returns Clients PeerID
216     ValueLatch<PeerID> peerIDLatch;
217     auto newPeerCallback = [&peerIDLatch](const PeerID newID, const FileDescriptor) {
218         peerIDLatch.set(newID);
219     };
220
221     s.setNewPeerCallback(newPeerCallback);
222
223     if (!s.isStarted()) {
224         s.start();
225     }
226
227     c.start();
228
229     PeerID peerID = peerIDLatch.get(TIMEOUT);
230     s.setNewPeerCallback(nullptr);
231     BOOST_REQUIRE_NE(peerID, static_cast<std::string>(ipc::UniqueID()));
232     return peerID;
233 }
234
235 void testEcho(Client& c, const MethodID methodID)
236 {
237     std::shared_ptr<SendData> sentData(new SendData(34));
238     std::shared_ptr<RecvData> recvData = c.callSync<SendData, RecvData>(methodID, sentData, TIMEOUT);
239     BOOST_REQUIRE(recvData);
240     BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
241 }
242
243 void testEcho(Service& s, const MethodID methodID, const PeerID& peerID)
244 {
245     std::shared_ptr<SendData> sentData(new SendData(56));
246     std::shared_ptr<RecvData> recvData = s.callSync<SendData, RecvData>(methodID, peerID, sentData, TIMEOUT);
247     BOOST_REQUIRE(recvData);
248     BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
249 }
250
251 BOOST_AUTO_TEST_SUITE(IPCSuite)
252
253 MULTI_FIXTURE_TEST_CASE(ConstructorDestructor, F, ThreadedFixture, GlibFixture)
254 {
255     Service s(F::getPoll(), SOCKET_PATH);
256     Client c(F::getPoll(), SOCKET_PATH);
257 }
258
259 MULTI_FIXTURE_TEST_CASE(ServiceAddRemoveMethod, F, ThreadedFixture, GlibFixture)
260 {
261     Service s(F::getPoll(), SOCKET_PATH);
262     s.setMethodHandler<EmptyData, EmptyData>(1, returnEmptyCallback);
263     s.setMethodHandler<SendData, RecvData>(1, returnDataCallback);
264
265     s.start();
266
267     s.setMethodHandler<SendData, RecvData>(1, echoCallback);
268     s.setMethodHandler<SendData, RecvData>(2, returnDataCallback);
269
270     Client c(F::getPoll(), SOCKET_PATH);
271     connectPeer(s, c);
272     testEcho(c, 1);
273
274     s.removeMethod(1);
275     s.removeMethod(2);
276
277     BOOST_CHECK_THROW(testEcho(c, 2), IPCException);
278 }
279
280 MULTI_FIXTURE_TEST_CASE(ClientAddRemoveMethod, F, ThreadedFixture, GlibFixture)
281 {
282     Service s(F::getPoll(), SOCKET_PATH);
283     Client c(F::getPoll(), SOCKET_PATH);
284     c.setMethodHandler<EmptyData, EmptyData>(1, returnEmptyCallback);
285     c.setMethodHandler<SendData, RecvData>(1, returnDataCallback);
286
287     PeerID peerID = connectPeer(s, c);
288
289     c.setMethodHandler<SendData, RecvData>(1, echoCallback);
290     c.setMethodHandler<SendData, RecvData>(2, returnDataCallback);
291
292     testEcho(s, 1, peerID);
293
294     c.removeMethod(1);
295     c.removeMethod(2);
296
297     BOOST_CHECK_THROW(testEcho(s, 1, peerID), IPCException);
298 }
299
300 MULTI_FIXTURE_TEST_CASE(MethodResultGetPeerID, F, ThreadedFixture, GlibFixture)
301 {
302     Service s(F::getPoll(), SOCKET_PATH);
303     Client c(F::getPoll(), SOCKET_PATH);
304
305     PeerID peerID = connectPeer(s, c);
306
307     s.setMethodHandler<SendData, RecvData>(
308         1,
309         [&peerID](const PeerID,
310                   std::shared_ptr<RecvData>&,
311                   MethodResult::Pointer methodResult) {
312             methodResult->setVoid();
313             BOOST_CHECK_EQUAL(peerID, methodResult->getPeerID());
314         }
315     );
316
317     std::shared_ptr<SendData> sentData(new SendData(32));
318     std::shared_ptr<RecvData> recvData = c.callSync<SendData, RecvData>(1,
319                                                                         sentData,
320                                                                         TIMEOUT);
321 }
322
323 MULTI_FIXTURE_TEST_CASE(ServiceStartStop, F, ThreadedFixture, GlibFixture)
324 {
325     Service s(F::getPoll(), SOCKET_PATH);
326
327     s.setMethodHandler<SendData, RecvData>(1, returnDataCallback);
328
329     s.start();
330     s.stop();
331     s.start();
332     s.stop();
333
334     s.start();
335     s.start();
336 }
337
338 MULTI_FIXTURE_TEST_CASE(ClientStartStop, F, ThreadedFixture, GlibFixture)
339 {
340     Service s(F::getPoll(), SOCKET_PATH);
341     Client c(F::getPoll(), SOCKET_PATH);
342     c.setMethodHandler<SendData, RecvData>(1, returnDataCallback);
343
344     c.start();
345     c.stop();
346     c.start();
347     c.stop();
348
349     c.start();
350     c.start();
351
352     c.stop();
353     c.stop();
354 }
355
356 MULTI_FIXTURE_TEST_CASE(SyncClientToServiceEcho, F, ThreadedFixture, GlibFixture)
357 {
358     Service s(F::getPoll(), SOCKET_PATH);
359     s.setMethodHandler<SendData, RecvData>(1, echoCallback);
360     s.setMethodHandler<SendData, RecvData>(2, echoCallback);
361
362     Client c(F::getPoll(), SOCKET_PATH);
363     connectPeer(s, c);
364
365     testEcho(c, 1);
366     testEcho(c, 2);
367 }
368
369 MULTI_FIXTURE_TEST_CASE(Restart, F, ThreadedFixture, GlibFixture)
370 {
371     Service s(F::getPoll(), SOCKET_PATH);
372     s.setMethodHandler<SendData, RecvData>(1, echoCallback);
373     s.start();
374     s.setMethodHandler<SendData, RecvData>(2, echoCallback);
375
376     Client c(F::getPoll(), SOCKET_PATH);
377     c.start();
378     testEcho(c, 1);
379     testEcho(c, 2);
380
381     c.stop();
382     c.start();
383
384     testEcho(c, 1);
385     testEcho(c, 2);
386
387     s.stop();
388     s.start();
389
390     BOOST_CHECK_THROW(testEcho(c, 2), IPCException);
391
392     c.stop();
393     c.start();
394
395     testEcho(c, 1);
396     testEcho(c, 2);
397 }
398
399 MULTI_FIXTURE_TEST_CASE(SyncServiceToClientEcho, F, ThreadedFixture, GlibFixture)
400 {
401     Service s(F::getPoll(), SOCKET_PATH);
402     Client c(F::getPoll(), SOCKET_PATH);
403     c.setMethodHandler<SendData, RecvData>(1, echoCallback);
404     PeerID peerID = connectPeer(s, c);
405
406     std::shared_ptr<SendData> sentData(new SendData(56));
407     std::shared_ptr<RecvData> recvData = s.callSync<SendData, RecvData>(1, peerID, sentData);
408     BOOST_REQUIRE(recvData);
409     BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
410 }
411
412 MULTI_FIXTURE_TEST_CASE(AsyncClientToServiceEcho, F, ThreadedFixture, GlibFixture)
413 {
414     std::shared_ptr<SendData> sentData(new SendData(34));
415     ValueLatch<std::shared_ptr<RecvData>> recvDataLatch;
416
417     // Setup Service and Client
418     Service s(F::getPoll(), SOCKET_PATH);
419     s.setMethodHandler<SendData, RecvData>(1, echoCallback);
420     s.start();
421     Client c(F::getPoll(), SOCKET_PATH);
422     c.start();
423
424     //Async call
425     auto dataBack = [&recvDataLatch](Result<RecvData> && r) {
426         recvDataLatch.set(r.get());
427     };
428     c.callAsync<SendData, RecvData>(1, sentData, dataBack);
429
430     // Wait for the response
431     std::shared_ptr<RecvData> recvData(recvDataLatch.get(TIMEOUT));
432     BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
433 }
434
435 MULTI_FIXTURE_TEST_CASE(AsyncServiceToClientEcho, F, ThreadedFixture, GlibFixture)
436 {
437     std::shared_ptr<SendData> sentData(new SendData(56));
438     ValueLatch<std::shared_ptr<RecvData>> recvDataLatch;
439
440     Service s(F::getPoll(), SOCKET_PATH);
441     Client c(F::getPoll(), SOCKET_PATH);
442     c.setMethodHandler<SendData, RecvData>(1, echoCallback);
443     PeerID peerID = connectPeer(s, c);
444
445     // Async call
446     auto dataBack = [&recvDataLatch](Result<RecvData> && r) {
447         recvDataLatch.set(r.get());
448     };
449
450     s.callAsync<SendData, RecvData>(1, peerID, sentData, dataBack);
451
452     // Wait for the response
453     std::shared_ptr<RecvData> recvData(recvDataLatch.get(TIMEOUT));
454     BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
455 }
456
457
458 MULTI_FIXTURE_TEST_CASE(SyncTimeout, F, ThreadedFixture, GlibFixture)
459 {
460     Service s(F::getPoll(), SOCKET_PATH);
461     s.setMethodHandler<SendData, RecvData>(1, longEchoCallback);
462
463     Client c(F::getPoll(), SOCKET_PATH);
464     connectPeer(s, c);
465
466     std::shared_ptr<SendData> sentData(new SendData(78));
467     BOOST_REQUIRE_THROW((c.callSync<SendData, RecvData>(1, sentData, TIMEOUT)), IPCException);
468 }
469
470 MULTI_FIXTURE_TEST_CASE(SerializationError, F, ThreadedFixture, GlibFixture)
471 {
472     Service s(F::getPoll(), SOCKET_PATH);
473     s.setMethodHandler<SendData, RecvData>(1, echoCallback);
474
475     Client c(F::getPoll(), SOCKET_PATH);
476     connectPeer(s, c);
477
478     std::shared_ptr<ThrowOnAcceptData> throwingData(new ThrowOnAcceptData());
479
480     BOOST_CHECK_THROW((c.callSync<ThrowOnAcceptData, RecvData>(1, throwingData)), IPCSerializationException);
481
482 }
483
484 MULTI_FIXTURE_TEST_CASE(ParseError, F, ThreadedFixture, GlibFixture)
485 {
486     Service s(F::getPoll(), SOCKET_PATH);
487     s.setMethodHandler<SendData, RecvData>(1, echoCallback);
488     s.start();
489
490     Client c(F::getPoll(), SOCKET_PATH);
491     c.start();
492
493     std::shared_ptr<SendData> sentData(new SendData(78));
494     BOOST_CHECK_THROW((c.callSync<SendData, ThrowOnAcceptData>(1, sentData, 10000)), IPCParsingException);
495 }
496
497 MULTI_FIXTURE_TEST_CASE(DisconnectedPeerError, F, ThreadedFixture, GlibFixture)
498 {
499     ValueLatch<Result<RecvData>> retStatusLatch;
500
501     Service s(F::getPoll(), SOCKET_PATH);
502
503     auto method = [](const PeerID, std::shared_ptr<ThrowOnAcceptData>&, MethodResult::Pointer methodResult) {
504         auto resultData = std::make_shared<SendData>(1);
505         methodResult->set<SendData>(resultData);
506     };
507
508     // Method will throw during serialization and disconnect automatically
509     s.setMethodHandler<SendData, ThrowOnAcceptData>(1, method);
510     s.start();
511
512     Client c(F::getPoll(), SOCKET_PATH);
513     c.start();
514
515     auto dataBack = [&retStatusLatch](Result<RecvData> && r) {
516         retStatusLatch.set(std::move(r));
517     };
518
519     std::shared_ptr<SendData> sentData(new SendData(78));
520     c.callAsync<SendData, RecvData>(1, sentData, dataBack);
521
522     // Wait for the response
523     Result<RecvData> result = retStatusLatch.get(TIMEOUT);
524
525     // The disconnection might have happened:
526     // - after sending the message (PEER_DISCONNECTED)
527     // - during external serialization (SERIALIZATION_ERROR)
528     BOOST_CHECK_THROW(result.get(), IPCException);
529 }
530
531
532 MULTI_FIXTURE_TEST_CASE(ReadTimeout, F, ThreadedFixture, GlibFixture)
533 {
534     Service s(F::getPoll(), SOCKET_PATH);
535     auto longEchoCallback = [](const PeerID, std::shared_ptr<RecvData>& data, MethodResult::Pointer methodResult) {
536         auto resultData = std::make_shared<LongSendData>(data->intVal, LONG_OPERATION_TIME);
537         methodResult->set<LongSendData>(resultData);
538     };
539     s.setMethodHandler<LongSendData, RecvData>(1, longEchoCallback);
540
541     Client c(F::getPoll(), SOCKET_PATH);
542     connectPeer(s, c);
543
544     // Test timeout on read
545     std::shared_ptr<SendData> sentData(new SendData(334));
546     BOOST_CHECK_THROW((c.callSync<SendData, RecvData>(1, sentData, TIMEOUT)), IPCException);
547 }
548
549
550 MULTI_FIXTURE_TEST_CASE(WriteTimeout, F, ThreadedFixture, GlibFixture)
551 {
552     Service s(F::getPoll(), SOCKET_PATH);
553     s.setMethodHandler<SendData, RecvData>(1, shortEchoCallback);
554     s.start();
555
556     Client c(F::getPoll(), SOCKET_PATH);
557     c.start();
558
559     // Test echo with a minimal timeout
560     std::shared_ptr<LongSendData> sentDataA(new LongSendData(34, SHORT_OPERATION_TIME));
561     std::shared_ptr<RecvData> recvData = c.callSync<LongSendData, RecvData>(1, sentDataA, TIMEOUT);
562     BOOST_REQUIRE(recvData);
563     BOOST_CHECK_EQUAL(recvData->intVal, sentDataA->intVal);
564
565     // Test timeout on write
566     std::shared_ptr<LongSendData> sentDataB(new LongSendData(34, LONG_OPERATION_TIME));
567     BOOST_CHECK_THROW((c.callSync<LongSendData, RecvData>(1, sentDataB, TIMEOUT)), IPCTimeoutException);
568 }
569
570
571 MULTI_FIXTURE_TEST_CASE(AddSignalInRuntime, F, ThreadedFixture, GlibFixture)
572 {
573     ValueLatch<std::shared_ptr<RecvData>> recvDataLatchA;
574     ValueLatch<std::shared_ptr<RecvData>> recvDataLatchB;
575
576     Service s(F::getPoll(), SOCKET_PATH);
577     Client c(F::getPoll(), SOCKET_PATH);
578     connectPeer(s, c);
579
580     auto handlerA = [&recvDataLatchA](const PeerID, std::shared_ptr<RecvData>& data) {
581         recvDataLatchA.set(data);
582     };
583
584     auto handlerB = [&recvDataLatchB](const PeerID, std::shared_ptr<RecvData>& data) {
585         recvDataLatchB.set(data);
586     };
587
588     c.setSignalHandler<RecvData>(1, handlerA);
589     c.setSignalHandler<RecvData>(2, handlerB);
590
591     // Wait for the signals to propagate to the Service
592     std::this_thread::sleep_for(std::chrono::milliseconds(2 * TIMEOUT));
593
594     auto sendDataA = std::make_shared<SendData>(1);
595     auto sendDataB = std::make_shared<SendData>(2);
596     s.signal<SendData>(2, sendDataB);
597     s.signal<SendData>(1, sendDataA);
598
599     // Wait for the signals to arrive
600     std::shared_ptr<RecvData> recvDataA(recvDataLatchA.get(TIMEOUT));
601     std::shared_ptr<RecvData> recvDataB(recvDataLatchB.get(TIMEOUT));
602     BOOST_CHECK_EQUAL(recvDataA->intVal, sendDataA->intVal);
603     BOOST_CHECK_EQUAL(recvDataB->intVal, sendDataB->intVal);
604 }
605
606
607 MULTI_FIXTURE_TEST_CASE(AddSignalOffline, F, ThreadedFixture, GlibFixture)
608 {
609     ValueLatch<std::shared_ptr<RecvData>> recvDataLatchA;
610     ValueLatch<std::shared_ptr<RecvData>> recvDataLatchB;
611
612     Service s(F::getPoll(), SOCKET_PATH);
613     Client c(F::getPoll(), SOCKET_PATH);
614
615     auto handlerA = [&recvDataLatchA](const PeerID, std::shared_ptr<RecvData>& data) {
616         recvDataLatchA.set(data);
617     };
618
619     auto handlerB = [&recvDataLatchB](const PeerID, std::shared_ptr<RecvData>& data) {
620         recvDataLatchB.set(data);
621     };
622
623     c.setSignalHandler<RecvData>(1, handlerA);
624     c.setSignalHandler<RecvData>(2, handlerB);
625
626     connectPeer(s, c);
627
628     // Wait for the information about the signals to propagate
629     std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT));
630
631     auto sendDataA = std::make_shared<SendData>(1);
632     auto sendDataB = std::make_shared<SendData>(2);
633     s.signal<SendData>(2, sendDataB);
634     s.signal<SendData>(1, sendDataA);
635
636     // Wait for the signals to arrive
637     std::shared_ptr<RecvData> recvDataA(recvDataLatchA.get(TIMEOUT));
638     std::shared_ptr<RecvData> recvDataB(recvDataLatchB.get(TIMEOUT));
639     BOOST_CHECK_EQUAL(recvDataA->intVal, sendDataA->intVal);
640     BOOST_CHECK_EQUAL(recvDataB->intVal, sendDataB->intVal);
641 }
642
643 MULTI_FIXTURE_TEST_CASE(UsersError, F, ThreadedFixture, GlibFixture)
644 {
645     const int TEST_ERROR_CODE = -234;
646     const std::string TEST_ERROR_MESSAGE = "Ay, caramba!";
647
648     Service s(F::getPoll(), SOCKET_PATH);
649     Client c(F::getPoll(), SOCKET_PATH);
650     auto clientID = connectPeer(s, c);
651
652     auto throwingMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&, MethodResult::Pointer) {
653         throw IPCUserException(TEST_ERROR_CODE, TEST_ERROR_MESSAGE);
654     };
655
656     auto sendErrorMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&, MethodResult::Pointer methodResult) {
657         methodResult->setError(TEST_ERROR_CODE, TEST_ERROR_MESSAGE);
658     };
659
660     s.setMethodHandler<SendData, RecvData>(1, throwingMethodHandler);
661     s.setMethodHandler<SendData, RecvData>(2, sendErrorMethodHandler);
662     c.setMethodHandler<SendData, RecvData>(1, throwingMethodHandler);
663     c.setMethodHandler<SendData, RecvData>(2, sendErrorMethodHandler);
664
665     std::shared_ptr<SendData> sentData(new SendData(78));
666
667     auto hasProperData = [&](const IPCUserException & e) {
668         return e.getCode() == TEST_ERROR_CODE && e.what() == TEST_ERROR_MESSAGE;
669     };
670
671     BOOST_CHECK_EXCEPTION((c.callSync<SendData, RecvData>(1, sentData, TIMEOUT)), IPCUserException, hasProperData);
672     BOOST_CHECK_EXCEPTION((s.callSync<SendData, RecvData>(1, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData);
673     BOOST_CHECK_EXCEPTION((c.callSync<SendData, RecvData>(2, sentData, TIMEOUT)), IPCUserException, hasProperData);
674     BOOST_CHECK_EXCEPTION((s.callSync<SendData, RecvData>(2, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData);
675 }
676
677 MULTI_FIXTURE_TEST_CASE(AsyncResult, F, ThreadedFixture, GlibFixture)
678 {
679     const int TEST_ERROR_CODE = -567;
680     const std::string TEST_ERROR_MESSAGE = "Ooo jooo!";
681
682     Service s(F::getPoll(), SOCKET_PATH);
683     Client c(F::getPoll(), SOCKET_PATH);
684     auto clientID = connectPeer(s, c);
685
686     auto errorMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&, MethodResult::Pointer methodResult) {
687         std::async(std::launch::async, [&, methodResult] {
688             std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME));
689             methodResult->setError(TEST_ERROR_CODE, TEST_ERROR_MESSAGE);
690         });
691     };
692
693     auto voidMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&, MethodResult::Pointer methodResult) {
694         std::async(std::launch::async, [methodResult] {
695             std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME));
696             methodResult->setVoid();
697         });
698     };
699
700     auto dataMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>& data, MethodResult::Pointer methodResult) {
701         std::async(std::launch::async, [data, methodResult] {
702             std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME));
703             methodResult->set(data);
704         });
705     };
706
707     s.setMethodHandler<SendData, RecvData>(1, errorMethodHandler);
708     s.setMethodHandler<EmptyData, RecvData>(2, voidMethodHandler);
709     s.setMethodHandler<SendData, RecvData>(3, dataMethodHandler);
710     c.setMethodHandler<SendData, RecvData>(1, errorMethodHandler);
711     c.setMethodHandler<EmptyData, RecvData>(2, voidMethodHandler);
712     c.setMethodHandler<SendData, RecvData>(3, dataMethodHandler);
713
714     std::shared_ptr<SendData> sentData(new SendData(90));
715
716     auto hasProperData = [&](const IPCUserException & e) {
717         return e.getCode() == TEST_ERROR_CODE && e.what() == TEST_ERROR_MESSAGE;
718     };
719
720     BOOST_CHECK_EXCEPTION((s.callSync<SendData, RecvData>(1, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData);
721     BOOST_CHECK_EXCEPTION((c.callSync<SendData, RecvData>(1, sentData, TIMEOUT)), IPCUserException, hasProperData);
722
723     BOOST_CHECK_NO_THROW((s.callSync<SendData, EmptyData>(2, clientID, sentData, TIMEOUT)));
724     BOOST_CHECK_NO_THROW((c.callSync<SendData, EmptyData>(2, sentData, TIMEOUT)));
725
726     std::shared_ptr<RecvData> recvData;
727     recvData = s.callSync<SendData, RecvData>(3, clientID, sentData, TIMEOUT);
728     BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
729     recvData = c.callSync<SendData, RecvData>(3, sentData, TIMEOUT);
730     BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
731 }
732
733 MULTI_FIXTURE_TEST_CASE(MixOperations, F, ThreadedFixture, GlibFixture)
734 {
735     utils::Latch l;
736
737     auto signalHandler = [&l](const PeerID, std::shared_ptr<RecvData>&) {
738         l.set();
739     };
740
741     Service s(F::getPoll(), SOCKET_PATH);
742     s.setMethodHandler<SendData, RecvData>(1, echoCallback);
743
744     Client c(F::getPoll(), SOCKET_PATH);
745     s.setSignalHandler<RecvData>(2, signalHandler);
746
747     connectPeer(s, c);
748
749     testEcho(c, 1);
750
751     auto data = std::make_shared<SendData>(1);
752     c.signal<SendData>(2, data);
753
754     BOOST_CHECK(l.wait(TIMEOUT));
755 }
756
757 MULTI_FIXTURE_TEST_CASE(FDSendReceive, F, ThreadedFixture, GlibFixture)
758 {
759     const char DATA[] = "Content of the file";
760     {
761         // Fill the file
762         fs::remove(TEST_FILE);
763         std::ofstream file(TEST_FILE);
764         file << DATA;
765         file.close();
766     }
767
768     auto methodHandler = [&](const PeerID, std::shared_ptr<EmptyData>&, MethodResult::Pointer methodResult) {
769         int fd = ::open(TEST_FILE.c_str(), O_RDONLY);
770         auto returnData = std::make_shared<FDData>(fd);
771         methodResult->set(returnData);
772     };
773
774     Service s(F::getPoll(), SOCKET_PATH);
775     s.setMethodHandler<FDData, EmptyData>(1, methodHandler);
776
777     Client c(F::getPoll(), SOCKET_PATH);
778     connectPeer(s, c);
779
780     std::shared_ptr<FDData> fdData;
781     std::shared_ptr<EmptyData> sentData(new EmptyData());
782     fdData = c.callSync<EmptyData, FDData>(1, sentData, TIMEOUT);
783
784     // Use the file descriptor
785     char buffer[sizeof(DATA)];
786     BOOST_REQUIRE(::read(fdData->fd.value, buffer, sizeof(buffer))>0);
787     BOOST_REQUIRE(strncmp(DATA, buffer, strlen(DATA))==0);
788     ::close(fdData->fd.value);
789 }
790
791 BOOST_AUTO_TEST_CASE(ConnectionLimit)
792 {
793     const unsigned oldLimit = utils::getMaxFDNumber();
794     const unsigned newLimit = 32;
795     ScopedDir scopedDir(TEST_DIR);
796
797     Channel c;
798
799     const pid_t chpid = ::fork();
800     BOOST_CHECK_NE(chpid, -1);
801
802     if (chpid) {
803         // Setup Service
804         ThreadDispatcher td;
805         Service s(td.getPoll(), SOCKET_PATH);
806         s.setMethodHandler<SendData, RecvData>(1, echoCallback);
807         s.start();
808
809         c.setLeft();
810         try {
811             // inform the Client
812             c.write(true);
813         } catch (...) {
814             kill(chpid, 9);
815             throw;
816         }
817
818         int status;
819         BOOST_CHECK_EQUAL(::waitpid(chpid, &status, 0), chpid);
820         BOOST_CHECK_EQUAL(status, EXIT_SUCCESS);
821     } else {
822         int ret = EXIT_FAILURE;
823         utils::setMaxFDNumber(newLimit);
824
825         c.setRight();
826         try {
827             // wait for the Service
828             c.read<char>();
829         } catch(...) {
830             ::_exit(EXIT_FAILURE);
831         }
832
833         // Setup Clients
834         ThreadDispatcher td;
835         std::list<Client> clients;
836         try {
837             for (unsigned i = 0; i < 2 * newLimit; ++i) {
838                 clients.emplace_back(td.getPoll(), SOCKET_PATH);
839                 clients.back().start();
840             }
841         } catch (const EventFDException& e) {
842             ret = EXIT_SUCCESS;
843         } catch (const IPCSocketException& e) {
844             if (e.getCode() == EMFILE) {
845                 ret = EXIT_SUCCESS;
846             }
847         }
848
849         utils::setMaxFDNumber(oldLimit);
850
851         ::_exit(ret);
852     }
853 }
854
855
856
857 BOOST_AUTO_TEST_SUITE_END()