Added API to nmlib for applications uninstallation. MqHandler refactored. Tests added.
authorLomtev Dmytro <d.lomtev@samsung.com>
Thu, 10 Aug 2017 07:59:32 +0000 (10:59 +0300)
committerLomtev Dmytro <d.lomtev@samsung.com>
Thu, 10 Aug 2017 08:00:35 +0000 (11:00 +0300)
40 files changed:
device_core/CMakeLists.txt
device_core/ctrl_app_lib/inc/iotchilddevice_impl.h
device_core/ctrl_app_lib/inc/mq_topic.h [new file with mode: 0644]
device_core/ctrl_app_lib/inc/nmlib.h
device_core/ctrl_app_lib/src/ctrl_app_support.cpp
device_core/ctrl_app_lib/src/iotchilddevice_impl.cpp
device_core/ctrl_app_lib/src/securitycontext.cpp
device_core/iotivity_lib/inc/device_commands.h [new file with mode: 0644]
device_core/iotivity_lib/inc/iotdevice.h
device_core/iotivity_lib/inc/iotdevice_impl.h
device_core/iotivity_lib/inc/mqhandler.h
device_core/iotivity_lib/inc/resource_callbacks.h
device_core/iotivity_lib/src/iotdevice_impl.cpp
device_core/iotivity_lib/src/iotivity.cpp
device_core/iotivity_lib/src/mq_topic.cpp [new file with mode: 0644]
device_core/iotivity_lib/src/mqhandler.cpp
device_core/iotivity_lib/src/resource_callbacks.cpp
device_core/nmdaemon/application_service.cpp
device_core/nmdaemon/commandhandler.cpp [new file with mode: 0644]
device_core/nmdaemon/commandhandler.h [new file with mode: 0644]
device_core/nmdaemon/control_resource.cpp
device_core/nmdaemon/control_resource.h
device_core/nmdaemon/icommandhandler.h [new file with mode: 0644]
device_core/nmdaemon/main_thread.cpp
device_core/nmdaemon/notification_handler_mq.cpp
device_core/nmdaemon/policyhandlermq.cpp
device_core/secserver/secserver.cpp
device_core/utest/CMakeLists.txt
device_core/utest/local_test_resources_init.cpp
device_core/utest/test_IoT.cpp
device_core/utest/test_all.cpp
device_core/utest/test_commandhandler.cpp [new file with mode: 0644]
device_core/utest/test_controlresource.cpp
device_core/utest/test_iot_dev_manager.cpp
device_core/utest/test_iot_notification.cpp
device_core/utest/test_iotdevice_impl.cpp [new file with mode: 0644]
device_core/utest/test_jsonutils.cpp
device_core/utest/test_mq.cpp
device_core/utest/test_mq_topic.cpp [new file with mode: 0644]
device_core/utest/test_rest.cpp

index 31dc61c..242407a 100644 (file)
@@ -37,7 +37,8 @@ IF("${FLAVOR}" STREQUAL "UBUNTU")
        SET (LIBDIR "${INSTALL_DIR}/usr/lib/")
        SET (TESTS_DIR "${INSTALL_DIR}/usr/apps/network-manager")
        SET (MANIFESTDIR "${INSTALL_DIR}/usr/share/packages")
-       SET (GTEST_LIB gtest gtest_main)
+       #SET (GTEST_LIB gtest gtest_main)
+       SET (GTEST_LIB gmock gmock_main)
 
        if (NOT DEFINED ENV{IOTIVITY_HOME})
                set(ENV{IOTIVITY_HOME} "$ENV{HOME}/iotivity/")
@@ -149,4 +150,4 @@ else()
                   COMMAND genhtml -o ${COV_FOLDER} ${COV_FOLDER}/utest_filtered.info
                   COMMAND echo "Coverage calculated."
                   COMMENT "Coverage stat with LCOV.\n")
-endif()
\ No newline at end of file
+endif()
index 7c91128..9f3d959 100644 (file)
@@ -74,6 +74,8 @@ public:
 
     void unOwnDevice() override;
 
