tests: Add support for subscribing to signals from a well-known name

Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie 2024-03-08 19:28:15 +00:00
parent 124b4571bb
commit 14c3d6938e

View File

@ -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();
}