Make abstraction of ClientRequest, DLLoader, Service 37/308437/1
authorYonggoo Kang <ygace.kang@samsung.com>
Mon, 25 Mar 2024 13:23:25 +0000 (22:23 +0900)
committerYonggoo Kang <ygace.kang@samsung.com>
Mon, 25 Mar 2024 13:28:19 +0000 (22:28 +0900)
- Enable to test each class
- Add m_notifyMe fd to notify to stop main loop
- Modify unittests to WebAuthn API
- Add unittests to ClientRequest
- Add unittests to DLLoader
- Add unittests to SocketManager

Change-Id: I721e08bae1515ac95f91aed4e2751acd7ea61bcb

19 files changed:
srcs/client/client-common.cpp
srcs/client/client-request-ga.h
srcs/client/client-request-mc.h
srcs/client/client-request.h
srcs/client/client.cpp
srcs/server/dl-loader.cpp
srcs/server/dl-loader.h
srcs/server/main.cpp
srcs/server/service.cpp
srcs/server/service.h
srcs/server/socket-manager.cpp
srcs/server/socket-manager.h
tests/CMakeLists.txt
tests/client-request-test.cpp [new file with mode: 0644]
tests/dl-loader-test.cpp [new file with mode: 0644]
tests/socket-manager-test.cpp [new file with mode: 0644]
tests/test-common.h [new file with mode: 0644]
tests/unittests.cpp
tests/webauthn-client-test.cpp

index ace6a62..d8dabfb 100644 (file)
  * @brief       This file is implementation of client-common functions.
  */
 
-#include <webauthn-log.h>
 #include <singleton.h>
+#include <webauthn-log.h>
 
 #define WEBAUTHN_CLIENT_LOG_TAG "WEBAUTHN-CLIENT"
 
 namespace {
 
-void webauthnClientEnableLogSystem(void) {
+void webauthnClientEnableLogSystem(void)
+{
     auto& logSystem = WA::Singleton<WA::WebAuthnLog>::Instance();
     if (!logSystem.IsTagSet())
         logSystem.SetTag(WEBAUTHN_CLIENT_LOG_TAG);
@@ -45,4 +46,3 @@ static void fini_lib(void)
 {
 
 }
-
index 2dcd76f..6ad3296 100644 (file)
 #include "client-request.h"
 
 namespace WA {
-class ClientRequestGA : public ClientRequest
-{
+class ClientRequestGA : public ClientRequest {
 public:
     typedef wauthn_pubkey_cred_request_options_s Options;
     typedef wauthn_ga_callbacks_s Callbacks;
     typedef wauthn_pubkey_credential_assertion_s PubKeyCred;
 
-    explicit ClientRequestGA() : ClientRequest(WebAuthnCall::GET_ASSERTION) {}
+    explicit ClientRequestGA() : ClientRequest(WebAuthnCall::GET_ASSERTION)
+    {
+    }
 };
+
 } //namespace WebAuthn
index 9c29688..c5a3170 100644 (file)
 #include "client-request.h"
 
 namespace WA {
-class ClientRequestMC : public ClientRequest
-{
+class ClientRequestMC : public ClientRequest {
 public:
     typedef wauthn_pubkey_cred_creation_options_s Options;
     typedef wauthn_mc_callbacks_s Callbacks;
     typedef wauthn_pubkey_credential_attestaion_s PubKeyCred;
 
-    explicit ClientRequestMC() : ClientRequest(WebAuthnCall::MAKE_CREDENTIAL) {}
+    explicit ClientRequestMC() : ClientRequest(WebAuthnCall::MAKE_CREDENTIAL)
+    {
+    }
 };
+
 } //namespace WebAuthn
index 1a9b2b1..d15b81b 100644 (file)
 
 #pragma once
 
-#include <stdexcept>
 #include <iostream>
+#include <stdexcept>
+#include <thread>
+#include <unistd.h>
+#include <utils.h>
 
 #include <connection.h>
 #include <message-buffer.h>
 #include <protocols.h>
-#include <webauthn-types.h>
 #include <webauthn-log.h>
-#include <utils.h>
-
+#include <webauthn-types.h>
 
 namespace WA {
 
-class ClientRequest {
+class GenericClientRequest {
 public:
-    explicit ClientRequest(WebAuthnCall action) :
-        m_action(action),
-        m_conn(std::make_unique<Connection>())
+    explicit GenericClientRequest(WebAuthnCall action, const char *interface) :
+        m_action(action), m_conn(std::make_unique<Connection>())
     {
-        int ret = m_conn->createConnect(SERVICE_SOCKET);
+        int ret = m_conn->createConnect(interface);
         if (ret != WAUTHN_ERROR_NONE)
             ThrowMsg(ServiceException::InActive, "Error in createConnect");
         m_buffer.InitForStreaming();
         Serialization::Serialize(m_buffer, static_cast<int>(m_action));
-        LogDebug("ClientRequest " << WebAuthnCallToString(m_action));
+        LogDebug("GenericClientRequest " << WebAuthnCallToString(m_action));
     }
 
-    ~ClientRequest()
-    {}
+    virtual ~GenericClientRequest()
+    {
+    }
 
     int getStatus() const
     {
@@ -61,11 +62,11 @@ public:
         return m_status != WAUTHN_ERROR_NONE;
     }
 
-    ClientRequest &send()
+    GenericClientRequest &send()
     {
         if (m_sent)
             throw std::logic_error(
-                "Only one call to ClientRequest::send() is allowed");
+                "Only one call to send() is allowed");
 
         m_sent = true;
         m_status = m_conn->send(m_buffer);
@@ -74,20 +75,20 @@ public:
         return *this;
     }
 
-    template <typename... T> ClientRequest &send(const T&... args)
+    template <typename... T> GenericClientRequest &send(const T&... args)
     {
         Serialization::Serialize(m_buffer, args...);
         return send();
     }
 
-    ClientRequest &recv()
+    GenericClientRequest &recv()
     {
         if (!m_sent)
             throw std::logic_error(
-                "Call to ClientRequest::send() must happen before call to ClientRequest::recv()");
+                "Call to send() must happen before call to recv()");
         if (failed())
             throw std::logic_error(
-                "ClientRequest::recv() not allowed if the request failed");
+                "recv() not allowed if the request failed");
         m_status = m_conn->recv(m_buffer);
         if (failed())
         {
@@ -99,27 +100,27 @@ public:
         return *this;
     }
 
-    template <typename... T> ClientRequest &recv(T&... args)
+    template <typename... T> GenericClientRequest &recv(T&... args)
     {
         recv();
         if (failed())
             throw std::logic_error(
-                "ClientRequest::recv() is failed. Pass to receiving response.");
+                "recv() is failed. Pass to receiving response.");
         Deserialization::Deserialize(m_buffer, args...);
         return *this;
     }
 
-    template <typename... T> ClientRequest &recv(T&&... args)
+    template <typename... T> GenericClientRequest &recv(T&&... args)
     {
         recv();
         if (failed())
             throw std::logic_error(
-                "ClientRequest::recv() is failed. Pass to receiving response.");
+                "recv() is failed. Pass to receiving response.");
         Deserialization::Deserialize(m_buffer, args...);
         return *this;
     }
 
-    template <typename... T> ClientRequest &sendRequest(const T&... args)
+    template <typename... T> GenericClientRequest &sendRequest(const T&... args)
     {
         Serialization::Serialize(m_buffer, args...);
         if (send().failed())
@@ -127,7 +128,7 @@ public:
         return recv();
     }
 
-    ClientRequest &sendRequest()
+    GenericClientRequest &sendRequest()
     {
         if (send().failed())
             return *this;
@@ -142,4 +143,65 @@ private:
     std::unique_ptr<Connection> m_conn;
 };
 
+class ClientRequest : public GenericClientRequest {
+public:
+    explicit ClientRequest(WebAuthnCall action) :
+        GenericClientRequest(action, SERVICE_SOCKET)
+    {
+    }
+
+    virtual ~ClientRequest()
+    {
+    }
+};
+
+template <typename A, typename B>
+void cb_worker(std::shared_ptr<GenericClientRequest> request, A &callbacks, B cred)
+{
+    int ret = try_catch([&]() -> int {
+        if (callbacks == nullptr || callbacks->response_callback == nullptr){
+            LogError("Invalid callback parameter");
+            return WAUTHN_ERROR_INVALID_PARAMETER;
+        }
+        if (callbacks->qrcode_callback == nullptr)
+            LogDebug("There is no qrcode_callback");
+        else{ //callbacks->qrcode_callback != nullptr
+            std::string qr_code;
+            if (request->recv(qr_code).failed())
+                LogError("Error on receive qrcode");
+            LogDebug("Received qr_contents: " << qr_code);
+            callbacks->qrcode_callback(qr_code.c_str(), callbacks->user_data);
+        }
+        if(request->recv(&cred).failed())
+            LogError("Error on receive response");
+        return WAUTHN_ERROR_NONE;
+    });
+    callbacks->response_callback(cred, wauthn_error_e(ret), callbacks->user_data);
+}
+
+template <typename T>
+int wauthn_process(const wauthn_client_data_s *client_data,
+                   const typename T::Options *options,
+                   typename T::Callbacks *callbacks)
+{
+    return try_catch([&]() -> int {
+        checkParameters(client_data, options, callbacks);
+        if (options->linked_device != nullptr)  // The qrcode_callback should not be called.
+        {
+            LogDebug("Adjust qrcode_callback to null");
+            callbacks->qrcode_callback = nullptr;
+        }
+        std::shared_ptr<T> request = std::make_shared<T>();
+
+        if (request->sendRequest(client_data, options).failed())
+            return request->getStatus();
+        LogDebug("Response: " << wauthn_error_to_string(request->getStatus()));
+
+        typename T::PubKeyCred *cred = NULL;
+        std::thread worker([request, callbacks, cred]{cb_worker(std::move(request), callbacks, cred);});
+        worker.detach();
+        return WAUTHN_ERROR_NONE;
+    });
+}
+
 } // namespace WebAuthn
index a97652a..ab6f4bd 100644 (file)
  * @brief       Wrap C++ functions to provide C APIs
  */
 
+#include <utils.h>
 #include <webauthn.h>
 #include <webauthn-log.h>
-#include <utils.h>
-#include <unistd.h>
-#include <thread>
-
-#include "client-request-mc.h"
 #include "client-request-ga.h"
-
-template <typename A, typename B>
-void cb_worker(std::shared_ptr<ClientRequest> request, A &callbacks, B cred)
-{
-    int ret = try_catch([&]() -> int {
-        if (callbacks == nullptr || callbacks->response_callback == nullptr){
-            LogError("Invalid callback parameter");
-            return WAUTHN_ERROR_INVALID_PARAMETER;
-        }
-        if (callbacks->qrcode_callback == nullptr)
-            LogDebug("There is no qrcode_callback");
-        else{ //callbacks->qrcode_callback != nullptr
-            std::string qr_code;
-            if (request->recv(qr_code).failed())
-                LogError("Error on receive qrcode");
-            LogDebug("Received qr_contents: " << qr_code);
-            callbacks->qrcode_callback(qr_code.c_str(), callbacks->user_data);
-        }
-        if(request->recv(&cred).failed())
-            LogError("Error on receive response");
-        return WAUTHN_ERROR_NONE;
-    });
-    callbacks->response_callback(cred, wauthn_error_e(ret), callbacks->user_data);
-}
-
-template <typename T>
-int wauthn_process(const wauthn_client_data_s *client_data,
-                   const typename T::Options *options,
-                   typename T::Callbacks *callbacks)
-{
-    return try_catch([&]() -> int {
-        checkParameters(client_data, options, callbacks);
-        if (options->linked_device != nullptr)  // The qrcode_callback should not be called.
-        {
-            LogDebug("Adjust qrcode_callback to null");
-            callbacks->qrcode_callback = nullptr;
-        }
-        std::shared_ptr<T> request = std::make_shared<T>();
-
-        if (request->sendRequest(client_data, options).failed())
-            return request->getStatus();
-        LogDebug("Response: " << wauthn_error_to_string(request->getStatus()));
-
-        typename T::PubKeyCred *cred = NULL;
-        std::thread worker([request, callbacks, cred]{cb_worker(std::move(request), callbacks, cred);});
-        worker.detach();
-        return WAUTHN_ERROR_NONE;
-    });
-}
+#include "client-request-mc.h"
 
 int wauthn_make_credential( const wauthn_client_data_s *client_data,
                             const wauthn_pubkey_cred_creation_options_s *options,
@@ -99,4 +47,4 @@ int wauthn_cancel()
             LogError("Error on cancel request, Response: " << wauthn_error_to_string(request.getStatus()));
         return request.getStatus();
     });
-}
\ No newline at end of file
+}
index 5b3ed9c..ac1d770 100644 (file)
  */
 
 #include <dl-loader.h>
