diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c index 3f53e1d7f..3d2a14e03 100644 --- a/gio/tests/gdbus-subscribe.c +++ b/gio/tests/gdbus-subscribe.c @@ -7,6 +7,9 @@ #include "gdbus-tests.h" +/* From the D-Bus Specification */ +#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 + #define DBUS_SERVICE_DBUS "org.freedesktop.DBus" #define DBUS_PATH_DBUS "/org/freedesktop/DBus" #define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS @@ -22,6 +25,9 @@ #define EXAMPLE_INTERFACE "org.gtk.GDBus.ExampleInterface" #define FOO_SIGNAL "Foo" +#define ALREADY_OWNED_NAME "org.gtk.Test.AlreadyOwned" +#define OWNED_LATER_NAME "org.gtk.Test.OwnedLater" + /* Log @s in a debug message. */ static inline const char * nonnull (const char *s, @@ -101,7 +107,8 @@ typedef struct typedef struct { - TestConn sender; + const char *string_sender; + TestConn unique_sender; const char *path; const char *iface; const char *member; @@ -109,11 +116,18 @@ typedef struct GDBusSignalFlags flags; } TestSubscribe; +typedef struct +{ + const char *name; + TestConn owner; +} TestOwnName; + typedef enum { TEST_ACTION_NONE = 0, TEST_ACTION_SUBSCRIBE, TEST_ACTION_EMIT_SIGNAL, + TEST_ACTION_OWN_NAME, } TestAction; typedef struct @@ -122,6 +136,7 @@ typedef struct union { TestEmitSignal signal; TestSubscribe subscribe; + TestOwnName own_name; } u; } TestStep; @@ -247,7 +262,7 @@ static const TestPlan plan_match_twice = { .action = TEST_ACTION_SUBSCRIBE, .u.subscribe = { - .sender = TEST_CONN_SERVICE, + .unique_sender = TEST_CONN_SERVICE, .path = EXAMPLE_PATH, .iface = EXAMPLE_INTERFACE, }, @@ -267,7 +282,7 @@ static const TestPlan plan_match_twice = { .action = TEST_ACTION_SUBSCRIBE, .u.subscribe = { - .sender = TEST_CONN_SERVICE, + .unique_sender = TEST_CONN_SERVICE, .path = EXAMPLE_PATH, .iface = EXAMPLE_INTERFACE, }, @@ -296,7 +311,7 @@ static const TestPlan plan_limit_by_unique_name = /* Subscriber wants to receive signals from service */ .action = TEST_ACTION_SUBSCRIBE, .u.subscribe = { - .sender = TEST_CONN_SERVICE, + .unique_sender = TEST_CONN_SERVICE, .path = EXAMPLE_PATH, .iface = EXAMPLE_INTERFACE, }, @@ -343,6 +358,62 @@ static const TestPlan plan_limit_by_unique_name = }, }; +static const TestPlan plan_limit_by_well_known_name = +{ + .description = "A subscription via a well-known name only accepts messages " + "sent by the owner of that well-known name", + .steps = { + { + /* Service already owns one name */ + .action = TEST_ACTION_OWN_NAME, + .u.own_name = { + .name = ALREADY_OWNED_NAME, + .owner = TEST_CONN_SERVICE + }, + }, + { + /* Subscriber wants to receive signals from service */ + .action = TEST_ACTION_SUBSCRIBE, + .u.subscribe = { + .string_sender = ALREADY_OWNED_NAME, + .path = EXAMPLE_PATH, + .iface = EXAMPLE_INTERFACE, + }, + }, + { + /* Subscriber wants to receive signals from service by another name */ + .action = TEST_ACTION_SUBSCRIBE, + .u.subscribe = { + .string_sender = OWNED_LATER_NAME, + .path = EXAMPLE_PATH, + .iface = EXAMPLE_INTERFACE, + }, + }, + { + /* Service claims another name */ + .action = TEST_ACTION_OWN_NAME, + .u.own_name = { + .name = OWNED_LATER_NAME, + .owner = TEST_CONN_SERVICE + }, + }, + { + /* Now the subscriber gets this signal twice, once for each + * subscription; and similarly each of the two proxies gets this + * signal twice */ + .action = TEST_ACTION_EMIT_SIGNAL, + .u.signal = { + .sender = TEST_CONN_SERVICE, + .path = EXAMPLE_PATH, + .iface = EXAMPLE_INTERFACE, + .member = FOO_SIGNAL, + .received_by_conn = 2, + .received_by_proxy = 2 + }, + }, + }, +}; + typedef struct { const TestPlan *plan; @@ -540,11 +611,16 @@ fixture_subscribe (Fixture *f, GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; const char *sender; - if (subscribe->sender != TEST_CONN_NONE) + if (subscribe->string_sender != NULL) { - sender = f->unique_names[subscribe->sender]; + sender = subscribe->string_sender; + g_test_message ("\tSender: %s", sender); + } + else if (subscribe->unique_sender != TEST_CONN_NONE) + { + sender = f->unique_names[subscribe->unique_sender]; g_test_message ("\tSender: %s %s", - test_conn_descriptions[subscribe->sender], + test_conn_descriptions[subscribe->unique_sender], sender); } else @@ -689,6 +765,43 @@ fixture_emit_signal (Fixture *f, connection_wait_for_bus (f->conns[signal->sender]); } +static void +fixture_own_name (Fixture *f, + const TestOwnName *own_name) +{ + GVariant *call_result; + guint32 flags; + guint32 result_code; + + g_test_message ("\tName: %s", own_name->name); + g_test_message ("\tOwner: %s", + test_conn_descriptions[own_name->owner]); + + /* For simplicity, we do this via a direct bus call rather than + * using g_bus_own_name_on_connection(). The flags in + * GBusNameOwnerFlags are numerically equal to those in the + * D-Bus wire protocol. */ + flags = G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE; + call_result = g_dbus_connection_call_sync (f->conns[own_name->owner], + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "RequestName", + g_variant_new ("(su)", + own_name->name, + flags), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &f->error); + g_assert_no_error (f->error); + g_assert_nonnull (call_result); + g_variant_get (call_result, "(u)", &result_code); + g_assert_cmpuint (result_code, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); + g_variant_unref (call_result); +} + static void fixture_run_plan (Fixture *f, const TestPlan *plan, @@ -721,6 +834,11 @@ fixture_run_plan (Fixture *f, fixture_emit_signal (f, &step->u.signal, i); break; + case TEST_ACTION_OWN_NAME: + g_test_message ("Step %u: claiming bus name", i); + fixture_own_name (f, &step->u.own_name); + break; + case TEST_ACTION_NONE: /* Padding to fill the rest of the array, do nothing */ break; @@ -933,6 +1051,7 @@ main (int argc, ADD_SUBSCRIBE_TEST (broadcast_from_anyone); ADD_SUBSCRIBE_TEST (match_twice); ADD_SUBSCRIBE_TEST (limit_by_unique_name); + ADD_SUBSCRIBE_TEST (limit_by_well_known_name); return g_test_run(); }