+    void deleteApp(const std::string& app_name) override;
+
     void setState(bool is_online) override
     {
         online = is_online;
diff --git a/device_core/ctrl_app_lib/inc/mq_topic.h b/device_core/ctrl_app_lib/inc/mq_topic.h
new file mode 100644 (file)
index 0000000..4b724cc
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * @brief  Class used to simplify work with topic names
+ * @date   Created 10.08.2017
+ * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
+ *         between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
+ *         and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea).
+ *         Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
+ * @author Mail to: <A HREF="mailto:d.lomtev@samsung.com">Dmytro Lomtev, d.lomtev@samsung.com</A>
+ */
+#ifndef MQ_TOPIC_H
+#define MQ_TOPIC_H
+
+#include <string>
+#include <vector>
+
+namespace NetworkManager
+{
+
+class MqTopic
+{
+public:
+    typedef std::vector<std::string> Parts;
+
+    /**
+     * @brief Base topic name used by iotivity MQ
+     */
+    static const std::string DEFAULT_MQ_BROKER_URI_ROOT;
+
+    /**
+     * @brief Construct from std::string (Ex.: /subtopic/topic), base topic will be added at the beginning of the name
+     *        if not present
+     * @param name [in] topic name
+     */
+    MqTopic(const std::string& name);
+
+    /**
+     * @brief Construct from vector (Ex.: {"/subtopic", "/topic"}), base topic will be added at the beginning of the
+     *        name if not present
+     * @param first [in] iterator pointing to first part of topic name
+     * @param last  [in] end iterator - pointing to position after the last part of topic name
+     */
+    MqTopic(Parts::const_iterator first, Parts::const_iterator last);
+
+    /**
+     * @brief Returns full topic name
+     * @return topic name as string
+     */
+    const std::string& getName() const
+    {
+        return topic;
+    }
+
+    /**
+     * @brief Returns rest of the topic name without base topic part
+     * @return topic name as string
+     */
+    std::string getSubName() const
+    {
+        return topic.substr(DEFAULT_MQ_BROKER_URI_ROOT.length());
+    }
+
+    /**
+     * @brief Returns topic name splitted to parts first of which is the base topic and others are topic name parts
+     *        prepended with "\"
+     * @return vector containing the topic name parts
+     */
+    Parts split() const;
+private:
+    std::string topic;
+};
+
+} // namespace NetworkManager
+
+#endif // MQ_TOPIC_H
index 2fabfa5..9c917b7 100644 (file)
@@ -321,6 +321,15 @@ NM_ErrorCode NM_setDevicePolicy(NM_hContext ctx, const char* dev_id, const char*
 NM_ErrorCode NM_getDeviceAgents(NM_hContext ctx, const char* dev_id, char** agents);
 
 /**
+ * @brief NM_deleteApp sends application uninstall request to specified device
+ * @param  ctx      [in] handle to context
+ * @param  dev_id   [in] device id
+ * @param  app_name [in] application name to delete
+ * @return error code
+ */
+NM_ErrorCode NM_deleteApp(NM_hContext ctx, const char* dev_id, const char* app_name);
+
+/**
  * @brief subscribeNotifications subscribes to secure server notifications.
  * Triggered by secure server to notify user.
  * @param ctx context handle for internal data storage
index 97ecab3..54e5bcc 100644 (file)
@@ -250,7 +250,7 @@ NM_ErrorCode NM_signIn(NM_hContext ctx, const char* login, const char* pass)
     FN_VISIT
     if (ctx == nullptr) return EC_NULL_POINTER;
     try
-    {   //FIXME: remove hardcoded value
+    {
         ctx->context->login(getCloudHost(), getDSMURI(), login, pass);
     }
     catch (HTTPError& e)
@@ -796,6 +796,30 @@ NM_ErrorCode NM_getDeviceAgents(NM_hContext ctx, const char* dev_id, char** agen
     return EC_OK;
 }
 
+NM_ErrorCode NM_deleteApp(NM_hContext ctx, const char* dev_id, const char* app_name)
+{
+    FN_VISIT
+    if (ctx == nullptr || dev_id == nullptr || app_name) return EC_NULL_POINTER;
+
+    try
+    {
+        auto dev = ctx->context->getIoTDevice(dev_id);
+        dev->deleteApp(app_name);
+    }
+    catch(NMexception& e)
+    {
+        LOG_E(TAG, "Delete applicatio error: %s, error code %d", e.what(), e.errorCode());
+        return static_cast<NM_ErrorCode>(e.errorCode());
+    }
+    catch (std::exception& e)
+    {
+        LOG_E(TAG, "Delete applicatio error: %s", e.what());
+        return EC_INTERNAL_ERROR;
+    }
+
+    return EC_OK;
+}
+
 void NM_freeCharBuffer(char* buffer)
 {
     if (buffer != nullptr) delete[] buffer;
index 5b1a42d..77b15e1 100644 (file)
@@ -52,4 +52,9 @@ void IoTChildDevice_impl::unOwnDevice()
     dev->unOwnDevice(uuid);
 }
 
+void IoTChildDevice_impl::deleteApp(const std::string& app_name)
+{
+    throw NMexception("IoTChildDevice_impl::deleteApp not implemeted", EC_NOT_IMPLEMENTED_YET);
+}
+
 }
index aad3454..b25b6c1 100644 (file)
@@ -292,19 +292,17 @@ void SecurityContext::subscribeNotifications(NM_NotificationCb callback, void* u
     };
 
     MqHandler* mq = iotivity->getMqHandler();
-    // TODO change UUID here to correct
-    mq->subscribe("/00000000-0000-0000-0000-000000000000/notification", observCb);
+
+    std::string user_notification_topic = "/" + iotivity->getCloudAuthId() + "/notification";
+    mq->subscribe(user_notification_topic, observCb);
 }
 
 void SecurityContext::unsubscribeNotifications()
 {
     FN_VISIT;
     MqHandler* mq = iotivity->getMqHandler();
-    if (mq)
-    {
-        // TODO change UUID here to correct
-        mq->unsubscribe("/00000000-0000-0000-0000-000000000000/notification");
-    }
+    std::string user_notification_topic = "/" + iotivity->getCloudAuthId() + "/notification";
+    mq->unsubscribe(user_notification_topic);
 }
 
 //void SecurityContext::unsubscribeOwnedPresence()
diff --git a/device_core/iotivity_lib/inc/device_commands.h b/device_core/iotivity_lib/inc/device_commands.h
new file mode 100644 (file)
index 0000000..6f5e56c
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef DEVICE_COMMANDS_H
+#define DEVICE_COMMANDS_H
+
+enum class DeviceCommands : int
+{
+    WRONG_COMMAND = 0,
+    UNOWN = 1,
+    UNINSTALL = 2,
+};
+
+#endif // DEVICE_COMMANDS_H
index 15a505d..990dbe7 100644 (file)
@@ -108,6 +108,12 @@ public:
     virtual void unOwnDevice() = 0;
 
     /**
+     * @brief deleteApp performes app uninstallation on remote device
+     * @param app_name [in] application name
+     */
+    virtual void deleteApp(const std::string& app_name) = 0;
+
+    /**
      * @brief setState sets online/offline state for device
      * @param state true if device is online
      */
index 02e64eb..45260f0 100644 (file)
@@ -18,8 +18,9 @@ public:
     const unsigned CALLBACK_WAIT_TIMEOUT_S = 3;
 
     IoTDevice_impl(std::shared_ptr<OC::OCResource> device_resource, bool connected = true);
-    IoTDevice_impl(const std::string& host, const std::string& uid, bool connected = true);
+
     IoTDevice_impl(const std::string& uid, const std::string& device_name, const std::string& device_type, const std::string& device_model);
+
     ~IoTDevice_impl() override;
 
     const std::string& getUUID() const override
@@ -73,6 +74,8 @@ public:
 
     void unOwnDevice() override;
 
+    void deleteApp(const std::string& app_name) override;
+
     void setState(bool is_online) override
     {
         online = is_online;
@@ -96,8 +99,10 @@ private:
     void ownCloudDevice();
     void ownPrimitiveDevice();
     void infoFromRepresentation(const OC::OCRepresentation& rep);
+    OC::OCResource::Ptr getControlResource();
+    void sendCommand(OC::OCResource::Ptr ctrl, const OC::OCRepresentation& rep);
 
-    std::shared_ptr<OC::OCResource> dev;
+    OC::OCResource::Ptr dev;
     std::string name;
     std::string model;
     std::string type;
index 6776723..8156d51 100644 (file)
 #include <map>
 #include "OCApi.h"
 #include "OCPlatform.h"
+#include "mq_topic.h"
 
-
+namespace NetworkManager
+{
 /**
  * @brief The MqHandler is class wrapper for MQ functionality of iotivity
  */
@@ -45,13 +47,6 @@ public:
     void subscribe(const std::string& subTopic, OC::ObserveCallback subscribeCB);
 
     /**
-     * @brief subscribe to existing topic
-     * @param subTopic sub topic that shoud be after root topic (Ex. '/srv/policy')
-     * @param subscribeCB method to that should be called after publish
-     */
-    void subscribeToExistingTopic(const std::string& subTopic, OC::ObserveCallback subscribeCB);
-
-    /**
      * @brief unsubscribe method to unsubscribe from topic
      * @param subTopic sub topic that shoud be after root topic (Ex. '/srv/policy')
      */
@@ -67,7 +62,7 @@ public:
      * @param subTopic sub topic that shoud be after root topic (Ex. '/srv/policy')
      * @return resource object that represent topic
      */
-    OC::OCResource::Ptr getTopic(const std::string& subTopic);
+    OC::OCResource::Ptr getTopic(const MqTopic& subTopic);
 
     /**
      * @brief Discovery Topic from MQ broker
@@ -76,10 +71,16 @@ public:
      * @param subTopic sub topic that shoud be after root topic (Ex. '/srv/policy')
      * @return resource object that represent topic
      */
-    OC::OCResource::Ptr discoveryTopic(const std::string& subTopic);
+    OC::OCResource::Ptr discoveryTopic(const MqTopic& subTopic);
 
-private:
+    /**
+     * @brief Try to find topic or create it if not found
+     * @param subTopic sub topic that has to be found or created
+     * @return resource object shared pointer on success and empty shared pointer if fails
+     */
+    OC::OCResource::Ptr findCreateTopic(const std::string& subTopic);
 
+private:
     /**
      * @brief topicCache contains cached topic resources to hold
      * them after subscribe
@@ -91,4 +92,6 @@ private:
     std::mutex handler_mutex;
 };
 
+} // namespace NetworkManager
+
 #endif // MQHANDLER_H
index 56cd383..f339817 100644 (file)
@@ -50,6 +50,7 @@ struct CallbackBase
     bool wait()
     {
         signal.wait_for(lock, DEFAULT_TIMEOUT, [this] { return fired; });
+        lock.unlock();
         return fired;
     }
 
@@ -214,7 +215,7 @@ struct MqDiscoveryTopicCallback : public CallbackBase
 {
     typedef std::shared_ptr<MqDiscoveryTopicCallback> Sptr;
     std::string topic;
-    std::shared_ptr<OC::OCResource> resource;
+    std::vector<OC::OCResource::Ptr> topics;
 
     /**
      * @brief MqDiscoveryTopicCallback constructor
index b99d7d6..94ee7b8 100644 (file)
@@ -9,6 +9,7 @@
 #include <functional>
 #include "resource_callbacks.h"
 #include "iotutils.h"
+#include "device_commands.h"
 
 #include "EasySetup.hpp"
 #include "ESRichCommon.h"
@@ -131,47 +132,6 @@ IoTDevice_impl::IoTDevice_impl(std::shared_ptr<OCResource> device_resource, bool
     LOG_D(TAG, "Device found [%s]:[%s] connectivity=0x%08x.", name.c_str(), uuid.c_str(), int(dev->connectivityType()));
 }
 
-IoTDevice_impl::IoTDevice_impl(const std::string& host, const std::string& uid, bool connected)
-    : name("unknown"), model("unknown"), type("unknown"), uuid(uid), spec_ver("unknown"), host(host), online(connected), cloud_accessibility(false)
-{
-    if (!online) return;
-
-    string uri{"/oic/res?di="};
-    uri += uuid;
-    uri += "&rt=oic.wk.d";
-
-    FindResourceCallback::Sptr type_callback = std::make_shared<FindResourceCallback>("oic.wk.d");
-    OCPlatform::findResource(host, uri,  static_cast<OCConnectivityType>(CT_ADAPTER_TCP | CT_IP_USE_V4), bind_callback(type_callback, PH::_1));
-
-    if (type_callback->wait())
-    {
-        dev = type_callback->resource;
-        auto rt = dev->getResourceTypes();
-        for (auto res_type : rt)
-        {
-            if (res_type.compare(0, dev_type_resource.length(), dev_type_resource) == 0)
-            {
-                type = res_type.substr(dev_type_resource.length());
-            }
-        }
-    }
-    else
-    {
-        LOG_D(TAG, "Fail to found device on URI: %s", uri.c_str());
-    }
-
-    if (dev)
-    {
-        GetResourceCallback::Sptr callback = std::make_shared<GetResourceCallback>();
-        auto result = dev->get("oic.wk.d", "oic.if.baseline", QueryParamsMap{}, bind_callback(callback, PH::_1, PH::_2, PH::_3));
-
-        if (OC_STACK_OK == result && callback->wait())
-        {
-            infoFromRepresentation(callback->representation);
-        }
-    }
-}
-
 IoTDevice_impl::IoTDevice_impl(const std::string& uid, const std::string& device_name, const std::string& device_type, const std::string& device_model)
     : dev(nullptr), name(device_name), model(device_model), type(device_type), uuid(uid), spec_ver("unknown"), host(""), online(false), cloud_accessibility(false)
 {
@@ -181,19 +141,14 @@ IoTDevice_impl::~IoTDevice_impl()
 {
 }
 
-void IoTDevice_impl::unOwnDevice()
+OCResource::Ptr IoTDevice_impl::getControlResource()
 {
-//    if (!dev)
-//    {
-//        throw IoTInternalError("Unowning of offline device requested", EC_ITEM_NOT_FOUND);
-//    }
     if(host.empty())
     {
         throw IoTInternalError("host is empty", EC_NOT_INITIALIZED);
     }
 
     auto iotinst = IoTivity::getInstance();
-//    OCResource::Ptr ctrl_resource = iotinst->findResource(dev->host(), CTRL_RESOURCE_TYPE);
     OCResource::Ptr ctrl_resource = iotinst->findResource(host, CTRL_RESOURCE_TYPE);
 
     if(!ctrl_resource)
@@ -201,9 +156,13 @@ void IoTDevice_impl::unOwnDevice()
         throw IoTInternalError("Control resource not found", EC_GENERIC_ERROR);
     }
 
-    QueryParamsMap query{{"state", "unown"}};
+    return ctrl_resource;
+}
+
+void IoTDevice_impl::sendCommand(OCResource::Ptr ctrl, const OC::OCRepresentation& representation)
+{
     PostResourceCallback::Sptr callback = std::make_shared<PostResourceCallback>();
-    auto result = ctrl_resource->post(OCRepresentation{}, query, bind_callback(callback, PH::_1, PH::_2, PH::_3));
+    auto result = ctrl->post(representation, QueryParamsMap{}, bind_callback(callback, PH::_1, PH::_2, PH::_3));
 
     if (OC_STACK_OK != result)
     {
@@ -216,6 +175,28 @@ void IoTDevice_impl::unOwnDevice()
     }
 }
 
+void IoTDevice_impl::unOwnDevice()
+{
+    auto ctrl_resource = getControlResource();
+    OCRepresentation request;
+    request.setValue("command", int(DeviceCommands::UNOWN));
+    sendCommand(ctrl_resource, request);
+}
+
+void IoTDevice_impl::deleteApp(const std::string& app_name)
+{
+    if (app_name.empty())
+    {
+        throw NMexception("deleteApp called with empty pid or name", EC_BAD_PARAMETER);
+    }
+
+    auto ctrl_resource = getControlResource();
+    OCRepresentation request;
+    request.setValue("command", int(DeviceCommands::UNINSTALL));
+    request.setValue("name", app_name);
+    sendCommand(ctrl_resource, request);
+}
+
 void IoTDevice_impl::setCloudProperties(const std::string& host, const std::string& provider, const std::string& token)
 {
     auto iotinst = IoTivity::getInstance();
index c967b3c..056e465 100644 (file)
@@ -134,6 +134,7 @@ MqHandler* IoTivity::getMqHandler()
     if (handler == nullptr)
     {
         LOG_W(TAG, "getMqHandler(): MqHandler uninitialized");
+        throw std::runtime_error("Failed to connect to message queue");
     }
     return handler;
 }
diff --git a/device_core/iotivity_lib/src/mq_topic.cpp b/device_core/iotivity_lib/src/mq_topic.cpp
new file mode 100644 (file)
index 0000000..f97e5a5
--- /dev/null
@@ -0,0 +1,55 @@
+#include <mq_topic.h>
+
+namespace NetworkManager
+{
+
+const std::string MqTopic::DEFAULT_MQ_BROKER_URI_ROOT = "/oic/ps";
+
+MqTopic::MqTopic(const std::string& name): topic(name)
+{
+    if (0 != topic.compare(0, DEFAULT_MQ_BROKER_URI_ROOT.length(), DEFAULT_MQ_BROKER_URI_ROOT))
+    {
+        topic = DEFAULT_MQ_BROKER_URI_ROOT + topic;
+    }
+}
+
+MqTopic::MqTopic(MqTopic::Parts::const_iterator first, MqTopic::Parts::const_iterator last)
+{
+    if (first == last || *first != DEFAULT_MQ_BROKER_URI_ROOT)
+    {
+        topic.append(DEFAULT_MQ_BROKER_URI_ROOT);
+    }
+
+    while(first != last)
+    {
+        topic.append(*first);
+        ++first;
+    }
+}
+
+MqTopic::Parts MqTopic::split() const
+{
+    Parts result;
+
+    // split root parent
+    auto start = topic.cbegin();
+    auto stop = start + DEFAULT_MQ_BROKER_URI_ROOT.length();
+    result.emplace_back(start, stop);
+
+    for (;stop != topic.cend();)
+    {
+        start = stop;
+
+        do
+        {
+            ++stop;
+        }
+        while (stop != topic.cend() && *stop != '/');
+
+        result.emplace_back(start, stop);
+    }
+
+    return result;
+}
+
+} // namespace NetworkManager
index 0955ac6..6677054 100644 (file)
 
 using namespace std;
 using namespace OC;
-using namespace NetworkManager;
 
 namespace PH = std::placeholders;
 
 namespace
 {
 
-static const vector<string>& DEFAULT_MQ_TYPES = {string(OC_RSRVD_RESOURCE_TYPE_MQ_BROKER)};
-static const vector<string>& DEFAULT_MQ_INTERFACES = {DEFAULT_INTERFACE};
+static const vector<string> DEFAULT_MQ_TYPES{string(OC_RSRVD_RESOURCE_TYPE_MQ_BROKER)};
+static const vector<string> DEFAULT_MQ_INTERFACES{DEFAULT_INTERFACE};
 static const string DEFAULT_MQ_BROKER_URI_ROOT = "/oic/ps";
 
 }
 
+namespace NetworkManager
+{
+
 MqHandler::MqHandler(const std::string& cloudHost):
     cloudHost(cloudHost)
 {
     brokerResource = OCPlatform::constructResourceObject(
                          cloudHost,
                          DEFAULT_MQ_BROKER_URI_ROOT,
-                         CT_DEFAULT, false,
+                         static_cast<OCConnectivityType>(CT_ADAPTER_TCP | CT_IP_USE_V4), false,
                          DEFAULT_MQ_TYPES,
                          DEFAULT_MQ_INTERFACES
                      );
@@ -48,91 +50,122 @@ MqHandler::MqHandler(const std::string& cloudHost):
         throw IoTInternalError("MQ Broker resource construct error.", EC_IOTIVITY_ERROR);
 }
 
-OC::OCResource::Ptr MqHandler::getTopic(const std::string& subTopic)
+OC::OCResource::Ptr MqHandler::getTopic(const MqTopic& topic)
 {
-    std::string topic = DEFAULT_MQ_BROKER_URI_ROOT + subTopic;
-    QueryParamsMap query;
-    OCRepresentation rep;
-    MqCreateTopicCallback::Sptr callback = std::make_shared<MqCreateTopicCallback>();
-
-    guardErrorCode(brokerResource->createMQTopic(
-                       rep, topic, query,
-                       bind_callback(callback, PH::_1, PH::_2, PH::_3),
-                       QualityOfService::HighQos), "createMQTopic()");
+    MqTopic::Parts parts = topic.split();
 
-    if (!callback->wait())
+    if (parts.size() < 2)
     {
-        LOG_E(TAG, "createMQTopic() cb not called.");
-        return nullptr;
+        throw IoTInternalError("Wrong topic name " + topic.getSubName(), EC_IOTIVITY_ERROR);
     }
 
-    switch (callback->errorCode)
+    auto stop = parts.begin() + 1;
+    OCResource::Ptr created_topic;
+
+    std::unique_lock<std::mutex> lock(handler_mutex);
+
+    do
     {
-    // Topic was first time created
-    case OC_STACK_RESOURCE_CREATED:
-        return callback->resource;
-
-    // Topic already exists
-    case OC_STACK_FORBIDDEN_REQ:
-        return OCPlatform::constructResourceObject(
-                   cloudHost,
-                   topic,
-                   CT_DEFAULT, false,
-                   DEFAULT_MQ_TYPES,
-                   DEFAULT_MQ_INTERFACES
-               );
-
-    default:
-        guardErrorCode((OCStackResult)callback->errorCode, "createMQTopic() cb");
-    }
-    LOG_E(TAG, "MqHandler::getTopic() failed");
-    return nullptr;
+        ++stop;
+        MqTopic parent_topic(parts.begin(), stop);
+        auto it = topicCache.find(parent_topic.getName());
+
+        if (it == topicCache.end())
+        {
+            lock.unlock();
+            MqCreateTopicCallback::Sptr callback = std::make_shared<MqCreateTopicCallback>();
+
+            guardErrorCode(brokerResource->createMQTopic(
+                               OCRepresentation{}, parent_topic.getName(), QueryParamsMap{},
+                               bind_callback(callback, PH::_1, PH::_2, PH::_3),
+                               QualityOfService::HighQos), "createMQTopic()");
+
+            if (!callback->wait())
+            {
+                LOG_E(TAG, "createMQTopic() cb not called.");
+                return nullptr;
+            }
+
+            switch (callback->errorCode)
+            {
+            // Topic was first time created
+            case OC_STACK_RESOURCE_CREATED:
+                created_topic = callback->resource;
+                break;
+
+            // Topic already exists
+            case OC_STACK_FORBIDDEN_REQ:
+                created_topic = OCPlatform::constructResourceObject(
+                           cloudHost,
+                           parent_topic.getName(),
+                           CT_DEFAULT, false,
+                           DEFAULT_MQ_TYPES,
+                           DEFAULT_MQ_INTERFACES
+                       );
+                break;
+
+            default:
+                guardErrorCode((OCStackResult)callback->errorCode, "createMQTopic() cb");
+            }
+
+            if (!created_topic)
+            {
+                LOG_E(TAG, "MqHandler::getTopic() Failed to construct topic %s", parent_topic.getName().c_str());
+                throw IoTInternalError("Failed to construct topic " + parent_topic.getName(), EC_IOTIVITY_ERROR);
+            }
+
+            lock.lock();
+            topicCache[parent_topic.getName()] = created_topic;
+        }
+    } while (stop != parts.end());
+
+    return created_topic;
 }
 
-OC::OCResource::Ptr MqHandler::discoveryTopic(const std::string& subTopic)
+OC::OCResource::Ptr MqHandler::discoveryTopic(const MqTopic& topic/*subTopic*/)
 {
-    std::string topic = DEFAULT_MQ_BROKER_URI_ROOT + subTopic;
     QueryParamsMap query;
-    MqDiscoveryTopicCallback::Sptr callback = std::make_shared<MqDiscoveryTopicCallback>(topic);
+    MqDiscoveryTopicCallback::Sptr callback = std::make_shared<MqDiscoveryTopicCallback>(topic.getName());
 
     guardErrorCode(brokerResource->discoveryMQTopics(
                        query,
                        bind_callback(callback, PH::_1, PH::_2, PH::_3),
                        QualityOfService::HighQos), "discoveryMQTopics()");
 
-    if (!callback->wait())
-    {
-        LOG_E(TAG, "discoveryMQTopic() cb not called.");
-        return nullptr;
-    }
+    callback->wait();
+
+    OCResource::Ptr resource;
 
-    switch (callback->errorCode)
+    int r = std::try_lock(callback->mtx, handler_mutex);
+    if (-1 == r)
     {
-    // Topic was discovered
-    case OC_STACK_OK:
-        return callback->resource;
 
-    default:
-        guardErrorCode((OCStackResult)callback->errorCode, "discoveryMQTopic() cb");
-    }
-    LOG_E(TAG, "MqHandler::discoveryTopic() failed");
-    return nullptr;
+        std::for_each(callback->topics.begin(), callback->topics.end(),
+            [this] (OCResource::Ptr ptr)
+            {
+                if (topicCache.find(ptr->uri()) == topicCache.end())
+                {
+                    topicCache[ptr->uri()] = ptr;
+                }
+            }
+        );
+
+        auto it = topicCache.find(topic.getName());
+        if (it != topicCache.end())
+        {
+            resource = it->second;
+        }
+
+        callback->mtx.unlock();
+        handler_mutex.unlock();
+   }
+
+    return resource;
 }
 
 void MqHandler::publish(const std::string& subTopic, const OCRepresentation& rep)
 {
-//    OC::OCResource::Ptr topicResource = getTopic(subTopic);
-//    if (!topicResource)
-//        return;
-
-    OC::OCResource::Ptr topicResource = nullptr;
-    topicResource = discoveryTopic(subTopic);
-    if(!topicResource)
-    {
-        topicResource = getTopic(subTopic);
-        if (!topicResource)
-            return;
-    }
+    OC::OCResource::Ptr topicResource = findCreateTopic(subTopic);
 
     PostResourceCallback::Sptr callback = std::make_shared<PostResourceCallback>();
 
@@ -150,41 +183,44 @@ void MqHandler::publish(const std::string& subTopic, const OCRepresentation& rep
     guardPostErrorCode(callback->errorCode, "publishMQTopic()");
 }
 
-void MqHandler::subscribe(const std::string& subTopic, ObserveCallback subscribeCB)
+OC::OCResource::Ptr MqHandler::findCreateTopic(const std::string& subTopic)
 {
-//    OC::OCResource::Ptr topicResource = getTopic(subTopic);
-//    if (!topicResource)
-//        return;
+    MqTopic topic(subTopic);
+    handler_mutex.lock();
 
-    OC::OCResource::Ptr topicResource = nullptr;
-    topicResource = discoveryTopic(subTopic);
-    if(!topicResource)
+    auto it = topicCache.find(topic.getName());
+    OC::OCResource::Ptr topicResource = it != topicCache.end() ? it->second : nullptr;
+
+    handler_mutex.unlock();
+
+    if (topicResource)
     {
-        topicResource = getTopic(subTopic);
-        if (!topicResource)
-            return;
+        return topicResource;
     }
 
+    topicResource = discoveryTopic(topic);
+
+    if(!topicResource)
     {
-        std::unique_lock<std::mutex> lock(handler_mutex);
-        topicCache[subTopic] = topicResource;
+        topicResource = getTopic(topic);
+
+        if (!topicResource)
+        {
+            throw IoTInternalError("Failed to find and create topic " + topic.getName(), EC_IOTIVITY_ERROR);
+        }
+
+        handler_mutex.lock();
+        topicCache[topic.getName()] = topicResource;
+        handler_mutex.unlock();
     }
 
-    QueryParamsMap query;
-    guardErrorCode(topicResource->subscribeMQTopic(ObserveType::Observe, query,
-                   subscribeCB, QualityOfService::HighQos), "subscribeMQTopic()");
+    return topicResource;
 }
 
-void MqHandler::subscribeToExistingTopic(const std::string& subTopic, OC::ObserveCallback subscribeCB)
+void MqHandler::subscribe(const std::string& subTopic, ObserveCallback subscribeCB)
 {
-    OC::OCResource::Ptr topicResource = discoveryTopic(subTopic);
+    OC::OCResource::Ptr topicResource = findCreateTopic(subTopic); //nullptr;
 
-    if (!topicResource)
-        return;
-    {
-        std::unique_lock<std::mutex> lock(handler_mutex);
-        topicCache[subTopic] = topicResource;
-    }
     QueryParamsMap query;
     guardErrorCode(topicResource->subscribeMQTopic(ObserveType::Observe, query,
                    subscribeCB, QualityOfService::HighQos), "subscribeMQTopic()");
@@ -192,12 +228,15 @@ void MqHandler::subscribeToExistingTopic(const std::string& subTopic, OC::Observ
 
 void MqHandler::unsubscribe(const std::string& subTopic)
 {
-    std::unique_lock<std::mutex> lock(handler_mutex);    
-    auto it = topicCache.find(subTopic);
+    std::unique_lock<std::mutex> lock(handler_mutex);
+    auto it = topicCache.find(DEFAULT_MQ_BROKER_URI_ROOT + subTopic);
     if (it != topicCache.end())
     {
         OC::OCResource::Ptr topicResource = it->second;
+        topicCache.erase(it);
+        lock.unlock();
         guardErrorCode(topicResource->unsubscribeMQTopic(QualityOfService::HighQos), "unsubscribeMQTopic()");
-        topicCache.erase (it);
     }
 }
+
+} // namespace NetworkManager
index 6cd5250..1606af6 100644 (file)
@@ -160,10 +160,12 @@ void MqDiscoveryTopicCallback::call(std::weak_ptr<MqDiscoveryTopicCallback> ctx,
     {
         std::unique_lock<std::mutex> ilock(p->mtx);
 
+        if (errorCode != OC_STACK_OK) return;
+
+        p->topics.push_back(resource);
+
         if(resource->uri() == p->topic)
         {
-            p->errorCode = errorCode;
-            p->resource = resource;
             p->signalize();
         }
     }
index 6b6a7d2..c1d7fea 100644 (file)
@@ -6,6 +6,7 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include <cassert>
+#include <algorithm>
 
 #include "application_service.h"
 
@@ -48,6 +49,10 @@ std::string ApplicationService::find_package_by_app_name(const std::string& app_
         }
 
         pclose(fp);
+
+        res.erase(std::remove_if(res.begin(), res.end(), [] (const char c){
+            return c == '\r' || c == '\n';
+        }), res.end());
     }
 
     return res;
diff --git a/device_core/nmdaemon/commandhandler.cpp b/device_core/nmdaemon/commandhandler.cpp
new file mode 100644 (file)
index 0000000..d025f09
--- /dev/null
@@ -0,0 +1,94 @@
+#include "commandhandler.h"
+#include "registration_mq.h"
+#include "device_commands.h"
+#include "application_service.h"
+
+namespace NMD
+{
+
+CommandHandler::CommandHandler(NetworkManager::IoTivity* iotivity,
+                               std::shared_ptr<HubResource> hub,
+                               std::shared_ptr<ReportHandler> report_handler,
+                               std::shared_ptr<PolicyHandler> policy_handler,
+                               std::shared_ptr<ProxyThread> proxy_thread,
+                               WorkingMode wmode,
+                               ThreadBase* main_thread)
+    : m_iotivity(iotivity)
+    , m_report_handler(report_handler)
+    , m_policy_handler(policy_handler)
+    , m_proxy_thread(proxy_thread)
+    , m_wmode(wmode)
+    , m_main_thread(main_thread)
+{
+    assert(iotivity);
+    assert(report_handler);
+    assert(policy_handler);
+    assert(proxy_thread);
+    assert(main_thread != nullptr);
+}
+
+bool CommandHandler::process(const OC::OCRepresentation& command)
+{
+    DeviceCommands action = static_cast<DeviceCommands>(command.getValue<int>("command"));
+
+    switch (action)
+    {
+    case DeviceCommands::UNOWN:
+        return unOwnCommand(command);
+    case DeviceCommands::UNINSTALL:
+        return uninstallCommand(command);
+    default:
+        return false;
+    }
+}
+
+bool CommandHandler::uninstallCommand(const OC::OCRepresentation& command)
+{
+    std::string name = command.getValue<std::string>("name");
+
+    if (name.empty()) return false;
+
+    if(name == "smack_test")
+    {
+        std::string pack_full_name = ApplicationService::find_package_by_app_name(name);
+        if(!pack_full_name.empty())
+        {
+            return 0 == ApplicationService::uninstall(pack_full_name);
+        }
+    }
+
+    return true;
+}
+
+bool CommandHandler::unOwnCommand(const OC::OCRepresentation& command)
+{
+    m_proxy_thread->addAction(std::async(std::launch::deferred, &CommandHandler::unOwnTask, this));
+    return true;
+}
+
+
+void CommandHandler::unOwnTask()
+{
+    if (m_wmode != WorkingMode::Primitive)
+    {
+        RegistrationMQ::unreg(m_iotivity->getDeviceID());
+    }
+
+    delete_config();
+
+    if (g_working_mode == WorkingMode::Hub)
+    {
+        // disable hub to send found devices list
+        assert(m_hub);
+        m_hub->setEnabled(false);
+        clear_hub_cache();
+        m_report_handler->disable();
+        m_policy_handler->disable();
+        m_proxy_thread->addAction(std::async(std::launch::deferred, &NetworkManager::IoTivity::unPublishAllResources, m_iotivity));
+        m_proxy_thread->addAction(std::async(std::launch::deferred, &HubResource::unownAll, m_hub.get()));
+    }
+
+    m_main_thread->stop();
+}
+
+} // namespace NMD
diff --git a/device_core/nmdaemon/commandhandler.h b/device_core/nmdaemon/commandhandler.h
new file mode 100644 (file)
index 0000000..48db6fe
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * @brief  Command handler implementation
+ *         Process commands:
+ *             - device unpairing
+ *             - application uninstallation
+ * @date   Created 10.08.2017
+ * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
+ *         between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
+ *         and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea).
+ *         Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
+ * @author Mail to: <A HREF="mailto:d.lomtev@samsung.com">Dmytro Lomtev, d.lomtev@samsung.com</A>
+ */
+#ifndef COMMANDHANDLER_H
+#define COMMANDHANDLER_H
+
+#include "iotivity.h"
+#include "hub_resource.h"
+#include "reporthandler.h"
+#include "policyhandler.h"
+#include "proxythread.h"
+#include "icommandhandler.h"
+#include "utils.h"
+
+namespace NMD
+{
+
+class CommandHandler : public ICommandHandler
+{
+public:
+    CommandHandler(NetworkManager::IoTivity* iotivity,
+                   std::shared_ptr<HubResource> hub,
+                   std::shared_ptr<ReportHandler> report_handler,
+                   std::shared_ptr<PolicyHandler> policy_handler,
+                   std::shared_ptr<ProxyThread> proxy_thread,
+                   WorkingMode wmode,
+                   ThreadBase* main_thread);
+
+    bool process(const OC::OCRepresentation& command) override;
+private:
+
+    bool unOwnCommand(const OC::OCRepresentation& command);
+
+    bool uninstallCommand(const OC::OCRepresentation& command);
+
+    void unOwnTask();
+
+    NetworkManager::IoTivity* m_iotivity;
+    std::shared_ptr<HubResource> m_hub;
+    std::shared_ptr<ReportHandler> m_report_handler;
+    std::shared_ptr<PolicyHandler> m_policy_handler;
+    std::shared_ptr<ProxyThread> m_proxy_thread;
+    WorkingMode m_wmode;
+    ThreadBase* m_main_thread;
+};
+
+} // namespace NMD
+
+#endif // COMMANDHANDLER_H
index 9d1ab3a..672434a 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * @brief  Resource used for device unowning
+ * @brief  Resource used for commands handling
  * @date   Created 10.07.2017
  * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
  *         between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
@@ -11,6 +11,7 @@
 #include "OCPlatform.h"
 #include "control_resource.h"
 #include "logging.h"
+#include <cassert>
 
 using namespace OC;
 
@@ -24,10 +25,11 @@ const std::string CTRL_RESOURCE_TYPE = "device.control";
 
 namespace NMD
 {
-ControlResource::ControlResource(ControlCallback&& cb)
+ControlResource::ControlResource(/*ControlCallback&& cb*/ICommandHandler* handler)
     : IotResource(CTRL_RESOURCE_URI, {CTRL_RESOURCE_TYPE}, {DEFAULT_INTERFACE})
-    , callback(cb)
+    , m_handler(handler)
 {
+    assert(nullptr != handler);
 }
 
 void ControlResource::setRepresentation(OCRepresentation& rep)
@@ -53,17 +55,16 @@ OCEntityHandlerResult ControlResource::entityHandler(std::shared_ptr<OCResourceR
             }
             else if(rt == "POST")
             {
-                auto query = request->getQueryParameters();
-                std::string state = query["state"];
+                const OCRepresentation& representation = request->getResourceRepresentation();
 
-                if (OC_STACK_OK == sendRepresentation(request))
+                if (!m_handler->process(representation))
                 {
-                    res = OC_EH_OK;
+                    return res;
                 }
 
-                if (callback)
+                if (OC_STACK_OK == sendRepresentation(request))
                 {
-                    callback(state);
+                    res = OC_EH_OK;
                 }
             }
             else if(rt == "DELETE")
index 4fe4080..5dc779e 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * @brief  Resource used for device unowning
+ * @brief  Resource used for commands handling
  * @date   Created 10.07.2017
  * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
  *         between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
@@ -15,6 +15,7 @@
 #include <functional>
 #include "OCApi.h"
 #include "iot_resource.h"
+#include "icommandhandler.h"
 
 namespace NMD
 {
@@ -22,9 +23,11 @@ namespace NMD
 class ControlResource : public NetworkManager::IotResource
 {
 public:
-    typedef std::function<void(const std::string&)> ControlCallback;
-
-    ControlResource(ControlCallback&& cb);
+    /**
+     * @brief Constructor
+     * @param handler [in] pointer to command handler object
+     */
+    ControlResource(ICommandHandler* handler);
 
     ControlResource(const ControlResource& obj) = delete;
 
@@ -37,7 +40,7 @@ public:
     OCEntityHandlerResult entityHandler(std::shared_ptr<OC::OCResourceRequest> request) override;
 
 private:
-    ControlCallback callback;
+    ICommandHandler* m_handler;
 };
 
 } // namespace NMD
diff --git a/device_core/nmdaemon/icommandhandler.h b/device_core/nmdaemon/icommandhandler.h
new file mode 100644 (file)
index 0000000..666acaf
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * @brief  Command handler abstract class
+ * @date   Created 10.08.2017
+ * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
+ *         between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
+ *         and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea).
+ *         Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
+ * @author Mail to: <A HREF="mailto:d.lomtev@samsung.com">Dmytro Lomtev, d.lomtev@samsung.com</A>
+ */
+#ifndef ICOMMANDHANDLER_H
+#define ICOMMANDHANDLER_H
+
+#include <OCApi.h>
+
+class ICommandHandler
+{
+public:
+    /**
+     * @brief process command
+     * @param command [in] command encapsulated in OCRepresentation object must contain "command" field
+     *        end optional fields specific for each type of command
+     * @return true if success and false otherwise
+     */
+    virtual bool process(const OC::OCRepresentation& command) = 0;
+
+    virtual ~ICommandHandler() = default;
+};
+
+#endif // ICOMMANDHANDLER_H
index 3de4170..e4d3eee 100644 (file)
@@ -21,6 +21,7 @@
 #endif
 #include "registration_mq.h"
 #include "application_service.h"
+#include "commandhandler.h"
 
 using namespace NetworkManager;
 namespace PH = std::placeholders;
@@ -169,13 +170,9 @@ void MainThread::routine()
             policy_hub_resource->registerResource();
         }
 
-        ControlResource control([this, &hub, &proxy_thread, iotivity, &policy_handler, &report_handler, &notification_handler](const std::string& state)
-        {
-            if(state == "unown")
-            {
-                proxy_thread->addAction(std::async(std::launch::deferred, &MainThread::unregister_proc, this, iotivity, hub, report_handler, policy_handler, notification_handler, proxy_thread));
-            }
-        });
+
+        CommandHandler command_handler(iotivity, hub, report_handler, policy_handler, proxy_thread, g_working_mode, this);
+        ControlResource control(&command_handler);
 
         if(OC_STACK_OK != control.registerResource())
         {
index 7e6689b..40ba1bf 100644 (file)
@@ -18,9 +18,7 @@ bool NotificationHandlerMQ::init()
 {
     auto iotivity = NetworkManager::IoTivity::getInstance();
     auto handler = iotivity->getMqHandler();
-    std::string parentTopic = "/" + iotivity->getCloudAuthId();
-    handler->getTopic(parentTopic);
-    std::string topic = parentTopic + "/notification";
+    std::string topic = "/" + iotivity->getCloudAuthId() + "/notification";
     handler->subscribe(topic, std::bind(&NotificationHandler::observeCallback, this, PH::_1, PH::_2, PH::_3, PH::_4));
 
     LOG_D(TAG, "Suscribed to topic [%s]", topic.c_str());
index c40788b..100c394 100644 (file)
@@ -57,29 +57,9 @@ bool PolicyHandlerMQ::init()
 {
     auto iotivity = NetworkManager::IoTivity::getInstance();
     auto handler = iotivity->getMqHandler();
-    std::string parentTopic = "/" + iotivity->getCloudAuthId();
-    handler->getTopic(parentTopic);
-    std::string topic = parentTopic + "/policy";
+    std::string topic = "/" + iotivity->getCloudAuthId() + "/policy";
     handler->subscribe(topic, std::bind(&PolicyHandler::observeCallback, this, PH::_1, PH::_2, PH::_3, PH::_4));
 
     LOG_D(TAG, "Suscribed to topic [%s]", topic.c_str());
     return true;
 }
-
-/**
- * This method was added for demo presentation only.
- * For some reason the server does not see the newly created topics
- * and can not connect to them.
- * So for demo presentation an existing topic is used.
- */
-//bool PolicyHandlerMQ::init()
-//{
-//    auto iotivity = NetworkManager::IoTivity::getInstance();
-//    auto handler = iotivity->getMqHandler();
-//    std::string parentTopic = "/2a12a5a1-dad1-438d-8141-dbe1629ea93e";
-//    std::string topic = parentTopic + "/policy";
-//    handler->subscribeToExistingTopic(topic, std::bind(&PolicyHandler::observeCallback, this, PH::_1, PH::_2, PH::_3, PH::_4));
-
-//    LOG_D(TAG, "Suscribed to topic [%s]", topic.c_str());
-//    return true;
-//}
index f278623..dc78209 100644 (file)
@@ -230,7 +230,6 @@ static void mainLoop()
     reportResouce.registerResource();
     reportResouce.setNotificationResource(&notifResource);
 
-    iot->getMqHandler()->getTopic("/srv");
     iot->getMqHandler()->subscribe("/srv/report", &subscribeCB);
     cout << "Subscribed on topic \"/srv/report\"" << endl << flush;
     iot->getMqHandler()->subscribe("/srv/policy", &policyCB);
@@ -248,7 +247,6 @@ static void mainLoop()
     g_callbackLock.wait(lock);
 
     MqHandler mqHandler(host);
-    mqHandler.getTopic("/00000000-0000-0000-0000-000000000000");
 
     cout << "Server resources publish success" << endl << flush;
 
index 21d83ef..d6d146b 100644 (file)
@@ -23,6 +23,8 @@ FILE(GLOB SRCS *.cpp
        ../nmdaemon/hub_resource.cpp
        ../nmdaemon/registration_mq.cpp
        ../nmdaemon/thread_base.cpp
+       ../nmdaemon/commandhandler.cpp
+       ../nmdaemon/application_service.cpp
        )
 
 add_executable (${PROJECT_NAME} ${SRCS})
index a1fface..250543b 100644 (file)
@@ -3,10 +3,12 @@
 #include <string>
 #include "iotivity.h"
 #include "hub_resource.h"
+#include "control_resource.h"
 #include <thread>
 #include <chrono>
 #include <boost/archive/text_oarchive.hpp>
 #include <boost/archive/text_iarchive.hpp>
+#include <signal.h>
 
 using namespace NetworkManager;
 using namespace NMD;
@@ -43,6 +45,15 @@ const TestDeviceInfo test_devices[] = {
     }
 };
 
+class HandlerMock : public ICommandHandler
+{
+public:
+    bool process(const OC::OCRepresentation& rep) override
+    {
+        return true;
+    }
+};
+
 }
 
 int child_process_routine()
@@ -76,10 +87,17 @@ int child_process_routine()
         return -1;
     }
 
