2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
25 #include <condition_variable>
32 #include <type_traits>
34 #include <boost/test/test_tools.hpp>
35 #include <boost_macros_wrapper.h>
37 #include <test_common.h>
38 #include <dpl/log/log.h>
40 #include <client-common.h>
41 #include <socket-manager.h>
42 #include <message-buffer.h>
48 size_t Random(size_t max)
50 static unsigned int seed = ::time(nullptr);
51 return ::rand_r(&seed) % max;
54 constexpr char SERVICE_SOCKET_TEST[] = "/tmp/.central-key-manager-test.sock";
55 constexpr CKM::InterfaceID SOCKET_ID_TEST = 42;
56 constexpr std::chrono::seconds CV_TIMEOUT(10);
58 struct TestSocketManager : public SocketManager {
59 size_t TimeoutQueueSize() const { return m_timeoutQueue.size(); }
62 #define THREAD_REQUIRE_MESSAGE(test, message) \
65 std::ostringstream os; \
66 os << __FILE__ << ":" << __LINE__ << " " << #test << " " << message; \
67 throw std::runtime_error(os.str()); \
71 #define THREAD_REQUIRE(test) THREAD_REQUIRE_MESSAGE(test, "")
73 class NoOpService : public GenericSocketService {
74 void Event(const AcceptEvent &) override {}
75 void Event(const WriteEvent &) override {}
76 void Event(const ReadEvent &) override {}
77 void Event(const CloseEvent &) override {}
78 void Event(const SecurityEvent &) override {}
80 void Start() override {}
81 void Stop() override {}
84 class TestConnection final : public ServiceConnection {
86 explicit TestConnection(const std::string& socketPath) :
87 ServiceConnection(socketPath.c_str()),
89 auto ret = prepareConnection();
90 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "ret = " << ret);
93 int Send(const CKM::RawBuffer &send_buf) {
94 m_sent += send_buf.size();
95 return ServiceConnection::send(SerializeMessage(send_buf));
99 void Receive(const T& logReceived) {
102 auto ret = m_socket.waitForSocket(POLLIN, 100);
103 BOOST_REQUIRE_MESSAGE(ret == 0, "ret = " << ret);
108 int ret = ServiceConnection::receive(m_recv);
109 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "ret = " << ret);
110 BOOST_REQUIRE(m_recv.Ready());
111 while (m_recv.Ready()) {
113 m_recv.Deserialize(tmp);
114 const auto size = tmp.size();
115 BOOST_REQUIRE_MESSAGE(size <= m_sent, size << ">" << m_sent);
121 size_t GetId() const { return m_id; }
126 MessageBuffer m_recv;
127 static inline size_t m_counter = 0;
130 class SocketManagerLoop final {
132 explicit SocketManagerLoop(SocketManager& manager) :
137 } catch (const std::exception& e) {
147 ~SocketManagerLoop() {
148 m_manager.MainLoopStop();
151 BOOST_CHECK_MESSAGE(!m_exception, m_what);
155 bool m_exception = false;
156 std::string m_what = "Unknown exception";
157 SocketManager& m_manager;
158 std::thread m_thread;
161 std::string Id2SockPath(int id) {
162 return std::string(SERVICE_SOCKET_TEST) + std::to_string(id);
165 void unlinkIfExists(const char* path) {
166 int ret = unlink(path);
168 BOOST_REQUIRE(ret == 0 || (ret == -1 && err == ENOENT));
171 enum class SockState {
178 SockState operator & (SockState lhs, SockState rhs) {
179 using T = std::underlying_type_t <SockState>;
180 return static_cast<SockState>(static_cast<T>(lhs) & static_cast<T>(rhs));
185 BOOST_AUTO_TEST_SUITE(SOCKET_MANAGER_TEST)
187 POSITIVE_TEST_CASE(StressTestGrowingTimeoutQueue)
189 constexpr unsigned INITIAL_CONNECTIONS = 20;
190 constexpr unsigned REPEATS = 100000;
191 constexpr auto INTERVAL = REPEATS/10;
193 class TestService final : public NoOpService {
195 ServiceDescriptionVector GetServiceDescription() override {
196 return ServiceDescriptionVector {
197 {SERVICE_SOCKET_TEST, "", SOCKET_ID_TEST}
200 void Event(const AcceptEvent &e) override {
201 std::unique_lock<std::mutex> lock(m_mutex);
203 THREAD_REQUIRE_MESSAGE(m_connections.empty() || m_connections.back().client != -1,
204 "Unexpected server entry waiting for client match " <<
205 m_connections.back().server);
207 m_connections.push_back({-1 , e.connectionID.sock});
209 LogDebug("AcceptEvent. Added: ? <=>" << e.connectionID.sock);
216 void Event(const CloseEvent &e) override {
217 std::unique_lock<std::mutex> lock(m_mutex);
218 THREAD_REQUIRE(!m_connections.empty());
220 auto serverMatch = [&](const SocketPair& pair){
221 return pair.server == e.connectionID.sock;
223 auto it = std::find_if(m_connections.begin(), m_connections.end(), serverMatch);
225 THREAD_REQUIRE_MESSAGE(it != m_connections.end(),
226 "Can't find connection for server socket = " <<
227 e.connectionID.sock);
229 LogDebug("CloseEvent. Removing: " << it->client << "<=>" << it->server);
230 THREAD_REQUIRE(it->client != -1);
232 m_connections.erase(it);
240 void ConnectAndWait(SockRAII& client) {
241 std::unique_lock<std::mutex> lock(m_mutex);
243 THREAD_REQUIRE_MESSAGE(m_connections.empty() || m_connections.back().client != -1,
244 "Unexpected server entry waiting for client match " <<
245 m_connections.back().server);
247 int ret = client.connect(GetServiceDescription()[0].serviceHandlerPath.c_str());
248 BOOST_REQUIRE(ret == CKM_API_SUCCESS);
250 LogDebug("Connected. Waiting for AcceptEvent for: " << client.get() << "<=> ?");
252 BOOST_REQUIRE(m_cv.wait_for(lock, CV_TIMEOUT, [&]{ return AcceptEventArrived(); }));
254 m_connections.back().client = client.get();
256 LogDebug("Accepted. Matched client & server: " << m_connections.back().client <<
257 "<=>" << m_connections.back().server);
260 void DisconnectAndWait(SockRAII& client) {
261 int sock = client.get();
264 LogDebug("Disconnected. Waiting for CloseEvent for: " << sock << "<=> ?");
266 std::unique_lock<std::mutex> lock(m_mutex);
267 BOOST_REQUIRE(m_cv.wait_for(lock, CV_TIMEOUT, [&]{ return ClientAbsent(sock); }));
270 void WaitForRemainingClosures() {
271 std::unique_lock<std::mutex> lock(m_mutex);
272 if (!m_connections.empty())
273 BOOST_TEST_MESSAGE("Waiting for remaining " << m_connections.size() <<
276 BOOST_REQUIRE(m_cv.wait_for(lock,
277 std::chrono::seconds(OVERRIDE_SOCKET_TIMEOUT + 2),
278 [&]{ return m_connections.empty(); }));
284 bool ClientAbsent(int client) const {
285 auto it = std::find_if(m_connections.begin(),
286 m_connections.end(), [&](const SocketPair& pair){
287 return pair.client == client;
289 return it == m_connections.end();
292 bool AcceptEventArrived() const {
293 return !m_connections.empty() && m_connections.back().client == -1;
296 void CompareSizes() const {
297 auto manager = static_cast<TestSocketManager*>(m_serviceManager);
298 THREAD_REQUIRE(m_connections.size() == manager->TimeoutQueueSize());
306 std::vector<SocketPair> m_connections;
307 std::condition_variable m_cv;
310 unlinkIfExists(SERVICE_SOCKET_TEST);
312 TestSocketManager manager;
313 auto service = new TestService();
314 manager.RegisterSocketService(service);
316 SocketManagerLoop loop(manager);
319 SockRAII socket[INITIAL_CONNECTIONS];
320 for (unsigned i=0;i<INITIAL_CONNECTIONS;i++)
321 service->ConnectAndWait(socket[i]);
323 BOOST_REQUIRE(manager.TimeoutQueueSize() == INITIAL_CONNECTIONS);
326 for(unsigned i=0;i<REPEATS;i++) {
327 service->ConnectAndWait(socket2);
328 service->DisconnectAndWait(socket2);
330 if ((i + 1) % INTERVAL == 0)
331 BOOST_TEST_MESSAGE("Creating connections: " << i + 1 << "/" << REPEATS);
334 // wait for remaining connections to close if any
335 service->WaitForRemainingClosures();
339 POSITIVE_TEST_CASE(StressTestRandomSocketEvents)
341 // Too many services or connections may trigger server side timeouts (OVERRIDE_SOCKET_TIMEOUT)
342 constexpr int SERVICES = 4;
343 constexpr int INTERVAL = 1000;
344 constexpr int REPEATS = 10000;
345 constexpr int MAX_CONNECTIONS = 4;
346 // client and server read 2048B and 4096B at once respectively
347 constexpr size_t MAX_BUF_SIZE = 5000;
358 class TestService final : public NoOpService {
360 explicit TestService(int id) :
361 m_desc({{Id2SockPath(id).c_str(), "", SOCKET_ID_TEST + id}}),
364 unlinkIfExists(GetSocketPath().c_str());
367 ServiceDescriptionVector GetServiceDescription() override { return m_desc; }
369 void Event(const ReadEvent &e) override {
370 LogDebug(e.connectionID.sock << ":" << e.connectionID.counter << " Received " <<
371 e.rawBuffer.size() << "B");
372 m_serviceManager->Write(e.connectionID, e.rawBuffer);
375 size_t GetConnectionCount() const { return m_connections.size(); }
377 void AddConnection() {
378 m_connections.emplace_back(new TestConnection(GetSocketPath()));
379 LogDebug(Prefix(m_connections.back()->GetId()) << "Connected");
382 void Disconnect(size_t idx) {
383 auto it = m_connections.begin() + idx;
384 auto cid = (*it)->GetId();
385 if (idx != m_connections.size() - 1)
386 *it = std::move(m_connections.back());
387 m_connections.pop_back();
388 LogDebug(Prefix(cid) << "Disconnected");
391 void Send(size_t idx) {
392 auto buffer = createRandom(Random(MAX_BUF_SIZE) + 1);
393 auto& conn = m_connections.at(idx);
394 auto ret = conn->Send(buffer);
395 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "ret = " << ret);
396 LogDebug(Prefix(conn->GetId())<< "Sent " << buffer.size() << "B");
399 void Receive(size_t idx) {
400 auto& conn = m_connections.at(idx);
401 conn->Receive([&](const size_t received) {
402 LogDebug(Prefix(conn->GetId()) << "Received " << received << "B");
407 const std::string& GetSocketPath() const {
408 return m_desc.at(0).serviceHandlerPath;
411 std::string Prefix(size_t idx) const {
412 return std::string(" ") + std::to_string(m_id) + ":" + std::to_string(idx) + " ";
415 ServiceDescriptionVector m_desc;
417 std::vector<std::unique_ptr<TestConnection>> m_connections;
420 SocketManager manager;
421 TestService* services[SERVICES];
423 for (int i = 0;i<SERVICES;i++) {
424 services[i] = new TestService(i);
425 manager.RegisterSocketService(services[i]);
428 SocketManagerLoop loop(manager);
430 for (unsigned i = 0;i < REPEATS; i++) {
432 auto service = services[Random(SERVICES)];
434 // always connect if there are no active connections
437 size_t cCnt = service->GetConnectionCount();
440 eIdx = static_cast<Event>(Random(CNT));
441 if (eIdx == CONNECT && cCnt == MAX_CONNECTIONS)
442 eIdx = SEND; // don't connect if there are too many
447 service->AddConnection();
451 service->Disconnect(cIdx);
459 service->Receive(cIdx);
463 BOOST_FAIL("Unexpected event");
466 if ((i + 1) % INTERVAL == 0)
467 BOOST_TEST_MESSAGE("Executing random socket actions: " << i + 1 << "/" << REPEATS);
471 NEGATIVE_TEST_CASE(CynaraSocket)
473 struct TestSocketManagerExt : public TestSocketManager {
474 void CreateSocket(int sock) {
475 SocketManager::CreateDefaultReadSocketDescription(sock, false);
478 void CloseSocket(int sock) { SocketManager::CloseSocket(sock); }
480 int OutOfRangeSocket() const { return static_cast<int>(m_socketDescriptionVector.size()); }
482 size_t OpenedSockets() const {
483 return std::count_if(m_socketDescriptionVector.begin(),
484 m_socketDescriptionVector.end(),
485 [](const SocketDescription& desc) { return desc.isOpen(); });
488 void RequireOpened(size_t opened) const {
489 BOOST_REQUIRE(opened == OpenedSockets());
491 BOOST_REQUIRE(m_timeoutQueue.empty());
494 void RequireCynara(int cynaraSocket) const {
495 BOOST_REQUIRE(m_cynaraSocket == cynaraSocket);
498 void RequireSocket(int fd, SockState state) const {
499 BOOST_REQUIRE(fd < OutOfRangeSocket());
501 BOOST_REQUIRE(((state & SockState::RD) == SockState::RD) == FD_ISSET(fd, &m_readSet));
502 BOOST_REQUIRE(((state & SockState::WR) == SockState::WR) == FD_ISSET(fd, &m_writeSet));
503 BOOST_REQUIRE((state == SockState::CLOSED) == !m_socketDescriptionVector[fd].isOpen());
507 constexpr int INVALID_FD = -1;
509 TestSocketManagerExt manager;
510 const size_t START_SOCKETS = manager.OpenedSockets();
511 const int OTHER_SOCKET = manager.OutOfRangeSocket();
512 const int CYNARA_SOCKET = OTHER_SOCKET + 1;
513 const int CLOSED_SOCKET = OTHER_SOCKET + 2;
514 const int NEW_CYNARA_SOCKET = OTHER_SOCKET + 3;
516 manager.RequireOpened(START_SOCKETS);
517 manager.RequireCynara(INVALID_FD);
520 manager.CreateSocket(OTHER_SOCKET);
521 manager.RequireOpened(START_SOCKETS + 1);
522 manager.RequireSocket(OTHER_SOCKET, SockState::RD);
523 manager.RequireCynara(INVALID_FD);
526 manager.CynaraSocket(INVALID_FD, CYNARA_SOCKET, false);
527 manager.RequireOpened(START_SOCKETS + 2);
528 manager.RequireSocket(CYNARA_SOCKET, SockState::RD);
529 manager.RequireCynara(CYNARA_SOCKET);
531 // invalid descriptors
532 manager.CynaraSocket(INVALID_FD, INVALID_FD, false);
533 manager.RequireOpened(START_SOCKETS + 2);
534 manager.RequireSocket(CYNARA_SOCKET, SockState::RD);
535 manager.RequireCynara(CYNARA_SOCKET);
538 manager.CynaraSocket(CLOSED_SOCKET, INVALID_FD, false);
539 manager.RequireOpened(START_SOCKETS + 2);
540 manager.RequireSocket(CYNARA_SOCKET, SockState::RD);
541 manager.RequireCynara(CYNARA_SOCKET);
542 manager.RequireSocket(CLOSED_SOCKET, SockState::CLOSED);
545 manager.CynaraSocket(OTHER_SOCKET, INVALID_FD, false);
546 manager.RequireOpened(START_SOCKETS + 2);
547 manager.RequireSocket(CYNARA_SOCKET, SockState::RD);
548 manager.RequireCynara(CYNARA_SOCKET);
549 manager.RequireSocket(OTHER_SOCKET, SockState::RD);
551 // close out of bounds
552 manager.CynaraSocket(manager.OutOfRangeSocket(), INVALID_FD, false);
553 manager.RequireOpened(START_SOCKETS + 2);
554 manager.RequireSocket(CYNARA_SOCKET, SockState::RD);
555 manager.RequireCynara(CYNARA_SOCKET);
557 // open already opened
558 manager.CynaraSocket(INVALID_FD, OTHER_SOCKET, false);
559 manager.RequireOpened(START_SOCKETS + 2);
560 manager.RequireSocket(CYNARA_SOCKET, SockState::RD);
561 manager.RequireCynara(CYNARA_SOCKET);
562 manager.RequireSocket(OTHER_SOCKET, SockState::RD);
564 // open already opened for cynara
565 manager.CynaraSocket(INVALID_FD, CYNARA_SOCKET, false);
566 manager.RequireOpened(START_SOCKETS + 2);
567 manager.RequireSocket(CYNARA_SOCKET, SockState::RD);
568 manager.RequireCynara(CYNARA_SOCKET);
570 // close old & open new cynara socket in WR mode
571 manager.CynaraSocket(CYNARA_SOCKET, NEW_CYNARA_SOCKET, true);
572 manager.RequireOpened(START_SOCKETS + 2);
573 manager.RequireSocket(NEW_CYNARA_SOCKET, SockState::RW);
574 manager.RequireCynara(NEW_CYNARA_SOCKET);
575 manager.RequireSocket(CYNARA_SOCKET, SockState::CLOSED);
578 manager.CynaraSocket(CYNARA_SOCKET, NEW_CYNARA_SOCKET, true);
579 manager.RequireOpened(START_SOCKETS + 2);
580 manager.RequireSocket(NEW_CYNARA_SOCKET, SockState::RW);
581 manager.RequireCynara(NEW_CYNARA_SOCKET);
582 manager.RequireSocket(CYNARA_SOCKET, SockState::CLOSED);
585 manager.CynaraSocket(NEW_CYNARA_SOCKET, NEW_CYNARA_SOCKET, false);
586 manager.RequireOpened(START_SOCKETS + 2);
587 manager.RequireSocket(NEW_CYNARA_SOCKET, SockState::RD);
588 manager.RequireCynara(NEW_CYNARA_SOCKET);
590 // again (no changes)
591 manager.CynaraSocket(NEW_CYNARA_SOCKET, NEW_CYNARA_SOCKET, false);
592 manager.RequireOpened(START_SOCKETS + 2);
593 manager.RequireSocket(NEW_CYNARA_SOCKET, SockState::RD);
594 manager.RequireCynara(NEW_CYNARA_SOCKET);
596 // close other socket manually
597 manager.CloseSocket(OTHER_SOCKET);
598 manager.RequireOpened(START_SOCKETS + 1);
599 manager.RequireSocket(OTHER_SOCKET, SockState::CLOSED);
601 // reopen other socket
602 manager.CreateSocket(OTHER_SOCKET);
603 manager.RequireOpened(START_SOCKETS + 2);
604 manager.RequireSocket(NEW_CYNARA_SOCKET, SockState::RD);
605 manager.RequireCynara(NEW_CYNARA_SOCKET);
606 manager.RequireSocket(OTHER_SOCKET, SockState::RD);
608 // close old closed cynara socket
609 manager.CynaraSocket(CYNARA_SOCKET, INVALID_FD, false);
610 manager.RequireOpened(START_SOCKETS + 2);
611 manager.RequireSocket(NEW_CYNARA_SOCKET, SockState::RD);
612 manager.RequireCynara(NEW_CYNARA_SOCKET);
613 manager.RequireSocket(CYNARA_SOCKET, SockState::CLOSED);
615 // open second cynara socket
616 manager.CynaraSocket(INVALID_FD, CYNARA_SOCKET, false);
617 manager.RequireOpened(START_SOCKETS + 2);
618 manager.RequireSocket(NEW_CYNARA_SOCKET, SockState::RD);
619 manager.RequireCynara(NEW_CYNARA_SOCKET);
620 manager.RequireSocket(CYNARA_SOCKET, SockState::CLOSED);
622 // close new cynara socket
623 manager.CynaraSocket(NEW_CYNARA_SOCKET, INVALID_FD, false);
624 manager.RequireOpened(START_SOCKETS + 1);
625 manager.RequireSocket(NEW_CYNARA_SOCKET, SockState::CLOSED);
626 manager.RequireCynara(INVALID_FD);
628 // close other socket manually
629 manager.CloseSocket(OTHER_SOCKET);
630 manager.RequireOpened(START_SOCKETS);
631 manager.RequireSocket(OTHER_SOCKET, SockState::CLOSED);
634 BOOST_AUTO_TEST_SUITE_END()