sdbus: kdbus: add test for adding async signal match
authorMaciej Slodczyk <m.slodczyk2@partner.samsung.com>
Mon, 30 Mar 2020 13:09:14 +0000 (15:09 +0200)
committerŁukasz Stelmach <l.stelmach@samsung.com>
Mon, 12 Feb 2024 15:37:48 +0000 (16:37 +0100)
Signed-off-by: Maciej Slodczyk <m.slodczyk2@partner.samsung.com>
packaging/test-runner.c
src/libsystemd/sd-bus/test-bus-async-match.c [new file with mode: 0644]
src/test/meson.build

index 02e9a66..27bb18d 100644 (file)
@@ -175,6 +175,11 @@ static struct test_case test_case_desc_15[] = {
         {NULL, NULL}
 };
 
+static struct test_case test_case_desc_16[] = {
+        {"", "Test (kdbus) async match"},
+        {NULL, NULL}
+};
+
 /* This table is used to start binaries */
 struct binary tests[] = {
         /*path, name, TC_table, timeout in us, prepare_args_handler, parse_function_handler, init_handler, clean_handler*/
@@ -193,6 +198,7 @@ struct binary tests[] = {
         {"/usr/lib/dbus-tests/test-suites/systemd-tests/test-bus-server",           "test-bus-server",           test_case_desc_13, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
         {"/usr/lib/dbus-tests/test-suites/systemd-tests/test-bus-signature",        "test-bus-signature",        test_case_desc_14, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
         {"/usr/lib/dbus-tests/test-suites/systemd-tests/test-bus-zero-copy",        "test-bus-zero-copy",        test_case_desc_15, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+        {"/usr/lib/dbus-tests/test-suites/systemd-tests/test-bus-async-match",      "test-bus-async-match",      test_case_desc_16, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
 };
 
 static char* args[3];
diff --git a/src/libsystemd/sd-bus/test-bus-async-match.c b/src/libsystemd/sd-bus/test-bus-async-match.c
new file mode 100644 (file)
index 0000000..9406b73
--- /dev/null
@@ -0,0 +1,283 @@
+#include <sd-event.h>
+#include <sd-bus.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+enum app_state {
+       APP_STATE_START = 0,
+       APP_STATE_MATCH_ADDED,
+       APP_STATE_SIGNAL_EMIT_DONE,
+       APP_STATE_FINISHED_OK,
+       APP_STATE_FINISHED_ERROR
+};
+struct app_data {
+       sd_event *event;
+       sd_bus *bus;
+       enum app_state state;
+};
+
+static void dump_msg(sd_bus_message *m)
+{
+       uint8_t t;
+       const char *type;
+       const char *sender;
+       const char *destination;
+       const char *path;
+       const char *interface;
+       const char *member;
+
+       if (sd_bus_message_get_type(m, &t) < 0) {
+               printf("could not fetch message type\n");
+               return;
+       }
+
+       sender = sd_bus_message_get_sender(m);
+       if (NULL == sender) {
+               sender = "unknown";
+       }
+
+       destination = sd_bus_message_get_destination(m);
+       if (NULL == destination) {
+               destination = "unknown";
+       }
+
+       path= sd_bus_message_get_path(m);
+       if (NULL == path) {
+               path = "unknown";
+       }
+
+       interface = sd_bus_message_get_interface(m);
+       if (NULL == interface) {
+               interface = "unknown";
+       }
+
+       member = sd_bus_message_get_member(m);
+       if (NULL == member) {
+               member = "unknown";
+       }
+
+       switch (t) {
+       case SD_BUS_MESSAGE_METHOD_CALL:
+               type = "method call";
+               break;
+       case SD_BUS_MESSAGE_METHOD_RETURN:
+               type = "method return";
+               break;
+       case SD_BUS_MESSAGE_METHOD_ERROR:
+               type = "method error";
+               break;
+       case SD_BUS_MESSAGE_SIGNAL:
+               type = "signal";
+               break;
+       default:
+               type = "???";
+               break;
+       }
+
+       printf("message type=%s sender=%s destination=%s path=%s interface=%s member=%s\n",
+                       type, sender, destination, path, interface, member);
+}
+
+static int timeout_callback(sd_event_source *s,        uint64_t usec, void *userdata)
+{
+       int r;
+       sd_bus_message *m;
+       struct app_data *app = (struct app_data *)userdata;
+
+       assert(app);
+       assert(app->bus);
+
+       printf("Test timed out\n");
+       app->state = APP_STATE_FINISHED_ERROR;
+       sd_event_exit(app->event, -1);
+
+       return 0;
+}
+
+static int install_match_callback(sd_bus_message *m, void *userdata,
+               sd_bus_error *ret_error)
+{
+       int r;
+       sd_bus_message *msg;
+       struct app_data *app = (struct app_data *)userdata;
+
+       assert(app);
+       assert(app->bus);
+       assert(app->event);
+
+       if (APP_STATE_MATCH_ADDED != app->state) {
+               fprintf(stderr, "Install match: wrong app state (%d)\n", app->state);
+               app->state = APP_STATE_FINISHED_ERROR;
+               sd_event_exit(app->event, sd_bus_error_get_errno(ret_error));
+               return 0;
+       }
+
+       if (NULL != ret_error && 0 != sd_bus_error_is_set(ret_error)) {
+               fprintf(stderr,
+                               "Failed to add match callback: %s/%s (%s)\n",
+                               ret_error->name,
+                               ret_error->message,
+                               strerror(sd_bus_error_get_errno(ret_error)));
+               app->state = APP_STATE_FINISHED_ERROR;
+               sd_event_exit(app->event, sd_bus_error_get_errno(ret_error));
+               return 0;
+       }
+
+       r = sd_bus_message_new_signal(app->bus, &msg,
+                       "/org/freedesktop/systemd1",
+                       "org.freedesktop.systemd1.Manager",
+                       "SystemdAsyncMatchTestSignal");
+
+       if (r < 0) {
+               fprintf(stderr, "Failed to add signal: %s\n", strerror(-r));
+               app->state = APP_STATE_FINISHED_ERROR;
+               sd_event_exit(app->event, r);
+               return r;
+       }
+
+       r = sd_bus_send(app->bus, msg, NULL);
+       if (r < 0) {
+               fprintf(stderr, "Failed to emit signal: %s\n", strerror(-r));
+               app->state = APP_STATE_FINISHED_ERROR;
+               sd_event_exit(app->event, r);
+               return r;
+       }
+
+       app->state = APP_STATE_SIGNAL_EMIT_DONE;
+       return 0;
+}
+
+static int signal_match_callback(sd_bus_message *m, void *userdata,
+               sd_bus_error *ret_error)
+{
+       struct app_data *app = (struct app_data *)userdata;
+
+       assert(app);
+       assert(app->bus);
+       assert(app->event);
+
+       if (APP_STATE_SIGNAL_EMIT_DONE != app->state) {
+               fprintf(stderr, "Match callback: wrong app state (%d)\n", app->state);
+               app->state = APP_STATE_FINISHED_ERROR;
+               sd_event_exit(app->event, -1);
+               return 0;
+       }
+
+       dump_msg(m);
+       app->state = APP_STATE_FINISHED_OK;
+       sd_event_exit(app->event, 0);
+       return 0;
+}
+
+int main(int argc, char *argv[]) {
+       struct app_data app = {
+               .state = APP_STATE_START
+       };
+       sd_bus_slot *slot;
+       sd_event_source *timeout;
+       int r;
+       sigset_t ss;
+       uint64_t now;
+       const char *match = "type='signal',interface='org.freedesktop.systemd1.Manager',path='/org/freedesktop/systemd1',member='SystemdAsyncMatchTestSignal'";
+
+       r = sd_event_default(&app.event);
+       if (r < 0) {
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+
+       if (sigemptyset(&ss) < 0 ||
+               sigaddset(&ss, SIGTERM) < 0 ||
+               sigaddset(&ss, SIGINT) < 0) {
+                       r = -errno;
+               app.state = APP_STATE_FINISHED_ERROR;
+                       goto finish;
+       }
+
+       /* Block SIGTERM first, so that the event loop can handle it */
+       if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0) {
+               r = -errno;
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+
+       r = sd_event_add_signal(app.event, NULL, SIGTERM, NULL, NULL);
+       if (r < 0) {
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+       r = sd_event_add_signal(app.event, NULL, SIGINT, NULL, NULL);
+       if (r < 0) {
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+
+       /* Connect to the system bus */
+       r = sd_bus_open_system(&app.bus);
+       if (r < 0) {
+               fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+
+       /* Add global test timeout callback */
+       r = sd_event_now(app.event, CLOCK_MONOTONIC, &now);
+       if (r < 0) {
+               fprintf(stderr, "Failed to get current timestamp: %s\n", strerror(-r));
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+
+       r = sd_event_add_time(app.event,
+                       &timeout,
+                       CLOCK_MONOTONIC,
+                       now + 5000000, /* 5 seconds */
+                       0,
+                       timeout_callback,
+                       &app);
+
+       if (r < 0) {
+               fprintf(stderr, "Failed to add global timeout: %s\n", strerror(-r));
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+
+       /* Add signal match callback */
+       r = sd_bus_add_match_async(app.bus, &slot, match, signal_match_callback,
+                       install_match_callback, &app);
+       if (r < 0) {
+               fprintf(stderr, "Failed to add match: %s\n", strerror(-r));
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+       app.state = APP_STATE_MATCH_ADDED;
+
+       /* Attach system bus events to manloop */
+       r = sd_bus_attach_event(app.bus, app.event, SD_EVENT_PRIORITY_NORMAL);
+       if (r < 0) {
+               fprintf(stderr, "Failed to attach system bus to mainloop: %s\n", strerror(-r));
+               app.state = APP_STATE_FINISHED_ERROR;
+               goto finish;
+       }
+
+       r = sd_event_loop(app.event);
+
+finish:
+       sd_event_source_set_enabled(timeout, SD_EVENT_OFF);
+
+       app.event = sd_event_unref(app.event);
+       slot = sd_bus_slot_unref(slot);
+       app.bus = sd_bus_unref(app.bus);
+
+       assert(app.state == APP_STATE_FINISHED_OK);
+
+       if (r < 0)
+               fprintf(stderr, "Test failed\n");
+       else
+               fprintf(stderr, "Test passed\n");
+
+       return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
index de31e97..e88f4f4 100644 (file)
@@ -959,6 +959,10 @@ tests += [
          [],
          []],
 
+        [['src/libsystemd/sd-bus/test-bus-async-match.c'],
+         [],
+         []],
+
         [['src/libsystemd/sd-bus/test-bus-match.c'],
          [],
          []],