diff --git a/tests/common/base-test-fixture.h b/tests/common/base-test-fixture.h
new file mode 100644
index 0000000000000000000000000000000000000000..976ee186b9fcb169989da7e8d3fa48886d4012cf
--- /dev/null
+++ b/tests/common/base-test-fixture.h
@@ -0,0 +1,109 @@
+/* WirePlumber
+ *
+ * Copyright © 2020 Collabora Ltd.
+ *    @author George Kiagiadakis <george.kiagiadakis@collabora.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "test-server.h"
+#include <wp/wp.h>
+
+typedef enum {
+  WP_BASE_TEST_FLAG_CLIENT_CORE = (1<<0),
+  WP_BASE_TEST_FLAG_DONT_CONNECT = (1<<1),
+} WpBaseTestFlags;
+
+typedef struct {
+  /* the local pipewire server */
+  WpTestServer server;
+
+  /* the main loop */
+  GMainContext *context;
+  GMainLoop *loop;
+
+  /* watchdog */
+  GSource *timeout_source;
+
+  /* our session manager core */
+  WpCore *core;
+
+  /* the "client" core, which receives proxies
+    (second client to our internal server) */
+  WpCore *client_core;
+
+} WpBaseTestFixture;
+
+static gboolean
+timeout_callback (WpBaseTestFixture * self)
+{
+  wp_message ("test timed out");
+  g_test_fail ();
+  g_main_loop_quit (self->loop);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+disconnected_callback (WpCore *core, WpBaseTestFixture * self)
+{
+  wp_message_object (core, "%s core disconnected",
+      (core == self->client_core) ? "client" : "sm");
+  g_test_fail ();
+  g_main_loop_quit (self->loop);
+}
+
+static void
+wp_base_test_fixture_setup (WpBaseTestFixture * self, WpBaseTestFlags flags)
+{
+  g_autoptr (WpProperties) props = NULL;
+
+  /* ensure types are loaded */
+  g_type_ensure (WP_TYPE_CORE);
+
+  /* init test server */
+  wp_test_server_setup (&self->server);
+
+  /* init our main loop */
+  self->context = g_main_context_new ();
+  self->loop = g_main_loop_new (self->context, FALSE);
+  g_main_context_push_thread_default (self->context);
+
+  /* watchdog */
+  self->timeout_source = g_timeout_source_new_seconds (3);
+  g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
+      self, NULL);
+  g_source_attach (self->timeout_source, self->context);
+
+  /* init our core */
+  props = wp_properties_new (PW_KEY_REMOTE_NAME, self->server.name, NULL);
+  self->core = wp_core_new (self->context, props);
+  g_signal_connect (self->core, "disconnected",
+      (GCallback) disconnected_callback, self);
+
+  if (!(flags & WP_BASE_TEST_FLAG_DONT_CONNECT))
+    g_assert_true (wp_core_connect (self->core));
+
+  /* init the second client's core */
+  if (flags & WP_BASE_TEST_FLAG_CLIENT_CORE) {
+    self->client_core = wp_core_new (self->context, props);
+    g_signal_connect (self->client_core, "disconnected",
+        (GCallback) disconnected_callback, self);
+
+    if (!(flags & WP_BASE_TEST_FLAG_DONT_CONNECT))
+      g_assert_true (wp_core_connect (self->client_core));
+  }
+}
+
+static void
+wp_base_test_fixture_teardown (WpBaseTestFixture * self)
+{
+  g_main_context_pop_thread_default (self->context);
+
+  g_clear_object (&self->client_core);
+  g_clear_object (&self->core);
+  g_clear_pointer (&self->timeout_source, g_source_unref);
+  g_clear_pointer (&self->loop, g_main_loop_unref);
+  g_clear_pointer (&self->context, g_main_context_unref);
+  wp_test_server_teardown (&self->server);
+}
diff --git a/tests/common/test-server.h b/tests/common/test-server.h
index 96cf0a01fb81de587c83fc9eda8c4c148ac686cc..11fdd3b8a1156adf2ab12c4333aa22a40bd158a0 100644
--- a/tests/common/test-server.h
+++ b/tests/common/test-server.h
@@ -8,6 +8,8 @@
 
 #include <pipewire/pipewire.h>
 #include <pipewire/impl.h>
+#include <glib.h>
+#include <unistd.h>
 
 typedef struct {
   gchar *name;
@@ -28,7 +30,8 @@ wp_test_server_setup (WpTestServer *self)
       NULL);
 
   self->thread_loop = pw_thread_loop_new ("wp-test-server", NULL);
-  self->context = pw_context_new (pw_thread_loop_get_loop (self->thread_loop), properties, 0);
+  self->context = pw_context_new (pw_thread_loop_get_loop (self->thread_loop),
+      properties, 0);
 
   pw_context_load_module (self->context, "libpipewire-module-access", NULL, NULL);
 
diff --git a/tests/modules/config-endpoint.c b/tests/modules/config-endpoint.c
index 3f61e3b611539d279ddb47043f62a397b1ca26a4..94ad755d65e14dd0ac8e231989d1a3d30e8b0513 100644
--- a/tests/modules/config-endpoint.c
+++ b/tests/modules/config-endpoint.c
@@ -6,89 +6,40 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include <pipewire/pipewire.h>
-
-#include <wp/wp.h>
-
+#include "../common/base-test-fixture.h"
 #include "config-endpoint/endpoint-audiotestsrc.h"
-#include "../common/test-server.h"
 #include "../../modules/module-config-endpoint/context.h"
 
 typedef struct {
-  WpTestServer server;
-  GThread *loop_thread;
-  GMainContext *context;
-  GMainLoop *loop;
-  GSource *timeout_source;
-  WpCore *core;
+  WpBaseTestFixture base;
 } TestConfigEndpointFixture;
 
