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