-#include <webauthn-log.h>
-#include <dlfcn.h>
 
 namespace WA {
-    DLLoader::DLLoader(std::string path) : m_libraryPath(std::move(path))
+
+DLLoader::DLLoader(std::string path) : m_libraryPath(std::move(path))
+{
+    LogDebug("Loading library: " << m_libraryPath);
+    m_libraryHandle = dlopen(m_libraryPath.c_str(), RTLD_LAZY | RTLD_LOCAL);
+    if (!m_libraryHandle)
     {
-        LogDebug("Loading library: " << m_libraryPath);
-        m_libraryHandle = dlopen(m_libraryPath.c_str(), RTLD_LAZY | RTLD_LOCAL);
-        if (!m_libraryHandle)
-        {
-            LogError("Unable to load library(" << m_libraryPath << "): " << dlerror());
-            throw std::runtime_error("Unable to load library");
-        }
+        LogError("Unable to load library(" << m_libraryPath << "): " << dlerror());
+        throw std::runtime_error("Unable to load library");
     }
-    DLLoader::~DLLoader()
-    {
-        LogDebug("Unloading library: " << m_libraryPath);
+}
+DLLoader::~DLLoader()
+{
+    LogDebug("Unloading library: " << m_libraryPath);
+    if (m_libraryHandle)
         dlclose(m_libraryHandle);
-    }
-    void* DLLoader::ResolveFunction(const std::string &name) noexcept
-    {
-        LogDebug("Resolving symbol: " << name << " from " << m_libraryPath);
-        void* sym = dlsym(m_libraryHandle, name.c_str());
-        if (!sym)
-            LogError("Unable to resolve symbol: " << name << " from " << m_libraryPath << ": " << dlerror());
-        return sym;
-    }
+}
 
 } // namespace WebAuthn
\ No newline at end of file
index c0fc56d..c285b32 100644 (file)
 
 #include <string>
 #include <stdexcept>