-    for (;;)
+    HandlerMock hm;
+
+    ControlResource res(&hm);
+
+    if (OC_STACK_OK != res.registerResource())
     {
-        std::this_thread::sleep_for(std::chrono::seconds(1));
+        std::cout << "register control resource failed" << std::endl;
+        return -1;
     }
 
+    std::this_thread::sleep_for(std::chrono::seconds(300));
+
     return 0;
 }
index 46f803f..cf90981 100644 (file)
@@ -31,6 +31,8 @@ using namespace OC;
 using namespace NetworkManager;
 
 extern std::string cloud_host;
+extern std::string TEST_ACCOUNT_LOGIN;
+extern std::string TEST_ACCOUNT_PASSWORD;
 
 class test_IoT_Fixture: public ::testing::Test
 {
@@ -109,8 +111,9 @@ TEST(test_IoT, signInIncorrectInput)
  * 1. Device id should be not empty
  * 2. No exceptions should be thrown
  */
-TEST_F(test_IoT_Fixture, getDeviceIdCorrect)
+TEST(test_IoT, getDeviceIdCorrect)
 {
+    IoTivity* iotivity = IoTivity::getInstance();
     string duid;
     ASSERT_NO_THROW(duid = iotivity->getDeviceID());
     ASSERT_NE("", duid);
@@ -124,101 +127,6 @@ TEST(test_IoT, test_IOT_ReportFormat)
     ASSERT_FALSE(NMD::makeReport("1", "sim", 0, "report data").empty());
 }
 
-/**
- * Test check report sender functional
- */
-TEST_F(test_IoT_Fixture, test_IOT_ReportSender)
-{
-    try
-    {
-//        shared_ptr<OCResource> report_res = IotResource::findResource( iotivity->host(),
-//        {OC_RSRVD_WELL_KNOWN_URI}, static_cast<OCConnectivityType>(CT_DEFAULT), 1, "core.security" );
-        shared_ptr<OCResource> report_res = iotivity->findResource(true, "core.security");
-        if(!report_res)
-            throw runtime_error("Failed to find report resource");
-
-        OCRepresentation rep;
-        rep.setValue("report", NMD::makeReport(iotivity->getDeviceID(), "report_name", 0, "{\"text\":\"report data\"}"));
-
-        if(IotResource::post(report_res, {"core.security"}, {DEFAULT_INTERFACE}, rep, QueryParamsMap()) != OC_STACK_OK)
-            throw runtime_error("Failed to post report");
-
-    }
-    catch (NMexception& e)
-    {
-        ADD_FAILURE() << e.what() << " " << e.errorCode();
-    }
-    catch (std::exception& e)
-    {
-        ADD_FAILURE() << e.what();
-    }
-}
-
-/**
- * Test check policy sender functional
- */
-TEST_F(test_IoT_Fixture, test_IOT_PolicySender)
-{
-    bool res = false;
-
-    try
-    {
-//        auto policy_res = IotResource::findResource(iotivity->host(), {OC_RSRVD_WELL_KNOWN_URI}, CT_DEFAULT, 1, "core.policy");
-        auto policy_res = iotivity->findResource(true, "core.policy");
-        ASSERT_TRUE(bool(policy_res)) << "Failed to find policy resource";
-
-        string device_id = iotivity->getDeviceID();
-        string agent_id = "3574462a-7efa-9449-4d9f-488734c79c0a";
-        string json_data = "[{\"group\": \"tv-extension\", \"policies\": [{\"name\": \"usb\", \"state\": 0, \"items\": []}, {\"name\": \"screen-capture\", \"state\": 1, \"items\": []}]}]";
-
-        static mutex mtx;
-        static mutex mtx1;
-        unique_lock<mutex> lck(mtx);
-        condition_variable cvar;
-        auto on_observe = [&](const HeaderOptions& /*_head_options*/, const OCRepresentation & _rep, const int& _ecode,
-                              const int& _seq_number)
-        {
-            unique_lock<mutex> lambda_lock(mtx1);
-            if (res) return;
-
-            // Transform representation to string
-            std::ostringstream oss;
-            for(auto it = _rep.begin(); it != _rep.end(); ++it)
-                oss << it->getValueToString();
-            oss.str();
-
-            if(oss.str().find(json_data) != string::npos)
-            {
-                res = true;
-                cvar.notify_all();
-            }
-        };
-
-        auto observ_result = policy_res->observe(ObserveType::Observe, QueryParamsMap{{"did", device_id}}, on_observe);
-
-        ASSERT_EQ(OC_STACK_OK, observ_result) << "Failed to observe policy resource";
-
-        OCRepresentation rep;
-        rep.setValue("policy", json_data);
-        auto post_result = IotResource::post(policy_res, {"core.policy"}, {DEFAULT_INTERFACE}, rep, QueryParamsMap({{"did", device_id}, {"agent", agent_id}}));
-        ASSERT_EQ(OC_STACK_OK, post_result) << "Failed to post policy";
-
-        cvar.wait_for(lck, chrono::seconds(3));
-
-//        IOT_Resource::cancelObserve(policy_res);
-    }
-    catch (NMexception& e)
-    {
-        ADD_FAILURE() << e.what() << " " << e.errorCode();
-    }
-    catch (std::exception& e)
-    {
-        ADD_FAILURE() << e.what();
-    }
-
-    ASSERT_TRUE(res);
-}
-
 TEST_F(test_IoT_Fixture, findResourceWork)
 {
     ASSERT_NO_THROW(iotivity->findResource(false, "", OC_RSRVD_WELL_KNOWN_URI, CT_DEFAULT));
index 55e82cb..fa8f7be 100644 (file)
@@ -1,9 +1,15 @@
 #include <iostream>
 #include <string>
 #include <gtest/gtest.h>
+#include <gmock/gmock.h>
 #include <unistd.h>
+#include <thread>
+#include <chrono>
+#include "iotivity.h"
 
 std::string cloud_host{"coap+tcp://106.125.46.44:5683"};
+std::string TEST_ACCOUNT_LOGIN{"admin@samsung.com"};
+std::string TEST_ACCOUNT_PASSWORD{"111111"};
 
 /**
  * @brief Child process routing for resource initialization used in functional tests
@@ -11,8 +17,26 @@ std::string cloud_host{"coap+tcp://106.125.46.44:5683"};
  */
 int child_process_routine();
 
+void signal_handler(int signal)
+{
+    if (signal == SIGUSR1)
+    {
+        NetworkManager::IoTivity::cleanUp();
+        exit(0);
+    }
+}
+
 int main(int argc, char** argv)
 {
+    auto sig_result = signal(SIGUSR1, signal_handler);
+    if (SIG_ERR == sig_result)
+    {
+        std::cout << "Failed to setup TERM signal handler" << std::endl;
+        return -1;
+    }
+
+    NetworkManager::IoTivity::setPersistentStoragePath("/tmp/temporary_persitent_storage.dat");
+
     pid_t pid = fork();
 
     if (pid < 0)
@@ -28,6 +52,8 @@ int main(int argc, char** argv)
 
     int result = -1;
 
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
     try
     {
         if (argc > 1 && argv[1][0] != '-')
@@ -35,6 +61,7 @@ int main(int argc, char** argv)
             cloud_host = std::string{"coap+tcp://"} + argv[1] + std::string{":5683"};
         }
         ::testing::InitGoogleTest(&argc, argv);
+//        ::testing::InitGoogleMock(&argc, argv);
         result = RUN_ALL_TESTS();
     }
     catch (std::exception& e)
@@ -46,9 +73,6 @@ int main(int argc, char** argv)
         std::cout << "Unknown exception" << std::endl;
     }
 
-    std::string cmd{"kill -9 "};
-    cmd.append(std::to_string(int(pid)));
-    system(cmd.c_str());
-
+    kill(pid, SIGUSR1);
     return result;
 }
