Client library functions 48/26048/4
authorMateusz Malicki <m.malicki2@samsung.com>
Thu, 14 Aug 2014 16:03:51 +0000 (18:03 +0200)
committerPiotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
Wed, 20 Aug 2014 09:16:41 +0000 (11:16 +0200)
    [Feature]      Add more functions to the client library.
    [Cause]        N/A
    [Solution]     N/A
    [Verification] Build, install, run test suite Client

Change-Id: Ided49f0363c5bb94669c272fda745510cd21d985

client/security-containers-client-impl.cpp
client/security-containers-client-impl.hpp
client/security-containers-client.cpp
client/security-containers-client.h
tests/unit_tests/client/configs/ut-client/containers/console1-dbus.conf
tests/unit_tests/client/configs/ut-client/containers/console2-dbus.conf
tests/unit_tests/client/configs/ut-client/containers/console3-dbus.conf
tests/unit_tests/client/configs/ut-client/libvirt-config/network1-filter.xml [new file with mode: 0644]
tests/unit_tests/client/configs/ut-client/libvirt-config/network2-filter.xml [new file with mode: 0644]
tests/unit_tests/client/configs/ut-client/libvirt-config/network3-filter.xml [new file with mode: 0644]
tests/unit_tests/client/ut-client.cpp

index 87c30f8..17315b0 100644 (file)
@@ -29,6 +29,7 @@
 #include <dbus/exception.hpp>
 #include <utils/glib-loop.hpp>
 #include <host-dbus-definitions.hpp>
+#include <container-dbus-definitions.hpp>
 
 #include <memory>
 #include <cstring>
@@ -47,6 +48,11 @@ const string SCCLIENT_EXCEPTION_MSG = "unspecified exception";
 const DbusInterfaceInfo hostDbusInterfaceInfo(api::host::BUS_NAME,
                                               api::host::OBJECT_PATH,
                                               api::host::INTERFACE);
+const DbusInterfaceInfo domainDbusInterfaceInfo(api::container::BUS_NAME,
+                                                api::container::OBJECT_PATH,
+                                                api::container::INTERFACE);
+
+template<typename T> struct fake_dependency: public std::false_type {};
 
 unique_ptr<ScopedGlibLoop> loop;
 
@@ -75,6 +81,45 @@ void toDict(GVariant* in, ScArrayString* keys, ScArrayString* values)
     *values = outv;
 }
 
