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

Frediano Ziglio fziglio at redhat.com
Wed Mar 1 16:48:35 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>

Acked-by: Frediano Ziglio <fziglio 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();
>  }


More information about the Spice-devel mailing list