diff --git a/device_core/utest/test_commandhandler.cpp b/device_core/utest/test_commandhandler.cpp
new file mode 100644 (file)
index 0000000..f95260a
--- /dev/null
@@ -0,0 +1,255 @@
+#include <iostream>
+#include <fstream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <stdexcept>
+#include "nmlib.h"
+#include "commandhandler.h"
+#include "device_commands.h"
+#include "securitycontext.h"
+#include "ctrl_app_support.h"
+
+using namespace NetworkManager;
+using namespace NMD;
+using ::testing::Return;
+using ::testing::StrEq;
+
+extern std::string cloud_host;
+extern std::string TEST_ACCOUNT_LOGIN;
+extern std::string TEST_ACCOUNT_PASSWORD;
+
+class ReportHandlerMock: public ReportHandler
+{
+public:
+    void pass(const OC::OCRepresentation& rep, const OC::QueryParamsMap& params) override
+    {
+
+    }
+};
+
+class PolicyHandlerMock : public PolicyHandler
+{
+public:
+    virtual void pass(const OC::OCRepresentation& rep, const OC::QueryParamsMap& params)
+    {
+
+    }
+
+    virtual bool init()
+    {
+
+    }
+};
+
+class test_commandhandler_fixture : public ::testing::Test
+{
+public:
+    static void SetUpTestCase()
+    {
+        ASSERT_EQ(EC_OK, NM_init(&ctx));
+        ASSERT_EQ(EC_OK, NM_signIn(ctx, TEST_ACCOUNT_LOGIN.c_str(), TEST_ACCOUNT_PASSWORD.c_str()));
+    }
+
+    static void TearDownTestCase()
+    {
+        ASSERT_NO_THROW(NM_signOut(ctx));
+        ASSERT_NO_THROW(NM_cleanup(&ctx));
+    }
+
+    static NM_hContext ctx;
+};
+
+NM_hContext test_commandhandler_fixture::ctx = nullptr;
+
+class MainThreadMock : public ThreadBase
+{
+public:
+    MOCK_METHOD0(stop, void ());
+};
+
+/**
+ * Test CommandHandler class UNOWN command for standard working mode
+ */
+TEST_F(test_commandhandler_fixture, test_unOwnTask_standard)
+{
+    MainThreadMock main_thread;
+
+    EXPECT_CALL(main_thread, stop())
+            .Times(1);
+
+    try
+    {
+        IoTivity* iot = ctx->instance;
+        EXPECT_TRUE(iot->isSignedIn());
+        std::shared_ptr<ProxyThread> proxy = std::make_shared<ProxyThread>();
+        std::shared_ptr<HubResource> hub  = nullptr;
+        std::shared_ptr<ReportHandler> rh = std::make_shared<ReportHandlerMock>();
+        std::shared_ptr<PolicyHandler> ph = std::make_shared<PolicyHandlerMock>();
+
+        proxy->start();
+
+        CommandHandler handler(iot, hub, rh, ph, proxy, WorkingMode::Standard, &main_thread);
+
+        OC::OCRepresentation rep;
+        rep.setValue("command", int(DeviceCommands::UNOWN));
+        handler.process(rep);
+        proxy->stop();
+        proxy->join();
+    }
+    catch (std::exception& e)
+    {
+        FAIL() << "Exception: " << e.what();
+    }
+}
+
+/**
+ * Test CommandHandler class UNOWN command for primitive working mode
+ */
+TEST_F(test_commandhandler_fixture, test_unOwnTask_primitive)
+{
+    MainThreadMock main_thread;
+
+    EXPECT_CALL(main_thread, stop())
+            .Times(1);
+
+    try
+    {
+        IoTivity* iot = ctx->instance;
+        EXPECT_TRUE(iot->isSignedIn());
+        std::shared_ptr<ProxyThread> proxy = std::make_shared<ProxyThread>();
+        std::shared_ptr<HubResource> hub  = nullptr;
+        std::shared_ptr<ReportHandler> rh = std::make_shared<ReportHandlerMock>();
+        std::shared_ptr<PolicyHandler> ph = std::make_shared<PolicyHandlerMock>();
+
+        proxy->start();
+        CommandHandler handler(iot, hub, rh, ph, proxy, WorkingMode::Primitive, &main_thread);
+
+        OC::OCRepresentation rep;
+        rep.setValue("command", int(DeviceCommands::UNOWN));
+        handler.process(rep);
+        proxy->stop();
+        proxy->join();
+    }
+    catch (std::exception& e)
+    {
+        FAIL() << "Exception: " << e.what();
+    }
+}
+
+/**
+ * Test CommandHandler class UNOWN command for hub working mode
+ */
+TEST_F(test_commandhandler_fixture, test_unOwnTask_hub)
+{
+    MainThreadMock main_thread;
+
+    EXPECT_CALL(main_thread, stop())
+            .Times(1);
+
+    try
+    {
+        IoTivity* iot = ctx->instance;
+        EXPECT_TRUE(iot->isSignedIn());
+        std::shared_ptr<ProxyThread> proxy = std::make_shared<ProxyThread>();
+        std::shared_ptr<HubResource> hub  = std::make_shared<HubResource>(iot, proxy, std::string{""});
+        std::shared_ptr<ReportHandler> rh = std::make_shared<ReportHandlerMock>();
+        std::shared_ptr<PolicyHandler> ph = std::make_shared<PolicyHandlerMock>();
+
+        proxy->start();
+        hub->registerResource();
+
+        CommandHandler handler(iot, hub, rh, ph, proxy, WorkingMode::Hub, &main_thread);
+
+        OC::OCRepresentation rep;
+        rep.setValue("command", int(DeviceCommands::UNOWN));
+        handler.process(rep);
+        proxy->stop();
+        proxy->join();
+    }
+    catch (std::exception& e)
+    {
+        FAIL() << "Exception: " << e.what();
+    }
+}
+
+namespace
+{
+const std::string test_executable{"smack_test"};
+const std::string test_rpm_query_stub_path{"/tmp/test_rpm_query_stub.txt"};
+const std::string test_executable_package_name = test_executable + ".1.2.3.4.rpm";
+}
+
+class ISystemMock
+{
+public:
+    virtual int system(const char*) = 0;
+    virtual void popen(const char*, const char*) = 0;
+    virtual ~ISystemMock() {};
+};
+
+class SystemMock : public ISystemMock
+{
+public:
+    MOCK_METHOD1(system, int (const char* cmd));
+    MOCK_METHOD2(popen, void (const char* file, const char* mode));
+    ~SystemMock() {};
+};
+
+SystemMock systemMock;
+
+int system(const char* cmd)
+{
+    return systemMock.system(cmd);
+}
+
+FILE* popen(const char *command, const char *type)
+{
+    systemMock.popen(command, type);
+    return fopen(test_rpm_query_stub_path.c_str(), "r");
+}
+
+
+TEST(test_commandhandler, test_uninstallTask)
+{
+    std::string system_cmd = "rpm -e " + test_executable_package_name + " > /dev/null";
+    std::string popen_cmd = "rpm -qa | grep " + test_executable;
+
+    EXPECT_CALL(systemMock, popen(StrEq(popen_cmd.c_str()), StrEq("r")))
+            .Times(1);
+    EXPECT_CALL(systemMock, system(StrEq(system_cmd.c_str())))
+            .Times(1)
+            .WillOnce(Return(0));
+
+
+    std::ofstream f{test_rpm_query_stub_path};
+    f << "package.1" << std::endl
+      << test_executable_package_name << std::endl
+      << "package.2" << std::endl;
+    f.close();
+
+    try
+    {
+        IoTivity* iot = IoTivity::getInstance();
+        std::shared_ptr<ProxyThread> proxy = std::make_shared<ProxyThread>();
+        std::shared_ptr<HubResource> hub  = std::make_shared<HubResource>(iot, proxy, std::string{""});
+        std::shared_ptr<ReportHandler> rh = std::make_shared<ReportHandlerMock>();
+        std::shared_ptr<PolicyHandler> ph = std::make_shared<PolicyHandlerMock>();
+        ThreadBase mt;
+        hub->registerResource();
+
+        CommandHandler handler(iot, hub, rh, ph, proxy, WorkingMode::Standard, &mt);
+
+        OC::OCRepresentation rep;
+        rep.setValue("command", int(DeviceCommands::UNINSTALL));
+        rep.setValue("pid", std::string{"1234"});
+        rep.setValue("name", test_executable);
+        handler.process(rep);
+    }
+    catch (std::exception& e)
+    {
+        FAIL() << "Exception: " << e.what();
+    }
+
+    EXPECT_EQ(0, remove(test_rpm_query_stub_path.c_str()));
+}
+
index 389fdc9..1475f49 100644 (file)
 #include <mutex>
 #include <condition_variable>
 #include <chrono>