+template<typename T>
+void toBasic(GVariant* in, T str)
+{
+    static_assert(fake_dependency<T>::value, "Must use specialization");
+    assert(!"Must use specialization");
+}
+
+template<>
+void toBasic(GVariant* in, char** str)
+{
+    assert(in);
+    assert(str);
+
+    gsize length;
+    const gchar* src = g_variant_get_string(in, &length);
+    char* buf = strndup(src, length);
+    *str = buf;
+}
+
+template<typename T>
+void toArray(GVariant* in, T** scArray)
+{
+    assert(in);
+    assert(scArray);
+
+    gsize size = g_variant_n_children(in);
+    T* ids = (T*)calloc(size + 1, sizeof(T));
+
+    GVariantIter iter;
+    GVariant* child;
+
+    g_variant_iter_init(&iter, in);
+    for (int i = 0; (child = g_variant_iter_next_value(&iter)); i++) {
+        toBasic(child, &ids[i]);
+        g_variant_unref(child);
+    }
+    *scArray = ids;
+}
+
 ScStatus toStatus(const std::exception& ex)
 {
     if (typeid(DbusCustomException) == typeid(ex)) {
@@ -203,6 +248,33 @@ ScStatus Client::callMethod(const DbusInterfaceInfo& info,
     return sc_get_status();
 }
 
+ScStatus Client::signalSubscribe(const DbusInterfaceInfo& info,
+                                 const string& name,
+                                 SignalCallback signalCallback)
+{
+    auto onSignal = [=](const std::string& /*senderBusName*/,
+                        const std::string & objectPath,
+                        const std::string & interface,
+                        const std::string & signalName,
+                        GVariant * parameters) {
+        if (objectPath == info.objectPath &&
+                interface == info.interface &&
+                signalName == name) {
+
+            signalCallback(parameters);
+        }
+    };
+    try {
+        mConnection->signalSubscribe(onSignal, info.busName);
+        mStatus = Status(SCCLIENT_SUCCESS);
+    } catch (const std::exception& ex) {
+        mStatus = Status(toStatus(ex), ex.what());
+    } catch (...) {
+        mStatus = Status(SCCLIENT_EXCEPTION);
+    }
+    return sc_get_status();
+}
+
 const char* Client::sc_get_status_message() noexcept
 {
     return mStatus.mMsg.c_str();
@@ -234,3 +306,96 @@ ScStatus Client::sc_get_container_dbuses(ScArrayString* keys, ScArrayString* val
     g_variant_unref(out);
     return ret;
 }
+
+ScStatus Client::sc_get_container_ids(ScArrayString* array) noexcept
+{
+    assert(array);
+
+    GVariant* out;
+    ScStatus ret = callMethod(hostDbusInterfaceInfo,
+                              api::host::METHOD_GET_CONTAINER_ID_LIST,
+                                          NULL,
+                                          "(as)",
+                                          &out);
+    if (ret != SCCLIENT_SUCCESS) {
+        return ret;
+    }
+    GVariant* unpacked;
+    g_variant_get(out, "(*)", &unpacked);
+    toArray(unpacked, array);
+    g_variant_unref(unpacked);
+    g_variant_unref(out);
+    return ret;
+}
+
+ScStatus Client::sc_get_active_container_id(ScString* id) noexcept
+{
+    assert(id);
+
+    GVariant* out;
+    ScStatus ret = callMethod(hostDbusInterfaceInfo,
+                              api::host::METHOD_GET_ACTIVE_CONTAINER_ID,
+                              NULL,
+                              "(s)",
+                              &out);
+    if (ret != SCCLIENT_SUCCESS) {
+        return ret;
+    }
+    GVariant* unpacked;
+    g_variant_get(out, "(*)", &unpacked);
+    toBasic(unpacked, id);
+    g_variant_unref(unpacked);
+    g_variant_unref(out);
+    return ret;
+}
+
+ScStatus Client::sc_set_active_container(const char* id) noexcept
+{
+    assert(id);
+
+    GVariant* args_in = g_variant_new("(s)", id);
+    return callMethod(hostDbusInterfaceInfo, api::host::METHOD_SET_ACTIVE_CONTAINER, args_in);
+}
+
+ScStatus Client::sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback)
+    noexcept
+{
+    assert(containerDbusStateCallback);
+
+    auto onSigal = [ = ](GVariant * parameters) {
+        const char* container;
+        const char* dbusAddress;
+        g_variant_get(parameters, "(&s&s)", &container, &dbusAddress);
+        containerDbusStateCallback(container, dbusAddress);
+    };
+
+    return signalSubscribe(hostDbusInterfaceInfo,
+                           api::host::SIGNAL_CONTAINER_DBUS_STATE,
+                           onSigal);
+}
+
+ScStatus Client::sc_notify_active_container(const char* application, const char* message) noexcept
+{
+    assert(application);
+    assert(message);
+
+    GVariant* args_in = g_variant_new("(ss)", application, message);
+    return callMethod(domainDbusInterfaceInfo,
+                      api::container::METHOD_NOTIFY_ACTIVE_CONTAINER,
+                      args_in);
+}
+
+ScStatus Client::sc_notification(ScNotificationCallback notificationCallback) noexcept
+{
+    assert(notificationCallback);
+
+    auto onSigal = [ = ](GVariant * parameters) {
+        const char* container;
+        const char* application;
+        const char* message;
+        g_variant_get(parameters, "(&s&s&s)", &container, &application, &message);
+        notificationCallback(container, application, message);
+    };
+
+    return signalSubscribe(domainDbusInterfaceInfo, api::container::SIGNAL_NOTIFICATION, onSigal);
+}
index f823cd1..aafcae0 100644 (file)
@@ -52,6 +52,7 @@ struct DbusInterfaceInfo {
  */
 class Client {
 private:
+    typedef std::function<void(GVariant* parameters)> SignalCallback;
     struct Status {
         Status(ScStatus status);
         Status(ScStatus status, const std::string& msg);
@@ -67,6 +68,9 @@ private:
                         GVariant* args_in,
                         const std::string& args_spec_out = std::string(),
                         GVariant** args_out = NULL);
+    ScStatus signalSubscribe(const DbusInterfaceInfo& info,
+                             const std::string& name,
+                             SignalCallback signalCallback);
 
 public:
     Client() noexcept;
@@ -103,6 +107,35 @@ public:
     ScStatus sc_get_container_dbuses(ScArrayString* keys, ScArrayString* values) noexcept;
 
     /**
+     *  @see ::sc_get_container_ids
+     */
+    ScStatus sc_get_container_ids(ScArrayString* array) noexcept;
+
+    /**
+     *  @see ::sc_get_active_container_id
+     */
+    ScStatus sc_get_active_container_id(ScString* id) noexcept;
+
+    /**
+     *  @see ::sc_set_active_container
+     */
+    ScStatus sc_set_active_container(const char* id) noexcept;
+
+    /**
+     *  @see ::sc_container_dbus_state
+     */
+    ScStatus sc_container_dbus_state(ScContainerDbusStateCallback containerDbusStateCallback) noexcept;
+
+    /**
+     *  @see ::sc_notify_active_container
+     */
+    ScStatus sc_notify_active_container(const char* application, const char* message) noexcept;
+
+    /**
+     *  @see ::sc_notification
+     */
+    ScStatus sc_notification(ScNotificationCallback notificationCallback) noexcept;
+    /**
      *  @see ::sc_start
      */
     static ScStatus sc_start() noexcept;
index 572f166..12a3d6d 100644 (file)
@@ -135,3 +135,36 @@ API ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArr
 {
     return getClient(client)->sc_get_container_dbuses(keys, values);
 }
+
+API ScStatus sc_get_container_ids(ScClient client, ScArrayString* array)
+{
+    return getClient(client)->sc_get_container_ids(array);
+}
+
+API ScStatus sc_get_active_container_id(ScClient client, ScString* id)
+{
+    return getClient(client)->sc_get_active_container_id(id);
+}
+
+API ScStatus sc_set_active_container(ScClient client, const char* id)
+{
+    return getClient(client)->sc_set_active_container(id);
+}
+
+API ScStatus sc_container_dbus_state(ScClient client,
+                                 ScContainerDbusStateCallback containerDbusStateCallback)
+{
+    return getClient(client)->sc_container_dbus_state(containerDbusStateCallback);
+}
+
+API ScStatus sc_notify_active_container(ScClient client,
+                                        const char* application,
+                                        const char* message)
+{
+    return getClient(client)->sc_notify_active_container(application, message);
+}
+
+API ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback)
+{
+    return getClient(client)->sc_notification(notificationCallback);
+}
index 692df31..01ca12c 100644 (file)
@@ -149,6 +149,11 @@ void sc_string_free(ScString string);
  ************************************************************************************************/
 
 /**
+ * Dbus state change callback function signature.
+ */
+typedef void (*ScContainerDbusStateCallback)(const char* containerId, const char* dbusAddress);
+
+/**
  * Get dbus address of each container.
  *
  * @param[in] client security-containers-server's client.
@@ -159,6 +164,78 @@ void sc_string_free(ScString string);
  */
 ScStatus sc_get_container_dbuses(ScClient client, ScArrayString* keys, ScArrayString* values);
 
+/**
+ * Get containers name.
+ *
+ * @param[in] client security-containers-server's client.
+ * @param[out] array Array of containers name.
+ * @return Status of this function call.
+ */
+ScStatus sc_get_container_ids(ScClient client, ScArrayString* array);
+
+/**
+ * Get active container name.
+ *
+ * @param[in] client security-containers-server's client.
+ * @param[out] id Active container name.
+ * @return Status of this function call.
+ */
+ScStatus sc_get_active_container_id(ScClient client, ScString* id);
+
+/**
+ * Set active container.
+ *
+ * @param client security-containers-server's client.
+ * @param id Container name.
+ * @return Status of this function call.
+ */
+ScStatus sc_set_active_container(ScClient client, const char* id);
+
+/**
+ * Register dbus state change callback function.
+ *
+ * The callback function will be invoked on a different thread
+ *
+ * @param client security-containers-server's client.
+ * @param containerDbusStateCallback Callback function.
+ * @return Status of this function call.
+ */
+ScStatus sc_container_dbus_state(ScClient client,
+                                 ScContainerDbusStateCallback containerDbusStateCallback);
+
+
+/*************************************************************************************************
+ *
+ *  org.tizen.containers.domain.manager interface
+ *
+ ************************************************************************************************/
+
+/**
+ * Notification callback function signature.
+ */
+typedef void (*ScNotificationCallback)(const char* container,
+                                       const char* application,
+                                       const char* message);
+/**
+ * Send message to active container.
+ *
+ * @param client security-containers-server's client.
+ * @param application Application name.
+ * @param message Message.
+ * @return Status of this function call.
+ */
+ScStatus sc_notify_active_container(ScClient client, const char* application, const char* message);
+
+/**
+ * Register notification callback function.
+ *
+ * The callback function will be invoked on a different thread.
+ *
+ * @param client security-containers-server's client.
+ * @param notificationCallback Callback function.
+ * @return Status of this function call.
+ */
+ScStatus sc_notification(ScClient client, ScNotificationCallback notificationCallback);
 #ifdef __cplusplus
 }
 #endif
index ef49f19..af3380b 100644 (file)
@@ -3,6 +3,7 @@
     "switchToDefaultAfterTimeout" : true,
     "config" : "../libvirt-config/console1-dbus.xml",
     "networkConfig" : "../libvirt-config/network1.xml",
+    "networkFilterConfig" : "../libvirt-config/network1-filter.xml",
     "cpuQuotaForeground" : -1,
     "cpuQuotaBackground" : 1000,
     "runMountPoint" : "/tmp/ut-containers-manager/console1-dbus",
index 76c5e49..0db0a8a 100644 (file)
@@ -3,6 +3,7 @@
     "switchToDefaultAfterTimeout" : false,
     "config" : "../libvirt-config/console2-dbus.xml",
     "networkConfig" : "../libvirt-config/network2.xml",
+    "networkFilterConfig" : "../libvirt-config/network2-filter.xml",
     "cpuQuotaForeground" : -1,
     "cpuQuotaBackground" : 1000,
     "runMountPoint" : "/tmp/ut-containers-manager/console2-dbus",
index 592cbfa..14a8a60 100644 (file)
@@ -3,6 +3,7 @@
     "switchToDefaultAfterTimeout" : true,
     "config" : "../libvirt-config/console3-dbus.xml",
     "networkConfig" : "../libvirt-config/network3.xml",
+    "networkFilterConfig" : "../libvirt-config/network3-filter.xml",
     "cpuQuotaForeground" : -1,
     "cpuQuotaBackground" : 1000,
     "runMountPoint" : "/tmp/ut-containers-manager/console3-dbus",
diff --git a/tests/unit_tests/client/configs/ut-client/libvirt-config/network1-filter.xml b/tests/unit_tests/client/configs/ut-client/libvirt-config/network1-filter.xml
new file mode 100644 (file)
index 0000000..bf39965
--- /dev/null
@@ -0,0 +1,3 @@
+<filter name='test-network-1-filter' chain='root'>
+    <uuid>abc79a77-0209-41a2-ab82-f767dfa5897e</uuid>
+</filter>
diff --git a/tests/unit_tests/client/configs/ut-client/libvirt-config/network2-filter.xml b/tests/unit_tests/client/configs/ut-client/libvirt-config/network2-filter.xml
new file mode 100644 (file)
index 0000000..f33c816
--- /dev/null
@@ -0,0 +1,3 @@
+<filter name='test-network-2-filter' chain='root'>
+    <uuid>703f53eb-c602-4383-9de9-62bbe843ba31</uuid>
+</filter>
diff --git a/tests/unit_tests/client/configs/ut-client/libvirt-config/network3-filter.xml b/tests/unit_tests/client/configs/ut-client/libvirt-config/network3-filter.xml
new file mode 100644 (file)
index 0000000..04310bd
--- /dev/null
@@ -0,0 +1,3 @@
+<filter name='test-network-3-filter' chain='root'>
+    <uuid>40943fcc-faec-4bfe-9e89-104945164d35</uuid>
+</filter>
index 1755874..cab82e1 100644 (file)
 #include "ut.hpp"
 #include <security-containers-client.h>
 
+#include "utils/latch.hpp"
 #include "containers-manager.hpp"
 
 #include <map>
 #include <string>
 #include <utility>
 #include <memory>
+#include <set>
+#include <tuple>
+#include <utility>
 
 using namespace security_containers;
+using namespace security_containers::utils;
 
 namespace {
 
@@ -46,6 +51,7 @@ struct Fixture {
     ~Fixture() { sc_stop(); };
 };
 
+const int EVENT_TIMEOUT = 5000; ///< ms
 const std::map<std::string, std::string> EXPECTED_DBUSES_STARTED = {
     {"ut-containers-manager-console1-dbus",
      "unix:path=/tmp/ut-containers-manager/console1-dbus/dbus/system_bus_socket"},
@@ -65,6 +71,13 @@ void convertDictToMap(ScArrayString keys,
     }
 }
 
+void convertArrayToSet(ScArrayString values, std::set<std::string>& ret)
+{
+    for (char** iValues = values; *iValues; iValues++) {
+        ret.insert(*iValues);
+    }
+}
+
 int getArrayStringLength(ScArrayString astring, int max_len = -1)
 {
     int i = 0;
@@ -76,6 +89,15 @@ int getArrayStringLength(ScArrayString astring, int max_len = -1)
     return i;
 }
 
+Latch signalReceivedLatch;
+std::vector< std::tuple<std::string, std::string, std::string> > receivedSignalMsg;
+
+void NotificationTestCallback(const char* container, const char* application, const char* message)
+{
+    receivedSignalMsg.push_back(std::make_tuple(container, application, message));
+    signalReceivedLatch.set();
+}
+
 } // namespace
 
 BOOST_FIXTURE_TEST_SUITE(Client, Fixture)
@@ -116,4 +138,102 @@ BOOST_AUTO_TEST_CASE(GetContainerDbusesTest)
     BOOST_WARN_NO_THROW(cm.reset());
 }
 
+BOOST_AUTO_TEST_CASE(GetContainerIdsTest)
+{
+    std::unique_ptr<ContainersManager> cm;
+    BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH)));
+    cm->startAll();
+    ScClient client;
+    ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE);
+    BOOST_REQUIRE(!sc_is_failed(status));
+    ScArrayString values;
+    status = sc_get_container_ids(client, &values);
+    BOOST_REQUIRE(!sc_is_failed(status));
+    BOOST_CHECK_EQUAL(getArrayStringLength(values, EXPECTED_DBUSES_STARTED.size() + 1),
+                      EXPECTED_DBUSES_STARTED.size());
+
+    std::set<std::string> containers;
+    convertArrayToSet(values, containers);
+
+    for (const auto& container : containers) {
+        BOOST_CHECK(EXPECTED_DBUSES_STARTED.find(container) != EXPECTED_DBUSES_STARTED.cend());
+    }
+    sc_array_string_free(values);
+    sc_client_free(client);
+
+    BOOST_WARN_NO_THROW(cm.reset());
+}
+
+BOOST_AUTO_TEST_CASE(GetActiveContainerIdTest)
+{
+    std::unique_ptr<ContainersManager> cm;
+    BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH)));
+    cm->startAll();
+
+    ScClient client;
+    ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE);
+    BOOST_REQUIRE(!sc_is_failed(status));
+    ScString container;
+    status = sc_get_active_container_id(client, &container);
+    BOOST_REQUIRE(!sc_is_failed(status));
+
+    BOOST_CHECK_EQUAL(container, cm->getRunningForegroundContainerId());
+
+    sc_string_free(container);
+    sc_client_free(client);
+
+    BOOST_WARN_NO_THROW(cm.reset());
+}
+
+BOOST_AUTO_TEST_CASE(SetActiveContainerTest)
+{
+    std::string newActiveContainerId = "ut-containers-manager-console2-dbus";
+
+    std::unique_ptr<ContainersManager> cm;
+    BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH)));
+    cm->startAll();
+    BOOST_REQUIRE_NE(newActiveContainerId, cm->getRunningForegroundContainerId());
+
+    ScClient client;
+    ScStatus status = sc_get_client(&client, SCCLIENT_SYSTEM_TYPE);
+    BOOST_REQUIRE(!sc_is_failed(status));
+    status = sc_set_active_container(client, newActiveContainerId.c_str());
+    BOOST_REQUIRE(!sc_is_failed(status));
+    BOOST_CHECK_EQUAL(newActiveContainerId, cm->getRunningForegroundContainerId());
+    sc_client_free(client);
+    BOOST_WARN_NO_THROW(cm.reset());
+}
+
+BOOST_AUTO_TEST_CASE(NotificationTest)
+{
+    std::string activeContainerId = "ut-containers-manager-console1-dbus";
+    std::unique_ptr<ContainersManager> cm;
+    BOOST_REQUIRE_NO_THROW(cm.reset(new ContainersManager(TEST_DBUS_CONFIG_PATH)));
+    cm->startAll();
+
+    std::map<std::string, ScClient> clients;
+    for (const auto& it : EXPECTED_DBUSES_STARTED) {
+        ScClient client;
+        ScStatus status = sc_get_client(&client, SCCLIENT_CUSTOM_TYPE, it.second.c_str());
+        BOOST_REQUIRE(!sc_is_failed(status));
+        clients[it.first] = client;
+    }
+    for (auto& client : clients) {
+        ScStatus status = sc_notification(client.second, NotificationTestCallback);
+        BOOST_REQUIRE(!sc_is_failed(status));
+    }
+    for (auto& client : clients) {
+        ScStatus status = sc_notify_active_container(client.second, "app", "msg");
+        BOOST_REQUIRE(!sc_is_failed(status));
+    }
+
+    BOOST_CHECK(signalReceivedLatch.waitForN(clients.size() - 1, EVENT_TIMEOUT));
+    BOOST_CHECK(signalReceivedLatch.empty());
+
+    for (auto& client : clients) {
+        sc_client_free(client.second);
+    }
+    BOOST_WARN_NO_THROW(cm.reset());
+}
+
 BOOST_AUTO_TEST_SUITE_END()