2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Jan Olszak <j.olszak@samsung.com>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
22 * @author Jan Olszak (j.olszak@samsung.com)
23 * @brief Tests of the IPC
26 // TODO: Test connection limit
27 // TODO: Refactor tests - function for setting up env
28 // TODO: Callback wrapper that waits till the callback is called
34 #include "ipc/service.hpp"
35 #include "ipc/client.hpp"
36 #include "ipc/types.hpp"
38 #include "config/fields.hpp"
39 #include "logger/logger.hpp"
46 #include <boost/filesystem.hpp>
48 using namespace security_containers;
49 using namespace security_containers::ipc;
50 namespace fs = boost::filesystem;
54 std::string socketPath;
57 : socketPath(fs::unique_path("/tmp/ipc-%%%%.socket").string())
62 fs::remove(socketPath);
68 SendData(int i = 0): intVal(i) {}
77 LongSendData(int i = 0, int waitTime = 1000): mSendData(i), mWaitTime(waitTime), intVal(i) {}
79 template<typename Visitor>
80 void accept(Visitor visitor)
82 std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTime));
83 mSendData.accept(visitor);
85 template<typename Visitor>
86 void accept(Visitor visitor) const
88 std::this_thread::sleep_for(std::chrono::milliseconds(mWaitTime));
89 mSendData.accept(visitor);
101 struct ThrowOnAcceptData {
102 template<typename Visitor>
105 throw std::runtime_error("intentional failure in accept");
107 template<typename Visitor>
108 void accept(Visitor) const
110 throw std::runtime_error("intentional failure in accept const");
114 std::shared_ptr<EmptyData> returnEmptyCallback(const FileDescriptor, std::shared_ptr<EmptyData>&)
116 return std::shared_ptr<EmptyData>(new EmptyData());
119 std::shared_ptr<SendData> returnDataCallback(const FileDescriptor, std::shared_ptr<SendData>&)
121 return std::shared_ptr<SendData>(new SendData(1));
124 std::shared_ptr<SendData> echoCallback(const FileDescriptor, std::shared_ptr<SendData>& data)
129 std::shared_ptr<SendData> longEchoCallback(const FileDescriptor, std::shared_ptr<SendData>& data)
131 std::this_thread::sleep_for(std::chrono::seconds(1));
135 FileDescriptor connect(Service& s, Client& c)
137 // Connects the Client to the Service and returns Clients FileDescriptor
140 std::condition_variable cv;
142 FileDescriptor peerFD = 0;
143 auto newPeerCallback = [&cv, &peerFD, &mutex](const FileDescriptor newFileDescriptor) {
144 std::unique_lock<std::mutex> lock(mutex);
145 peerFD = newFileDescriptor;
149 s.setNewPeerCallback(newPeerCallback);
151 if (!s.isStarted()) {
157 std::unique_lock<std::mutex> lock(mutex);
158 BOOST_CHECK(cv.wait_for(lock, std::chrono::milliseconds(1000), [&peerFD]() {
165 void testEcho(Client& c, const MethodID methodID)
167 std::shared_ptr<SendData> sentData(new SendData(34));
168 std::shared_ptr<SendData> recvData = c.callSync<SendData, SendData>(methodID, sentData);
169 BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
172 void testEcho(Service& s, const MethodID methodID, const FileDescriptor peerFD)
174 std::shared_ptr<SendData> sentData(new SendData(56));
175 std::shared_ptr<SendData> recvData = s.callSync<SendData, SendData>(methodID, peerFD, sentData);
176 BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
182 BOOST_FIXTURE_TEST_SUITE(IPCSuite, Fixture)
184 BOOST_AUTO_TEST_CASE(ConstructorDestructor)
186 Service s(socketPath);
187 Client c(socketPath);
190 BOOST_AUTO_TEST_CASE(ServiceAddRemoveMethod)
192 Service s(socketPath);
194 s.addMethodHandler<EmptyData, EmptyData>(1, returnEmptyCallback);
195 s.addMethodHandler<SendData, SendData>(1, returnDataCallback);
199 s.addMethodHandler<SendData, SendData>(1, echoCallback);
200 s.addMethodHandler<SendData, SendData>(2, returnDataCallback);
202 Client c(socketPath);
209 BOOST_CHECK_THROW(testEcho(c, 2), IPCException);
212 BOOST_AUTO_TEST_CASE(ClientAddRemoveMethod)
214 Service s(socketPath);
215 Client c(socketPath);
216 c.addMethodHandler<EmptyData, EmptyData>(1, returnEmptyCallback);
217 c.addMethodHandler<SendData, SendData>(1, returnDataCallback);
219 FileDescriptor peerFD = connect(s, c);
221 c.addMethodHandler<SendData, SendData>(1, echoCallback);
222 c.addMethodHandler<SendData, SendData>(2, returnDataCallback);
224 testEcho(s, 1, peerFD);
229 BOOST_CHECK_THROW(testEcho(s, 1, peerFD), IPCException);
232 BOOST_AUTO_TEST_CASE(ServiceStartStop)
234 Service s(socketPath);
236 s.addMethodHandler<SendData, SendData>(1, returnDataCallback);
247 BOOST_AUTO_TEST_CASE(ClientStartStop)
249 Service s(socketPath);
250 Client c(socketPath);
251 c.addMethodHandler<SendData, SendData>(1, returnDataCallback);
265 BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho)
267 Service s(socketPath);
268 s.addMethodHandler<SendData, SendData>(1, echoCallback);
269 s.addMethodHandler<SendData, SendData>(2, echoCallback);
272 Client c(socketPath);
278 BOOST_AUTO_TEST_CASE(Restart)
280 Service s(socketPath);
281 s.addMethodHandler<SendData, SendData>(1, echoCallback);
283 s.addMethodHandler<SendData, SendData>(2, echoCallback);
285 Client c(socketPath);
303 BOOST_AUTO_TEST_CASE(SyncServiceToClientEcho)
305 Service s(socketPath);
306 Client c(socketPath);
307 c.addMethodHandler<SendData, SendData>(1, echoCallback);
308 FileDescriptor peerFD = connect(s, c);
310 std::shared_ptr<SendData> sentData(new SendData(56));
311 std::shared_ptr<SendData> recvData = s.callSync<SendData, SendData>(1, peerFD, sentData);
312 BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
315 BOOST_AUTO_TEST_CASE(AsyncClientToServiceEcho)
317 // Setup Service and Client
318 Service s(socketPath);
319 s.addMethodHandler<SendData, SendData>(1, echoCallback);
321 Client c(socketPath);
325 std::condition_variable cv;
328 std::shared_ptr<SendData> sentData(new SendData(34));
329 std::shared_ptr<SendData> recvData;
330 auto dataBack = [&cv, &recvData, &mutex](ipc::Status status, std::shared_ptr<SendData>& data) {
331 BOOST_CHECK(status == ipc::Status::OK);
332 std::unique_lock<std::mutex> lock(mutex);
336 c.callAsync<SendData, SendData>(1, sentData, dataBack);
338 // Wait for the response
339 std::unique_lock<std::mutex> lock(mutex);
340 BOOST_CHECK(cv.wait_for(lock, std::chrono::milliseconds(100), [&recvData]() {
341 return static_cast<bool>(recvData);
344 BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
347 BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho)
349 Service s(socketPath);
350 Client c(socketPath);
351 c.addMethodHandler<SendData, SendData>(1, echoCallback);
352 FileDescriptor peerFD = connect(s, c);
355 std::shared_ptr<SendData> sentData(new SendData(56));
356 std::shared_ptr<SendData> recvData;
359 std::condition_variable cv;
360 auto dataBack = [&cv, &recvData, &mutex](ipc::Status status, std::shared_ptr<SendData>& data) {
361 BOOST_CHECK(status == ipc::Status::OK);
362 std::unique_lock<std::mutex> lock(mutex);
367 s.callAsync<SendData, SendData>(1, peerFD, sentData, dataBack);
369 // Wait for the response
370 std::unique_lock<std::mutex> lock(mutex);
371 BOOST_CHECK(cv.wait_for(lock, std::chrono::milliseconds(1000), [&recvData]() {
372 return recvData.get() != nullptr;
375 BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
379 BOOST_AUTO_TEST_CASE(SyncTimeout)
381 Service s(socketPath);
382 s.addMethodHandler<SendData, SendData>(1, longEchoCallback);
385 Client c(socketPath);
388 std::shared_ptr<SendData> sentData(new SendData(78));
390 BOOST_CHECK_THROW((c.callSync<SendData, SendData>(1, sentData, 10)), IPCException); //TODO it fails from time to time
393 BOOST_AUTO_TEST_CASE(SerializationError)
395 Service s(socketPath);
396 s.addMethodHandler<SendData, SendData>(1, echoCallback);
399 Client c(socketPath);
402 std::shared_ptr<ThrowOnAcceptData> throwingData(new ThrowOnAcceptData());
404 BOOST_CHECK_THROW((c.callSync<ThrowOnAcceptData, SendData>(1, throwingData)), IPCSerializationException);
408 BOOST_AUTO_TEST_CASE(ParseError)
410 Service s(socketPath);
411 s.addMethodHandler<SendData, SendData>(1, echoCallback);
414 Client c(socketPath);
417 std::shared_ptr<SendData> sentData(new SendData(78));
418 BOOST_CHECK_THROW((c.callSync<SendData, ThrowOnAcceptData>(1, sentData, 10000)), IPCParsingException);
421 BOOST_AUTO_TEST_CASE(DisconnectedPeerError)
423 Service s(socketPath);
425 auto method = [](const FileDescriptor, std::shared_ptr<ThrowOnAcceptData>&) {
426 return std::shared_ptr<SendData>(new SendData(1));
429 // Method will throw during serialization and disconnect automatically
430 s.addMethodHandler<SendData, ThrowOnAcceptData>(1, method);
433 Client c(socketPath);
437 std::condition_variable cv;
438 ipc::Status retStatus = ipc::Status::UNDEFINED;
440 auto dataBack = [&cv, &retStatus, &mutex](ipc::Status status, std::shared_ptr<SendData>&) {
441 std::unique_lock<std::mutex> lock(mutex);
446 std::shared_ptr<SendData> sentData(new SendData(78));
447 c.callAsync<SendData, SendData>(1, sentData, dataBack);
449 // Wait for the response
450 std::unique_lock<std::mutex> lock(mutex);
451 BOOST_CHECK(cv.wait_for(lock, std::chrono::seconds(10), [&retStatus]() {
452 return retStatus != ipc::Status::UNDEFINED;
454 BOOST_CHECK(retStatus == ipc::Status::PEER_DISCONNECTED); //TODO it fails from time to time
458 BOOST_AUTO_TEST_CASE(ReadTimeout)
460 Service s(socketPath);
461 auto longEchoCallback = [](const FileDescriptor, std::shared_ptr<SendData>& data) {
462 return std::shared_ptr<LongSendData>(new LongSendData(data->intVal));
464 s.addMethodHandler<LongSendData, SendData>(1, longEchoCallback);
467 Client c(socketPath);
470 // Test timeout on read
471 std::shared_ptr<SendData> sentData(new SendData(334));
472 BOOST_CHECK_THROW((c.callSync<SendData, SendData>(1, sentData, 100)), IPCException);
476 BOOST_AUTO_TEST_CASE(WriteTimeout)
478 Service s(socketPath);
479 s.addMethodHandler<SendData, SendData>(1, echoCallback);
482 Client c(socketPath);
485 // Test echo with a minimal timeout
486 std::shared_ptr<LongSendData> sentDataA(new LongSendData(34, 10 /*ms*/));
487 std::shared_ptr<SendData> recvData = c.callSync<LongSendData, SendData>(1, sentDataA, 100);
488 BOOST_CHECK_EQUAL(recvData->intVal, sentDataA->intVal);
490 // Test timeout on write
491 std::shared_ptr<LongSendData> sentDataB(new LongSendData(34, 1000 /*ms*/));
492 BOOST_CHECK_THROW((c.callSync<LongSendData, SendData>(1, sentDataB, 100)), IPCTimeoutException);
496 BOOST_AUTO_TEST_CASE(AddSignalInRuntime)
498 Service s(socketPath);
499 Client c(socketPath);
502 std::atomic_bool isHandlerACalled(false);
503 auto handlerA = [&isHandlerACalled](const FileDescriptor, std::shared_ptr<SendData>&) {
504 isHandlerACalled = true;
507 std::atomic_bool isHandlerBCalled(false);
508 auto handlerB = [&isHandlerBCalled](const FileDescriptor, std::shared_ptr<SendData>&) {
509 isHandlerBCalled = true;
512 c.addSignalHandler<SendData>(1, handlerA);
513 c.addSignalHandler<SendData>(2, handlerB);
515 auto data = std::make_shared<SendData>(1);
516 s.signal<SendData>(2, data);
517 s.signal<SendData>(1, data);
519 // Wait for the signals to arrive
520 std::this_thread::sleep_for(std::chrono::milliseconds(100)); //TODO wait_for
521 BOOST_CHECK(isHandlerACalled && isHandlerBCalled);
525 BOOST_AUTO_TEST_CASE(AddSignalOffline)
527 Service s(socketPath);
528 Client c(socketPath);
530 std::atomic_bool isHandlerACalled(false);
531 auto handlerA = [&isHandlerACalled](const FileDescriptor, std::shared_ptr<SendData>&) {
532 isHandlerACalled = true;
535 std::atomic_bool isHandlerBCalled(false);
536 auto handlerB = [&isHandlerBCalled](const FileDescriptor, std::shared_ptr<SendData>&) {
537 isHandlerBCalled = true;
540 c.addSignalHandler<SendData>(1, handlerA);
541 c.addSignalHandler<SendData>(2, handlerB);
545 // Wait for the information about the signals to propagate
546 std::this_thread::sleep_for(std::chrono::milliseconds(100));
547 auto data = std::make_shared<SendData>(1);
548 s.signal<SendData>(2, data);
549 s.signal<SendData>(1, data);
551 // Wait for the signals to arrive
552 std::this_thread::sleep_for(std::chrono::milliseconds(100)); //TODO wait_for
553 BOOST_CHECK(isHandlerACalled && isHandlerBCalled);
557 // BOOST_AUTO_TEST_CASE(ConnectionLimitTest)
559 // unsigned oldLimit = ipc::getMaxFDNumber();
560 // ipc::setMaxFDNumber(50);
562 // // Setup Service and many Clients
563 // Service s(socketPath);
564 // s.addMethodHandler<SendData, SendData>(1, echoCallback);
567 // std::list<Client> clients;
568 // for (int i = 0; i < 100; ++i) {
570 // clients.push_back(Client(socketPath));
571 // clients.back().start();
575 // unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
576 // std::mt19937 generator(seed);
577 // for (auto it = clients.begin(); it != clients.end(); ++it) {
579 // std::shared_ptr<SendData> sentData(new SendData(generator()));
580 // std::shared_ptr<SendData> recvData = it->callSync<SendData, SendData>(1, sentData);
581 // BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
585 // ipc::setMaxFDNumber(oldLimit);
590 BOOST_AUTO_TEST_SUITE_END()