+#include "device_commands.h"
 
 using namespace NMD;
 using namespace OC;
 using namespace NetworkManager;
 
+class HandlerMock : public ICommandHandler
+{
+public:
+    bool process(const OCRepresentation& rep) override
+    {
+        return true;
+    }
+};
+
 /**
  * @brief TEST for ControlResource used in device unowning usecase
  * 1. IoTivity initialization
@@ -35,13 +45,6 @@ TEST(test_ControlResource, test_all)
     {
         IoTivity* iot = IoTivity::getInstance();
         bool cb_called = false;
-        ControlResource res([&](const std::string& state)
-        {
-            cb_called = true;
-            ASSERT_EQ("unown", state);
-        });
-
-        res.registerResource();
 
         std::shared_ptr<OCResource> control;
         std::mutex mtx;
@@ -75,7 +78,8 @@ TEST(test_ControlResource, test_all)
 
 
         OCRepresentation rep;
-        QueryParamsMap params{{"state", "unown"}};
+        rep.setValue("command", int(DeviceCommands::UNOWN));
+        QueryParamsMap params;
         flag = false;
 
         control->post(rep, params,
@@ -88,10 +92,6 @@ TEST(test_ControlResource, test_all)
         cv.wait_for(lock, std::chrono::seconds(1), [&flag]{ return flag; });
 
         ASSERT_TRUE(flag);
-
-        ASSERT_NO_THROW(res.setRepresentation(rep));
-
-        ASSERT_TRUE(cb_called);
     }
     catch (std::exception& e)
     {
index 612cbd7..a56ed27 100644 (file)
@@ -21,8 +21,8 @@
 using namespace NetworkManager;
 
 extern std::string cloud_host;
-const std::string TEST_ACCOUNT_LOGIN{"admin@samsung.com"};
-const std::string TEST_ACCOUNT_PASSWORD{"111111"};
+extern std::string TEST_ACCOUNT_LOGIN;
+extern std::string TEST_ACCOUNT_PASSWORD;
 
 class IoTDevManagerTest: public ::testing::Test
 {
@@ -585,7 +585,7 @@ TEST_F(IoTDevManagerTestWithReg, reportTest)
  * 2. Get policy and compare with posted
  * 3. Free memory
  */
