Handle job signals from systemd 23/30723/2
authorLukasz Wojciechowski <l.wojciechow@partner.samsung.com>
Mon, 24 Nov 2014 04:31:40 +0000 (05:31 +0100)
committerLukasz Wojciechowski <l.wojciechow@partner.samsung.com>
Mon, 24 Nov 2014 17:11:42 +0000 (18:11 +0100)
A set of currently running jobs was added. Jobs are identified
with unique job path created by systemd.
Every time a start/stop/restart command is sent to systemd,
related job is added to set.
When JobNew signal is received its handler puts it also in the set.
Job is removed from the set, when JobRemoved signal is delivered from
systemd.
After each action generating a job in systemd unit (start/stop/restart)
program waits until all jobs from the set are removed.

Timeouts used earlier to "synchronize" action calls are removed.

Change-Id: Id944c9f52ecfeb06efabdb9424c835d09af7bb4f

tests/common/dbus_access.cpp
tests/common/dbus_access.h

index b81de1fa8a5fdaab2c3528f373cbd7552a85b5d5..9990d02617768842f4fef36abc9fe136b8726ca0 100644 (file)
@@ -161,8 +161,7 @@ void DBusAccess::sendToService(const char *method) {
     appendToMsg("fail");
     sendMsgWithReply();
     getMsgReply();
-    handleObjectPathMsgReply();
-    usleep(50000);
+    m_runningJobs.insert(handleObjectPathMsgReply());
 }
 
 void DBusAccess::sendResetFailedToService() {
@@ -175,24 +174,112 @@ void DBusAccess::sendResetFailedToService() {
 
 DBusHandlerResult DBusAccess::messageHandler(DBusConnection *conn, DBusMessage *msg, void *t) {
     (void) conn;
-    (void) msg;
-    (void) t;
+    DBusAccess* self = reinterpret_cast<DBusAccess*>(t);
+
+    if (self->isSignal(msg, "JobRemoved"))
+        self->signalJobRemovedHandler(msg);
+    else if (self->isSignal(msg, "JobNew"))
+        self->signalJobNewHandler(msg);
 
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
+bool DBusAccess::isSignal(DBusMessage *msg, const char *signal) {
+    return dbus_message_is_signal(msg, m_dbus_systemd_manager_interface.c_str(), signal);
+}
+
+void DBusAccess::signalJobRemovedHandler(DBusMessage *msg) {
+    DBusMessageIter iter;
+    RUNNER_ASSERT_MSG(dbus_message_iter_init(msg, &iter) != 0,
+        "Message has no arguments");
+
+    if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&iter)) {
+        RUNNER_FAIL_MSG("uint32 type expected");
+    }
+    uint32_t id;
+    dbus_message_iter_get_basic(&iter, &id);
+
+    dbus_message_iter_next (&iter);
+    if (DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type(&iter)) {
+        RUNNER_FAIL_MSG("Object path type expected");
+    }
+    char *path;
+    dbus_message_iter_get_basic(&iter, &path);
+
+    dbus_message_iter_next (&iter);
+    if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&iter)) {
+        RUNNER_FAIL_MSG("String type expected");
+    }
+    char *unit;
+    dbus_message_iter_get_basic(&iter, &unit);
+
+    dbus_message_iter_next (&iter);
+    if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&iter)) {
+        RUNNER_FAIL_MSG("String type expected");
+    }
+    char *result;
+    dbus_message_iter_get_basic(&iter, &result);
+
+    if(m_service_name == unit) {
+        RUNNER_ASSERT_MSG(strcmp(result, "done") == 0 || strcmp(result, "canceled") == 0,
+                          "RemoveJob signal delivered bad news. Job wasn't completed successfully: "
+                              << "expected job results = {done, canceled}, "
+                              << "received job result = " << result << ", "
+                              << "for job with id = " << id << ", "
+                              << "and path = " << path);
+        m_runningJobs.erase(path);
+    }
+}
+
+void DBusAccess::signalJobNewHandler(DBusMessage *msg) {
+    DBusMessageIter iter;
+    RUNNER_ASSERT_MSG(dbus_message_iter_init(msg, &iter) != 0,
+        "Message has no arguments");
+
+    if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&iter)) {
+        RUNNER_FAIL_MSG("uint32 type expected");
+    }
+    uint32_t id;
+    dbus_message_iter_get_basic(&iter, &id);
+
+    dbus_message_iter_next (&iter);
+    if (DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type(&iter)) {
+        RUNNER_FAIL_MSG("Object path type expected");
+    }
+    char *path;
+    dbus_message_iter_get_basic(&iter, &path);
+
+    dbus_message_iter_next (&iter);
+    if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&iter)) {
+        RUNNER_FAIL_MSG("String type expected");
+    }
+    char *unit;
+    dbus_message_iter_get_basic(&iter, &unit);
+
+    if(m_service_name == unit)
+        m_runningJobs.insert(path);
+}
+
+void DBusAccess::waitForRunningJobsFinish() {
+    while (!m_runningJobs.empty())
+        dbus_connection_read_write_dispatch(m_conn, -1);
+}
+
 void DBusAccess::startService() {
     sendToService("StartUnit");
+    waitForRunningJobsFinish();
     sendResetFailedToService();
 }
 
 void DBusAccess::stopService() {
     sendToService("StopUnit");
+    waitForRunningJobsFinish();
     sendResetFailedToService();
 }
 
 void DBusAccess::restartService() {
     sendToService("RestartUnit");
+    waitForRunningJobsFinish();
     sendResetFailedToService();
 }
 
index cb9fdf3aafbda13a61c28d6c75a20cad23b25c67..d59339f0bd42fabbccc482dec08e73d0b0d28637 100644 (file)
@@ -29,6 +29,7 @@
 #include <dbus-glib.h>
 #include <glib-object.h>
 
+#include <set>
 #include <string>
 
 class DBusAccess {
@@ -58,6 +59,10 @@ private:
     void sendResetFailedToService();
 
     static DBusHandlerResult messageHandler(DBusConnection *conn, DBusMessage *msg, void *t);
+    bool isSignal(DBusMessage *msg, const char *signal);
+    void signalJobRemovedHandler(DBusMessage *msg);
+    void signalJobNewHandler(DBusMessage *msg);
+    void waitForRunningJobsFinish();
 
     DBusConnection *m_conn;
     DBusMessage *m_msg;
@@ -70,6 +75,8 @@ private:
     const std::string m_dbus_systemd_destination;
     const std::string m_dbus_systemd_path;
     const std::string m_dbus_systemd_manager_interface;
+
+    std::set<std::string> m_runningJobs;
 };
 
 #endif // _DBUS_ACCESS_H_