[Spice-devel] [spice-server v5 5/5] test-vdagent: Make test case more useful

Christophe Fergeau cfergeau at redhat.com
Tue Feb 28 12:21:56 UTC 2017


This switches the test to using the GTest API, and add several tests
related to https://bugzilla.redhat.com/show_bug.cgi?id=1411194

This uses some API not available in glib 2.28, so this checks we have a
new enough glib before building this test, and disables warnings when
using too new glib API when building it.

The "multiple-vmc-devices" is based off code written by Frediano Ziglio.

Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
---
 server/tests/Makefile.am    |  10 ++-
 server/tests/test-vdagent.c | 173 ++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 166 insertions(+), 17 deletions(-)

diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index af0bd20..816546c 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -45,6 +45,7 @@ check_PROGRAMS =				\
 	test-loop				\
 	test-qxl-parsing			\
 	test-stat-file				\
+	test-vdagent				\
 	$(NULL)
 
 noinst_PROGRAMS =				\
@@ -56,7 +57,6 @@ noinst_PROGRAMS =				\
 	test-playback				\
 	test-display-resolution-changes		\
 	test-two-servers			\
-	test-vdagent				\
 	test-display-width-stride		\
 	spice-server-replay			\
 	$(check_PROGRAMS)			\
@@ -112,6 +112,14 @@ libtest_stat4_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=1 -DTEST_RED_WORK
 
 test_qxl_parsing_LDADD = ../libserver.la $(LDADD)
 
+# Fallback implementations are provided for older glibs for the recent glib
+# methods this test is using, so no need to warn about them
+test_vdagent_CPPFLAGS =			\
+	$(AM_CPPFLAGS)			\
+	-UGLIB_VERSION_MIN_REQUIRED	\
+	-UGLIB_VERSION_MAX_ALLOWED	\
+	$(NULL)
+
 if HAVE_GSTREAMER
 test_gst_SOURCES = test-gst.c \
 	$(NULL)
diff --git a/server/tests/test-vdagent.c b/server/tests/test-vdagent.c
index e06229e..a4d48ee 100644
--- a/server/tests/test-vdagent.c
+++ b/server/tests/test-vdagent.c
@@ -37,14 +37,98 @@ int ping_ms = 100;
 #define MIN(a, b) ((a) > (b) ? (b) : (a))
 #endif
 