-TEST_F(IoTDevManagerWithOwned, policyTest)
+TEST_F(IoTDevManagerWithOwned, DISABLED_policyTest)
 {
     std::string policy = R"-([
     {
index 676ee46..3a681dc 100644 (file)
@@ -37,6 +37,7 @@ public:
         std::string host(cloud_host);
 
         ASSERT_NO_THROW(iot->signUp(host, auth_provider, password));
+        ASSERT_TRUE(iot->isSignedIn());
     }
 
     void TearDown() override
@@ -90,7 +91,6 @@ static void notificationCb(NM_NotificationData data, void* inUserData)
  * 2. Check callback was called
  * 3. Check user data was transferd
  */
-#ifndef __BUILD_PRIMITIVE__
 TEST_F(TestIotNotification, correct)
 {
     std::mutex notificationMtx;
@@ -119,7 +119,6 @@ TEST_F(TestIotNotification, correct)
     ASSERT_TRUE(userDataCheck.firstCallbackFired);
     ASSERT_TRUE(userDataCheck.lastCallbackFired);
 }
-#endif /* __BUILD_PRIMITIVE__ */
 
 static void notification2Cb(NM_NotificationData data, void* inUserData)
 {
diff --git a/device_core/utest/test_iotdevice_impl.cpp b/device_core/utest/test_iotdevice_impl.cpp
new file mode 100644 (file)
index 0000000..c01f553
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * @brief  Tests for IoTDevice_impl
+ * @date   Created 8.08.2017
+ * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
+ *         between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
+ *         and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea).
+ *         Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
+ * @author Mail to: <A HREF="mailto:d.lomtev@samsung.com">Dmytro Lomtev, d.lomtev@samsung.com</A>
+ */
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <OCApi.h>
+#include <OCPlatform.h>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
+#include "iotivity.h"
+#include "control_resource.h"
+#include "iotdevice_impl.h"
+
+using namespace OC;
+using namespace NetworkManager;
+
+
+class ResourceMock : public OC::OCResource
+{
+public:
+    MOCK_CONST_METHOD0(host, std::string ());
+};
+
+/**
+ * @brief TEST for ControlResource used in device unowning usecase
+ * 1. IoTivity initialization
+ * 2. Create and register ControlResource
+ * 3. ControlResource discovery
+ * 4. Post "unown" request
+ * 4. Check ControlResource entityHandler called and posted state is "unown"
+ */
+TEST(test_IoTDevice_Impl, test_all)
+{
+    try
+    {
+        IoTivity* iot = IoTivity::getInstance();
+        ASSERT_NE(nullptr, iot);
+        const std::string uuid = "1234567890";
+        const std::string name = "Test device";
+        const std::string type = "iotdevice";
+        const std::string model = "test model";
+        IoTDevice_impl dev(uuid, name, type, model);
+        EXPECT_EQ(uuid, dev.getUUID());
+        EXPECT_EQ(name, dev.getName());
+        EXPECT_EQ(type, dev.getType());
+        EXPECT_EQ(model, dev.getModel());
+        EXPECT_EQ(uuid, dev.getRouting());
+        EXPECT_FALSE(dev.isCloudAccessibility());
+        EXPECT_FALSE(dev.isOnline());
+        EXPECT_FALSE(dev.isActive());
+
+        OCResource::Ptr ctrl_resource = iot->findResource("", "device.control");
+
+        if(!ctrl_resource)
+        {
+            throw std::runtime_error("Test control resource not found");
+        }
+
+        OCConnectivityType connectivityType = CT_DEFAULT;
+        std::string host = ctrl_resource->host();
+        std::string uri = "/resource";
+        std::vector<std::string> types = {"intel.rpost"};
+        std::vector<std::string> ifaces = {DEFAULT_INTERFACE};
+
+        ASSERT_FALSE(host.empty());
+
+        auto res = OCPlatform::constructResourceObject(host, uri, connectivityType, false, types, ifaces);
+
+        ASSERT_FALSE(!res) << "Resource not constructed";
+
+        dev.activate(res);
+        EXPECT_EQ(host, dev.getHost());
+        EXPECT_TRUE(dev.isActive());
+        EXPECT_TRUE(dev.isOnline());
+
+        EXPECT_NO_THROW(dev.unOwnDevice());
+
+        EXPECT_ANY_THROW(dev.deleteApp(""));
+        EXPECT_NO_THROW(dev.deleteApp("app1"));
+
+        dev.deactivate();
+        EXPECT_FALSE(dev.isOnline());
+        EXPECT_FALSE(dev.isActive());
+    }
+    catch (std::exception& e)
+    {
+        FAIL() << "Exception: " << e.what();
+    }
+}
index e9f0ba5..a56d021 100644 (file)
@@ -40,7 +40,7 @@ TEST(JsonUtilsTest, ToDeviceTest)
     EXPECT_EQ("s8", device->getName());
     EXPECT_EQ("phone", device->getType());
     EXPECT_EQ("samsung s8 edge", device->getModel());
-    EXPECT_EQ(true, device->isOnline());
+    EXPECT_FALSE(device->isOnline()); // IoTDevice's created from the JSON are offline despite "status" flag
 }
 
 TEST(JsonUtilsTest, ToDeviceListTestBadCase)