-static gboolean
-timeout_callback (TestConfigEndpointFixture *self)
-{
-  g_message ("test timed out");
-  g_test_fail ();
-  g_main_loop_quit (self->loop);
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-disconnected_callback (WpCore *core, TestConfigEndpointFixture *self)
-{
-  g_message ("core disconnected");
-  g_test_fail ();
-  g_main_loop_quit (self->loop);
-}
-
 static void
 config_endpoint_setup (TestConfigEndpointFixture *self, gconstpointer data)
 {
-  g_autoptr (WpProperties) props = NULL;
+  wp_base_test_fixture_setup (&self->base, 0);
 
-  /* Create the server and load audiotestsrc */
-  wp_test_server_setup (&self->server);
-  pw_thread_loop_lock (self->server.thread_loop);
-  pw_context_add_spa_lib (self->server.context, "audiotestsrc",
+  /* load audiotestsrc */
+  pw_thread_loop_lock (self->base.server.thread_loop);
+  pw_context_add_spa_lib (self->base.server.context, "audiotestsrc",
       "audiotestsrc/libspa-audiotestsrc");
-  if (!pw_context_load_module (self->server.context,
+  if (!pw_context_load_module (self->base.server.context,
         "libpipewire-module-spa-node", "audiotestsrc", NULL)) {
-    pw_thread_loop_unlock (self->server.thread_loop);
+    pw_thread_loop_unlock (self->base.server.thread_loop);
     g_test_skip ("audiotestsrc SPA plugin is not installed");
     return;
   }
-  pw_thread_loop_unlock (self->server.thread_loop);
-
-  /* Create the main context and loop */
-  self->context = g_main_context_new ();
-  self->loop = g_main_loop_new (self->context, FALSE);
-  g_main_context_push_thread_default (self->context);
-
-  /* Set a timeout source */
-  self->timeout_source = g_timeout_source_new_seconds (3);
-  g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
-      self, NULL);
-  g_source_attach (self->timeout_source, self->context);
-
-  /* Create the core */
-  props = wp_properties_new (PW_KEY_REMOTE_NAME, self->server.name, NULL);
-  self->core = wp_core_new (self->context, props);
-  g_signal_connect (self->core, "disconnected",
-      (GCallback) disconnected_callback, self);
+  pw_thread_loop_unlock (self->base.server.thread_loop);
 
   /* Register the wp-endpoint-audiotestsrc */
-  wp_factory_new (self->core, "wp-endpoint-audiotestsrc",
+  wp_factory_new (self->base.core, "wp-endpoint-audiotestsrc",
       wp_endpoint_audiotestsrc_factory);
 }
 
 static void
 config_endpoint_teardown (TestConfigEndpointFixture *self, gconstpointer data)
 {
-  g_clear_object (&self->core);
-  g_clear_pointer (&self->timeout_source, g_source_unref);
-  g_clear_pointer (&self->loop, g_main_loop_unref);
-  g_clear_pointer (&self->context, g_main_context_unref);
-  wp_test_server_teardown (&self->server);
+  wp_base_test_fixture_teardown (&self->base);
 }
 
 static void
@@ -96,20 +47,20 @@ on_audiotestsrc_created (WpConfigEndpointContext *ctx, WpEndpoint *ep,
     TestConfigEndpointFixture *f)
 {
   g_assert_nonnull (ep);
-  g_main_loop_quit (f->loop);
+  g_main_loop_quit (f->base.loop);
 }
 
 static void
 basic (TestConfigEndpointFixture *f, gconstpointer data)
 {
   /* Set the configuration path */
-  g_autoptr (WpConfiguration) config = wp_configuration_get_instance (f->core);
+  g_autoptr (WpConfiguration) config = wp_configuration_get_instance (f->base.core);
   g_assert_nonnull (config);
   wp_configuration_add_path (config, "config-endpoint/basic");
 
   /* Create the context and handle the endpoint-created callback */
   g_autoptr (WpConfigEndpointContext) ctx =
-      wp_config_endpoint_context_new (f->core);
+      wp_config_endpoint_context_new (f->base.core);
   g_assert_nonnull (ctx);
   g_assert_cmpint (wp_config_endpoint_context_get_length (ctx), ==, 0);
 
@@ -117,11 +68,8 @@ basic (TestConfigEndpointFixture *f, gconstpointer data)
   g_signal_connect (ctx, "endpoint-created",
       (GCallback) on_audiotestsrc_created, f);
 
-  /* Connect */
-  g_assert_true (wp_core_connect (f->core));
-
   /* Run the main loop */
-  g_main_loop_run (f->loop);
+  g_main_loop_run (f->base.loop);
 
   /* Check if the endpoint was created */
   g_assert_cmpint (wp_config_endpoint_context_get_length (ctx), ==, 1);
diff --git a/tests/modules/config-policy.c b/tests/modules/config-policy.c
index c2f06ef2a2ba584a11f665dbcbda9280e72a9602..53c293095dafe82eacf3700712e701d77c1fdf59 100644
--- a/tests/modules/config-policy.c
+++ b/tests/modules/config-policy.c
@@ -6,80 +6,30 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include <pipewire/pipewire.h>
-
-#include <wp/wp.h>
-
+#include "../common/base-test-fixture.h"
 #include "config-policy/context.h"
-#include "../common/test-server.h"
 
 typedef struct {
-  WpTestServer server;
-  GMainContext *context;
-  GMainLoop *loop;
-  GSource *timeout_source;
-  WpCore *core;
+  WpBaseTestFixture base;
 } TestConfigPolicyFixture;
 
-static gboolean
-timeout_callback (TestConfigPolicyFixture *self)
-{
-  g_message ("test timed out");
-  g_test_fail ();
-  g_main_loop_quit (self->loop);
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-disconnected_callback (WpCore *core, TestConfigPolicyFixture *self)
-{
-  g_message ("core disconnected");
-  g_test_fail ();
-  g_main_loop_quit (self->loop);
-}
-
 static void
 config_policy_setup (TestConfigPolicyFixture *self, gconstpointer user_data)
 {
-  g_autoptr (WpProperties) props = NULL;
-
-  /* Create the server and load audioconvert plugin */
-  wp_test_server_setup (&self->server);
-
-  /* Create the main context and loop */
-  self->context = g_main_context_new ();
-  self->loop = g_main_loop_new (self->context, FALSE);
-  g_main_context_push_thread_default (self->context);
-
-  /* Set a timeout source */
-  self->timeout_source = g_timeout_source_new_seconds (3);
-  g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
-      self, NULL);
-  g_source_attach (self->timeout_source, self->context);
-
-  /* Create the core */
-  props = wp_properties_new (PW_KEY_REMOTE_NAME, self->server.name, NULL);
-  self->core = wp_core_new (self->context, props);
-  g_signal_connect (self->core, "disconnected",
-      (GCallback) disconnected_callback, self);
+  wp_base_test_fixture_setup (&self->base, 0);
 }
 
 static void
 config_policy_teardown (TestConfigPolicyFixture *self, gconstpointer user_data)
 {
-  g_clear_object (&self->core);
-  g_clear_pointer (&self->timeout_source, g_source_unref);
-  g_clear_pointer (&self->loop, g_main_loop_unref);
-  g_clear_pointer (&self->context, g_main_context_unref);
-  wp_test_server_teardown (&self->server);
+  wp_base_test_fixture_teardown (&self->base);
 }
 
 static void
 playback (TestConfigPolicyFixture *f, gconstpointer data)
 {
-  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (f->core,
-      f->loop, "config-policy/config-playback");
+  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
+      f->base.core, f->base.loop, "config-policy/config-playback");
   WpBaseEndpointLink *link = NULL;
   g_autoptr (WpBaseEndpoint) src = NULL;
   g_autoptr (WpBaseEndpoint) sink = NULL;
@@ -87,9 +37,6 @@ playback (TestConfigPolicyFixture *f, gconstpointer data)
   g_autoptr (WpBaseEndpoint) ep2 = NULL;
   g_autoptr (WpBaseEndpoint) ep3 = NULL;
 
-  /* Connect */
-  g_assert_true (wp_core_connect (f->core));
-
   /* Create the device endpoint */
   ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Fake/Sink",
       PW_DIRECTION_INPUT, NULL, NULL, 0);
@@ -131,17 +78,14 @@ playback (TestConfigPolicyFixture *f, gconstpointer data)
 static void
 capture (TestConfigPolicyFixture *f, gconstpointer data)
 {
-  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (f->core,
-      f->loop, "config-policy/config-capture");
+  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
+      f->base.core, f->base.loop, "config-policy/config-capture");
   WpBaseEndpointLink *link = NULL;
   g_autoptr (WpBaseEndpoint) src = NULL;
   g_autoptr (WpBaseEndpoint) sink = NULL;
   g_autoptr (WpBaseEndpoint) ep1 = NULL;
   g_autoptr (WpBaseEndpoint) ep2 = NULL;
 
-  /* Connect */
-  g_assert_true (wp_core_connect (f->core));
-
   /* Create the device endpoint */
   ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Fake/Source",
       PW_DIRECTION_OUTPUT, NULL, NULL, 0);
@@ -167,8 +111,8 @@ capture (TestConfigPolicyFixture *f, gconstpointer data)
 static void
 playback_capture (TestConfigPolicyFixture *f, gconstpointer data)
 {
-  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (f->core,
-      f->loop, "config-policy/config-playback-capture");
+  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
+      f->base.core, f->base.loop, "config-policy/config-playback-capture");
   WpBaseEndpointLink *link = NULL;
   g_autoptr (WpBaseEndpoint) src = NULL;
   g_autoptr (WpBaseEndpoint) sink = NULL;
@@ -177,9 +121,6 @@ playback_capture (TestConfigPolicyFixture *f, gconstpointer data)
   g_autoptr (WpBaseEndpoint) ep3 = NULL;
   g_autoptr (WpBaseEndpoint) ep4 = NULL;
 
-  /* Connect */
-  g_assert_true (wp_core_connect (f->core));
-
   /* Create the device endpoints */
   ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Fake/Sink",
       PW_DIRECTION_INPUT, NULL, NULL, 0);
@@ -225,8 +166,8 @@ playback_capture (TestConfigPolicyFixture *f, gconstpointer data)
 static void
 playback_priority (TestConfigPolicyFixture *f, gconstpointer data)
 {
-  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (f->core,
-      f->loop, "config-policy/config-playback-priority");
+  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
+      f->base.core, f->base.loop, "config-policy/config-playback-priority");
   WpBaseEndpointLink *link = NULL;
   g_autoptr (WpBaseEndpoint) src = NULL;
   g_autoptr (WpBaseEndpoint) sink = NULL;
@@ -237,9 +178,6 @@ playback_priority (TestConfigPolicyFixture *f, gconstpointer data)
   g_autoptr (WpBaseEndpoint) ep4 = NULL;
   g_autoptr (WpBaseEndpoint) ep5 = NULL;
 
-  /* Connect */
-  g_assert_true (wp_core_connect (f->core));
-
   /* Create the device endpoint with 4 streams */
   dev = wp_config_policy_context_add_endpoint (ctx, "dev", "Fake/Sink",
       PW_DIRECTION_INPUT, NULL, NULL, 4);
@@ -318,8 +256,8 @@ playback_priority (TestConfigPolicyFixture *f, gconstpointer data)
 static void
 playback_keep (TestConfigPolicyFixture *f, gconstpointer data)
 {
-  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (f->core,
-      f->loop, "config-policy/config-playback-keep");
+  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
+      f->base.core, f->base.loop, "config-policy/config-playback-keep");
   WpBaseEndpointLink *link = NULL;
   g_autoptr (WpBaseEndpoint) src = NULL;
   g_autoptr (WpBaseEndpoint) sink = NULL;
@@ -327,9 +265,6 @@ playback_keep (TestConfigPolicyFixture *f, gconstpointer data)
   g_autoptr (WpBaseEndpoint) ep2 = NULL;
   g_autoptr (WpBaseEndpoint) ep3 = NULL;
 
-  /* Connect */
-  g_assert_true (wp_core_connect (f->core));
-
   /* Create the device endpoint */
   ep1 = wp_config_policy_context_add_endpoint (ctx, "ep1", "Fake/Sink",
       PW_DIRECTION_INPUT, NULL, NULL, 0);
@@ -371,8 +306,8 @@ playback_keep (TestConfigPolicyFixture *f, gconstpointer data)
 static void
 playback_role (TestConfigPolicyFixture *f, gconstpointer data)
 {
-  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (f->core,
-      f->loop, "config-policy/config-playback-role");
+  g_autoptr (WpConfigPolicyContext) ctx = wp_config_policy_context_new (
+      f->base.core, f->base.loop, "config-policy/config-playback-role");
   WpBaseEndpointLink *link = NULL;
   g_autoptr (WpBaseEndpoint) src = NULL;
   g_autoptr (WpBaseEndpoint) sink = NULL;
@@ -381,9 +316,6 @@ playback_role (TestConfigPolicyFixture *f, gconstpointer data)
   g_autoptr (WpBaseEndpoint) ep2 = NULL;
   g_autoptr (WpBaseEndpoint) ep3 = NULL;
 
-  /* Connect */
-  g_assert_true (wp_core_connect (f->core));
-
   /* Create the device with 2 roles: "0" with id 0, and "1" with id 1 */
   dev = wp_config_policy_context_add_endpoint (ctx, "dev", "Fake/Sink",
       PW_DIRECTION_INPUT, NULL, NULL, 2);
diff --git a/tests/modules/config-static-nodes.c b/tests/modules/config-static-nodes.c
index c04e750256eca81ec28664e5b5e909b516666fc3..4f173fb1f60e1f3561e0bb921fe98a7b09727146 100644
--- a/tests/modules/config-static-nodes.c
+++ b/tests/modules/config-static-nodes.c
@@ -6,81 +6,33 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include <pipewire/pipewire.h>
-
-#include <wp/wp.h>
-
-#include "../common/test-server.h"
+#include "../common/base-test-fixture.h"
 #include "../../modules/module-config-static-nodes/context.h"
 
 typedef struct {
-  WpTestServer server;
-  GMainContext *context;
-  GMainLoop *loop;
-  GSource *timeout_source;
-  WpCore *core;
+  WpBaseTestFixture base;
 } TestConfigStaticNodesFixture;
 
-static gboolean
-timeout_callback (TestConfigStaticNodesFixture *self)
-{
-  g_message ("test timed out");
-  g_test_fail ();
-  g_main_loop_quit (self->loop);
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-disconnected_callback (WpCore *core, TestConfigStaticNodesFixture *self)
-{
-  g_message ("core disconnected");
-  g_test_fail ();
-  g_main_loop_quit (self->loop);
-}
-
 static void
 config_static_nodes_setup (TestConfigStaticNodesFixture *self,
     gconstpointer data)
 {
-  g_autoptr (WpProperties) props = NULL;
+  wp_base_test_fixture_setup (&self->base, WP_BASE_TEST_FLAG_DONT_CONNECT);
 
-  /* Create the server and load audioconvert plugin */
-  wp_test_server_setup (&self->server);
-  pw_thread_loop_lock (self->server.thread_loop);
-  pw_context_add_spa_lib (self->server.context, "audio.convert*",
+  /* load audioconvert plugin */
+  pw_thread_loop_lock (self->base.server.thread_loop);
+  pw_context_add_spa_lib (self->base.server.context, "audio.convert*",
       "audioconvert/libspa-audioconvert");
-  pw_context_load_module (self->server.context,
+  pw_context_load_module (self->base.server.context,
       "libpipewire-module-spa-node-factory", NULL, NULL);
-  pw_thread_loop_unlock (self->server.thread_loop);
-
-  /* Create the main context and loop */
-  self->context = g_main_context_new ();
-  self->loop = g_main_loop_new (self->context, FALSE);
-  g_main_context_push_thread_default (self->context);
-
-  /* Set a timeout source */
-  self->timeout_source = g_timeout_source_new_seconds (3);
-  g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
-      self, NULL);
-  g_source_attach (self->timeout_source, self->context);
-
-  /* Create the core */
-  props = wp_properties_new (PW_KEY_REMOTE_NAME, self->server.name, NULL);
-  self->core = wp_core_new (self->context, props);
-  g_signal_connect (self->core, "disconnected",
-      (GCallback) disconnected_callback, self);
+  pw_thread_loop_unlock (self->base.server.thread_loop);
 }
 
 static void
 config_static_nodes_teardown (TestConfigStaticNodesFixture *self,
     gconstpointer data)
 {
-  g_clear_object (&self->core);
-  g_clear_pointer (&self->timeout_source, g_source_unref);
-  g_clear_pointer (&self->loop, g_main_loop_unref);
-  g_clear_pointer (&self->context, g_main_context_unref);
-  wp_test_server_teardown (&self->server);
+  wp_base_test_fixture_teardown (&self->base);
 }
 
 static void
@@ -88,20 +40,20 @@ on_node_created (WpConfigStaticNodesContext *ctx, WpProxy *proxy,
     TestConfigStaticNodesFixture *f)
 {
   g_assert_nonnull (proxy);
-  g_main_loop_quit (f->loop);
+  g_main_loop_quit (f->base.loop);
 }
 
 static void
 basic (TestConfigStaticNodesFixture *f, gconstpointer data)
 {
   /* Set the configuration path */
-  g_autoptr (WpConfiguration) config = wp_configuration_get_instance (f->core);
+  g_autoptr (WpConfiguration) config = wp_configuration_get_instance (f->base.core);
   g_assert_nonnull (config);
   wp_configuration_add_path (config, "config-static-nodes/basic");
 
   /* Create the context */
   g_autoptr (WpConfigStaticNodesContext) ctx =
-      wp_config_static_nodes_context_new (f->core);
+      wp_config_static_nodes_context_new (f->base.core);
   g_assert_nonnull (ctx);
   g_assert_cmpint (wp_config_static_nodes_context_get_length (ctx), ==, 0);
 
@@ -109,10 +61,10 @@ basic (TestConfigStaticNodesFixture *f, gconstpointer data)
   g_signal_connect (ctx, "node-created", (GCallback) on_node_created, f);
 
   /* Connect */
-  g_assert_true (wp_core_connect (f->core));
+  g_assert_true (wp_core_connect (f->base.core));
 
   /* Run the main loop */
-  g_main_loop_run (f->loop);
+  g_main_loop_run (f->base.loop);
 
   /* Check if the node was created */
   g_assert_cmpint (wp_config_static_nodes_context_get_length (ctx), ==, 1);
diff --git a/tests/wp/endpoint.c b/tests/wp/endpoint.c
index b3df220448def4b1c94643699ba9244d2b45764f..7429591f92e98a8443f5433c41057a6cab2a5521 100644
--- a/tests/wp/endpoint.c
+++ b/tests/wp/endpoint.c
@@ -6,11 +6,8 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include <wp/wp.h>
-#include <pipewire/pipewire.h>
-#include <pipewire/extensions/session-manager.h>
-
-#include "../common/test-server.h"
+#include "../common/base-test-fixture.h"
+#include <pipewire/extensions/session-manager/keys.h>
 
 struct _TestSiEndpoint
 {
@@ -115,20 +112,9 @@ test_si_endpoint_class_init (TestSiEndpointClass * klass)
 /*******************/
 
 typedef struct {
-  /* the local pipewire server */
-  WpTestServer server;
-
-  /* the main loop */
-  GMainContext *context;
-  GMainLoop *loop;
-  GSource *timeout_source;
+  WpBaseTestFixture base;
 
-  /* the client that exports */
-  WpCore *export_core;
   WpObjectManager *export_om;
-
-  /* the client that receives a proxy */
-  WpCore *proxy_core;
   WpObjectManager *proxy_om;
 
   WpProxy *impl_endpoint;
@@ -138,80 +124,20 @@ typedef struct {
 
 } TestEndpointFixture;
 
-static gboolean
-timeout_callback (TestEndpointFixture *fixture)
-{
-  g_message ("test timed out");
-  g_test_fail ();
-  g_main_loop_quit (fixture->loop);
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-test_endpoint_disconnected (WpCore *core, TestEndpointFixture *fixture)
-{
-  g_message ("core disconnected");
-  g_test_fail ();
-  g_main_loop_quit (fixture->loop);
-}
-
 static void
 test_endpoint_setup (TestEndpointFixture *self, gconstpointer user_data)
 {
-  wp_spa_type_init (TRUE);
-
-  g_autoptr (WpProperties) props = NULL;
-
-  wp_test_server_setup (&self->server);
-  pw_thread_loop_lock (self->server.thread_loop);
-  if (!pw_context_load_module (self->server.context,
-      "libpipewire-module-session-manager", NULL, NULL)) {
-    pw_thread_loop_unlock (self->server.thread_loop);
-    g_test_skip ("libpipewire-module-session-manager is not installed");
-    return;
-  }
-  pw_thread_loop_unlock (self->server.thread_loop);
-
-  props = wp_properties_new (PW_KEY_REMOTE_NAME, self->server.name, NULL);
-  self->context = g_main_context_new ();
-  self->loop = g_main_loop_new (self->context, FALSE);
-
-  self->export_core = wp_core_new (self->context, props);
+  wp_base_test_fixture_setup (&self->base, WP_BASE_TEST_FLAG_CLIENT_CORE);
   self->export_om = wp_object_manager_new ();
-
-  self->proxy_core = wp_core_new (self->context, props);
   self->proxy_om = wp_object_manager_new ();
-
-  g_main_context_push_thread_default (self->context);
-
-  /* watchdogs */
-  g_signal_connect (self->export_core, "disconnected",
-      (GCallback) test_endpoint_disconnected, self);
-  g_signal_connect (self->proxy_core, "disconnected",
-      (GCallback) test_endpoint_disconnected, self);
-
-  self->timeout_source = g_timeout_source_new_seconds (3);
-  g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
-      self, NULL);
-  g_source_attach (self->timeout_source, self->context);
 }
 
 static void
 test_endpoint_teardown (TestEndpointFixture *self, gconstpointer user_data)
 {
-  g_main_context_pop_thread_default (self->context);
-
   g_clear_object (&self->proxy_om);
-  g_clear_object (&self->proxy_core);
   g_clear_object (&self->export_om);
-  g_clear_object (&self->export_core);
-  g_clear_pointer (&self->timeout_source, g_source_unref);
-  g_clear_pointer (&self->loop, g_main_loop_unref);
-  g_clear_pointer (&self->context, g_main_context_unref);
-  wp_test_server_teardown (&self->server);
-
-  wp_spa_type_deinit ();
+  wp_base_test_fixture_teardown (&self->base);
 }
 
 static void
@@ -227,7 +153,7 @@ test_endpoint_basic_impl_object_added (WpObjectManager *om,
   fixture->impl_endpoint = WP_PROXY (endpoint);
 
   if (++fixture->n_events == 3)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -243,7 +169,7 @@ test_endpoint_basic_impl_object_removed (WpObjectManager *om,
   fixture->impl_endpoint = NULL;
 
   if (++fixture->n_events == 2)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -259,7 +185,7 @@ test_endpoint_basic_proxy_object_added (WpObjectManager *om,
   fixture->proxy_endpoint = WP_PROXY (endpoint);
 
   if (++fixture->n_events == 3)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -275,7 +201,7 @@ test_endpoint_basic_proxy_object_removed (WpObjectManager *om,
   fixture->proxy_endpoint = NULL;
 
   if (++fixture->n_events == 2)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -302,7 +228,7 @@ test_endpoint_basic_export_done (WpSessionItem * item, GAsyncResult * res,
   g_assert_no_error (error);
 
   if (++fixture->n_events == 3)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -318,7 +244,7 @@ test_endpoint_basic_session_bound (WpProxy * session, GAsyncResult * res,
 
   g_assert_true (WP_IS_IMPL_SESSION (session));
 
-  g_main_loop_quit (fixture->loop);
+  g_main_loop_quit (fixture->base.loop);
 }
 
 #if 0
@@ -331,7 +257,7 @@ test_endpoint_basic_control_changed (WpEndpoint * endpoint,
   g_assert_true (WP_IS_ENDPOINT (endpoint));
 
   if (++fixture->n_events == 2)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -343,7 +269,7 @@ test_endpoint_basic_notify_properties (WpEndpoint * endpoint, GParamSpec * param
   g_assert_true (WP_IS_ENDPOINT (endpoint));
 
   if (++fixture->n_events == 2)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 #endif
 
@@ -364,9 +290,7 @@ test_endpoint_basic (TestEndpointFixture *fixture, gconstpointer data)
   wp_object_manager_add_interest (fixture->export_om,
       WP_TYPE_ENDPOINT, NULL,
       WP_PROXY_FEATURES_STANDARD | WP_PROXY_FEATURE_CONTROLS);
-  wp_core_install_object_manager (fixture->export_core, fixture->export_om);
-
-  g_assert_true (wp_core_connect (fixture->export_core));
+  wp_core_install_object_manager (fixture->base.core, fixture->export_om);
 
   /* set up the proxy side */
   g_signal_connect (fixture->proxy_om, "object-added",
@@ -376,17 +300,15 @@ test_endpoint_basic (TestEndpointFixture *fixture, gconstpointer data)
   wp_object_manager_add_interest (fixture->proxy_om,
       WP_TYPE_ENDPOINT, NULL,
       WP_PROXY_FEATURES_STANDARD | WP_PROXY_FEATURE_CONTROLS);
-  wp_core_install_object_manager (fixture->proxy_core, fixture->proxy_om);
-
-  g_assert_true (wp_core_connect (fixture->proxy_core));
+  wp_core_install_object_manager (fixture->base.client_core, fixture->proxy_om);
 
   /* create session */
-  session = wp_impl_session_new (fixture->export_core);
+  session = wp_impl_session_new (fixture->base.core);
   wp_proxy_augment (WP_PROXY (session), WP_PROXY_FEATURE_BOUND, NULL,
       (GAsyncReadyCallback) test_endpoint_basic_session_bound, fixture);
 
   /* run until session is bound */
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (wp_proxy_get_features (WP_PROXY (session)), &,
       WP_PROXY_FEATURE_BOUND);
   g_assert_cmpint (wp_proxy_get_bound_id (WP_PROXY (session)), >, 0);
@@ -405,7 +327,7 @@ test_endpoint_basic (TestEndpointFixture *fixture, gconstpointer data)
 
   /* run until objects are created and features are cached */
   fixture->n_events = 0;
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 3);
   g_assert_nonnull (fixture->impl_endpoint);
   g_assert_nonnull (fixture->proxy_endpoint);
@@ -477,7 +399,7 @@ test_endpoint_basic (TestEndpointFixture *fixture, gconstpointer data)
 
   /* run until the change is on both sides */
   fixture->n_events = 0;
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 2);
 
   /* test round 2: verify the value change on both sides */
@@ -506,7 +428,7 @@ test_endpoint_basic (TestEndpointFixture *fixture, gconstpointer data)
   g_assert_true (wp_endpoint_set_control (WP_ENDPOINT (endpoint), "mute", ctrl));
 
   /* run until the change is on both sides */
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 2);
 
   /* test round 3: verify the value change on both sides */
@@ -534,7 +456,7 @@ test_endpoint_basic (TestEndpointFixture *fixture, gconstpointer data)
   wp_impl_endpoint_set_property (endpoint, "test.property", "changed-value");
 
   /* run until the change is on both sides */
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 2);
 
   /* test round 4: verify the property change on both sides */
@@ -558,7 +480,7 @@ test_endpoint_basic (TestEndpointFixture *fixture, gconstpointer data)
   g_clear_object (&endpoint);
 
   /* run until objects are destroyed */
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 2);
   g_assert_null (fixture->impl_endpoint);
   g_assert_null (fixture->proxy_endpoint);
diff --git a/tests/wp/proxy.c b/tests/wp/proxy.c
index dc2cf4ca56bbd95cebe0694cb7e50bb3d5990af4..d10fad5b64fabe3512462d75b1ccd6e1acb44133 100644
--- a/tests/wp/proxy.c
+++ b/tests/wp/proxy.c
@@ -6,83 +6,28 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include <wp/wp.h>
-#include <pipewire/pipewire.h>
-#include <spa/pod/iter.h>
-
-#include "../common/test-server.h"
+#include "../common/base-test-fixture.h"
 
 typedef struct {
-  /* the local pipewire server */
-  WpTestServer server;
-
-  /* the main loop */
-  GMainContext *context;
-  GMainLoop *loop;
-  GSource *timeout_source;
-
-  /* the client wireplumber core */
-  WpCore *core;
+  WpBaseTestFixture base;
 
   /* the object manager that listens for proxies */
   WpObjectManager *om;
 
 } TestProxyFixture;
 
-static gboolean
-timeout_callback (TestProxyFixture *fixture)
-{
-  g_message ("test timed out");
-  g_test_fail ();
-  g_main_loop_quit (fixture->loop);
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-test_proxy_disconnected (WpCore *core, TestProxyFixture *fixture)
-{
-  g_message ("core disconnected");
-  g_test_fail ();
-  g_main_loop_quit (fixture->loop);
-}
-
 static void
 test_proxy_setup (TestProxyFixture *self, gconstpointer user_data)
 {
-  g_autoptr (WpProperties) props = NULL;
-
-  wp_test_server_setup (&self->server);
-
-  props = wp_properties_new (PW_KEY_REMOTE_NAME, self->server.name, NULL);
-  self->context = g_main_context_new ();
-  self->loop = g_main_loop_new (self->context, FALSE);
-  self->core = wp_core_new (self->context, props);
+  wp_base_test_fixture_setup (&self->base, 0);
   self->om = wp_object_manager_new ();
-
-  g_main_context_push_thread_default (self->context);
-
-  /* watchdogs */
-  g_signal_connect (self->core, "disconnected",
-      (GCallback) test_proxy_disconnected, self);
-
-  self->timeout_source = g_timeout_source_new_seconds (3);
-  g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
-      self, NULL);
-  g_source_attach (self->timeout_source, self->context);
 }
 
 static void
 test_proxy_teardown (TestProxyFixture *self, gconstpointer user_data)
 {
-  g_main_context_pop_thread_default (self->context);
-
   g_clear_object (&self->om);
-  g_clear_object (&self->core);
-  g_clear_pointer (&self->timeout_source, g_source_unref);
-  g_clear_pointer (&self->loop, g_main_loop_unref);
-  g_clear_pointer (&self->context, g_main_context_unref);
-  wp_test_server_teardown (&self->server);
+  wp_base_test_fixture_teardown (&self->base);
 }
 
 static void
@@ -96,7 +41,7 @@ test_proxy_basic_augmented (WpProxy *proxy, GAsyncResult *res,
   g_assert_true (wp_proxy_get_features (proxy) & WP_PROXY_FEATURE_PW_PROXY);
   g_assert_nonnull (wp_proxy_get_pw_proxy (proxy));
 
-  g_main_loop_quit (fixture->loop);
+  g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -139,10 +84,9 @@ test_proxy_basic (TestProxyFixture *fixture, gconstpointer data)
       (GCallback) test_proxy_basic_object_added, fixture);
 
   wp_object_manager_add_interest (fixture->om, WP_TYPE_CLIENT, NULL, 0);
-  wp_core_install_object_manager (fixture->core, fixture->om);
+  wp_core_install_object_manager (fixture->base.core, fixture->om);
 
-  g_assert_true (wp_core_connect (fixture->core));
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
 }
 
 typedef struct {
@@ -177,7 +121,7 @@ test_node_enum_params_done (WpProxy *node, GAsyncResult *res,
     g_assert_cmpstr ("PropInfo", ==, wp_spa_pod_get_object_type_name (pod));
   }
 
-  g_main_loop_quit (data->fixture->loop);
+  g_main_loop_quit (data->fixture->base.loop);
   g_free (data);
 }
 
@@ -223,16 +167,16 @@ static void
 test_node (TestProxyFixture *fixture, gconstpointer data)
 {
   /* load audiotestsrc on the server side */
-  pw_thread_loop_lock (fixture->server.thread_loop);
-  pw_context_add_spa_lib (fixture->server.context, "audiotestsrc",
+  pw_thread_loop_lock (fixture->base.server.thread_loop);
+  pw_context_add_spa_lib (fixture->base.server.context, "audiotestsrc",
       "audiotestsrc/libspa-audiotestsrc");
-  if (!pw_context_load_module (fixture->server.context,
+  if (!pw_context_load_module (fixture->base.server.context,
         "libpipewire-module-spa-node", "audiotestsrc", NULL)) {
-    pw_thread_loop_unlock (fixture->server.thread_loop);
+    pw_thread_loop_unlock (fixture->base.server.thread_loop);
     g_test_skip ("audiotestsrc SPA plugin is not installed");
     return;
   }
-  pw_thread_loop_unlock (fixture->server.thread_loop);
+  pw_thread_loop_unlock (fixture->base.server.thread_loop);
 
   /* we should be able to see this exported audiotestsrc node on the client */
   g_signal_connect (fixture->om, "object-added",
@@ -242,10 +186,9 @@ test_node (TestProxyFixture *fixture, gconstpointer data)
      when the signal is fired */
   wp_object_manager_add_interest (fixture->om,
       WP_TYPE_NODE, NULL, WP_PROXY_FEATURES_STANDARD);
-  wp_core_install_object_manager (fixture->core, fixture->om);
+  wp_core_install_object_manager (fixture->base.core, fixture->om);
 
-  g_assert_true (wp_core_connect (fixture->core));
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
 }
 
 gint
diff --git a/tests/wp/session.c b/tests/wp/session.c
index 491dc620903b3486c20d0ee19d2a901d6981687d..e07834ec8f50496ccb1c77cbe9766ef11ad27ab0 100644
--- a/tests/wp/session.c
+++ b/tests/wp/session.c
@@ -6,27 +6,13 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include <wp/wp.h>
-#include <pipewire/pipewire.h>
-#include <pipewire/extensions/session-manager.h>
-
-#include "../common/test-server.h"
+#include "../common/base-test-fixture.h"
+#include <pipewire/extensions/session-manager/keys.h>
 
 typedef struct {
-  /* the local pipewire server */
-  WpTestServer server;
-
-  /* the main loop */
-  GMainContext *context;
-  GMainLoop *loop;
-  GSource *timeout_source;
+  WpBaseTestFixture base;
 
-  /* the client that exports */
-  WpCore *export_core;
   WpObjectManager *export_om;
-
-  /* the client that receives a proxy */
-  WpCore *proxy_core;
   WpObjectManager *proxy_om;
 
   WpImplSession *impl_session;
@@ -36,81 +22,20 @@ typedef struct {
 
 } TestSessionFixture;
 
-static gboolean
-timeout_callback (TestSessionFixture *fixture)
-{
-  g_message ("test timed out");
-  g_test_fail ();
-  g_main_loop_quit (fixture->loop);
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-test_session_disconnected (WpCore *core, TestSessionFixture *fixture)
-{
-  g_message ("core disconnected");
-  g_test_fail ();
-  g_main_loop_quit (fixture->loop);
-}
-
 static void
 test_session_setup (TestSessionFixture *self, gconstpointer user_data)
 {
-  /* Register custom wireplumber session types */
-  wp_spa_type_init (TRUE);
-
-  g_autoptr (WpProperties) props = NULL;
-
-  wp_test_server_setup (&self->server);
-  pw_thread_loop_lock (self->server.thread_loop);
-  if (!pw_context_load_module (self->server.context,
-      "libpipewire-module-session-manager", NULL, NULL)) {
-    pw_thread_loop_unlock (self->server.thread_loop);
-    g_test_skip ("libpipewire-module-session-manager is not installed");
-    return;
-  }
-  pw_thread_loop_unlock (self->server.thread_loop);
-
-  props = wp_properties_new (PW_KEY_REMOTE_NAME, self->server.name, NULL);
-  self->context = g_main_context_new ();
-  self->loop = g_main_loop_new (self->context, FALSE);
-
-  self->export_core = wp_core_new (self->context, props);
+  wp_base_test_fixture_setup (&self->base, WP_BASE_TEST_FLAG_CLIENT_CORE);
   self->export_om = wp_object_manager_new ();
-
-  self->proxy_core = wp_core_new (self->context, props);
   self->proxy_om = wp_object_manager_new ();
-
-  g_main_context_push_thread_default (self->context);
-
-  /* watchdogs */
-  g_signal_connect (self->export_core, "disconnected",
-      (GCallback) test_session_disconnected, self);
-  g_signal_connect (self->proxy_core, "disconnected",
-      (GCallback) test_session_disconnected, self);
-
-  self->timeout_source = g_timeout_source_new_seconds (3);
-  g_source_set_callback (self->timeout_source, (GSourceFunc) timeout_callback,
-      self, NULL);
-  g_source_attach (self->timeout_source, self->context);
 }
 
 static void
 test_session_teardown (TestSessionFixture *self, gconstpointer user_data)
 {
-  g_main_context_pop_thread_default (self->context);
-
   g_clear_object (&self->proxy_om);
-  g_clear_object (&self->proxy_core);
   g_clear_object (&self->export_om);
-  g_clear_object (&self->export_core);
-  g_clear_pointer (&self->timeout_source, g_source_unref);
-  g_clear_pointer (&self->loop, g_main_loop_unref);
-  g_clear_pointer (&self->context, g_main_context_unref);
-  wp_test_server_teardown (&self->server);
-
-  wp_spa_type_deinit ();
+  wp_base_test_fixture_teardown (&self->base);
 }
 
 static void
@@ -125,7 +50,7 @@ test_session_basic_exported_object_added (WpObjectManager *om,
   fixture->impl_session = WP_IMPL_SESSION (session);
 
   if (++fixture->n_events == 3)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -140,7 +65,7 @@ test_session_basic_exported_object_removed (WpObjectManager *om,
   fixture->impl_session = NULL;
 
   if (++fixture->n_events == 2)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -155,7 +80,7 @@ test_session_basic_proxy_object_added (WpObjectManager *om,
   fixture->proxy_session = WP_PROXY (session);
 
   if (++fixture->n_events == 3)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -170,7 +95,7 @@ test_session_basic_proxy_object_removed (WpObjectManager *om,
   fixture->proxy_session = NULL;
 
   if (++fixture->n_events == 2)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -187,7 +112,7 @@ test_session_basic_export_done (WpProxy * session, GAsyncResult * res,
   g_assert_true (WP_IS_IMPL_SESSION (session));
 
   if (++fixture->n_events == 3)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -200,7 +125,7 @@ test_session_basic_default_endpoint_changed (WpSession * session,
   g_assert_true (WP_IS_SESSION (session));
 
   if (++fixture->n_events == 2)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -212,7 +137,7 @@ test_session_basic_notify_properties (WpSession * session, GParamSpec * param,
   g_assert_true (WP_IS_SESSION (session));
 
   if (++fixture->n_events == 2)
-    g_main_loop_quit (fixture->loop);
+    g_main_loop_quit (fixture->base.loop);
 }
 
 static void
@@ -228,9 +153,7 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data)
   wp_object_manager_add_interest (fixture->export_om,
       WP_TYPE_IMPL_SESSION, NULL,
       WP_SESSION_FEATURES_STANDARD);
-  wp_core_install_object_manager (fixture->export_core, fixture->export_om);
-
-  g_assert_true (wp_core_connect (fixture->export_core));
+  wp_core_install_object_manager (fixture->base.core, fixture->export_om);
 
   /* set up the proxy side */
   g_signal_connect (fixture->proxy_om, "object-added",
@@ -240,12 +163,10 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data)
   wp_object_manager_add_interest (fixture->proxy_om,
       WP_TYPE_SESSION, NULL,
       WP_SESSION_FEATURES_STANDARD);
-  wp_core_install_object_manager (fixture->proxy_core, fixture->proxy_om);
-
-  g_assert_true (wp_core_connect (fixture->proxy_core));
+  wp_core_install_object_manager (fixture->base.client_core, fixture->proxy_om);
 
   /* create session */
-  session = wp_impl_session_new (fixture->export_core);
+  session = wp_impl_session_new (fixture->base.core);
   wp_impl_session_set_property (session, "test.property", "test-value");
   wp_session_set_default_endpoint (WP_SESSION (session),
       "wp-session-default-endpoint-audio-sink", 5);
@@ -270,7 +191,7 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data)
 
   /* run until objects are created and features are cached */
   fixture->n_events = 0;
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 3);
   g_assert_nonnull (fixture->impl_session);
   g_assert_nonnull (fixture->proxy_session);
@@ -317,7 +238,7 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data)
 
   /* run until the change is on both sides */
   fixture->n_events = 0;
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 2);
 
   /* test round 2: verify the value change on both sides */
@@ -340,7 +261,7 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data)
       "wp-session-default-endpoint-audio-source", 44);
 
   /* run until the change is on both sides */
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 2);
 
   /* test round 3: verify the value change on both sides */
@@ -356,7 +277,7 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data)
   wp_impl_session_set_property (session, "test.property", "changed-value");
 
   /* run until the change is on both sides */
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 2);
 
   /* test round 4: verify the property change on both sides */
@@ -379,7 +300,7 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data)
   g_clear_object (&session);
 
   /* run until objects are destroyed */
-  g_main_loop_run (fixture->loop);
+  g_main_loop_run (fixture->base.loop);
   g_assert_cmpint (fixture->n_events, ==, 2);
   g_assert_null (fixture->impl_session);
   g_assert_null (fixture->proxy_session);