-static void pinger(SPICE_GNUC_UNUSED void *opaque)
+#if !GLIB_CHECK_VERSION(2, 34, 0)
+
+/* The code in this #ifdef block is taken from glib and is licensed under the
+ * GNU Lesser General Public License version 2 or later.
+ *
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Modified by the GLib Team and others 1997-2000.  See GLib AUTHORS
+ * file for a list of people on the GLib Team.
+ */
+
+typedef struct {
+    gchar *log_domain;
+    GLogLevelFlags log_level;
+    gchar *pattern;
+} GTestExpectedMessage;
+
+static GSList *expected_messages = NULL;
+
+static gboolean fatal_log_filter(const gchar *log_domain,
+                                 GLogLevelFlags log_level,
+                                 const gchar *msg,
+                                 gpointer user_data)
+{
+    GTestExpectedMessage *expected = expected_messages->data;
+
+    if ((g_strcmp0(expected->log_domain, log_domain) == 0)
+            && ((log_level & expected->log_level) == expected->log_level)
+            && (g_pattern_match_simple(expected->pattern, msg))) {
+        expected_messages = g_slist_delete_link(expected_messages,
+                                                expected_messages);
+        g_free (expected->log_domain);
+        g_free (expected->pattern);
+        g_free (expected);
+
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static void
+g_test_assert_expected_messages_internal (const char     *domain,
+                                          const char     *file,
+                                          int             line,
+                                          const char     *func)
+{
+  if (expected_messages)
+    {
+      GTestExpectedMessage *expected;
+      gchar *message;
+
+      expected = expected_messages->data;
+
+      message = g_strdup_printf ("Did not see expected message %s: %s",
+                                 expected->log_domain ? expected->log_domain : "**",
+                                 expected->pattern);
+      g_error ("%s", message);
+      g_free (message);
+    }
+}
+
+#define g_test_assert_expected_messages() g_test_assert_expected_messages_internal (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC)
+
+static void
+g_test_expect_message (const gchar    *log_domain,
+                       GLogLevelFlags  log_level,
+                       const gchar    *pattern)
 {
-    // show_channels is not thread safe - fails if disconnections / connections occur
-    //show_channels(server);
+  GTestExpectedMessage *expected;
 
-    core->timer_start(ping_timer, ping_ms);
+  g_return_if_fail (log_level != 0);
+  g_return_if_fail (pattern != NULL);
+  g_return_if_fail (~log_level & G_LOG_LEVEL_ERROR);
+
+  if (expected_messages == NULL)
+    {
+      g_test_log_set_fatal_handler(fatal_log_filter, NULL);
+    }
+
+  expected = g_new (GTestExpectedMessage, 1);
+  expected->log_domain = g_strdup (log_domain);
+  expected->log_level = log_level;
+  expected->pattern = g_strdup (pattern);
+
+  if ((log_level & G_LOG_LEVEL_MASK) <= G_LOG_LEVEL_WARNING)
+    {
+      expected_messages = g_slist_append (expected_messages, expected);
+    }
 }
 
+#endif /* GLIB_CHECK_VERSION(2, 34, 0) */
+
+
 static int vmc_write(SPICE_GNUC_UNUSED SpiceCharDeviceInstance *sin,
                      SPICE_GNUC_UNUSED const uint8_t *buf,
                      int len)
@@ -62,6 +146,13 @@ static int vmc_read(SPICE_GNUC_UNUSED SpiceCharDeviceInstance *sin,
     static unsigned message_size;
     int ret;
 
+    if (pos == sizeof(message)) {
+        g_message("sent whole message");
+        pos++; /* Only print message once */
+    }
+    if (pos > sizeof(message)) {
+        return 0;
+    }
     if (pos == 0) {
         VDIChunkHeader *hdr = (VDIChunkHeader *)message;
         VDAgentMessage *msg = (VDAgentMessage *)&hdr[1];
@@ -83,9 +174,6 @@ static int vmc_read(SPICE_GNUC_UNUSED SpiceCharDeviceInstance *sin,
     ret = MIN(message_size - pos, len);
     memcpy(buf, &message[pos], ret);
     pos += ret;
-    if (pos == message_size) {
-        pos = 0;
-    }
     //printf("vmc_read %d (ret %d)\n", len, ret);
     return ret;
 }
@@ -105,24 +193,77 @@ static SpiceCharDeviceInterface vmc_interface = {
     .read               = vmc_read,
 };
 
-SpiceCharDeviceInstance vmc_instance = {
+static SpiceCharDeviceInstance vmc_instance = {
     .subtype = "vdagent",
 };
 
-int main(void)
+static void test_multiple_vmc_devices(void)
 {
-    Test *test;
+    SpiceCharDeviceInstance vmc_instances[2] = {
+        { .subtype = "vdagent", },
+        { .subtype = "vdagent", }
+    };
+    int status;
 
-    core = basic_event_loop_init();
-    test = test_new(core);
+    SpiceCoreInterface *core = basic_event_loop_init();
+    Test *test = test_new(core);
 
+    g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
+                          "*spice_server_char_device_add_interface: vdagent already attached");
+    g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+                          "*spice_server_remove_interface: assertion ?char_device->st != NULL'*");
+    vmc_instances[0].base.sif = &vmc_interface.base;
+    spice_server_add_interface(test->server, &vmc_instances[0].base);
+    vmc_instances[1].base.sif = &vmc_interface.base;
+    spice_server_add_interface(test->server, &vmc_instances[1].base);
+    status = spice_server_remove_interface(&vmc_instances[1].base);
+    g_assert_cmpint(status, ==, -1);
+    status = spice_server_remove_interface(&vmc_instances[0].base);
+    g_assert_cmpint(status, ==, 0);
+    g_test_assert_expected_messages();
+    test_destroy(test);
+    basic_event_loop_destroy();
+}
+
+static void test_duplicate_removal(void)
+{
+    SpiceCoreInterface *core = basic_event_loop_init();
+    Test *test = test_new(core);
+    int status;
+
+    g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+                          "*spice_server_remove_interface: assertion ?char_device->st != NULL'*");
+    vmc_instance.base.sif = &vmc_interface.base;
+    spice_server_add_interface(test->server, &vmc_instance.base);
+    status = spice_server_remove_interface(&vmc_instance.base);
+    g_assert_cmpint(status, ==, 0);
+    status = spice_server_remove_interface(&vmc_instance.base);
+    g_assert_cmpint(status, ==, -1);
+    g_test_assert_expected_messages();
+    test_destroy(test);
+    basic_event_loop_destroy();
+}
+
+static void test_agent_to_server(void)
+{
+    SpiceCoreInterface *core = basic_event_loop_init();
+    Test *test = test_new(core);
+
+    g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "sent whole message");
     vmc_instance.base.sif = &vmc_interface.base;
     spice_server_add_interface(test->server, &vmc_instance.base);
+    g_test_assert_expected_messages();
+    test_destroy(test);
+    basic_event_loop_destroy();
+}
 
-    ping_timer = core->timer_add(pinger, NULL);
-    core->timer_start(ping_timer, ping_ms);
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
 
-    basic_event_loop_mainloop();
+    g_test_add_func("/server/vdagent/agent-to-server", test_agent_to_server);
+    g_test_add_func("/server/vdagent/duplicate-removal", test_duplicate_removal);
+    g_test_add_func("/server/vdagent/multiple-vmc-devices", test_multiple_vmc_devices);
 
-    return 0;
+    return g_test_run();
 }
-- 
2.9.3



More information about the Spice-devel mailing list