index 1b80610..52429e0 100644 (file)
@@ -40,6 +40,7 @@ public:
         try
         {
             iot->signUp(host, auth_provider, password);
+            ASSERT_TRUE(iot->isSignedIn());
         }
         catch(std::exception& e)
         {
@@ -101,36 +102,42 @@ static void subscribeCB(const HeaderOptions &,
  */
 TEST_F(TestIotMQ, publishCorrect)
 {
-    std::string stringToPublish("test");
-    std::string stringToPublish2("test2");
-    OCRepresentation rep;
-    rep["message"] = stringToPublish;
+    try
+    {
+        std::string stringToPublish("test");
+        std::string stringToPublish2("test2");
+        OCRepresentation rep;
+        rep["message"] = stringToPublish;
+
+        std::mutex notificationMtx;
+        std::unique_lock<std::mutex> notificationLock(notificationMtx);
 
-    std::mutex notificationMtx;
-    std::unique_lock<std::mutex> notificationLock(notificationMtx);
 
+        auto mqHandler = iot->getMqHandler();
 
-    MqHandler subMqHandler(cloud_host);
-    subMqHandler.getTopic("/srv");
-    subMqHandler.subscribe("/srv/test2", &subscribeCB);
+        mqHandler->subscribe("/topic1/test2", &subscribeCB);
 
-    MqHandler pubMqHandler(cloud_host);
-    pubMqHandler.publish("/srv/test2", rep);
+        mqHandler->publish("/topic1/test2", rep);
 
-    notificationCV.wait_for(
-        notificationLock,
-        std::chrono::seconds(3)
-    );
+        notificationCV.wait_for(
+            notificationLock,
+            std::chrono::seconds(3)
+        );
 
-    subMqHandler.unsubscribe("/srv/test2");
+        mqHandler->unsubscribe("/topic1/test2");
 
-    rep["message"] = stringToPublish2;
-    pubMqHandler.publish("/srv/test2", rep);
+        rep["message"] = stringToPublish2;
+        mqHandler->publish("/topic1/test2", rep);
 
-    ASSERT_TRUE(firstCallbackFired);
-    ASSERT_TRUE(lastCallbackFired);
-    ASSERT_TRUE(normalCallbackFired);
-    ASSERT_EQ(stringToPublish, reveicedString);
+        ASSERT_TRUE(firstCallbackFired);
+        ASSERT_TRUE(lastCallbackFired);
+        ASSERT_TRUE(normalCallbackFired);
+        ASSERT_EQ(stringToPublish, reveicedString);
+    }
+    catch (std::exception& e)
+    {
+        FAIL() << "Exception: " << e.what() << std::endl;
+    }
 }
 
 /**
diff --git a/device_core/utest/test_mq_topic.cpp b/device_core/utest/test_mq_topic.cpp
new file mode 100644 (file)
index 0000000..07ff7df
--- /dev/null
@@ -0,0 +1,72 @@
+#include <gtest/gtest.h>
+#include "mq_topic.h"
+
+using namespace NetworkManager;
+
+
+TEST(test_MqTopic, test_constructor_string)
+{
+    const std::string name{"/parent/topic_mid/topic_top"};
+
+    MqTopic topic(name);
+    ASSERT_EQ(MqTopic::DEFAULT_MQ_BROKER_URI_ROOT + name, topic.getName());
+}
+
+TEST(test_MqTopic, test_constructor_iterator)
+{
+    const std::string t1 = "/parent";
+    const std::string t2 = "/mid";
+    const std::string t3 = "/high";
+    const std::string t4 = "/top";
+    MqTopic::Parts parts{t1, t2, t3, t4};
+
+    auto start = parts.begin();
+    auto next = parts.begin();
+
+    ++next;
+    MqTopic topic1(start, next);
+    ASSERT_EQ(MqTopic::DEFAULT_MQ_BROKER_URI_ROOT + t1, topic1.getName());
+    ASSERT_EQ(t1, topic1.getSubName());
+
+    ++next;
+    MqTopic topic2(start, next);
+    ASSERT_EQ(MqTopic::DEFAULT_MQ_BROKER_URI_ROOT + t1 + t2, topic2.getName());
+    ASSERT_EQ(t1 + t2, topic2.getSubName());
+
+    ++next;
+    MqTopic topic3(start, next);
+    ASSERT_EQ(MqTopic::DEFAULT_MQ_BROKER_URI_ROOT + t1 + t2 + t3, topic3.getName());
+    ASSERT_EQ(t1 + t2 + t3, topic3.getSubName());
+
+    ++next;
+    MqTopic topic4(start, next);
+    ASSERT_EQ(MqTopic::DEFAULT_MQ_BROKER_URI_ROOT + t1 + t2 + t3 + t4, topic4.getName());
+    ASSERT_NE(MqTopic::DEFAULT_MQ_BROKER_URI_ROOT + t1 + t2 + t3 + t4, topic4.getSubName());
+    ASSERT_EQ(t1 + t2 + t3 + t4, topic4.getSubName());
+}
+
+TEST(test_MqTopic, test_split)
+{
+    const std::string t1 = "/parent";
+    const std::string t2 = "/mid";
+    const std::string t3 = "/high";
+    const std::string t4 = "/top";
+    MqTopic::Parts parts{t1, t2, t3, t4};
+
+    const std::string ready = t1 + t2 + t3 + t4;
+    MqTopic topic(ready);
+    auto splitted = topic.split();
+
+    auto splitted_it = splitted.cbegin();
+    auto parts_it = parts.cbegin();
+    ASSERT_EQ(MqTopic::DEFAULT_MQ_BROKER_URI_ROOT, *splitted_it);
+    ++splitted_it;
+
+    for (;parts_it != parts.cend(); ++parts_it, ++splitted_it)
+    {
+        ASSERT_NE(splitted_it, splitted.cend());
+        EXPECT_EQ(*parts_it, *splitted_it);
+    }
+
+    EXPECT_EQ(splitted.cend(), splitted_it);
+}
index 7f55e89..984b0f0 100644 (file)
@@ -101,32 +101,6 @@ const TestDeviceRegInfo test_device =
 
 const std::string microsoft_agent_id{"3574462a-7efa-9449-4d9f-488734c79c0a"};
 
-std::string policy = R"-([
-{
-    "group": "tv-extension",
-    "policies":
-    [
-        {
-            "name": "bluetooth",
-            "state": 1,
-            "items":
-            [
-            ]
-        },
-        {
-            "name": "iptables",
-            "state": -1,
-            "items":
-            [
-                "127.0.0.0/24|UDP|10-1024",
-                "1.1.1.1|TCP|80,443",
-                "4.4.4.4"
-            ]
-        }
-    ]
-}
-])-";
-
 }
 
 /**
@@ -176,30 +150,21 @@ TEST(test_REST, test_policyUseCase)
             iotivity->getMqHandler()->publish("/srv/reg", rep);
         }
 
-        OC::OCRepresentation rep;
-        rep.setValue("duid", test_device.duid);
-        rep.setValue("agent_id", microsoft_agent_id);
-        rep.setValue("policy", policy);
-
-        iotivity->getMqHandler()->publish("/srv/policy", rep);
-
         std::this_thread::sleep_for(std::chrono::seconds(5));
 
-        std::string received_policy = service.getPolicy(test_device.duid);
-        received_policy.erase(std::remove_if(received_policy.begin(), received_policy.end(), [](const char& c){
-            return std::isspace(c);
-        }), received_policy.end());
-
-        policy.erase(std::remove_if(policy.begin(), policy.end(), [](const char& c){
-            return std::isspace(c);
-        }), policy.end());
-
-        std::cout << std::endl << std::endl << policy << std::endl << std::endl << received_policy << std::endl;
-        ASSERT_FALSE(received_policy.empty()) << "Empty policyc received";
-        ASSERT_NE(std::string::npos, received_policy.find(policy)) << "Sent and received policy differ";
+        try
+        {
+            std::string received_policy = service.getPolicy(test_device.duid);
+            std::cout << received_policy << std::endl;
+            EXPECT_FALSE(received_policy.empty()) << "Empty policy received";
+        }
+        catch(std::exception& e)
+        {
+            EXPECT_FALSE(true) << "Exception: " << e.what();
+        }
 
-        rep.erase("policy");
-        rep.erase("agent_id");
+        OC::OCRepresentation rep;
+        rep.setValue("duid", test_device.duid);
         iotivity->getMqHandler()->publish("/srv/unreg", rep);
     }
     catch(std::exception& e)