+#include <webauthn-log.h>
+#include <dlfcn.h>
 
 namespace WA {
 
 class DLLoader {
 public:
+    DLLoader() = default;
     explicit DLLoader(std::string path);
-    ~DLLoader();
+    virtual ~DLLoader();
 
-    void* ResolveFunction(const std::string &name) noexcept;
+    virtual void *ResolveFunction(const std::string &name) noexcept
+    {
+        LogDebug("Resolving symbol: " << name << " from " << m_libraryPath);
+        void *sym = dlsym(m_libraryHandle, name.c_str());
+        if (!sym)
+            LogError("Unable to resolve symbol: " << name << " from " << m_libraryPath << ": " << dlerror());
+        return sym;
+    }
 
     template<typename ReturnValue, typename... Args>
     ReturnValue Invoke(const std::string &name, Args... args)
index be2d760..dd84b94 100644 (file)
@@ -38,7 +38,8 @@ int webauthn_manager()
     LogDebug("Start!");
     WA::SocketManager manager;
     try{
-        auto service = std::make_unique<WA::Service>();
+        auto service = std::make_unique<WA::Service>(
+            std::make_shared<DLLoader>(WAH_PLUGIN_SO_PATH_HYBRID));
         manager.RegisterSocketService(std::move(service));
         manager.MainLoop();
         return EXIT_SUCCESS;
index 0462f72..9a603fe 100644 (file)
@@ -25,7 +25,6 @@
 #include <service.h>
 #include <unistd.h>
 #include <utils.h>
-#include <webauthn-hal.h>
 
 #include "request-mc.h"
 #include "request-ga.h"
 
 namespace WA {
 
-Service::Service() : m_pluginHybrid(std::make_shared<DLLoader>(WAH_PLUGIN_SO_PATH_HYBRID)){}
-
-SocketManager *Service::GetSocketmanager()
+SocketManager *GenericService::GetSocketmanager()
 {
     return this->m_serviceManager;
 }
 
-void Service::ProcessEvent(Event &&msg)
+void GenericService::ProcessEvent(Event &&msg)
 {
     LogDebug("Processing message for socket " << msg.connectionID.sock <<
              " counter " << msg.connectionID.counter);
@@ -77,7 +74,7 @@ void Service::ProcessEvent(Event &&msg)
 }
 
 template <typename T>
-void Service::Worker(SocketManager::ConnectionID connectionID,
+void GenericService::Worker(SocketManager::ConnectionID connectionID,
     wauthn_client_data_s *clientData,
     typename T::Options *options)
 {
@@ -113,7 +110,7 @@ void Service::Worker(SocketManager::ConnectionID connectionID,
 }
 
 template <typename T>
-void Service::Process(Event &&msg)
+void GenericService::Process(Event &&msg)
 {
     wauthn_client_data_s *clientData;
     typename T::Options *options;
@@ -138,12 +135,12 @@ void Service::Process(Event &&msg)
     m_serviceManager->Write(msg.connectionID, std::move(responseBuffer));
     if (0 == isBusy)
     {
-        std::thread worker(&Service::Worker<T>, this, msg.connectionID, clientData, options);
+        std::thread worker(&GenericService::Worker<T>, this, msg.connectionID, clientData, options);
         worker.detach();
     }
 }
 
-void Service::Cancel(Event &&msg)
+void GenericService::Cancel(Event &&msg)
 {
     int ret = WAUTHN_ERROR_NONE;
     int isBusy = CheckBusyAndCred(msg.connectionID);
@@ -167,13 +164,13 @@ void Service::Cancel(Event &&msg)
     m_serviceManager->Write(msg.connectionID, std::move(responseBuffer));
 }
 
-void Service::UnsetBusy()
+void GenericService::UnsetBusy()
 {
     std::lock_guard<std::mutex> ulock(m_isBusyMutex);
     m_isBusy = false;
 }
 
-int Service::CheckBusyAndCred(SocketManager::ConnectionID connectionID)
+int GenericService::CheckBusyAndCred(SocketManager::ConnectionID connectionID)
 {
     std::lock_guard<std::mutex> ulock(m_isBusyMutex);
     if (m_isBusy)
@@ -202,7 +199,7 @@ int Service::CheckBusyAndCred(SocketManager::ConnectionID connectionID)
     }
 }
 
-int Service::CheckBusyAndSet(SocketManager::ConnectionID connectionID)
+int GenericService::CheckBusyAndSet(SocketManager::ConnectionID connectionID)
 {
     std::lock_guard<std::mutex> ulock(m_isBusyMutex);
     if (m_isBusy)
@@ -219,12 +216,12 @@ int Service::CheckBusyAndSet(SocketManager::ConnectionID connectionID)
     }
 }
 
-int Service::SetCredentials(SocketManager::ConnectionID connectionID)
+int GenericService::SetCredentials(SocketManager::ConnectionID connectionID)
 {
     return GetCredentials(connectionID, &m_credentials);
 }
 
-int Service::GetCredentials(SocketManager::ConnectionID connectionID, Cred *creds)
+int GenericService::GetCredentials(SocketManager::ConnectionID connectionID, Cred *creds)
 {
     socklen_t length = sizeof(ucred);
     if (0 > getsockopt(connectionID.sock, SOL_SOCKET, SO_PEERCRED, &creds->cred, &length)) {
index d77dd13..6b2483b 100644 (file)
@@ -25,6 +25,7 @@
 #include <protocols.h>
 #include <mutex>
 #include <webauthn-types.h>
+#include <webauthn-hal.h>
 #include "socket-manager.h"
 #include "dl-loader.h"
 
@@ -32,7 +33,7 @@ namespace WA {
 
 typedef struct __struct_user_data
 {
-    Service *service;
+    GenericService *service;
     SocketManager::ConnectionID connectionID;
 }user_data_s;
 
@@ -45,15 +46,13 @@ struct Cred {
     ucred cred;
 };
 
-class Service final
+class GenericService
 {
-    SocketManager *m_serviceManager = nullptr;
 public:
-    static inline const SocketManager::ServiceDescription DESCRIPTION{
-        SERVICE_SOCKET,  /* path */
-        "*"              /* smackLabel label (not used, we rely on systemd) */
-    };
-    explicit Service();
+    explicit GenericService(std::shared_ptr<DLLoader> pluginHybrid) :
+        m_pluginHybrid(pluginHybrid) {}
+
+    virtual ~GenericService() {}
     void SetSocketManager(SocketManager *manager) {
         m_serviceManager = manager;
     }
@@ -70,10 +69,7 @@ public:
      */
     SocketManager *GetSocketmanager();
 
-    /**
-     * Unset to server is not busy
-     */
-    void UnsetBusy();
+    virtual SocketManager::ServiceDescription GetServiceDescription() = 0;
 
 private:
     template <typename T>
@@ -121,9 +117,29 @@ private:
      */
     int GetCredentials(SocketManager::ConnectionID connectionID, Cred *creds);
 
+    /**
+     * Unset to server is not busy
+     */
+    void UnsetBusy();
+
+    SocketManager *m_serviceManager = nullptr;
     bool m_isBusy = false;
     std::mutex m_isBusyMutex;
     Cred m_credentials;
     std::shared_ptr<DLLoader> m_pluginHybrid;
 };
+
+class Service : public GenericService {
+public:
+    explicit Service(std::shared_ptr<DLLoader> pluginHybrid) :
+        GenericService(pluginHybrid) {}
+    virtual ~Service() {}
+    SocketManager::ServiceDescription GetServiceDescription() override {
+        return SocketManager::ServiceDescription {
+            SERVICE_SOCKET,  /* path */
+            "*"              /* smackLabel label (not used, we rely on systemd) */
+        };
+    }
+};
+
 } // namespace WebAuthn
index 1eba34f..8cab0fc 100644 (file)
@@ -74,6 +74,11 @@ SocketManager::SocketManager()
 {
     FD_ZERO(&m_readSet);
 
+    if ((m_notifyMe = eventfd(0, 0)) < 0)
+        ThrowErrno(Exception::InitFailed, "eventfd");
+    LogInfo("Eventfd desc: " << m_notifyMe);
+    RegisterFdForReading(m_notifyMe);
+
     // std::thread bases on pthread so this should work fine
     sigset_t set;
     sigemptyset(&set);
@@ -96,6 +101,7 @@ SocketManager::~SocketManager() {
     // All service sockets have been closed. Close internal descriptors.
     close(m_signalFd);
     close(m_listenSock);
+    close(m_notifyMe);
 }
 
 void SocketManager::ReadyForAccept() {
@@ -212,8 +218,8 @@ void SocketManager::MainLoop() {
 
     // Daemon is ready to work.
     sd_notify(0, "READY=1");
-
-    for (;;) {
+    m_working = true;
+    while (m_working) {
         fd_set readSet = m_readSet;
 
         int ret = 0;
@@ -247,6 +253,12 @@ void SocketManager::MainLoop() {
             FD_CLR(m_listenSock, &readSet);
             ret--;
         }
+        if (FD_ISSET(m_notifyMe, &readSet)) {
+            eventfd_t dummyValue;
+            TEMP_FAILURE_RETRY(eventfd_read(m_notifyMe, &dummyValue));
+            FD_CLR(m_notifyMe, &readSet);
+            ret--;
+        }
         for (int i = 0; ret; ++i) {
             if (FD_ISSET(i, &readSet)) {
                 ReadyForRead(i);
@@ -256,6 +268,12 @@ void SocketManager::MainLoop() {
     }
 }
 
+void SocketManager::MainLoopStop()
+{
+    m_working = false;
+    NotifyMe();
+}
+
 int SocketManager::GetSocketFromSystemD(const ServiceDescription &desc)
 {
     int fd;
@@ -349,12 +367,17 @@ void SocketManager::CreateDomainSocket(const ServiceDescription &desc)
         " Handler: " << desc.serviceHandlerPath.c_str());
 }
 
-void SocketManager::RegisterSocketService(std::unique_ptr<Service> service) {
+void SocketManager::RegisterSocketService(std::unique_ptr<GenericService> service) {
     service->SetSocketManager(this);
-    CreateDomainSocket(Service::DESCRIPTION);
+    CreateDomainSocket(service->GetServiceDescription());
     m_service = std::move(service);
 }
 
+void SocketManager::NotifyMe()
+{
+    TEMP_FAILURE_RETRY(eventfd_write(m_notifyMe, 1));
+}
+
 void SocketManager::Close(ConnectionID connectionID) {
     std::lock_guard<std::mutex> ulock(m_serverProcessMutex);
     if (connectionID.counter == m_socketDescriptionVector[connectionID.sock].counter)
index 0300819..455c4bb 100644 (file)
@@ -31,7 +31,7 @@
 
 namespace WA {
 
-class Service;
+class GenericService;
 
 class SocketManager final {
 public:
@@ -53,8 +53,9 @@ public:
     SocketManager();
     virtual ~SocketManager();
     void MainLoop();
+    void MainLoopStop();
 
-    void RegisterSocketService(std::unique_ptr<Service> service);
+    void RegisterSocketService(std::unique_ptr<GenericService> service);
     void Close(ConnectionID connectionID);
     void Write(ConnectionID connectionID, MessageBuffer &&messageBuffer);
     MessageBuffer newMessage();
@@ -71,6 +72,7 @@ private:
     void ReadyForAccept();
     bool GotSigTerm() const;
     void CloseSocket(int sock);
+    void NotifyMe();
 
     void RegisterFdForReading(int fd);
 
@@ -91,16 +93,17 @@ private:
     };
 
     SocketDescriptionVector m_socketDescriptionVector;
-    std::unique_ptr<Service> m_service;
+    std::unique_ptr<GenericService> m_service;
     fd_set m_readSet;
     int m_maxDesc = -1;
-    int m_signalFd, m_listenSock = -1;
+    int m_signalFd, m_listenSock = -1, m_notifyMe;
     time_t m_nextGenerationStart = 0;
     std::mutex m_eventQueueMutex;
     std::mutex m_serverProcessMutex;
     std::queue<WriteBuffer> m_writeBufferQueue;
     std::queue<ConnectionID> m_closeQueue;
     bool m_enableActivation = false;
+    bool m_working = false;
 };
 
 } // namespace WebAuthn
index 4a9976b..463a1f9 100644 (file)
@@ -2,13 +2,21 @@ PKG_CHECK_MODULES(UNIT_TESTS_DEPS
     REQUIRED
     dlog
     gtest
+    libsystemd
     )
 
 SET(UNIT_TESTS_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/unittests.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/webauthn-client-test.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/client-request-test.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/file-lock-test.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/serialization-test.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/dl-loader-test.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/socket-manager-test.cpp
+
+    ${PRJ_SRC_SERVER_PATH}/dl-loader.cpp
+    ${PRJ_SRC_SERVER_PATH}/service.cpp
+    ${PRJ_SRC_SERVER_PATH}/socket-manager.cpp
 )
 
 SET_SOURCE_FILES_PROPERTIES(
@@ -26,6 +34,7 @@ INCLUDE_DIRECTORIES(
     ${PRJ_SRC_CLIENT_PATH}
     ${PRJ_SRC_COMMON_PATH}
     ${PRJ_SRC_SERVER_PATH}
+    ${PRJ_TEST_PATH}
     )
 
 LINK_DIRECTORIES(${UNIT_TESTS_DEPS_LIBRARY_DIRS})
diff --git a/tests/client-request-test.cpp b/tests/client-request-test.cpp
new file mode 100644 (file)
index 0000000..8fe86ac
--- /dev/null
@@ -0,0 +1,688 @@
+/*
+ *  Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ *
+ *
+ * @file        socket-manager-test.cpp
+ * @version     1.0
+ * @brief       unit tests for socket-manager
+ */
+
+#include "test-common.h"
+
+#include <client-request.h>
+#include <dl-loader.h>
+#include <socket-manager.h>
+#include <gtest/gtest.h>
+#include <iostream>
+#include <service.h>
+
+namespace WA {
+
+typedef enum __client_request_test_case {
+    TC_MC_without_QR_callback_P                 = 0,
+    TC_MC_with_QR_callback_P                    = 1,
+    TC_GA_without_QR_callback_P                 = 2,
+    TC_GA_with_QR_callback_P                    = 3,
+    TC_not_allowed_N                            = 4,
+    TC_cancel_P                                 = 5
+} client_request_test_case_e;
+
+namespace ClientRequestTestData {
+    unsigned char clientDataJsonRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char attestationObjectRaw[16] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char authenticatorDataRaw[26] = {0x21, 0x22, 0x23, 0x24, };
+    unsigned char subjectPubkeyInfoRaw[36] = {0x31, 0x32, 0x33, 0x34, };
+    wauthn_const_buffer_s clientDataJson = {clientDataJsonRaw, sizeof(clientDataJsonRaw)};
+    wauthn_const_buffer_s attestationObject = {attestationObjectRaw, sizeof(attestationObjectRaw)};
+    unsigned int transports = 3;
+    wauthn_const_buffer_s authenticatorData = {authenticatorDataRaw, sizeof(authenticatorDataRaw)};
+    wauthn_const_buffer_s subjectPubkeyInfo = {subjectPubkeyInfoRaw, sizeof(subjectPubkeyInfoRaw)};
+    wauthn_cose_algorithm_e pubkey_alg = WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256;
+    wauthn_authenticator_attestation_response_s authenticatorAttestationResponse
+            = {&clientDataJson, &attestationObject, transports, &authenticatorData, &subjectPubkeyInfo, pubkey_alg};
+    wauthn_authenticator_attestation_response_s emptyAuthenticatorAttestationResponse
+            = {nullptr, nullptr, 0x00, nullptr, nullptr, pubkey_alg};
+
+    unsigned char signatureRaw[26] = {0x21, 0x22, 0x23, 0x24, };
+    unsigned char userHandleRaw[36] = {0x31, 0x32, 0x33, 0x34, };
+    wauthn_const_buffer_s signature = {signatureRaw, sizeof(signatureRaw)};
+    wauthn_const_buffer_s userHandle = {userHandleRaw, sizeof(userHandleRaw)};
+    wauthn_authenticator_assertion_response_s authenticatorAssertionResponse
+            = {&clientDataJson, &authenticatorData, &signature, &userHandle, &attestationObject};
+    wauthn_authenticator_assertion_response_s emptyAuthenticatorAssertionResponse
+            = {nullptr, nullptr, nullptr, nullptr, nullptr};
+
+    const char *name = "test name";
+    const char *id = "test id";
+    wauthn_rp_entity_s rpEntity = {name, id};
+    wauthn_rp_entity_s emptyRpEntiy = {nullptr, nullptr};
+
+    unsigned char idRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    wauthn_const_buffer_s bufferId = {idRaw, sizeof(idRaw)};
+    const char *displayName = "test displayName";
+    wauthn_user_entity_s userEntity = {const_cast<char*>(name), &bufferId, const_cast<char*>(displayName)};
+    wauthn_user_entity_s emptyUserEntity = {nullptr, nullptr, nullptr};
+
+    wauthn_pubkey_cred_type_e pubkeyCredType = PCT_PUBLIC_KEY;
+    wauthn_pubkey_cred_param_s credParam0 = {pubkeyCredType, WAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256};
+    wauthn_pubkey_cred_param_s credParam1 = {pubkeyCredType, WAUTHN_COSE_ALGORITHM_ECDSA_P521_WITH_SHA512};
+    wauthn_pubkey_cred_param_s pubkeyCredParam2[2] = {credParam0, credParam1};
+    wauthn_pubkey_cred_params_s pubkeyCredParams2 = {sizeof(pubkeyCredParam2)/sizeof(pubkeyCredParam2[0]), pubkeyCredParam2};
+    wauthn_pubkey_cred_param_s pubkeyCredParam1[1] = {credParam0};
+    wauthn_pubkey_cred_params_s pubkeyCredParams1 = {sizeof(pubkeyCredParam1)/sizeof(pubkeyCredParam1[0]), pubkeyCredParam1};
+    wauthn_pubkey_cred_params_s emptyPubkeyCredParams = {0, nullptr};
+
+    wauthn_pubkey_cred_descriptor_s pubkeyCredDescriptor = {pubkeyCredType, &bufferId, 3};
+    wauthn_pubkey_cred_descriptor_s emptyPubkeyCredDescriptor = {pubkeyCredType, nullptr, 0};
+
+    unsigned char idRaw0[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char idRaw1[16] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_const_buffer_s bufferId0 = {idRaw0, sizeof(idRaw0)};
+    wauthn_const_buffer_s bufferId1 = {idRaw1, sizeof(idRaw1)};
+    wauthn_pubkey_cred_descriptor_s credDescriptor0 = {pubkeyCredType, &bufferId0, 3};
+    wauthn_pubkey_cred_descriptor_s credDescriptor1 = {pubkeyCredType, &bufferId1, 13};
+    wauthn_pubkey_cred_descriptor_s pubkeyCredDescriptor2[2] = {credDescriptor0, credDescriptor1};
+    wauthn_pubkey_cred_descriptors_s pubkeyCredDescriptors2 = {sizeof(pubkeyCredDescriptor2)/sizeof(pubkeyCredDescriptor2[0]),
+                                                                pubkeyCredDescriptor2};
+    wauthn_pubkey_cred_descriptor_s pubkeyCredDescriptor1[1] = {credDescriptor0};
+    wauthn_pubkey_cred_descriptors_s pubkeyCredDescriptors1 = {sizeof(pubkeyCredDescriptor1)/sizeof(pubkeyCredDescriptor1[0]),
+                                                                pubkeyCredDescriptor1};
+    wauthn_pubkey_cred_descriptors_s emptyPubkeyCredDescriptors = {0, nullptr};
+
+    unsigned char extensionIdRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char extensionValueRaw[16] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_const_buffer_s extensionId = {extensionIdRaw, sizeof(extensionIdRaw)};
+    wauthn_const_buffer_s extensionValue = {extensionValueRaw, sizeof(extensionValueRaw)};
+    wauthn_authentication_ext_s authenticationExt = {&extensionId, &extensionValue};
+    wauthn_authentication_ext_s emptyAuthenticationExt = {nullptr, nullptr};
+
+    unsigned char extensionIdRaw1[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char extensionValueRaw1[16] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_const_buffer_s extensionId1 = {extensionIdRaw1, sizeof(extensionIdRaw1)};
+    wauthn_const_buffer_s extensionValue1 = {extensionValueRaw1, sizeof(extensionValueRaw1)};
+    wauthn_authentication_ext_s authenticationExt1 = {&extensionId1, &extensionValue1};
+    wauthn_authentication_ext_s authenticationExtArr1[1] = {authenticationExt};
+    wauthn_authentication_ext_s authenticationExtArr2[2] = {authenticationExt, authenticationExt1};
+    wauthn_authentication_exts_s authenticationExts1 = {sizeof(authenticationExtArr1)/sizeof(authenticationExtArr1[0]),
+                                                                authenticationExtArr1};
+    wauthn_authentication_exts_s authenticationExts2 = {sizeof(authenticationExtArr2)/sizeof(authenticationExtArr2[0]),
+                                                                authenticationExtArr2};
+    wauthn_authentication_exts_s emptyAuthenticationExts = {0, nullptr};
+
+    wauthn_authenticator_attachment_e attachment = AA_PLATFORM;
+    wauthn_resident_key_requirement_e resident_key = RKR_PREFERRED;
+    bool require_resident_key = false;
+    wauthn_user_verification_requirement_e user_verification = UVR_DISCOURAGED;
+    wauthn_authenticator_sel_cri_s authenticatorSelCri = {attachment, resident_key,
+                                require_resident_key, user_verification};
+
+    wauthn_pubkey_cred_hint_e hint0 = PCH_SECURITY_KEY;
+    wauthn_pubkey_cred_hint_e hint1 = PCH_CLIENT_DEVICE;
+    wauthn_pubkey_cred_hint_e pubkeyCredHint1[1] = {hint0};
+    wauthn_pubkey_cred_hint_e pubkeyCredHint2[2] = {hint0, hint1};
+    wauthn_pubkey_cred_hints_s pubkeyCredHints1 = {sizeof(pubkeyCredHint1)/sizeof(pubkeyCredHint1[0]), pubkeyCredHint1};
+    wauthn_pubkey_cred_hints_s pubkeyCredHints2 = {sizeof(pubkeyCredHint2)/sizeof(pubkeyCredHint2[0]), pubkeyCredHint2};
+    wauthn_pubkey_cred_hints_s emptyPubkeyCredHints = {0, nullptr};
+
+    unsigned char contactIdRaw[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char linkIdRaw[16] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char linkSecretRaw[26] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char authenticatorPubkeyRaw[16] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char authenticatorNameRaw[26] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char authPubkeyRaw[36] = {0x11, 0x12, 0x13, 0x14, };
+    unsigned char tunnelServerDomainRaw[36] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_const_buffer_s contactId = {contactIdRaw, sizeof(contactIdRaw)};
+    wauthn_const_buffer_s linkId = {linkIdRaw, sizeof(linkIdRaw)};
+    wauthn_const_buffer_s linkSecret = {linkSecretRaw, sizeof(linkSecretRaw)};
+    wauthn_const_buffer_s authenticatorPubkey = {authenticatorPubkeyRaw, sizeof(authenticatorPubkeyRaw)};
+    wauthn_const_buffer_s authenticatorName = {authenticatorNameRaw, sizeof(authenticatorNameRaw)};
+    wauthn_const_buffer_s authPubkey = {authPubkeyRaw, sizeof(authPubkeyRaw)};
+    wauthn_const_buffer_s tunnelServerDomain = {tunnelServerDomainRaw, sizeof(tunnelServerDomainRaw)};
+    wauthn_hybrid_linked_data_s hybirdLinkedData = {&contactId, &linkId, &linkSecret, &authenticatorPubkey,
+                                &authenticatorName, &signature, &authPubkey, &tunnelServerDomain};
+    wauthn_hybrid_linked_data_s emptyHybirdLinkedData = {nullptr, nullptr, nullptr, nullptr,
+                                            nullptr, nullptr, nullptr, nullptr};
+
+    unsigned char bufferRaw0[06] = {0x01, 0x02, 0x03, 0x04, };
+    unsigned char bufferRaw1[16] = {0x11, 0x12, 0x13, 0x14, };
+    wauthn_const_buffer_s buffer0 = {bufferRaw0, sizeof(bufferRaw0)};
+    wauthn_const_buffer_s buffer1 = {bufferRaw1, sizeof(bufferRaw1)};
+    wauthn_const_buffer_s attestationFormat1[1] = {buffer0};
+    wauthn_const_buffer_s attestationFormat2[2] = {buffer0, buffer1};
+    wauthn_attestation_formats_s attestationFormats1 = {sizeof(attestationFormat1)/sizeof(attestationFormat1[0]),
+                                                            attestationFormat1};
+    wauthn_attestation_formats_s attestationFormats2 = {sizeof(attestationFormat2)/sizeof(attestationFormat2[0]),
+                                                            attestationFormat2};
+    wauthn_attestation_formats_s emptyAttestationFormats = {0, nullptr};
+
+    unsigned long timeout = 1000;
+    wauthn_attestation_pref_e attestation = AP_DIRECT;
+    wauthn_pubkey_cred_creation_options_s pubkeyCredCreationOptions = {&rpEntity, &userEntity,
+            &pubkeyCredParams2, timeout, &pubkeyCredDescriptors2, &authenticatorSelCri, &pubkeyCredHints2,
+            attestation, &attestationFormats1, &authenticationExts2, &hybirdLinkedData};
+    wauthn_pubkey_cred_creation_options_s pubkeyCredCreationOptionsWithQR = {&rpEntity, &userEntity,
+            &pubkeyCredParams2, timeout, &pubkeyCredDescriptors2, &authenticatorSelCri, &pubkeyCredHints2,
+            attestation, &attestationFormats1, &authenticationExts2, nullptr};
+    wauthn_pubkey_cred_creation_options_s emptyPubkeyCredCreationOptions = {nullptr, nullptr,
+            nullptr, 0, nullptr, nullptr, nullptr, AP_NONE, nullptr, nullptr, nullptr};
+
+    const char *rpId = "test RP ID";
+    wauthn_pubkey_cred_request_options_s pubkeyCredRequestOptions = {timeout, const_cast<char *>(rpId),
+            &pubkeyCredDescriptors2, user_verification, &pubkeyCredHints2, attestation, &attestationFormats1,
+            &authenticationExts2, &hybirdLinkedData};
+    wauthn_pubkey_cred_request_options_s pubkeyCredRequestOptionsWithQR = {timeout, const_cast<char *>(rpId),
+            &pubkeyCredDescriptors2, user_verification, &pubkeyCredHints2, attestation, &attestationFormats1,
+            &authenticationExts2, nullptr};
+    wauthn_pubkey_cred_request_options_s emptyPubkeyCredRequestOptions = {0, nullptr,
+            nullptr, UVR_NONE, nullptr, AP_NONE, nullptr, nullptr, nullptr};
+
+    wauthn_pubkey_credential_attestaion_s pubkeyCredentialAttestation = {&bufferId, pubkeyCredType, &bufferId0,
+            &authenticatorAttestationResponse, attachment, &authenticationExts2, &hybirdLinkedData};
+    wauthn_pubkey_credential_attestaion_s emptyPubkeyCredentialAttestation = {nullptr, pubkeyCredType, nullptr,
+            nullptr, attachment, nullptr, nullptr};
+
+    wauthn_pubkey_credential_assertion_s pubkeyCredentialAssertion = {&bufferId, pubkeyCredType, &bufferId0,
+            &authenticatorAssertionResponse, attachment, &authenticationExts2, &hybirdLinkedData};
+    wauthn_pubkey_credential_assertion_s emptyPubkeyCredentialAssertion = {nullptr, pubkeyCredType, nullptr,
+            nullptr, attachment, nullptr, nullptr};
+
+    wauthn_hash_algorithm_e hashAlg = WAUTHN_HASH_ALGORITHM_SHA_256;
+    wauthn_client_data_s clientData = {&bufferId, hashAlg};
+    wauthn_client_data_s emptyClientData = {nullptr, hashAlg};
+}
+
+class TestClientRequest : public GenericClientRequest {
+public:
+    explicit TestClientRequest(WebAuthnCall action) :
+        GenericClientRequest(action, TEST_SERVICE_SOCKET) {}
+    virtual ~TestClientRequest() {}
+};
+
+class TestClientRequestMC : public TestClientRequest
+{
+public:
+    typedef wauthn_pubkey_cred_creation_options_s Options;
+    typedef wauthn_mc_callbacks_s Callbacks;
+    typedef wauthn_pubkey_credential_attestaion_s PubKeyCred;
+
+    explicit TestClientRequestMC() : TestClientRequest(WebAuthnCall::MAKE_CREDENTIAL) {}
+};
+
+class TestClientRequestGA : public TestClientRequest
+{
+public:
+    typedef wauthn_pubkey_cred_request_options_s Options;
+    typedef wauthn_ga_callbacks_s Callbacks;
+    typedef wauthn_pubkey_credential_assertion_s PubKeyCred;
+
+    explicit TestClientRequestGA() : TestClientRequest(WebAuthnCall::GET_ASSERTION) {}
+};
+
+void wah_make_credential(const wauthn_client_data_s *client_data,
+                         const wauthn_pubkey_cred_creation_options_s *options,
+                         wauthn_mc_callbacks_s *callbacks)
+{
+    std::cout << "IN wah_make_credential by TestDLLoader" << std::endl;
+    if (client_data == NULL)
+        std::cout << "client_data is null" << std::endl;
+    else
+        std::cout << "client_data->hash_alg: " << client_data->hash_alg << std::endl;
+
+    if (options == NULL)
+        std::cout << "options is null" << std::endl;
+    else
+        std::cout << "options->timeout,attestation: " << options->timeout <<
+            ", " << options->attestation << std::endl;
+    sleep(1);
+    if (callbacks->qrcode_callback != nullptr)
+        callbacks->qrcode_callback(std::string("FIDO:/TestDLLoader-wah_make_credential").c_str(),
+                                   callbacks->user_data);
+    else
+        std::cout << "callbacks->qrcode_callback is null" << std::endl;
+    sleep(1);
+    callbacks->response_callback(nullptr, WAUTHN_ERROR_NONE, callbacks->user_data);
+}
+
+void wah_get_assertion(const wauthn_client_data_s *client_data,
+                       const wauthn_pubkey_cred_request_options_s *options,
+                       wauthn_ga_callbacks_s *callbacks)
+{
+    std::cout << "IN wah_get_assertion by TestDLLoader" << std::endl;
+    if (client_data == NULL)
+        std::cout << "client_data is null" << std::endl;
+    else
+        std::cout << "client_data->hash_alg: " << client_data->hash_alg << std::endl;
+
+    if (options == NULL)
+        std::cout << "options is null" << std::endl;
+    else
+        std::cout << "options->timeout,attestation: " << options->timeout <<
+            ", " << options->attestation << std::endl;
+    sleep(1);
+    if (callbacks->qrcode_callback != nullptr)
+        callbacks->qrcode_callback(std::string("FIDO:/TestDLLoader-wah_get_assertion").c_str(),
+                                   callbacks->user_data);
+    sleep(1);
+    callbacks->response_callback(nullptr, WAUTHN_ERROR_NONE, callbacks->user_data);
+}
+
+int wah_cancel()
+{
+    std::cout << "IN wah_cancel by TestDLLoader" << std::endl;
+    return WAUTHN_ERROR_NONE;
+}
+
+class TestDLLoader : public DLLoader {
+public:
+    explicit TestDLLoader ()
+    {
+        try{
+            DLLoader("");
+        }catch (...) {}
+    }
+    void* ResolveFunction(const std::string &name) noexcept override
+    {
+        if (name == WAH_API_MC)
+            return (void *) (&wah_make_credential);
+        else if (name == WAH_API_GA)
+            return (void *) (&wah_get_assertion);
+        else if (name == WAH_API_CANCEL)
+            return (void *) (&wah_cancel);
+        else
+            return nullptr;
+    }
+};
+
+class TestService : public GenericService {
+public:
+    SocketManager::ServiceDescription GetServiceDescription() override {
+        return SocketManager::ServiceDescription {
+            TEST_SERVICE_SOCKET,  /* path */
+            "*"              /* smackLabel label (not used, we rely on systemd) */
+    };
+    }
+    TestService(std::shared_ptr<DLLoader> pluginHybrid) :
+        GenericService(pluginHybrid) {}
+    virtual ~TestService() {}
+};
+
+class SocketManagerLoop final {
+public:
+    explicit SocketManagerLoop(SocketManager& manager) :
+        m_manager(manager),
+        m_thread([&]{
+            try {
+                manager.MainLoop();
+            } catch (const std::exception& e) {
+                m_exception = true;
+                m_what = e.what();
+            } catch (...) {
+                m_exception = true;
+            }
+        })
+    {
+    }
+
+    ~SocketManagerLoop() {
+        m_manager.MainLoopStop();
+        m_thread.join();
+    }
+
+private:
+    bool m_exception = false;
+    std::string m_what = "Unknown exception";
+    SocketManager& m_manager;
+    std::thread m_thread;
+};
+
+typedef struct _test_user_data_s {
+    char *test_data;
+    int test_int;
+    client_request_test_case_e tc_num;
+} test_user_data_s;
+
+void _client_test_print_user_data(void *user_data)
+{
+    std::cout << "user_data is not null, data=" <<
+        (static_cast<test_user_data_s*>(user_data))->test_data <<
+        ", int=" << (static_cast<test_user_data_s*>(user_data))->test_int <<
+        ", tc_num=" << (static_cast<test_user_data_s*>(user_data))->tc_num << std::endl;
+}
+
+void client_request_test_cb_display_qrcode(const char *qr_contents, void *user_data)
+{
+    std::cout << "QR Code: " << std::string(qr_contents) << std::endl;
+    if (user_data == nullptr)
+        std::cout << "user_data is null" << std::endl;
+    else
+        _client_test_print_user_data(user_data);
+
+}
+void client_request_test_cb_mc_on_response(
+    const wauthn_pubkey_credential_attestaion_s *pubkey_cred,
+    wauthn_error_e result,
+    void *user_data)
+{
+    std::cout << "mc response, result: " << wauthn_error_to_string(result) << std::endl;
+    if (pubkey_cred == nullptr)
+        std::cout << "pubkey_cred is null" << std::endl;
+    else
+        std::cout << "pubkey_cred is not null: " <<
+            pubkey_cred->type << ", " <<
+            pubkey_cred->authenticator_attachment << std::endl;
+    if (user_data == nullptr)
+        std::cout << "user_data is null" << std::endl;
+    else
+        _client_test_print_user_data(user_data);
+
+}
+
+void client_request_test_cb_ga_on_response(
+    const wauthn_pubkey_credential_assertion_s *pubkey_cred,
+    wauthn_error_e result,
+    void *user_data)
+{
+    std::cout << "ga response, result: " << wauthn_error_to_string(result) << std::endl;
+    if (pubkey_cred == nullptr)
+        std::cout << "pubkey_cred is null" << std::endl;
+    else
+        std::cout << "pubkey_cred is not null" << std::endl;
+    if (user_data == nullptr)
+        std::cout << "user_data is null" << std::endl;
+    else
+        _client_test_print_user_data(user_data);
+}
+
+class ClientRequestTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        // Do initialization if needed.
+    }
+
+    void TearDown() override {
+        // Do deinitialization if needed.
+    }
+};
+
+
+TEST_F(ClientRequestTest, MC_without_QR_callback_P)
+{
+    int ret = 1;
+    WA::SocketManager manager;
+    try{
+        auto service = std::make_unique<WA::TestService>(std::make_shared<TestDLLoader>());
+        manager.RegisterSocketService(std::move(service));
+        SocketManagerLoop loop(manager);
+
+        {
+            int retVal = WAUTHN_ERROR_NONE;
+            wauthn_mc_callbacks_s *callbacks = nullptr;
+            callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
+            callbacks->qrcode_callback = client_request_test_cb_display_qrcode;
+            callbacks->response_callback = client_request_test_cb_mc_on_response;
+            test_user_data_s *userdata = (test_user_data_s*) calloc(1, sizeof(test_user_data_s));
+            userdata->test_data = (char*)("user data");
+            userdata->test_int = 999;
+            userdata->tc_num = TC_MC_without_QR_callback_P;
+            callbacks->user_data = userdata;
+            retVal = wauthn_process<TestClientRequestMC>(&ClientRequestTestData::clientData,
+                &ClientRequestTestData::pubkeyCredCreationOptions, callbacks);
+
+            EXPECT_EQ(retVal, WAUTHN_ERROR_NONE)
+                    << "[wauthn_process<TestClientRequestMC>] failed. "
+                    << "retVal=" << wauthn_error_to_string(ret) << std::endl;
+            sleep(5);
+            free(userdata);
+            free(callbacks);
+        }
+        sleep(1);
+        ret = 0;
+    } catch (...) {
+        std::cout << "Error in starting service, unknown exception occured" << std::endl;
+        ret = -1;
+    }
+    EXPECT_EQ(ret, 0);
+}
+
+TEST_F(ClientRequestTest, MC_with_QR_callback_P)
+{
+    int ret = 1;
+    WA::SocketManager manager;
+    try{
+        auto service = std::make_unique<WA::TestService>(std::make_shared<TestDLLoader>());
+        manager.RegisterSocketService(std::move(service));
+        SocketManagerLoop loop(manager);
+
+        {
+            int retVal = WAUTHN_ERROR_NONE;
+            wauthn_mc_callbacks_s *callbacks = nullptr;
+            callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
+            callbacks->qrcode_callback = client_request_test_cb_display_qrcode;
+            callbacks->response_callback = client_request_test_cb_mc_on_response;
+            test_user_data_s *userdata = (test_user_data_s*) calloc(1, sizeof(test_user_data_s));
+            userdata->test_data = (char*)("user data");
+            userdata->test_int = 999;
+            userdata->tc_num = TC_MC_with_QR_callback_P;
+            callbacks->user_data = userdata;
+            retVal = wauthn_process<TestClientRequestMC>(&ClientRequestTestData::clientData,
+                &ClientRequestTestData::pubkeyCredCreationOptionsWithQR, callbacks);
+
+            EXPECT_EQ(retVal, WAUTHN_ERROR_NONE)
+                    << "[wauthn_process<TestClientRequestMC>] failed. "
+                    << "retVal=" << wauthn_error_to_string(ret) << std::endl;
+            sleep(5);
+            free(userdata);
+            free(callbacks);
+        }
+        sleep(1);
+        ret = 0;
+    } catch (...) {
+        std::cout << "Error in starting service, unknown exception occured" << std::endl;
+        ret = -1;
+    }
+    EXPECT_EQ(ret, 0);
+}
+
+
+TEST_F(ClientRequestTest, GA_without_QR_callback_P)
+{
+    int ret = 1;
+    WA::SocketManager manager;
+    try{
+        auto service = std::make_unique<WA::TestService>(std::make_shared<TestDLLoader>());
+        manager.RegisterSocketService(std::move(service));
+        SocketManagerLoop loop(manager);
+
+        {
+            int retVal = WAUTHN_ERROR_NONE;
+            wauthn_ga_callbacks_s *callbacks = nullptr;
+            callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
+            callbacks->qrcode_callback = client_request_test_cb_display_qrcode;
+            callbacks->response_callback = client_request_test_cb_ga_on_response;
+            test_user_data_s *userdata = (test_user_data_s*) calloc(1, sizeof(test_user_data_s));
+            userdata->test_data = (char*)("user data");
+            userdata->test_int = 999;
+            userdata->tc_num = TC_GA_without_QR_callback_P;
+            callbacks->user_data = userdata;
+            retVal = wauthn_process<TestClientRequestGA>(&ClientRequestTestData::clientData,
+                &ClientRequestTestData::pubkeyCredRequestOptions, callbacks);
+
+            EXPECT_EQ(retVal, WAUTHN_ERROR_NONE)
+                    << "[wauthn_process<TestClientRequestGA>] failed. "
+                    << "retVal=" << wauthn_error_to_string(ret) << std::endl;
+            sleep(5);
+            free(userdata);
+            free(callbacks);
+        }
+        sleep(1);
+        ret = 0;
+    } catch (...) {
+        std::cout << "Error in starting service, unknown exception occured" << std::endl;
+        ret = -1;
+    }
+    EXPECT_EQ(ret, 0);
+}
+
+TEST_F(ClientRequestTest, GA_with_QR_callback_P)
+{
+    int ret = 1;
+    WA::SocketManager manager;
+    try{
+        auto service = std::make_unique<WA::TestService>(std::make_shared<TestDLLoader>());
+        manager.RegisterSocketService(std::move(service));
+        SocketManagerLoop loop(manager);
+
+        {
+            int retVal = WAUTHN_ERROR_NONE;
+            wauthn_ga_callbacks_s *callbacks = nullptr;
+            callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
+            callbacks->qrcode_callback = client_request_test_cb_display_qrcode;
+            callbacks->response_callback = client_request_test_cb_ga_on_response;
+            test_user_data_s *userdata = (test_user_data_s*) calloc(1, sizeof(test_user_data_s));
+            userdata->test_data = (char*)("user data");
+            userdata->test_int = 999;
+            userdata->tc_num = TC_GA_with_QR_callback_P;
+            callbacks->user_data = userdata;
+            retVal = wauthn_process<TestClientRequestGA>(&ClientRequestTestData::clientData,
+                &ClientRequestTestData::pubkeyCredRequestOptionsWithQR, callbacks);
+
+            EXPECT_EQ(retVal, WAUTHN_ERROR_NONE)
+                    << "[wauthn_process<TestClientRequestGA>] failed. "
+                    << "retVal=" << wauthn_error_to_string(ret) << std::endl;
+            sleep(5);
+            free(userdata);
+            free(callbacks);
+        }
+        sleep(1);
+        ret = 0;
+    } catch (...) {
+        std::cout << "Error in starting service, unknown exception occured" << std::endl;
+        ret = -1;
+    }
+    EXPECT_EQ(ret, 0);
+}
+
+TEST_F(ClientRequestTest, not_allowed_N)
+{
+    int ret = 1;
+    WA::SocketManager manager;
+    try{
+        auto service = std::make_unique<WA::TestService>(std::make_shared<TestDLLoader>());
+        manager.RegisterSocketService(std::move(service));
+        SocketManagerLoop loop(manager);
+
+        {
+            int retVal = WAUTHN_ERROR_NONE;
+            wauthn_mc_callbacks_s *mc_callbacks = nullptr;
+            mc_callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
+            mc_callbacks->qrcode_callback = client_request_test_cb_display_qrcode;
+            mc_callbacks->response_callback = client_request_test_cb_mc_on_response;
+            test_user_data_s *mc_userdata = (test_user_data_s*) calloc(1, sizeof(test_user_data_s));
+            mc_userdata->test_data = (char*)("user data");
+            mc_userdata->test_int = 999;
+            mc_userdata->tc_num = TC_not_allowed_N;
+            mc_callbacks->user_data = mc_userdata;
+            retVal = wauthn_process<TestClientRequestMC>(&ClientRequestTestData::clientData,
+                &ClientRequestTestData::pubkeyCredCreationOptions, mc_callbacks);
+
+            EXPECT_EQ(retVal, WAUTHN_ERROR_NONE)
+                << "[wauthn_process<TestClientRequestMC>] failed. "
+                << "retVal=" << wauthn_error_to_string(ret) << std::endl;
+
+            sleep(1);
+
+            wauthn_ga_callbacks_s *ga_callbacks = nullptr;
+            ga_callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
+            ga_callbacks->qrcode_callback = client_request_test_cb_display_qrcode;
+            ga_callbacks->response_callback = client_request_test_cb_ga_on_response;
+            test_user_data_s *ga_userdata = (test_user_data_s*) calloc(1, sizeof(test_user_data_s));
+            ga_userdata->test_data = (char*)("user data");
+            ga_userdata->test_int = 999;
+            ga_userdata->tc_num = TC_not_allowed_N;
+            ga_callbacks->user_data = ga_userdata;
+            retVal = wauthn_process<TestClientRequestGA>(&ClientRequestTestData::clientData,
+                &ClientRequestTestData::pubkeyCredRequestOptions, ga_callbacks);
+
+            EXPECT_EQ(retVal, WAUTHN_ERROR_NOT_ALLOWED)
+                << "[wauthn_process<TestClientRequestGA>] failed. "
+                << "ret=" << wauthn_error_to_string(retVal) << std::endl;
+
+            sleep(5);
+            free(mc_userdata);
+            free(ga_userdata);
+            free(mc_callbacks);
+            free(ga_callbacks);
+        }
+        sleep(1);
+        ret = 0;
+    } catch (...) {
+        std::cout << "Error in starting service, unknown exception occured" << std::endl;
+        ret = -1;
+    }
+    EXPECT_EQ(ret, 0);
+}
+
+
+TEST_F(ClientRequestTest, cancel_P)
+{
+    int ret = 1;
+    WA::SocketManager manager;
+    try{
+        auto service = std::make_unique<WA::TestService>(std::make_shared<TestDLLoader>());
+        manager.RegisterSocketService(std::move(service));
+        SocketManagerLoop loop(manager);
+
+        {
+            int retVal = WAUTHN_ERROR_NONE;
+            wauthn_mc_callbacks_s *mc_callbacks = nullptr;
+            mc_callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
+            mc_callbacks->qrcode_callback = client_request_test_cb_display_qrcode;
+            mc_callbacks->response_callback = client_request_test_cb_mc_on_response;
+            test_user_data_s *mc_userdata = (test_user_data_s*) calloc(1, sizeof(test_user_data_s));
+            mc_userdata->test_data = (char*)("user data");
+            mc_userdata->test_int = 999;
+            mc_userdata->tc_num = TC_cancel_P;
+            mc_callbacks->user_data = mc_userdata;
+            retVal = wauthn_process<TestClientRequestMC>(&ClientRequestTestData::clientData,
+                &ClientRequestTestData::pubkeyCredCreationOptions, mc_callbacks);
+
+            EXPECT_EQ(retVal, WAUTHN_ERROR_NONE)
+                << "[wauthn_process<TestClientRequestMC>] failed. "
+                << "retVal=" << wauthn_error_to_string(ret) << std::endl;
+
+            sleep(1);
+            TestClientRequest request(WebAuthnCall::CANCEL);
+            if (request.sendRequest().failed())
+                LogError("Error on cancel request, Response: "
+                    << wauthn_error_to_string(request.getStatus()));
+            retVal = request.getStatus();
+
+            EXPECT_EQ(retVal, WAUTHN_ERROR_NONE)
+                << "[wauthn_cancel] failed. "
+                << "ret=" << wauthn_error_to_string(retVal) << std::endl;
+            sleep(5);
+            free(mc_userdata);
+            free(mc_callbacks);
+        }
+        sleep(1);
+        ret = 0;
+    } catch (...) {
+        std::cout << "Error in starting service, unknown exception occured" << std::endl;
+        ret = -1;
+    }
+    EXPECT_EQ(ret, 0);
+}
+
+} // namespace WebAuthn
diff --git a/tests/dl-loader-test.cpp b/tests/dl-loader-test.cpp
new file mode 100644 (file)
index 0000000..0b01902
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ *
+ *
+ * @file        dl-loader-test.cpp
+ * @version     1.0
+ * @brief       unit tests for dl-loader
+ */
+
+#include "test-common.h"
+
+#include <dl-loader.h>
+#include <gtest/gtest.h>
+#include <webauthn-hal.h>
+#include <iostream>
+
+namespace WA {
+
+class DLLoaderTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        // Do initialization if needed.
+    }
+
+    void TearDown() override {
+        // Do deinitialization if needed.
+    }
+};
+
+TEST_F(DLLoaderTest, DLLoader_P)
+{
+    int ret = 0;
+    try{
+        auto dlLoader = std::make_unique<DLLoader>(WAH_PLUGIN_SO_PATH_HYBRID);
+    } catch (...)
+    {
+        std::cout << "Error in make_unique DLLoader" << std::endl;
+        ret = -1;
+    }
+
+    EXPECT_EQ(ret, 0);
+}
+
+TEST_F(DLLoaderTest, DLLoader_N)
+{
+    int ret = 0;
+    try{
+        auto dlLoader = std::make_unique<DLLoader>("invalid_so_path");
+    } catch (...)
+    {
+        std::cout << "Error in make_unique DLLoader" << std::endl;
+        ret = -1;
+    }
+
+    EXPECT_EQ(ret, -1);
+}
+
+TEST_F(DLLoaderTest, Invoke_P)
+{
+    int ret = 0;
+    try{
+        auto dlLoader = std::make_unique<DLLoader>(WAH_PLUGIN_SO_PATH_HYBRID);
+        dlLoader->Invoke<int>(WAH_API_CANCEL);
+    } catch (...)
+    {
+        std::cout << "Error in make_unique DLLoader" << std::endl;
+        ret = -1;
+    }
+
+    EXPECT_EQ(ret, 0);
+}
+
+TEST_F(DLLoaderTest, Invoke_N)
+{
+    int ret = 0;
+    try{
+        auto dlLoader = std::make_unique<DLLoader>(WAH_PLUGIN_SO_PATH_HYBRID);
+        dlLoader->Invoke<int>("invalid_api_name");
+    } catch (...)
+    {
+        std::cout << "Error in make_unique DLLoader" << std::endl;
+        ret = -1;
+    }
+
+    EXPECT_EQ(ret, -1);
+}
+
+} // namespace WebAuthn
diff --git a/tests/socket-manager-test.cpp b/tests/socket-manager-test.cpp
new file mode 100644 (file)
index 0000000..bd64567
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ *
+ *
+ * @file        socket-manager-test.cpp
+ * @version     1.0
+ * @brief       unit tests for socket-manager
+ */
+
+#include "test-common.h"
+
+#include <dl-loader.h>
+#include <socket-manager.h>
+#include <gtest/gtest.h>
+#include <iostream>
+#include <service.h>
+
+namespace WA {
+
+class TestService : public GenericService {
+public:
+    SocketManager::ServiceDescription GetServiceDescription() override {
+        return SocketManager::ServiceDescription {
+            TEST_SERVICE_SOCKET,  /* path */
+            "*"              /* smackLabel label (not used, we rely on systemd) */
+    };
+    }
+    TestService(std::shared_ptr<DLLoader> pluginHybrid) :
+        GenericService(pluginHybrid) {}
+    virtual ~TestService() {}
+};
+
+class SocketManagerTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        // Do initialization if needed.
+    }
+
+    void TearDown() override {
+        // Do deinitialization if needed.
+    }
+};
+
+class SocketManagerLoop final {
+public:
+    explicit SocketManagerLoop(SocketManager& manager) :
+        m_manager(manager),
+        m_thread([&]{
+            try {
+                manager.MainLoop();
+            } catch (const std::exception& e) {
+                m_exception = true;
+                m_what = e.what();
+            } catch (...) {
+                m_exception = true;
+            }
+        })
+    {
+    }
+
+    ~SocketManagerLoop() {
+        m_manager.MainLoopStop();
+        m_thread.join();
+    }
+
+private:
+    bool m_exception = false;
+    std::string m_what = "Unknown exception";
+    SocketManager& m_manager;
+    std::thread m_thread;
+};
+
+
+TEST_F(SocketManagerTest, mainloop_P)
+{
+    int ret = 1;
+    WA::SocketManager manager;
+    try{
+        auto service = std::make_unique<WA::TestService>(std::make_shared<DLLoader>(WAH_PLUGIN_SO_PATH_HYBRID));
+        manager.RegisterSocketService(std::move(service));
+        SocketManagerLoop loop(manager);
+        sleep(1);
+        ret = 0;
+    } catch (...) {
+        std::cout << "Error in starting service, unknown exception occured" << std::endl;
+        ret = -1;
+    }
+    EXPECT_EQ(ret, 0);
+}
+
+} // namespace WebAuthn
\ No newline at end of file
diff --git a/tests/test-common.h b/tests/test-common.h
new file mode 100644 (file)
index 0000000..71ef689
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ *
+ *
+ * @file        test-common.h
+ * @version     1.0
+ * @brief       common header for test
+ */
+
+#pragma once
+
+#include <webauthn-types.h>
+
+namespace WA {
+
+inline constexpr auto TEST_SERVICE_SOCKET = "/tmp/.webauthn-test.socket";
+
+inline constexpr auto WAH_API_MC = "wah_make_credential";
+inline constexpr auto WAH_API_GA = "wah_get_assertion";
+inline constexpr auto WAH_API_CANCEL = "wah_cancel";
+
+} // namespace WebAuthn
\ No newline at end of file
index 954fa9e..0934c6d 100644 (file)
@@ -32,13 +32,10 @@ extern "C" void __gcov_flush(void);
 
 int main(int argc, char *argv[])
 {
-
     WA::Singleton<WA::WebAuthnLog>::Instance().SetTag(WEBAUTHN_TEST_LOG_TAG);
-
     bool ret = false;
-    LogDebug("START");
 #ifdef GCOV_BUILD
-    LogDebug("SET GCOV_PREFIX");
+    std::cout << "SET GCOV_PREFIX" << std::endl;
     setenv("GCOV_PREFIX", "/tmp", 1);
 #endif
     try {
@@ -48,7 +45,6 @@ int main(int argc, char *argv[])
         ret = true;
     }
 #ifdef GCOV_BUILD
-    LogDebug("The webauthn-server process need to be stopped to flush gcov");
     std::cout << "The webauthn-server process need to be stopped to flush gcov"
               << std::endl;
 #endif
index 62745ba..5c5be43 100644 (file)
 #include <gtest/gtest.h>
 #include <unistd.h>
 #include <webauthn.h>
-#include <thread>
-namespace WA {
-
-using std::thread;
 
-#define WEBAUTHN_CODE_DESCRIBE(name) case name: return #name
+namespace WA {
 
 namespace CommonTestData {
     unsigned char clientDataJsonRaw[06] = {0x01, 0x02, 0x03, 0x04, };
@@ -195,11 +191,6 @@ namespace CommonTestData {
     wauthn_client_data_s emptyClientData = {nullptr, hashAlg};
 }
 
-typedef struct _user_data_s {
-    char *test_data;
-    int test_int;
-} user_data_s;
-
 class WebAuthnTest : public ::testing::Test {
 protected:
     void SetUp() override {
@@ -210,11 +201,13 @@ protected:
         // Do deinitialization if needed.
     }
 };
+
 void test_cb_display_qrcode(const char *qr_contents, void *user_data)
 {
     std::cout << "QR Code: " << std::string(qr_contents) << std::endl;
     if (user_data == nullptr)
         std::cout << "user_data is null" << std::endl;
+
 }
 void test_cb_mc_on_response(const wauthn_pubkey_credential_attestaion_s *pubkey_cred,
                               wauthn_error_e result,
@@ -225,15 +218,10 @@ void test_cb_mc_on_response(const wauthn_pubkey_credential_attestaion_s *pubkey_
         std::cout << "pubkey_cred is null" << std::endl;
     else
         std::cout << "pubkey_cred is not null: " <<
-        pubkey_cred->type << ", " <<
-        pubkey_cred->authenticator_attachment << std::endl;
+            pubkey_cred->type << ", " <<
+            pubkey_cred->authenticator_attachment << std::endl;
     if (user_data == nullptr)
         std::cout << "user_data is null" << std::endl;
-    else
-        std::cout << "user_data is not null:" <<
-        (static_cast<user_data_s*>(user_data))->test_data <<
-        ", " << (static_cast<user_data_s*>(user_data))->test_int << std::endl;
-
 }
 
 void test_cb_ga_on_response(const wauthn_pubkey_credential_assertion_s *pubkey_cred,
@@ -247,153 +235,146 @@ void test_cb_ga_on_response(const wauthn_pubkey_credential_assertion_s *pubkey_c
         std::cout << "pubkey_cred is not null" << std::endl;
     if (user_data == nullptr)
         std::cout << "user_data is null" << std::endl;
-    else
-        std::cout << "user_data is not null:" <<
-        (static_cast<user_data_s*>(user_data))->test_data <<
-        ", " << (static_cast<user_data_s*>(user_data))->test_int << std::endl;
-
 }
 
-TEST_F(WebAuthnTest, testMCRequest)
+TEST_F(WebAuthnTest, invalid_client_data_N)
 {
     int ret = WAUTHN_ERROR_NONE;
 
-    wauthn_mc_callbacks_s *callbacks = nullptr;
-    callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
-    callbacks->qrcode_callback = test_cb_display_qrcode;
-    callbacks->response_callback = test_cb_mc_on_response;
-    user_data_s *userdata = (user_data_s*) calloc(1, sizeof(user_data_s));
-    userdata->test_data = (char*)("user data");
-    userdata->test_int = 10;
-    callbacks->user_data = userdata;
-    ret = wauthn_make_credential(&CommonTestData::clientData,
-        &CommonTestData::pubkeyCredCreationOptions,
-        callbacks);
+    wauthn_mc_callbacks_s *mc_callbacks = nullptr;
+    mc_callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
+    mc_callbacks->qrcode_callback = test_cb_display_qrcode;
+    mc_callbacks->response_callback = test_cb_mc_on_response;
+    ret = wauthn_make_credential(nullptr,
+                                 &CommonTestData::pubkeyCredCreationOptions,
+                                 mc_callbacks);
 
-    EXPECT_EQ(ret, WAUTHN_ERROR_NONE)
-            << "[wauthn_make_credential] failed. " << "ret=" << wauthn_error_to_string(ret) << std::endl;
-    std::cout << "wauthn_make_credential ret=" << wauthn_error_to_string(ret) << std::endl;
-    sleep(10);
-}
-TEST_F(WebAuthnTest, testMCRequestQR)
-{
-    int ret = WAUTHN_ERROR_NONE;
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_make_credential] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
 
-    wauthn_mc_callbacks_s *callbacks = nullptr;
-    callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
-    callbacks->qrcode_callback = test_cb_display_qrcode;
-    callbacks->response_callback = test_cb_mc_on_response;
-    user_data_s *userdata = (user_data_s*) calloc(1, sizeof(user_data_s));
-    userdata->test_data = (char*)("user data");
-    userdata->test_int = 10;
-    callbacks->user_data = userdata;
-    ret = wauthn_make_credential(&CommonTestData::clientData,
-        &CommonTestData::pubkeyCredCreationOptionsWithQR,
-        callbacks);
+    ret = WAUTHN_ERROR_NONE;
+    wauthn_ga_callbacks_s *ga_callbacks = nullptr;
+    ga_callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
+    ga_callbacks->qrcode_callback = test_cb_display_qrcode;
+    ga_callbacks->response_callback = test_cb_ga_on_response;
+    ret = wauthn_get_assertion(nullptr,
+                               &CommonTestData::pubkeyCredRequestOptions,
+                               ga_callbacks);
+
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_get_assertion] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
 
-    EXPECT_EQ(ret, WAUTHN_ERROR_NONE)
-            << "[wauthn_make_credential] failed. " << "ret=" << wauthn_error_to_string(ret) << std::endl;
-    std::cout << "wauthn_make_credential ret=" << wauthn_error_to_string(ret) << std::endl;
-    sleep(10);
+    free(mc_callbacks);
+    free(ga_callbacks);
 }
 
-TEST_F(WebAuthnTest, testGARequest)
+TEST_F(WebAuthnTest, invalid_options_N)
 {
     int ret = WAUTHN_ERROR_NONE;
 
-    wauthn_ga_callbacks_s *callbacks = nullptr;
-    callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
-    callbacks->qrcode_callback = test_cb_display_qrcode;
-    callbacks->response_callback = test_cb_ga_on_response;
-    user_data_s *userdata = (user_data_s*) calloc(1, sizeof(user_data_s));
-    userdata->test_data = (char*)("user data");
-    userdata->test_int = 10;
-    callbacks->user_data = userdata;
-    ret = wauthn_get_assertion(&CommonTestData::clientData,
-        &CommonTestData::pubkeyCredRequestOptions,
-        callbacks);
-    EXPECT_EQ(ret, WAUTHN_ERROR_NONE)
-            << "[wauthn_get_assertion] failed. " << "ret=" << wauthn_error_to_string(ret) << std::endl;
-    std::cout << "wauthn_get_assertion ret=" << wauthn_error_to_string(ret) << std::endl;
-    sleep(10);
-}
+    wauthn_mc_callbacks_s *mc_callbacks = nullptr;
+    mc_callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
+    mc_callbacks->qrcode_callback = test_cb_display_qrcode;
+    mc_callbacks->response_callback = test_cb_mc_on_response;
+    ret = wauthn_make_credential(&CommonTestData::clientData,
+                                 nullptr,
+                                 mc_callbacks);
 
-TEST_F(WebAuthnTest, testGARequestQR)
-{
-    int ret = WAUTHN_ERROR_NONE;
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_make_credential] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
 
-    wauthn_ga_callbacks_s *callbacks = nullptr;
-    callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
-    callbacks->qrcode_callback = test_cb_display_qrcode;
-    callbacks->response_callback = test_cb_ga_on_response;
-    user_data_s *userdata = (user_data_s*) calloc(1, sizeof(user_data_s));
-    userdata->test_data = (char*)("user data");
-    userdata->test_int = 10;
-    callbacks->user_data = userdata;
+    ret = WAUTHN_ERROR_NONE;
+    wauthn_ga_callbacks_s *ga_callbacks = nullptr;
+    ga_callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
+    ga_callbacks->qrcode_callback = test_cb_display_qrcode;
+    ga_callbacks->response_callback = test_cb_ga_on_response;
     ret = wauthn_get_assertion(&CommonTestData::clientData,
-        &CommonTestData::pubkeyCredRequestOptionsWithQR,
-        callbacks);
-    EXPECT_EQ(ret, WAUTHN_ERROR_NONE)
-            << "[wauthn_get_assertion] failed. " << "ret=" << wauthn_error_to_string(ret) << std::endl;
-    std::cout << "wauthn_get_assertion ret=" << wauthn_error_to_string(ret) << std::endl;
-    sleep(10);
+                               nullptr,
+                               ga_callbacks);
+
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_get_assertion] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
+
+    free(mc_callbacks);
+    free(ga_callbacks);
 }
 
-TEST_F(WebAuthnTest, testNotAllowedByBusy)
+TEST_F(WebAuthnTest, invalid_callbacks_N)
 {
     int ret = WAUTHN_ERROR_NONE;
+    ret = wauthn_make_credential(&CommonTestData::clientData,
+                                 &CommonTestData::pubkeyCredCreationOptions,
+                                 nullptr);
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_make_credential] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
 
+    ret = WAUTHN_ERROR_NONE;
     wauthn_mc_callbacks_s *mc_callbacks = nullptr;
     mc_callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
     mc_callbacks->qrcode_callback = test_cb_display_qrcode;
-    mc_callbacks->response_callback = test_cb_mc_on_response;
+    mc_callbacks->response_callback = nullptr;
     ret = wauthn_make_credential(&CommonTestData::clientData,
-        &CommonTestData::pubkeyCredCreationOptions,
-        mc_callbacks);
-
-    EXPECT_EQ(ret, WAUTHN_ERROR_NONE)
-            << "[wauthn_make_credential] failed. " << "ret=" << wauthn_error_to_string(ret) << std::endl;
-    std::cout << "wauthn_make_credential ret=" << wauthn_error_to_string(ret) << std::endl;
+                                 &CommonTestData::pubkeyCredCreationOptions,
+                                 mc_callbacks);
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_make_credential] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
 
-    sleep(1);
+    ret = WAUTHN_ERROR_NONE;
+    ret = wauthn_get_assertion(&CommonTestData::clientData,
+                               &CommonTestData::pubkeyCredRequestOptions,
+                               nullptr);
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_get_assertion] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
 
+    ret = WAUTHN_ERROR_NONE;
     wauthn_ga_callbacks_s *ga_callbacks = nullptr;
     ga_callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
     ga_callbacks->qrcode_callback = test_cb_display_qrcode;
-    ga_callbacks->response_callback = test_cb_ga_on_response;
+    ga_callbacks->response_callback = nullptr;
     ret = wauthn_get_assertion(&CommonTestData::clientData,
-        &CommonTestData::pubkeyCredRequestOptions,
-        ga_callbacks);
-
-    EXPECT_EQ(ret, WAUTHN_ERROR_NOT_ALLOWED)
-            << "[wauthn_get_assertion] failed. " << "ret=" << wauthn_error_to_string(ret) << std::endl;
-    std::cout << "wauthn_get_assertion ret=" << wauthn_error_to_string(ret) << std::endl;
-    sleep(10);
+                               &CommonTestData::pubkeyCredRequestOptions,
+                               ga_callbacks);
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_get_assertion] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
+    free(mc_callbacks);
+    free(ga_callbacks);
 }
 
-TEST_F(WebAuthnTest, testCancelOK)
+TEST_F(WebAuthnTest, miss_qr_callback_without_linked_data_N)
 {
     int ret = WAUTHN_ERROR_NONE;
-
     wauthn_mc_callbacks_s *mc_callbacks = nullptr;
     mc_callbacks = (wauthn_mc_callbacks_s*) calloc(1, sizeof(wauthn_mc_callbacks_s));
-    mc_callbacks->qrcode_callback = test_cb_display_qrcode;
+    mc_callbacks->qrcode_callback = nullptr;
     mc_callbacks->response_callback = test_cb_mc_on_response;
     ret = wauthn_make_credential(&CommonTestData::clientData,
-        &CommonTestData::pubkeyCredCreationOptionsWithQR,
-        mc_callbacks);
+                                 &CommonTestData::pubkeyCredCreationOptionsWithQR,
+                                 mc_callbacks);
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_make_credential] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
 
-    EXPECT_EQ(ret, WAUTHN_ERROR_NONE)
-            << "[wauthn_make_credential] failed. " << "ret=" << wauthn_error_to_string(ret) << std::endl;
-    std::cout << "wauthn_make_credential ret=" << wauthn_error_to_string(ret) << std::endl;
-
-    sleep(1);
-
-    ret = wauthn_cancel();
-    EXPECT_EQ(ret, WAUTHN_ERROR_NONE)
-            << "[wauthn_cancel] failed. " << "ret=" << wauthn_error_to_string(ret) << std::endl;
-    std::cout << "wauthn_cancel ret=" << wauthn_error_to_string(ret) << std::endl;
-    sleep(10);
+    ret = WAUTHN_ERROR_NONE;
+    wauthn_ga_callbacks_s *ga_callbacks = nullptr;
+    ga_callbacks = (wauthn_ga_callbacks_s*) calloc(1, sizeof(wauthn_ga_callbacks_s));
+    ga_callbacks->qrcode_callback = nullptr;
+    ga_callbacks->response_callback = test_cb_ga_on_response;
+    ret = wauthn_get_assertion(&CommonTestData::clientData,
+                               &CommonTestData::pubkeyCredRequestOptionsWithQR,
+                               nullptr);
+    EXPECT_EQ(ret, WAUTHN_ERROR_INVALID_PARAMETER)
+        << "[wauthn_get_assertion] failed. "
+        << "ret=" << wauthn_error_to_string(ret) << std::endl;
+    free(mc_callbacks);
+    free(ga_callbacks);
 }
 
 } // namespace WA