[Spice-commits] cfg.mk server/tests

Frediano Ziglio fziglio at kemper.freedesktop.org
Fri Nov 25 13:53:06 UTC 2016


 cfg.mk                                          |    2 
 server/tests/Makefile.am                        |   78 +-
 server/tests/basic-event-loop.c                 |  137 +++
 server/tests/basic-event-loop.h                 |   29 
 server/tests/basic_event_loop.c                 |  137 ---
 server/tests/basic_event_loop.h                 |   29 
 server/tests/regression-test.py                 |   25 
 server/tests/regression_test.py                 |   25 
 server/tests/replay.c                           |    2 
 server/tests/spice-codecs-parsing-test.c        |  131 ---
 server/tests/spice-options-test.c               |   61 -
 server/tests/stat-file-test.c                   |  105 --
 server/tests/stream-test.c                      |  157 ----
 server/tests/test-codecs-parsing.c              |  131 +++
 server/tests/test-display-base.c                |  932 ++++++++++++++++++++++++
 server/tests/test-display-base.h                |  146 +++
 server/tests/test-display-no-ssl.c              |   72 +
 server/tests/test-display-resolution-changes.c  |   86 ++
 server/tests/test-display-streaming.c           |  253 ++++++
 server/tests/test-display-width-stride.c        |  121 +++
 server/tests/test-empty-success.c               |   93 ++
 server/tests/test-fail-on-null-core-interface.c |   30 
 server/tests/test-just-sockets-no-ssl.c         |   35 
 server/tests/test-loop.c                        |    2 
 server/tests/test-multiple.py                   |  121 +++
 server/tests/test-options.c                     |   61 +
 server/tests/test-playback.c                    |  126 +++
 server/tests/test-stat-file.c                   |  105 ++
 server/tests/test-stream.c                      |  157 ++++
 server/tests/test-two-servers.c                 |   54 +
 server/tests/test-vdagent.c                     |   75 +
 server/tests/test_display_base.c                |  932 ------------------------
 server/tests/test_display_base.h                |  146 ---
 server/tests/test_display_no_ssl.c              |   72 -
 server/tests/test_display_resolution_changes.c  |   86 --
 server/tests/test_display_streaming.c           |  253 ------
 server/tests/test_display_width_stride.c        |  121 ---
 server/tests/test_empty_success.c               |   93 --
 server/tests/test_fail_on_null_core_interface.c |   30 
 server/tests/test_just_sockets_no_ssl.c         |   35 
 server/tests/test_multiple.py                   |  121 ---
 server/tests/test_playback.c                    |  126 ---
 server/tests/test_two_servers.c                 |   54 -
 server/tests/test_vdagent.c                     |   75 -
 44 files changed, 2831 insertions(+), 2831 deletions(-)

New commits:
commit e05cf93a01501e8dd9325255a07c29ab529374fe
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Fri Nov 25 13:11:18 2016 +0000

    tests: Normalize test names
    
    Use dash instead of underscores for file names. This is coherent
    with rest of file names.
    Rename all tests to test-XXX and remove the spice- prefix when
    present. This is coherent with most of the tests.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/cfg.mk b/cfg.mk
index 3e5d345..4068309 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -142,7 +142,7 @@ exclude_file_name_regexp--sc_prohibit_have_config_h = ^*/.*(c|cpp|h)
 
 exclude_file_name_regexp--sc_unmarked_diagnostics = ^.*\.(c|py|h)
 
-exclude_file_name_regexp--sc_prohibit_path_max_allocation = server/tests/test_display_base.c
+exclude_file_name_regexp--sc_prohibit_path_max_allocation = server/tests/test-display-base.c
 
 exclude_file_name_regexp--sc_cast_of_argument_to_free = server/red-replay-qxl.c
 
diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index 626cd81..c55d21d 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -21,10 +21,10 @@ endif
 noinst_LIBRARIES = libtest.a
 
 libtest_a_SOURCES =				\
-	basic_event_loop.c			\
-	basic_event_loop.h			\
-	test_display_base.c			\
-	test_display_base.h			\
+	basic-event-loop.c			\
+	basic-event-loop.h			\
+	test-display-base.c			\
+	test-display-base.h			\
 	$(NULL)
 
 LDADD =								\
@@ -37,27 +37,27 @@ LDADD =								\
 	$(NULL)
 
 check_PROGRAMS =				\
-	spice-codecs-parsing-test		\
-	spice-options-test			\
-	stat_test				\
-	stream-test				\
+	test-codecs-parsing			\
+	test-options				\
+	test-stat				\
+	test-stream				\
 	test-agent-msg-filter			\
 	test-loop				\
 	test-qxl-parsing			\
-	stat-file-test				\
+	test-stat-file				\
 	$(NULL)
 
 noinst_PROGRAMS =				\
-	test_display_no_ssl			\
-	test_display_streaming			\
-	test_empty_success			\
-	test_fail_on_null_core_interface	\
-	test_just_sockets_no_ssl		\
-	test_playback				\
-	test_display_resolution_changes		\
-	test_two_servers			\
-	test_vdagent				\
-	test_display_width_stride		\
+	test-display-no-ssl			\
+	test-display-streaming			\
+	test-empty-success			\
+	test-fail-on-null-core-interface	\
+	test-just-sockets-no-ssl		\
+	test-playback				\
+	test-display-resolution-changes		\
+	test-two-servers			\
+	test-vdagent				\
+	test-display-width-stride		\
 	spice-server-replay			\
 	$(check_PROGRAMS)			\
 	$(NULL)
@@ -66,16 +66,16 @@ TESTS = $(check_PROGRAMS)			\
 	$(NULL)
 
 noinst_LIBRARIES += \
-	libstat_test1.a \
-	libstat_test2.a \
-	libstat_test3.a \
-	libstat_test4.a \
+	libtest-stat1.a \
+	libtest-stat2.a \
+	libtest-stat3.a \
+	libtest-stat4.a \
 	$(NULL)
 
 spice_server_replay_SOURCES = replay.c		\
 	../event-loop.c				\
-	basic_event_loop.c			\
-	basic_event_loop.h
+	basic-event-loop.c			\
+	basic-event-loop.h
 
 spice_server_replay_LDADD =					\
 	$(top_builddir)/spice-common/common/libspice-common.la	\
@@ -85,25 +85,25 @@ spice_server_replay_LDADD =					\
 	$(SPICE_NONPKGCONFIG_LIBS)		                \
 	$(NULL)
 
-stat_test_SOURCES = stat-main.c
-stat_test_LDADD = \
-	libstat_test1.a \
-	libstat_test2.a \
-	libstat_test3.a \
-	libstat_test4.a \
+test_stat_SOURCES = stat-main.c
+test_stat_LDADD = \
+	libtest-stat1.a \
+	libtest-stat2.a \
+	libtest-stat3.a \
+	libtest-stat4.a \
 	$(LDADD) \
 	$(NULL)
 
-libstat_test1_a_SOURCES = stat-test.c
-libstat_test1_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=0 -DTEST_RED_WORKER_STAT=0 -DTEST_NAME=stat_test1
+libtest_stat1_a_SOURCES = stat-test.c
+libtest_stat1_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=0 -DTEST_RED_WORKER_STAT=0 -DTEST_NAME=stat_test1
 
-libstat_test2_a_SOURCES = stat-test.c
-libstat_test2_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=0 -DTEST_RED_WORKER_STAT=1 -DTEST_NAME=stat_test2
+libtest_stat2_a_SOURCES = stat-test.c
+libtest_stat2_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=0 -DTEST_RED_WORKER_STAT=1 -DTEST_NAME=stat_test2
 
-libstat_test3_a_SOURCES = stat-test.c
-libstat_test3_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=1 -DTEST_RED_WORKER_STAT=0 -DTEST_NAME=stat_test3
+libtest_stat3_a_SOURCES = stat-test.c
+libtest_stat3_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=1 -DTEST_RED_WORKER_STAT=0 -DTEST_NAME=stat_test3
 
-libstat_test4_a_SOURCES = stat-test.c
-libstat_test4_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=1 -DTEST_RED_WORKER_STAT=1 -DTEST_NAME=stat_test4
+libtest_stat4_a_SOURCES = stat-test.c
+libtest_stat4_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=1 -DTEST_RED_WORKER_STAT=1 -DTEST_NAME=stat_test4
 
 test_qxl_parsing_LDADD = ../libserver.la $(LDADD)
diff --git a/server/tests/basic-event-loop.c b/server/tests/basic-event-loop.c
new file mode 100644
index 0000000..4cc797b
--- /dev/null
+++ b/server/tests/basic-event-loop.c
@@ -0,0 +1,137 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <string.h>
+
+#include "red-common.h"
+#include "spice/macros.h"
+#include <common/ring.h>
+#include <common/mem.h>
+#include "basic-event-loop.h"
+
+int debug = 0;
+
+#define DPRINTF(x, format, ...) { \
+    if (x <= debug) { \
+        printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \
+    } \
+}
+
+static SpiceCoreInterfaceInternal base_core_interface;
+static GMainContext *main_context = NULL;
+
+GMainContext *basic_event_loop_get_context(void)
+{
+    return main_context;
+}
+
+static void event_loop_channel_event(int event, SpiceChannelEventInfo *info)
+{
+    DPRINTF(0, "channel event con, type, id, event: %d, %d, %d, %d",
+            info->connection_id, info->type, info->id, event);
+}
+
+void basic_event_loop_mainloop(void)
+{
+    GMainLoop *loop = g_main_loop_new(main_context, FALSE);
+
+    g_main_loop_run(loop);
+    g_main_loop_unref(loop);
+}
+
+static void ignore_sigpipe(void)
+{
+    struct sigaction act;
+
+    memset(&act, 0, sizeof(act));
+    sigfillset(&act.sa_mask);
+    act.sa_handler = SIG_IGN;
+    sigaction(SIGPIPE, &act, NULL);
+}
+
+static SpiceTimer* base_timer_add(SpiceTimerFunc func, void *opaque)
+{
+    return base_core_interface.timer_add(&base_core_interface, func, opaque);
+}
+
+static void base_timer_start(SpiceTimer *timer, uint32_t ms)
+{
+    base_core_interface.timer_start(&base_core_interface, timer, ms);
+}
+
+static void base_timer_cancel(SpiceTimer *timer)
+{
+    base_core_interface.timer_cancel(&base_core_interface, timer);
+}
+
+static void base_timer_remove(SpiceTimer *timer)
+{
+    base_core_interface.timer_remove(&base_core_interface, timer);
+}
+
+static SpiceWatch *base_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+{
+    return base_core_interface.watch_add(&base_core_interface, fd, event_mask, func, opaque);
+}
+
+static void base_watch_update_mask(SpiceWatch *watch, int event_mask)
+{
+    base_core_interface.watch_update_mask(&base_core_interface, watch, event_mask);
+}
+
+static void base_watch_remove(SpiceWatch *watch)
+{
+    base_core_interface.watch_remove(&base_core_interface, watch);
+}
+
+static SpiceCoreInterface core = {
+    .base = {
+        .major_version = SPICE_INTERFACE_CORE_MAJOR,
+        .minor_version = SPICE_INTERFACE_CORE_MINOR,
+    },
+    .timer_add = base_timer_add,
+    .timer_start = base_timer_start,
+    .timer_cancel = base_timer_cancel,
+    .timer_remove = base_timer_remove,
+    .watch_add = base_watch_add,
+    .watch_update_mask = base_watch_update_mask,
+    .watch_remove = base_watch_remove,
+    .channel_event = event_loop_channel_event,
+};
+
+SpiceCoreInterface *basic_event_loop_init(void)
+{
+    ignore_sigpipe();
+    spice_assert(main_context == NULL);
+    main_context = g_main_context_new();
+    base_core_interface = event_loop_core;
+    base_core_interface.main_context = main_context;
+
+    return &core;
+}
+
+void basic_event_loop_destroy(void)
+{
+    spice_assert(main_context != NULL);
+    g_main_context_unref(main_context);
+    main_context = NULL;
+}
diff --git a/server/tests/basic-event-loop.h b/server/tests/basic-event-loop.h
new file mode 100644
index 0000000..593532b
--- /dev/null
+++ b/server/tests/basic-event-loop.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef __BASIC_EVENT_LOOP_H__
+#define __BASIC_EVENT_LOOP_H__
+
+#include <spice.h>
+#include <glib.h>
+
+GMainContext *basic_event_loop_get_context(void);
+SpiceCoreInterface *basic_event_loop_init(void);
+void basic_event_loop_destroy(void);
+void basic_event_loop_mainloop(void);
+
+#endif // __BASIC_EVENT_LOOP_H__
diff --git a/server/tests/basic_event_loop.c b/server/tests/basic_event_loop.c
deleted file mode 100644
index 2029424..0000000
--- a/server/tests/basic_event_loop.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <signal.h>
-#include <string.h>
-
-#include "red-common.h"
-#include "spice/macros.h"
-#include <common/ring.h>
-#include <common/mem.h>
-#include "basic_event_loop.h"
-
-int debug = 0;
-
-#define DPRINTF(x, format, ...) { \
-    if (x <= debug) { \
-        printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \
-    } \
-}
-
-static SpiceCoreInterfaceInternal base_core_interface;
-static GMainContext *main_context = NULL;
-
-GMainContext *basic_event_loop_get_context(void)
-{
-    return main_context;
-}
-
-static void event_loop_channel_event(int event, SpiceChannelEventInfo *info)
-{
-    DPRINTF(0, "channel event con, type, id, event: %d, %d, %d, %d",
-            info->connection_id, info->type, info->id, event);
-}
-
-void basic_event_loop_mainloop(void)
-{
-    GMainLoop *loop = g_main_loop_new(main_context, FALSE);
-
-    g_main_loop_run(loop);
-    g_main_loop_unref(loop);
-}
-
-static void ignore_sigpipe(void)
-{
-    struct sigaction act;
-
-    memset(&act, 0, sizeof(act));
-    sigfillset(&act.sa_mask);
-    act.sa_handler = SIG_IGN;
-    sigaction(SIGPIPE, &act, NULL);
-}
-
-static SpiceTimer* base_timer_add(SpiceTimerFunc func, void *opaque)
-{
-    return base_core_interface.timer_add(&base_core_interface, func, opaque);
-}
-
-static void base_timer_start(SpiceTimer *timer, uint32_t ms)
-{
-    base_core_interface.timer_start(&base_core_interface, timer, ms);
-}
-
-static void base_timer_cancel(SpiceTimer *timer)
-{
-    base_core_interface.timer_cancel(&base_core_interface, timer);
-}
-
-static void base_timer_remove(SpiceTimer *timer)
-{
-    base_core_interface.timer_remove(&base_core_interface, timer);
-}
-
-static SpiceWatch *base_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
-{
-    return base_core_interface.watch_add(&base_core_interface, fd, event_mask, func, opaque);
-}
-
-static void base_watch_update_mask(SpiceWatch *watch, int event_mask)
-{
-    base_core_interface.watch_update_mask(&base_core_interface, watch, event_mask);
-}
-
-static void base_watch_remove(SpiceWatch *watch)
-{
-    base_core_interface.watch_remove(&base_core_interface, watch);
-}
-
-static SpiceCoreInterface core = {
-    .base = {
-        .major_version = SPICE_INTERFACE_CORE_MAJOR,
-        .minor_version = SPICE_INTERFACE_CORE_MINOR,
-    },
-    .timer_add = base_timer_add,
-    .timer_start = base_timer_start,
-    .timer_cancel = base_timer_cancel,
-    .timer_remove = base_timer_remove,
-    .watch_add = base_watch_add,
-    .watch_update_mask = base_watch_update_mask,
-    .watch_remove = base_watch_remove,
-    .channel_event = event_loop_channel_event,
-};
-
-SpiceCoreInterface *basic_event_loop_init(void)
-{
-    ignore_sigpipe();
-    spice_assert(main_context == NULL);
-    main_context = g_main_context_new();
-    base_core_interface = event_loop_core;
-    base_core_interface.main_context = main_context;
-
-    return &core;
-}
-
-void basic_event_loop_destroy(void)
-{
-    spice_assert(main_context != NULL);
-    g_main_context_unref(main_context);
-    main_context = NULL;
-}
diff --git a/server/tests/basic_event_loop.h b/server/tests/basic_event_loop.h
deleted file mode 100644
index 593532b..0000000
--- a/server/tests/basic_event_loop.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef __BASIC_EVENT_LOOP_H__
-#define __BASIC_EVENT_LOOP_H__
-
-#include <spice.h>
-#include <glib.h>
-
-GMainContext *basic_event_loop_get_context(void);
-SpiceCoreInterface *basic_event_loop_init(void);
-void basic_event_loop_destroy(void);
-void basic_event_loop_mainloop(void);
-
-#endif // __BASIC_EVENT_LOOP_H__
diff --git a/server/tests/regression-test.py b/server/tests/regression-test.py
new file mode 100755
index 0000000..5aad1a7
--- /dev/null
+++ b/server/tests/regression-test.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+from subprocess import PIPE, Popen
+import Image
+import ImageChops
+
+
+def spicy_screenshot():
+    cmd = "spicy-screenshot -h localhost -p 5912 -o output.ppm"
+    p = Popen(cmd, shell=True)
+    p.wait()
+
+def verify():
+    base = Image.open("base_test.ppm")
+    output = Image.open("output.ppm")
+    return ImageChops.difference(base, output).getbbox()
+
+if __name__ == "__main__":
+    spicy_screenshot()
+    diff = verify()
+
+    if diff is None:
+        print("\033[1;32mSUCCESS: No regressions were found!\033[1;m")
+    else:
+        print("\033[1;31mFAIL: Regressions were found!\n\033[1;m"
+              "\033[1;31m      Please, take a look in your code and go fix it!\033[1;m")
diff --git a/server/tests/regression_test.py b/server/tests/regression_test.py
deleted file mode 100755
index 5aad1a7..0000000
--- a/server/tests/regression_test.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/python
-from subprocess import PIPE, Popen
-import Image
-import ImageChops
-
-
-def spicy_screenshot():
-    cmd = "spicy-screenshot -h localhost -p 5912 -o output.ppm"
-    p = Popen(cmd, shell=True)
-    p.wait()
-
-def verify():
-    base = Image.open("base_test.ppm")
-    output = Image.open("output.ppm")
-    return ImageChops.difference(base, output).getbbox()
-
-if __name__ == "__main__":
-    spicy_screenshot()
-    diff = verify()
-
-    if diff is None:
-        print("\033[1;32mSUCCESS: No regressions were found!\033[1;m")
-    else:
-        print("\033[1;31mFAIL: Regressions were found!\n\033[1;m"
-              "\033[1;31m      Please, take a look in your code and go fix it!\033[1;m")
diff --git a/server/tests/replay.c b/server/tests/replay.c
index 6c6e01e..f32fa2f 100644
--- a/server/tests/replay.c
+++ b/server/tests/replay.c
@@ -36,7 +36,7 @@
 #include <pthread.h>
 
 #include <spice/macros.h>
-#include "test_display_base.h"
+#include "test-display-base.h"
 #include <common/log.h>
 
 static SpiceCoreInterface *core;
diff --git a/server/tests/spice-codecs-parsing-test.c b/server/tests/spice-codecs-parsing-test.c
deleted file mode 100644
index 0e23553..0000000
--- a/server/tests/spice-codecs-parsing-test.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2016 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <glib.h>
-#include <spice.h>
-
-/* GLIB_CHECK_VERSION(2, 40, 0) */
-#ifndef g_assert_nonnull
-#define g_assert_nonnull g_assert
-#endif
-
-static void codecs_good(void)
-{
-    guint i;
-    const gchar *codecs[] = {
-        "",
-        ";",
-        ";;;;",
-        "spice:mjpeg",
-        "spice:mjpeg;;;",
-        "spice:mjpeg;;spice:mjpeg;;;",
-        ";;spice:mjpeg;;spice:mjpeg;;;",
-#if defined(HAVE_GSTREAMER_1_0) || defined(HAVE_GSTREAMER_0_10)
-        "gstreamer:mjpeg;gstreamer:h264;gstreamer:vp8;",
-        ";;spice:mjpeg;;gstreamer:mjpeg;gstreamer:h264;gstreamer:vp8;",
-#endif
-    };
-
-    SpiceServer *server = spice_server_new();
-
-    g_assert_nonnull(server);
-
-    for (i = 0; i < G_N_ELEMENTS(codecs); ++i) {
-        g_assert_cmpint(spice_server_set_video_codecs(server, codecs[i]), ==, 0);
-    }
-
-    spice_server_destroy(server);
-}
-
-/* g_test_expect_message is available since Glib 2.34 */
-#if GLIB_CHECK_VERSION(2, 34, 0)
-static void codecs_bad(void)
-{
-    guint i;
-    const struct {
-        const gchar *codecs;
-        const GLogLevelFlags log_level;
-        const gchar *error_message;
-    } test_cases[] = {
-        {
-            NULL,
-            G_LOG_LEVEL_CRITICAL,
-            "*assertion 'codecs != NULL' failed"
-        },{
-            ";:;",
-            G_LOG_LEVEL_WARNING,
-            "*spice: invalid encoder:codec value*",
-        },{
-            "::::",
-            G_LOG_LEVEL_WARNING,
-            "*spice: invalid encoder:codec value*",
-        },{
-            "missingcolon",
-            G_LOG_LEVEL_WARNING,
-            "*spice: invalid encoder:codec value*",
-        },{
-            ":missing_encoder",
-            G_LOG_LEVEL_WARNING,
-            "*spice: invalid encoder:codec value*",
-        },{
-            "missing_value:;",
-            G_LOG_LEVEL_WARNING,
-            "*spice: invalid encoder:codec value*",
-        },{
-            "unknown_encoder:mjpeg",
-            G_LOG_LEVEL_WARNING,
-            "*spice: unknown video encoder unknown_encoder",
-        },{
-            "spice:unknown_codec",
-            G_LOG_LEVEL_WARNING,
-            "*spice: unknown video codec unknown_codec",
-        },
-#if !defined(HAVE_GSTREAMER_1_0) && !defined(HAVE_GSTREAMER_0_10)
-        {
-            "gstreamer:mjpeg",
-            G_LOG_LEVEL_WARNING,
-            "*spice: unsupported video encoder gstreamer",
-        }
-#endif
-    };
-
-    SpiceServer *server = spice_server_new();
-
-    g_assert_nonnull(server);
-
-    for (i = 0; i < G_N_ELEMENTS(test_cases); ++i) {
-        g_test_expect_message(G_LOG_DOMAIN, test_cases[i].log_level, test_cases[i].error_message);
-        g_assert_cmpint(spice_server_set_video_codecs(server, test_cases[i].codecs), ==, 0);
-        g_test_assert_expected_messages();
-    }
-
-    spice_server_destroy(server);
-}
-#endif
-
-int main(int argc, char *argv[])
-{
-    g_test_init(&argc, &argv, NULL);
-
-    g_test_add_func("/server/codecs-good", codecs_good);
-#if GLIB_CHECK_VERSION(2, 34, 0)
-    g_test_add_func("/server/codecs-bad", codecs_bad);
-#endif
-
-    return g_test_run();
-}
diff --git a/server/tests/spice-options-test.c b/server/tests/spice-options-test.c
deleted file mode 100644
index 72ec215..0000000
--- a/server/tests/spice-options-test.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2016 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <glib.h>
-#include <spice.h>
-
-#include "basic_event_loop.h"
-
-/* GLIB_CHECK_VERSION(2, 40, 0) */
-#ifndef g_assert_nonnull
-#define g_assert_nonnull g_assert
-#endif
-
-static void agent_options(void)
-{
-    SpiceCoreInterface *core ;
-    SpiceServer *server = spice_server_new();
-
-    g_assert_nonnull(server);
-
-    core = basic_event_loop_init();
-    g_assert_nonnull(core);
-
-    /* test before init */
-    spice_server_set_agent_mouse(server, 0);
-    spice_server_set_agent_copypaste(server, 0);
-    spice_server_set_agent_file_xfer(server, 0);
-
-    g_assert_cmpint(spice_server_init(server, core), ==, 0);
-
-    /* test after init */
-    spice_server_set_agent_mouse(server, 0);
-    spice_server_set_agent_copypaste(server, 0);
-    spice_server_set_agent_file_xfer(server, 0);
-
-    spice_server_destroy(server);
-}
-
-int main(int argc, char *argv[])
-{
-    g_test_init(&argc, &argv, NULL);
-
-    g_test_add_func("/server/agent options", agent_options);
-
-    return g_test_run();
-}
diff --git a/server/tests/stat-file-test.c b/server/tests/stat-file-test.c
deleted file mode 100644
index 09b0c7a..0000000
--- a/server/tests/stat-file-test.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2016 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <glib.h>
-#include <spice.h>
-
-#include "stat-file.h"
-
-/* GLIB_CHECK_VERSION(2, 40, 0) */
-#ifndef g_assert_nonnull
-#define g_assert_nonnull g_assert
-#endif
-#ifndef g_assert_null
-#define g_assert_null(ptr) g_assert((ptr) == NULL)
-#endif
-
-static void stat_file(void)
-{
-    RedStatFile *stat_file;
-    StatNodeRef ref, refs[10];
-    uint64_t *counter, *counters[10] SPICE_GNUC_UNUSED;
-    int i;
-    char *filename = NULL;
-    char name[20];
-
-    /* create */
-    stat_file = stat_file_new(10);
-
-    g_assert_nonnull(stat_file);
-    g_assert_nonnull(stat_file_get_shm_name(stat_file));
-    filename = strdup(stat_file_get_shm_name(stat_file));
-    g_assert(access(filename, R_OK));
-
-    /* fill all nodes */
-    for (i = 0; i < 10; ++i) {
-        sprintf(name, "node %d", i);
-        ref = stat_file_add_node(stat_file, INVALID_STAT_REF, name, TRUE);
-        refs[i] = ref;
-        g_assert_cmpuint(ref,!=,INVALID_STAT_REF);
-    }
-
-    /* should fail */
-    ref = stat_file_add_node(stat_file, INVALID_STAT_REF, "invalid", TRUE);
-    g_assert_cmpuint(ref,==,INVALID_STAT_REF);
-
-    /* we should find already present nodes */
-    for (i = 0; i < 10; ++i) {
-        /* the formula used here is to take nodes here and there.
-         * As 17 and 10 are coprime numbers you'll get the same numbers
-         * after 10 iterations */
-        sprintf(name, "node %d", (i * 17 + 5) % 10);
-        ref = stat_file_add_node(stat_file, INVALID_STAT_REF, name, TRUE);
-        g_assert_cmpuint(ref,!=,INVALID_STAT_REF);
-    }
-
-    /* delete some nodes */
-    for (i = 0; i < 6; ++i) {
-        /* see above why the formula is used */
-        int n = (i * 23 + 3) % 10;
-        stat_file_remove_node(stat_file, refs[n]);
-        refs[n] = INVALID_STAT_REF;
-    }
-
-    /* now there should be some place for some counters */
-    for (i = 0; i < 6; ++i) {
-        sprintf(name, "counter %d", i);
-        counter = stat_file_add_counter(stat_file, INVALID_STAT_REF, name, TRUE);
-        counters[i] = counter;
-        g_assert_nonnull(counter);
-    }
-    counter = stat_file_add_counter(stat_file, INVALID_STAT_REF, "invalid", TRUE);
-    g_assert_null(counter);
-
-    stat_file_unlink(stat_file);
-    g_assert_null(stat_file_get_shm_name(stat_file));
-    g_assert_cmpint(access(filename, F_OK),==,-1);
-    free(filename);
-}
-
-int main(int argc, char *argv[])
-{
-    g_test_init(&argc, &argv, NULL);
-
-    g_test_add_func("/server/stat-file", stat_file);
-
-    return g_test_run();
-}
diff --git a/server/tests/stream-test.c b/server/tests/stream-test.c
deleted file mode 100644
index 8a34a0d..0000000
--- a/server/tests/stream-test.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2016 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <common/log.h>
-#include "reds-stream.h"
-#include "basic_event_loop.h"
-
-static SpiceServer *server = NULL;
-
-static int server_init(void)
-{
-    SpiceCoreInterface *core = basic_event_loop_init();
-    server = spice_server_new();
-
-    return spice_server_init(server, core);
-}
-
-
-/*
- * Based on code from Keith Packard:
- * http://keithp.com/blogs/fd-passing/
- */
-static ssize_t
-sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
-{
-    ssize_t size;
-
-    if (fd) {
-        struct msghdr msg;
-        struct iovec iov;
-        union {
-            struct cmsghdr cmsghdr;
-            char control[CMSG_SPACE(sizeof (int))];
-        } cmsgu;
-        struct cmsghdr *cmsg;
-
-        iov.iov_base = buf;
-        iov.iov_len = bufsize;
-
-        msg.msg_name = NULL;
-        msg.msg_namelen = 0;
-        msg.msg_iov = &iov;
-        msg.msg_iovlen = 1;
-        msg.msg_control = cmsgu.control;
-        msg.msg_controllen = sizeof(cmsgu.control);
-        size = recvmsg(sock, &msg, 0);
-        if (size < 0) {
-            perror ("recvmsg");
-            exit(1);
-        }
-        cmsg = CMSG_FIRSTHDR(&msg);
-        if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
-            if (cmsg->cmsg_level != SOL_SOCKET) {
-                fprintf(stderr, "invalid cmsg_level %d\n",
-                        cmsg->cmsg_level);
-                exit(1);
-            }
-            if (cmsg->cmsg_type != SCM_RIGHTS) {
-                fprintf(stderr, "invalid cmsg_type %d\n",
-                        cmsg->cmsg_type);
-                exit(1);
-            }
-
-            memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
-        } else
-            *fd = -1;
-    } else {
-        size = read(sock, buf, bufsize);
-        if (size < 0) {
-            perror("read");
-            exit(1);
-        }
-    }
-
-    return size;
-}
-
-int main(int argc, char *argv[])
-{
-    RedsStream *st[2];
-    int sv[2];
-    int ret, fd = -1;
-    char c;
-
-    spice_return_val_if_fail(server_init() == 0, -1);
-
-    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) == -1) {
-        spice_error("socketpair failed %s", strerror(errno));
-        return -1;
-    }
-
-    st[0] = reds_stream_new(server, sv[0]);
-    spice_assert(reds_stream_is_plain_unix(st[0]));
-    st[1] = reds_stream_new(server, sv[1]);
-    spice_assert(reds_stream_is_plain_unix(st[1]));
-
-    /* send stdin, for the fun of it */
-    ret = reds_stream_send_msgfd(st[0], 0);
-    spice_assert(ret == 1);
-    ret = sock_fd_read(sv[1], &c, 1, &fd);
-    spice_assert(c == '@');
-    spice_assert(ret == 1);
-    spice_assert(fd != -1);
-    close(fd);
-
-    /* send invalid fd behaviour */
-    ret = reds_stream_send_msgfd(st[0], -1);
-    spice_assert(ret == 1);
-    ret = sock_fd_read(sv[1], &c, 1, &fd);
-    spice_assert(c == '@');
-    spice_assert(ret == 1);
-    spice_assert(fd == -1);
-
-    /* batch test */
-    ret = reds_stream_send_msgfd(st[0], 0);
-    spice_assert(ret == 1);
-    ret = reds_stream_send_msgfd(st[0], 0);
-    spice_assert(ret == 1);
-    ret = sock_fd_read(sv[1], &c, 1, &fd);
-    spice_assert(c == '@');
-    spice_assert(ret == 1);
-    spice_assert(fd != -1);
-    close(fd);
-    ret = sock_fd_read(sv[1], &c, 1, &fd);
-    spice_assert(c == '@');
-    spice_assert(ret == 1);
-    spice_assert(fd != -1);
-    close(fd);
-
-    reds_stream_free(st[0]);
-    reds_stream_free(st[1]);
-
-    return 0;
-}
diff --git a/server/tests/test-codecs-parsing.c b/server/tests/test-codecs-parsing.c
new file mode 100644
index 0000000..0e23553
--- /dev/null
+++ b/server/tests/test-codecs-parsing.c
@@ -0,0 +1,131 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2016 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <glib.h>
+#include <spice.h>
+
+/* GLIB_CHECK_VERSION(2, 40, 0) */
+#ifndef g_assert_nonnull
+#define g_assert_nonnull g_assert
+#endif
+
+static void codecs_good(void)
+{
+    guint i;
+    const gchar *codecs[] = {
+        "",
+        ";",
+        ";;;;",
+        "spice:mjpeg",
+        "spice:mjpeg;;;",
+        "spice:mjpeg;;spice:mjpeg;;;",
+        ";;spice:mjpeg;;spice:mjpeg;;;",
+#if defined(HAVE_GSTREAMER_1_0) || defined(HAVE_GSTREAMER_0_10)
+        "gstreamer:mjpeg;gstreamer:h264;gstreamer:vp8;",
+        ";;spice:mjpeg;;gstreamer:mjpeg;gstreamer:h264;gstreamer:vp8;",
+#endif
+    };
+
+    SpiceServer *server = spice_server_new();
+
+    g_assert_nonnull(server);
+
+    for (i = 0; i < G_N_ELEMENTS(codecs); ++i) {
+        g_assert_cmpint(spice_server_set_video_codecs(server, codecs[i]), ==, 0);
+    }
+
+    spice_server_destroy(server);
+}
+
+/* g_test_expect_message is available since Glib 2.34 */
+#if GLIB_CHECK_VERSION(2, 34, 0)
+static void codecs_bad(void)
+{
+    guint i;
+    const struct {
+        const gchar *codecs;
+        const GLogLevelFlags log_level;
+        const gchar *error_message;
+    } test_cases[] = {
+        {
+            NULL,
+            G_LOG_LEVEL_CRITICAL,
+            "*assertion 'codecs != NULL' failed"
+        },{
+            ";:;",
+            G_LOG_LEVEL_WARNING,
+            "*spice: invalid encoder:codec value*",
+        },{
+            "::::",
+            G_LOG_LEVEL_WARNING,
+            "*spice: invalid encoder:codec value*",
+        },{
+            "missingcolon",
+            G_LOG_LEVEL_WARNING,
+            "*spice: invalid encoder:codec value*",
+        },{
+            ":missing_encoder",
+            G_LOG_LEVEL_WARNING,
+            "*spice: invalid encoder:codec value*",
+        },{
+            "missing_value:;",
+            G_LOG_LEVEL_WARNING,
+            "*spice: invalid encoder:codec value*",
+        },{
+            "unknown_encoder:mjpeg",
+            G_LOG_LEVEL_WARNING,
+            "*spice: unknown video encoder unknown_encoder",
+        },{
+            "spice:unknown_codec",
+            G_LOG_LEVEL_WARNING,
+            "*spice: unknown video codec unknown_codec",
+        },
+#if !defined(HAVE_GSTREAMER_1_0) && !defined(HAVE_GSTREAMER_0_10)
+        {
+            "gstreamer:mjpeg",
+            G_LOG_LEVEL_WARNING,
+            "*spice: unsupported video encoder gstreamer",
+        }
+#endif
+    };
+
+    SpiceServer *server = spice_server_new();
+
+    g_assert_nonnull(server);
+
+    for (i = 0; i < G_N_ELEMENTS(test_cases); ++i) {
+        g_test_expect_message(G_LOG_DOMAIN, test_cases[i].log_level, test_cases[i].error_message);
+        g_assert_cmpint(spice_server_set_video_codecs(server, test_cases[i].codecs), ==, 0);
+        g_test_assert_expected_messages();
+    }
+
+    spice_server_destroy(server);
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/server/codecs-good", codecs_good);
+#if GLIB_CHECK_VERSION(2, 34, 0)
+    g_test_add_func("/server/codecs-bad", codecs_bad);
+#endif
+
+    return g_test_run();
+}
diff --git a/server/tests/test-display-base.c b/server/tests/test-display-base.c
new file mode 100644
index 0000000..bf1475d
--- /dev/null
+++ b/server/tests/test-display-base.c
@@ -0,0 +1,932 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <wait.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include "spice.h"
+#include <spice/qxl_dev.h>
+
+#include "test-display-base.h"
+#include "red-channel.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#define MEM_SLOT_GROUP_ID 0
+
+#define NOTIFY_DISPLAY_BATCH (SINGLE_PART/2)
+#define NOTIFY_CURSOR_BATCH 10
+
+/* Parts cribbed from spice-display.h/.c/qxl.c */
+
+typedef struct SimpleSpiceUpdate {
+    QXLCommandExt ext; // first
+    QXLDrawable drawable;
+    QXLImage image;
+    uint8_t *bitmap;
+} SimpleSpiceUpdate;
+
+typedef struct SimpleSurfaceCmd {
+    QXLCommandExt ext; // first
+    QXLSurfaceCmd surface_cmd;
+} SimpleSurfaceCmd;
+
+static void test_spice_destroy_update(SimpleSpiceUpdate *update)
+{
+    if (!update) {
+        return;
+    }
+    if (update->drawable.clip.type != SPICE_CLIP_TYPE_NONE) {
+        uint8_t *ptr = (uint8_t*)update->drawable.clip.data;
+        free(ptr);
+    }
+    free(update->bitmap);
+    free(update);
+}
+
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 320
+
+#define SINGLE_PART 4
+static const int angle_parts = 64 / SINGLE_PART;
+static int unique = 1;
+static int color = -1;
+static int c_i = 0;
+
+/* Used for automated tests */
+static int control = 3; //used to know when we can take a screenshot
+static int rects = 16; //number of rects that will be draw
+static int has_automated_tests = 0; //automated test flag
+
+__attribute__((noreturn))
+static void sigchld_handler(SPICE_GNUC_UNUSED int signal_num) // wait for the child process and exit
+{
+    int status;
+    wait(&status);
+    exit(0);
+}
+
+static void regression_test(void)
+{
+    pid_t pid;
+
+    if (--rects != 0) {
+        return;
+    }
+
+    rects = 16;
+
+    if (--control != 0) {
+        return;
+    }
+
+    pid = fork();
+    if (pid == 0) {
+        char buf[PATH_MAX];
+        char *argv[] = { NULL };
+        char *envp[] = {buf, NULL};
+
+        snprintf(buf, sizeof(buf), "PATH=%s", getenv("PATH"));
+        execve("regression-test.py", argv, envp);
+    } else if (pid > 0) {
+        return;
+    }
+}
+
+static void set_cmd(QXLCommandExt *ext, uint32_t type, QXLPHYSICAL data)
+{
+    ext->cmd.type = type;
+    ext->cmd.data = data;
+    ext->cmd.padding = 0;
+    ext->group_id = MEM_SLOT_GROUP_ID;
+    ext->flags = 0;
+}
+
+static void simple_set_release_info(QXLReleaseInfo *info, intptr_t ptr)
+{
+    info->id = ptr;
+    //info->group_id = MEM_SLOT_GROUP_ID;
+}
+
+typedef struct Path {
+    int t;
+    int min_t;
+    int max_t;
+} Path;
+
+static void path_init(Path *path, int min, int max)
+{
+    path->t = min;
+    path->min_t = min;
+    path->max_t = max;
+}
+
+static void path_progress(Path *path)
+{
+    path->t = (path->t+1)% (path->max_t - path->min_t) + path->min_t;
+}
+
+Path path;
+
+static void draw_pos(Test *test, int t, int *x, int *y)
+{
+#ifdef CIRCLE
+    *y = test->primary_height/2 + (test->primary_height/3)*cos(t*2*M_PI/angle_parts);
+    *x = test->primary_width/2 + (test->primary_width/3)*sin(t*2*M_PI/angle_parts);
+#else
+    *y = test->primary_height*(t % SINGLE_PART)/SINGLE_PART;
+    *x = ((test->primary_width/SINGLE_PART)*(t / SINGLE_PART)) % test->primary_width;
+#endif
+}
+
+/* bitmap and rects are freed, so they must be allocated with malloc */
+SimpleSpiceUpdate *test_spice_create_update_from_bitmap(uint32_t surface_id,
+                                                        QXLRect bbox,
+                                                        uint8_t *bitmap,
+                                                        uint32_t num_clip_rects,
+                                                        QXLRect *clip_rects)
+{
+    SimpleSpiceUpdate *update;
+    QXLDrawable *drawable;
+    QXLImage *image;
+    uint32_t bw, bh;
+
+    bh = bbox.bottom - bbox.top;
+    bw = bbox.right - bbox.left;
+
+    update   = calloc(sizeof(*update), 1);
+    update->bitmap = bitmap;
+    drawable = &update->drawable;
+    image    = &update->image;
+
+    drawable->surface_id      = surface_id;
+
+    drawable->bbox            = bbox;
+    if (num_clip_rects == 0) {
+        drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
+    } else {
+        QXLClipRects *cmd_clip;
+
+        cmd_clip = calloc(sizeof(QXLClipRects) + num_clip_rects*sizeof(QXLRect), 1);
+        cmd_clip->num_rects = num_clip_rects;
+        cmd_clip->chunk.data_size = num_clip_rects*sizeof(QXLRect);
+        cmd_clip->chunk.prev_chunk = cmd_clip->chunk.next_chunk = 0;
+        memcpy(cmd_clip + 1, clip_rects, cmd_clip->chunk.data_size);
+
+        drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
+        drawable->clip.data = (intptr_t)cmd_clip;
+
+        free(clip_rects);
+    }
+    drawable->effect          = QXL_EFFECT_OPAQUE;
+    simple_set_release_info(&drawable->release_info, (intptr_t)update);
+    drawable->type            = QXL_DRAW_COPY;
+    drawable->surfaces_dest[0] = -1;
+    drawable->surfaces_dest[1] = -1;
+    drawable->surfaces_dest[2] = -1;
+
+    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
+    drawable->u.copy.src_bitmap      = (intptr_t)image;
+    drawable->u.copy.src_area.right  = bw;
+    drawable->u.copy.src_area.bottom = bh;
+
+    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, unique);
+    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
+    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
+    image->bitmap.stride     = bw * 4;
+    image->descriptor.width  = image->bitmap.x = bw;
+    image->descriptor.height = image->bitmap.y = bh;
+    image->bitmap.data = (intptr_t)bitmap;
+    image->bitmap.palette = 0;
+    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
+
+    set_cmd(&update->ext, QXL_CMD_DRAW, (intptr_t)drawable);
+
+    return update;
+}
+
+static SimpleSpiceUpdate *test_spice_create_update_solid(uint32_t surface_id, QXLRect bbox, uint32_t color)
+{
+    uint8_t *bitmap;
+    uint32_t *dst;
+    uint32_t bw;
+    uint32_t bh;
+    uint32_t i;
+
+    bw = bbox.right - bbox.left;
+    bh = bbox.bottom - bbox.top;
+
+    bitmap = malloc(bw * bh * 4);
+    dst = (uint32_t *)bitmap;
+
+    for (i = 0 ; i < bh * bw ; ++i, ++dst) {
+        *dst = color;
+    }
+
+    return test_spice_create_update_from_bitmap(surface_id, bbox, bitmap, 0, NULL);
+}
+
+static SimpleSpiceUpdate *test_spice_create_update_draw(Test *test, uint32_t surface_id, int t)
+{
+    int top, left;
+    uint8_t *dst;
+    uint8_t *bitmap;
+    int bw, bh;
+    int i;
+    QXLRect bbox;
+
+    draw_pos(test, t, &left, &top);
+    if ((t % angle_parts) == 0) {
+        c_i++;
+    }
+
+    if (surface_id != 0) {
+        color = (color + 1) % 2;
+    } else {
+        color = surface_id;
+    }
+
+    unique++;
+
+    bw       = test->primary_width/SINGLE_PART;
+    bh       = 48;
+
+    bitmap = dst = malloc(bw * bh * 4);
+    //printf("allocated %p\n", dst);
+
+    for (i = 0 ; i < bh * bw ; ++i, dst+=4) {
+        *dst = (color+i % 255);
+        *(dst+((1+c_i)%3)) = 255 - color;
+        *(dst+((2+c_i)%3)) = (color * (color + i)) & 0xff;
+        *(dst+((3+c_i)%3)) = 0;
+    }
+
+    bbox.left = left; bbox.top = top;
+    bbox.right = left + bw; bbox.bottom = top + bh;
+    return test_spice_create_update_from_bitmap(surface_id, bbox, bitmap, 0, NULL);
+}
+
+static SimpleSpiceUpdate *test_spice_create_update_copy_bits(Test *test, uint32_t surface_id)
+{
+    SimpleSpiceUpdate *update;
+    QXLDrawable *drawable;
+    int bw, bh;
+    QXLRect bbox = {
+        .left = 10,
+        .top = 0,
+    };
+
+    update   = calloc(sizeof(*update), 1);
+    drawable = &update->drawable;
+
+    bw       = test->primary_width/SINGLE_PART;
+    bh       = 48;
+    bbox.right = bbox.left + bw;
+    bbox.bottom = bbox.top + bh;
+    //printf("allocated %p, %p\n", update, update->bitmap);
+
+    drawable->surface_id      = surface_id;
+
+    drawable->bbox            = bbox;
+    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
+    drawable->effect          = QXL_EFFECT_OPAQUE;
+    simple_set_release_info(&drawable->release_info, (intptr_t)update);
+    drawable->type            = QXL_COPY_BITS;
+    drawable->surfaces_dest[0] = -1;
+    drawable->surfaces_dest[1] = -1;
+    drawable->surfaces_dest[2] = -1;
+
+    drawable->u.copy_bits.src_pos.x = 0;
+    drawable->u.copy_bits.src_pos.y = 0;
+
+    set_cmd(&update->ext, QXL_CMD_DRAW, (intptr_t)drawable);
+
+    return update;
+}
+
+static int format_to_bpp(int format)
+{
+    switch (format) {
+    case SPICE_SURFACE_FMT_8_A:
+        return 1;
+    case SPICE_SURFACE_FMT_16_555:
+    case SPICE_SURFACE_FMT_16_565:
+        return 2;
+    case SPICE_SURFACE_FMT_32_xRGB:
+    case SPICE_SURFACE_FMT_32_ARGB:
+        return 4;
+    }
+    abort();
+}
+
+static SimpleSurfaceCmd *create_surface(int surface_id, int format, int width, int height, uint8_t *data)
+{
+    SimpleSurfaceCmd *simple_cmd = calloc(sizeof(SimpleSurfaceCmd), 1);
+    QXLSurfaceCmd *surface_cmd = &simple_cmd->surface_cmd;
+    int bpp = format_to_bpp(format);
+
+    set_cmd(&simple_cmd->ext, QXL_CMD_SURFACE, (intptr_t)surface_cmd);
+    simple_set_release_info(&surface_cmd->release_info, (intptr_t)simple_cmd);
+    surface_cmd->type = QXL_SURFACE_CMD_CREATE;
+    surface_cmd->flags = 0; // ?
+    surface_cmd->surface_id = surface_id;
+    surface_cmd->u.surface_create.format = format;
+    surface_cmd->u.surface_create.width = width;
+    surface_cmd->u.surface_create.height = height;
+    surface_cmd->u.surface_create.stride = -width * bpp;
+    surface_cmd->u.surface_create.data = (intptr_t)data;
+    return simple_cmd;
+}
+
+static SimpleSurfaceCmd *destroy_surface(int surface_id)
+{
+    SimpleSurfaceCmd *simple_cmd = calloc(sizeof(SimpleSurfaceCmd), 1);
+    QXLSurfaceCmd *surface_cmd = &simple_cmd->surface_cmd;
+
+    set_cmd(&simple_cmd->ext, QXL_CMD_SURFACE, (intptr_t)surface_cmd);
+    simple_set_release_info(&surface_cmd->release_info, (intptr_t)simple_cmd);
+    surface_cmd->type = QXL_SURFACE_CMD_DESTROY;
+    surface_cmd->flags = 0; // ?
+    surface_cmd->surface_id = surface_id;
+    return simple_cmd;
+}
+
+static void create_primary_surface(Test *test, uint32_t width,
+                                   uint32_t height)
+{
+    QXLDevSurfaceCreate surface = { 0, };
+
+    spice_assert(height <= MAX_HEIGHT);
+    spice_assert(width <= MAX_WIDTH);
+    spice_assert(height > 0);
+    spice_assert(width > 0);
+
+    surface.format     = SPICE_SURFACE_FMT_32_xRGB;
+    surface.width      = test->primary_width = width;
+    surface.height     = test->primary_height = height;
+    surface.stride     = -width * 4; /* negative? */
+    surface.mouse_mode = TRUE; /* unused by red_worker */
+    surface.flags      = 0;
+    surface.type       = 0;    /* unused by red_worker */
+    surface.position   = 0;    /* unused by red_worker */
+    surface.mem        = (uint64_t)&test->primary_surface;
+    surface.group_id   = MEM_SLOT_GROUP_ID;
+
+    test->width = width;
+    test->height = height;
+
+    spice_qxl_create_primary_surface(&test->qxl_instance, 0, &surface);
+}
+
+QXLDevMemSlot slot = {
+.slot_group_id = MEM_SLOT_GROUP_ID,
+.slot_id = 0,
+.generation = 0,
+.virt_start = 0,
+.virt_end = ~0,
+.addr_delta = 0,
+.qxl_ram_size = ~0,
+};
+
+static void attache_worker(QXLInstance *qin, QXLWorker *_qxl_worker)
+{
+    Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance);
+
+    if (test->qxl_worker) {
+        if (test->qxl_worker != _qxl_worker)
+            printf("%s ignored, %p is set, ignoring new %p\n", __func__,
+                   test->qxl_worker, _qxl_worker);
+        else
+            printf("%s ignored, redundant\n", __func__);
+        return;
+    }
+    printf("%s\n", __func__);
+    test->qxl_worker = _qxl_worker;
+    spice_qxl_add_memslot(&test->qxl_instance, &slot);
+    create_primary_surface(test, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    spice_server_vm_start(test->server);
+}
+
+static void set_compression_level(SPICE_GNUC_UNUSED QXLInstance *qin,
+                                  SPICE_GNUC_UNUSED int level)
+{
+    printf("%s\n", __func__);
+}
+
+static void set_mm_time(SPICE_GNUC_UNUSED QXLInstance *qin,
+                        SPICE_GNUC_UNUSED uint32_t mm_time)
+{
+}
+
+// we now have a secondary surface
+#define MAX_SURFACE_NUM 2
+
+static void get_init_info(SPICE_GNUC_UNUSED QXLInstance *qin,
+                          QXLDevInitInfo *info)
+{
+    memset(info, 0, sizeof(*info));
+    info->num_memslots = 1;
+    info->num_memslots_groups = 1;
+    info->memslot_id_bits = 1;
+    info->memslot_gen_bits = 1;
+    info->n_surfaces = MAX_SURFACE_NUM;
+}
+
+// We shall now have a ring of commands, so that we can update
+// it from a separate thread - since get_command is called from
+// the worker thread, and we need to sometimes do an update_area,
+// which cannot be done from red_worker context (not via dispatcher,
+// since you get a deadlock, and it isn't designed to be done
+// any other way, so no point testing that).
+int commands_end = 0;
+int commands_start = 0;
+struct QXLCommandExt* commands[1024];
+
+#define COMMANDS_SIZE COUNT(commands)
+
+static void push_command(QXLCommandExt *ext)
+{
+    spice_assert(commands_end - commands_start < (int) COMMANDS_SIZE);
+    commands[commands_end % COMMANDS_SIZE] = ext;
+    commands_end++;
+}
+
+static struct QXLCommandExt *get_simple_command(void)
+{
+    struct QXLCommandExt *ret = commands[commands_start % COMMANDS_SIZE];
+    spice_assert(commands_start < commands_end);
+    commands_start++;
+    return ret;
+}
+
+static int get_num_commands(void)
+{
+    return commands_end - commands_start;
+}
+
+// called from spice_server thread (i.e. red_worker thread)
+static int get_command(SPICE_GNUC_UNUSED QXLInstance *qin,
+                       struct QXLCommandExt *ext)
+{
+    if (get_num_commands() == 0) {
+        return FALSE;
+    }
+    *ext = *get_simple_command();
+    return TRUE;
+}
+
+static void produce_command(Test *test)
+{
+    Command *command;
+    QXLWorker *qxl_worker = test->qxl_worker;
+
+    spice_assert(qxl_worker);
+
+    if (test->has_secondary)
+        test->target_surface = 1;
+
+    if (!test->num_commands) {
+        usleep(1000);
+        return;
+    }
+
+    command = &test->commands[test->cmd_index];
+    if (command->cb) {
+        command->cb(test, command);
+    }
+    switch (command->command) {
+        case SLEEP:
+             printf("sleep %u seconds\n", command->sleep.secs);
+             sleep(command->sleep.secs);
+             break;
+        case PATH_PROGRESS:
+            path_progress(&path);
+            break;
+        case SIMPLE_UPDATE: {
+            QXLRect rect = {
+                .left = 0,
+                .right = (test->target_surface == 0 ? test->primary_width : test->width),
+                .top = 0,
+                .bottom = (test->target_surface == 0 ? test->primary_height : test->height)
+            };
+            if (rect.right > 0 && rect.bottom > 0) {
+                spice_qxl_update_area(&test->qxl_instance, test->target_surface, &rect, NULL, 0, 1);
+            }
+            break;
+        }
+
+        /* Drawing commands, they all push a command to the command ring */
+        case SIMPLE_COPY_BITS:
+        case SIMPLE_DRAW_SOLID:
+        case SIMPLE_DRAW_BITMAP:
+        case SIMPLE_DRAW: {
+            SimpleSpiceUpdate *update;
+
+            if (has_automated_tests)
+            {
+                if (control == 0) {
+                     return;
+                }
+
+                regression_test();
+            }
+
+            switch (command->command) {
+            case SIMPLE_COPY_BITS:
+                update = test_spice_create_update_copy_bits(test, 0);
+                break;
+            case SIMPLE_DRAW:
+                update = test_spice_create_update_draw(test, 0, path.t);
+                break;
+            case SIMPLE_DRAW_BITMAP:
+                update = test_spice_create_update_from_bitmap(command->bitmap.surface_id,
+                        command->bitmap.bbox, command->bitmap.bitmap,
+                        command->bitmap.num_clip_rects, command->bitmap.clip_rects);
+                break;
+            case SIMPLE_DRAW_SOLID:
+                update = test_spice_create_update_solid(command->solid.surface_id,
+                        command->solid.bbox, command->solid.color);
+                break;
+            default: /* Just to shut up GCC warning (-Wswitch) */
+                break;
+            }
+            push_command(&update->ext);
+            break;
+        }
+
+        case SIMPLE_CREATE_SURFACE: {
+            SimpleSurfaceCmd *update;
+            if (command->create_surface.data) {
+                spice_assert(command->create_surface.surface_id > 0);
+                spice_assert(command->create_surface.surface_id < MAX_SURFACE_NUM);
+                spice_assert(command->create_surface.surface_id == 1);
+                update = create_surface(command->create_surface.surface_id,
+                                        command->create_surface.format,
+                                        command->create_surface.width,
+                                        command->create_surface.height,
+                                        command->create_surface.data);
+            } else {
+                update = create_surface(test->target_surface, SPICE_SURFACE_FMT_32_xRGB,
+                                        SURF_WIDTH, SURF_HEIGHT,
+                                        test->secondary_surface);
+            }
+            push_command(&update->ext);
+            test->has_secondary = 1;
+            break;
+        }
+
+        case SIMPLE_DESTROY_SURFACE: {
+            SimpleSurfaceCmd *update;
+            test->has_secondary = 0;
+            update = destroy_surface(test->target_surface);
+            test->target_surface = 0;
+            push_command(&update->ext);
+            break;
+        }
+
+        case DESTROY_PRIMARY:
+            spice_qxl_destroy_primary_surface(&test->qxl_instance, 0);
+            break;
+
+        case CREATE_PRIMARY:
+            create_primary_surface(test,
+                    command->create_primary.width, command->create_primary.height);
+            break;
+    }
+    test->cmd_index = (test->cmd_index + 1) % test->num_commands;
+}
+
+static int req_cmd_notification(QXLInstance *qin)
+{
+    Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance);
+
+    test->core->timer_start(test->wakeup_timer, test->wakeup_ms);
+    return TRUE;
+}
+
+static void do_wakeup(void *opaque)
+{
+    Test *test = opaque;
+    int notify;
+
+    test->cursor_notify = NOTIFY_CURSOR_BATCH;
+    for (notify = NOTIFY_DISPLAY_BATCH; notify > 0;--notify) {
+        produce_command(test);
+    }
+
+    test->core->timer_start(test->wakeup_timer, test->wakeup_ms);
+    spice_qxl_wakeup(&test->qxl_instance);
+}
+
+static void release_resource(SPICE_GNUC_UNUSED QXLInstance *qin,
+                             struct QXLReleaseInfoExt release_info)
+{
+    QXLCommandExt *ext = (QXLCommandExt*)(unsigned long)release_info.info->id;
+    //printf("%s\n", __func__);
+    spice_assert(release_info.group_id == MEM_SLOT_GROUP_ID);
+    switch (ext->cmd.type) {
+        case QXL_CMD_DRAW:
+            test_spice_destroy_update((void*)ext);
+            break;
+        case QXL_CMD_SURFACE:
+            free(ext);
+            break;
+        case QXL_CMD_CURSOR: {
+            QXLCursorCmd *cmd = (QXLCursorCmd *)(unsigned long)ext->cmd.data;
+            if (cmd->type == QXL_CURSOR_SET) {
+                free(cmd);
+            }
+            free(ext);
+            break;
+        }
+        default:
+            abort();
+    }
+}
+
+#define CURSOR_WIDTH 32
+#define CURSOR_HEIGHT 32
+
+static struct {
+    QXLCursor cursor;
+    uint8_t data[CURSOR_WIDTH * CURSOR_HEIGHT * 4]; // 32bit per pixel
+} cursor;
+
+static void cursor_init()
+{
+    cursor.cursor.header.unique = 0;
+    cursor.cursor.header.type = SPICE_CURSOR_TYPE_COLOR32;
+    cursor.cursor.header.width = CURSOR_WIDTH;
+    cursor.cursor.header.height = CURSOR_HEIGHT;
+    cursor.cursor.header.hot_spot_x = 0;
+    cursor.cursor.header.hot_spot_y = 0;
+    cursor.cursor.data_size = CURSOR_WIDTH * CURSOR_HEIGHT * 4;
+
+    // X drivers addes it to the cursor size because it could be
+    // cursor data information or another cursor related stuffs.
+    // Otherwise, the code will break in client/cursor.cpp side,
+    // that expect the data_size plus cursor information.
+    // Blame cursor protocol for this. :-)
+    cursor.cursor.data_size += 128;
+    cursor.cursor.chunk.data_size = cursor.cursor.data_size;
+    cursor.cursor.chunk.prev_chunk = cursor.cursor.chunk.next_chunk = 0;
+}
+
+static int get_cursor_command(QXLInstance *qin, struct QXLCommandExt *ext)
+{
+    Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance);
+    static int set = 1;
+    static int x = 0, y = 0;
+    QXLCursorCmd *cursor_cmd;
+    QXLCommandExt *cmd;
+
+    if (!test->cursor_notify) {
+        return FALSE;
+    }
+
+    test->cursor_notify--;
+    cmd = calloc(sizeof(QXLCommandExt), 1);
+    cursor_cmd = calloc(sizeof(QXLCursorCmd), 1);
+
+    cursor_cmd->release_info.id = (unsigned long)cmd;
+
+    if (set) {
+        cursor_cmd->type = QXL_CURSOR_SET;
+        cursor_cmd->u.set.position.x = 0;
+        cursor_cmd->u.set.position.y = 0;
+        cursor_cmd->u.set.visible = TRUE;
+        cursor_cmd->u.set.shape = (unsigned long)&cursor;
+        // Only a white rect (32x32) as cursor
+        memset(cursor.data, 255, sizeof(cursor.data));
+        set = 0;
+    } else {
+        cursor_cmd->type = QXL_CURSOR_MOVE;
+        cursor_cmd->u.position.x = x++ % test->primary_width;
+        cursor_cmd->u.position.y = y++ % test->primary_height;
+    }
+
+    cmd->cmd.data = (unsigned long)cursor_cmd;
+    cmd->cmd.type = QXL_CMD_CURSOR;
+    cmd->group_id = MEM_SLOT_GROUP_ID;
+    cmd->flags    = 0;
+    *ext = *cmd;
+    //printf("%s\n", __func__);
+    return TRUE;
+}
+
+static int req_cursor_notification(SPICE_GNUC_UNUSED QXLInstance *qin)
+{
+    printf("%s\n", __func__);
+    return TRUE;
+}
+
+static void notify_update(SPICE_GNUC_UNUSED QXLInstance *qin,
+                          SPICE_GNUC_UNUSED uint32_t update_id)
+{
+    printf("%s\n", __func__);
+}
+
+static int flush_resources(SPICE_GNUC_UNUSED QXLInstance *qin)
+{
+    printf("%s\n", __func__);
+    return TRUE;
+}
+
+static int client_monitors_config(SPICE_GNUC_UNUSED QXLInstance *qin,
+                                  VDAgentMonitorsConfig *monitors_config)
+{
+    if (!monitors_config) {
+        printf("%s: NULL monitors_config\n", __func__);
+    } else {
+        printf("%s: %d\n", __func__, monitors_config->num_of_monitors);
+    }
+    return 0;
+}
+
+static void set_client_capabilities(QXLInstance *qin,
+                                    uint8_t client_present,
+                                    uint8_t caps[58])
+{
+    Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance);
+
+    printf("%s: present %d caps %d\n", __func__, client_present, caps[0]);
+    if (test->on_client_connected && client_present) {
+        test->on_client_connected(test);
+    }
+    if (test->on_client_disconnected && !client_present) {
+        test->on_client_disconnected(test);
+    }
+}
+
+QXLInterface display_sif = {
+    .base = {
+        .type = SPICE_INTERFACE_QXL,
+        .description = "test",
+        .major_version = SPICE_INTERFACE_QXL_MAJOR,
+        .minor_version = SPICE_INTERFACE_QXL_MINOR
+    },
+    .attache_worker = attache_worker,
+    .set_compression_level = set_compression_level,
+    .set_mm_time = set_mm_time,
+    .get_init_info = get_init_info,
+
+    /* the callbacks below are called from spice server thread context */
+    .get_command = get_command,
+    .req_cmd_notification = req_cmd_notification,
+    .release_resource = release_resource,
+    .get_cursor_command = get_cursor_command,
+    .req_cursor_notification = req_cursor_notification,
+    .notify_update = notify_update,
+    .flush_resources = flush_resources,
+    .client_monitors_config = client_monitors_config,
+    .set_client_capabilities = set_client_capabilities,
+};
+
+/* interface for tests */
+void test_add_display_interface(Test* test)
+{
+    spice_server_add_interface(test->server, &test->qxl_instance.base);
+}
+
+static SpiceBaseInterface base = {
+    .type          = SPICE_INTERFACE_CHAR_DEVICE,
+    .description   = "test spice virtual channel char device",
+    .major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
+    .minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
+};
+
+SpiceCharDeviceInstance vdagent_sin = {
+    .base = {
+        .sif = &base,
+    },
+    .subtype = "vdagent",
+};
+
+void test_add_agent_interface(SpiceServer *server)
+{
+    spice_server_add_interface(server, &vdagent_sin.base);
+}
+
+void test_set_simple_command_list(Test *test, int *simple_commands, int num_commands)
+{
+    int i;
+
+    /* FIXME: leaks */
+    test->commands = malloc(sizeof(*test->commands) * num_commands);
+    memset(test->commands, 0, sizeof(*test->commands) * num_commands);
+    test->num_commands = num_commands;
+    for (i = 0 ; i < num_commands; ++i) {
+        test->commands[i].command = simple_commands[i];
+    }
+}
+
+void test_set_command_list(Test *test, Command *commands, int num_commands)
+{
+    test->commands = commands;
+    test->num_commands = num_commands;
+}
+
+
+Test *test_new(SpiceCoreInterface *core)
+{
+    int port = 5912;
+    Test *test = spice_new0(Test, 1);
+    SpiceServer* server = spice_server_new();
+
+    test->qxl_instance.base.sif = &display_sif.base;
+    test->qxl_instance.id = 0;
+
+    test->core = core;
+    test->server = server;
+    test->wakeup_ms = 1;
+    test->cursor_notify = NOTIFY_CURSOR_BATCH;
+    // some common initialization for all display tests
+    printf("TESTER: listening on port %d (unsecure)\n", port);
+    spice_server_set_port(server, port);
+    spice_server_set_noauth(server);
+    spice_server_init(server, core);
+
+    cursor_init();
+    path_init(&path, 0, angle_parts);
+    test->has_secondary = 0;
+    test->wakeup_timer = core->timer_add(do_wakeup, test);
+    return test;
+}
+
+void init_automated()
+{
+    struct sigaction sa;
+
+    memset(&sa, 0, sizeof sa);
+    sa.sa_handler = &sigchld_handler;
+    sigaction(SIGCHLD, &sa, NULL);
+}
+
+__attribute__((noreturn))
+void usage(const char *argv0, const int exitcode)
+{
+#ifdef AUTOMATED_TESTS
+    const char *autoopt=" [--automated-tests]";
+#else
+    const char *autoopt="";
+#endif
+
+    printf("usage: %s%s\n", argv0, autoopt);
+    exit(exitcode);
+}
+
+void spice_test_config_parse_args(int argc, char **argv)
+{
+    struct option options[] = {
+#ifdef AUTOMATED_TESTS
+        {"automated-tests", no_argument, &has_automated_tests, 1},
+#endif
+        {NULL, 0, NULL, 0},
+    };
+    int option_index;
+    int val;
+
+    while ((val = getopt_long(argc, argv, "", options, &option_index)) != -1) {
+        switch (val) {
+        case '?':
+            printf("unrecognized option '%s'\n", argv[optind - 1]);
+            usage(argv[0], EXIT_FAILURE);
+        case 0:
+            break;
+        }
+    }
+
+    if (argc > optind) {
+        printf("unknown argument '%s'\n", argv[optind]);
+        usage(argv[0], EXIT_FAILURE);
+    }
+    if (has_automated_tests) {
+        init_automated();
+    }
+    return;
+}
diff --git a/server/tests/test-display-base.h b/server/tests/test-display-base.h
new file mode 100644
index 0000000..7b5b509
--- /dev/null
+++ b/server/tests/test-display-base.h
@@ -0,0 +1,146 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef __TEST_DISPLAY_BASE_H__
+#define __TEST_DISPLAY_BASE_H__
+
+#include <spice.h>
+#include "basic-event-loop.h"
+
+#define COUNT(x) ((sizeof(x)/sizeof(x[0])))
+
+/*
+ * simple queue for commands.
+ * each command can have up to two parameters (grow as needed)
+ *
+ * TODO: switch to gtk main loop. Then add gobject-introspection. then
+ * write tests in python/guile/whatever.
+ */
+typedef enum {
+    PATH_PROGRESS,
+    SIMPLE_CREATE_SURFACE,
+    SIMPLE_DRAW,
+    SIMPLE_DRAW_BITMAP,
+    SIMPLE_DRAW_SOLID,
+    SIMPLE_COPY_BITS,
+    SIMPLE_DESTROY_SURFACE,
+    SIMPLE_UPDATE,
+    DESTROY_PRIMARY,
+    CREATE_PRIMARY,
+    SLEEP
+} CommandType;
+
+typedef struct CommandCreatePrimary {
+    uint32_t width;
+    uint32_t height;
+} CommandCreatePrimary;
+
+typedef struct CommandCreateSurface {
+    uint32_t surface_id;
+    uint32_t format;
+    uint32_t width;
+    uint32_t height;
+    uint8_t *data;
+} CommandCreateSurface;
+
+typedef struct CommandDrawBitmap {
+    QXLRect bbox;
+    uint8_t *bitmap;
+    uint32_t surface_id;
+    uint32_t num_clip_rects;
+    QXLRect *clip_rects;
+} CommandDrawBitmap;
+
+typedef struct CommandDrawSolid {
+    QXLRect bbox;
+    uint32_t color;
+    uint32_t surface_id;
+} CommandDrawSolid;
+
+typedef struct CommandSleep {
+    uint32_t secs;
+} CommandSleep;
+
+typedef struct Command Command;
+typedef struct Test Test;
+
+struct Command {
+    CommandType command;
+    void (*cb)(Test *test, Command *command);
+    void *cb_opaque;
+    union {
+        CommandCreatePrimary create_primary;
+        CommandDrawBitmap bitmap;
+        CommandDrawSolid solid;
+        CommandSleep sleep;
+        CommandCreateSurface create_surface;
+    };
+};
+
+#define MAX_HEIGHT 2048
+#define MAX_WIDTH 2048
+
+#define SURF_WIDTH 320
+#define SURF_HEIGHT 240
+
+struct Test {
+    SpiceCoreInterface *core;
+    SpiceServer *server;
+
+    QXLInstance qxl_instance;
+    QXLWorker *qxl_worker;
+
+    uint8_t primary_surface[MAX_HEIGHT * MAX_WIDTH * 4];
+    int primary_height;
+    int primary_width;
+
+    SpiceTimer *wakeup_timer;
+    int wakeup_ms;
+
+    int cursor_notify;
+
+    uint8_t secondary_surface[SURF_WIDTH * SURF_HEIGHT * 4];
+    int has_secondary;
+
+    // Current mode (set by create_primary)
+    int width;
+    int height;
+
+    // qxl scripted rendering commands and io
+    Command *commands;
+    int num_commands;
+    int cmd_index;
+
+    int target_surface;
+
+    // callbacks
+    void (*on_client_connected)(Test *test);
+    void (*on_client_disconnected)(Test *test);
+};
+
+void test_set_simple_command_list(Test *test, int *command, int num_commands);
+void test_set_command_list(Test *test, Command *command, int num_commands);
+void test_add_display_interface(Test *test);
+void test_add_agent_interface(SpiceServer *server); // TODO - Test *test
+Test* test_new(SpiceCoreInterface* core);
+
+uint32_t test_get_width(void);
+uint32_t test_get_height(void);
+
+void spice_test_config_parse_args(int argc, char **argv);
+
+#endif /* __TEST_DISPLAY_BASE_H__ */
diff --git a/server/tests/test-display-no-ssl.c b/server/tests/test-display-no-ssl.c
new file mode 100644
index 0000000..8b3a09b
--- /dev/null
+++ b/server/tests/test-display-no-ssl.c
@@ -0,0 +1,72 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Test ground for developing specific tests.
+ *
+ * Any specific test can start of from here and set the server to the
+ * specific required state, and create specific operations or reuse
+ * existing ones in the test_display_base supplied queue.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include "test-display-base.h"
+
+SpiceCoreInterface *core;
+SpiceTimer *ping_timer;
+
+void show_channels(SpiceServer *server);
+
+int ping_ms = 100;
+
+void pinger(SPICE_GNUC_UNUSED void *opaque)
+{
+    // show_channels is not thread safe - fails if disconnections / connections occur
+    //show_channels(server);
+
+    core->timer_start(ping_timer, ping_ms);
+}
+
+int simple_commands[] = {
+    //SIMPLE_CREATE_SURFACE,
+    //SIMPLE_DRAW,
+    //SIMPLE_DESTROY_SURFACE,
+    //PATH_PROGRESS,
+    SIMPLE_DRAW,
+    //SIMPLE_COPY_BITS,
+    SIMPLE_UPDATE,
+};
+
+int main(void)
+{
+    Test *test;
+
+    core = basic_event_loop_init();
+    test = test_new(core);
+    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESSION_OFF);
+    test_add_display_interface(test);
+    test_add_agent_interface(test->server);
+    test_set_simple_command_list(test, simple_commands, COUNT(simple_commands));
+
+    ping_timer = core->timer_add(pinger, NULL);
+    core->timer_start(ping_timer, ping_ms);
+
+    basic_event_loop_mainloop();
+
+    return 0;
+}
diff --git a/server/tests/test-display-resolution-changes.c b/server/tests/test-display-resolution-changes.c
new file mode 100644
index 0000000..b68a648
--- /dev/null
+++ b/server/tests/test-display-resolution-changes.c
@@ -0,0 +1,86 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Recreate the primary surface endlessly.
+ */
+
+#include <config.h>
+#include <math.h>
+#include <stdlib.h>
+#include "test-display-base.h"
+
+SpiceTimer *ping_timer;
+
+void show_channels(SpiceServer *server);
+
+int ping_ms = 100;
+
+void pinger(void *opaque)
+{
+    Test *test = opaque;
+    // show_channels is not thread safe - fails if disconnections / connections occur
+    //show_channels(server);
+
+    test->core->timer_start(ping_timer, ping_ms);
+}
+
+void set_primary_params(SPICE_GNUC_UNUSED Test *test,
+                        Command *command)
+{
+#if 0
+    static int toggle = 0;
+
+    if (toggle) {
+        *arg1 = 800;
+        *arg2 = 600;
+    } else {
+        *arg1 = 1024;
+        *arg2 = 768;
+    }
+    toggle = 1 - toggle;
+#endif
+    static int count = 0;
+
+    command->create_primary.width = 800 + sin((float)count / 6) * 200;
+    command->create_primary.height = 600 + cos((float)count / 6) * 200;
+    count++;
+}
+
+static Command commands[] = {
+    {DESTROY_PRIMARY, NULL, .cb_opaque = NULL,},
+    {CREATE_PRIMARY, set_primary_params, .cb_opaque = NULL},
+};
+
+int main(void)
+{
+    SpiceCoreInterface *core;
+    Test *test;
+
+    core = basic_event_loop_init();
+    test = test_new(core);
+    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESSION_OFF);
+    test_add_display_interface(test);
+    test_set_command_list(test, commands, COUNT(commands));
+
+    ping_timer = core->timer_add(pinger, test);
+    core->timer_start(ping_timer, ping_ms);
+
+    basic_event_loop_mainloop();
+
+    return 0;
+}
diff --git a/server/tests/test-display-streaming.c b/server/tests/test-display-streaming.c
new file mode 100644
index 0000000..6e945fd
--- /dev/null
+++ b/server/tests/test-display-streaming.c
@@ -0,0 +1,253 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/* Do repeated updates to the same rectangle to trigger stream creation.
+ *
+ * TODO: check that stream actually starts programatically (maybe stap?)
+ * TODO: stop updating same rect, check (prog) that stream stops
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <glib.h>
+
+#include "test-display-base.h"
+
+static int sized;
+static int render_last_frame;
+
+static void create_overlay(Command *command , int width, int height)
+{
+    CommandDrawBitmap *cmd = &command->bitmap;
+    uint32_t *dst;
+
+    cmd->surface_id = 0;
+
+    cmd->bbox.left = 0;
+    cmd->bbox.top = 0;
+    cmd->bbox.right = width;
+    cmd->bbox.bottom = height;
+
+    cmd->num_clip_rects = 0;
+    cmd->bitmap = g_malloc(width * height * 4 );
+    dst = (uint32_t *)cmd->bitmap;
+    for (int i = 0; i < width * height; i++, dst++) {
+        *dst = 0x8B008B;
+    }
+
+}
+
+#define NUM_COMMANDS 2000
+#define SIZED_INTERVAL 100
+#define OVERLAY_FRAME 500
+#define OVERLAY_WIDTH 200
+#define OVERLAY_HEIGHT 200
+
+/*
+ * Create a frame in a stream that displays a row that moves
+ * from the top to the bottom repeatedly.
+ * Upon the OVERLAY_FRAME-th, a drawable is created on top of a part of the stream,
+ * and from then on, all the stream frames has a clipping that keeps this drawable
+ * visible, and in addition a clipping_factor is subtracted from the right limit of their clipping.
+ * If sized=TRUE, a higher and wider frame than the original stream is created every SIZED_INTERVAL.
+ * The sized frames can be distinguished by a change in the color of the top and bottom limits of the
+ * surface.
+ */
+static void create_clipped_frame(Test *test, Command *command, int clipping_factor)
+{
+    static int count = 0;
+    CommandDrawBitmap *cmd = &command->bitmap;
+    int max_height = test->height;
+    int max_width = test->width;
+    int width;
+    int height;
+    int cur_line, end_line;
+    uint32_t *dst;
+
+    count++;
+    if (count == NUM_COMMANDS) {
+        count = 0;
+    }
+    if (count == OVERLAY_FRAME) {
+        create_overlay(command, OVERLAY_WIDTH, OVERLAY_HEIGHT);
+        return;
+    }
+
+    cmd->surface_id = 0;
+
+    cmd->bbox.left = 0;
+    cmd->bbox.right = max_width - 50;
+    assert(max_height > 600);
+    cmd->bbox.top = 50;
+    cmd->bbox.bottom = max_height - 50;
+    height = cmd->bbox.bottom  - cmd->bbox.top;
+    width = cmd->bbox.right - cmd->bbox.left;
+    cur_line = (height/30)*(count % 30);
+    end_line = cur_line + (height/30);
+    if (end_line >= height || height - end_line < 8) {
+        end_line = height;
+    }
+
+    if (sized && count % SIZED_INTERVAL == 0) {
+
+        cmd->bbox.top = 0;
+        cmd->bbox.bottom = max_height;
+        cmd->bbox.left = 0;
+        cmd->bbox.right = max_width;
+        height = max_height;
+        width = max_width;
+        cur_line += 50;
+        end_line += 50;
+    }
+
+    cmd->bitmap = g_malloc(width*height*4);
+    memset(cmd->bitmap, 0xff, width*height*4);
+    dst = (uint32_t *)(cmd->bitmap + cur_line*width*4);
+    for (; cur_line < end_line; cur_line++) {
+        int col;
+        for (col = 0; col < width; col++, dst++) {
+            *dst = 0x00FF00;
+        }
+    }
+    if (sized && count % SIZED_INTERVAL == 0) {
+        int i;
+        uint32_t color = 0xffffff & rand();
+
+        dst = (uint32_t *)cmd->bitmap;
+
+        for (i = 0; i < 50*width; i++, dst++) {
+            *dst = color;
+        }
+
+        dst = ((uint32_t *)(cmd->bitmap + (height - 50)*4*width));
+
+        for (i = 0; i < 50*width; i++, dst++) {
+            *dst = color;
+        }
+    }
+
+    if (count < OVERLAY_FRAME) {
+        cmd->num_clip_rects = 0;
+    } else {
+        cmd->num_clip_rects = 2;
+        cmd->clip_rects = calloc(sizeof(QXLRect), 2);
+        cmd->clip_rects[0].left = OVERLAY_WIDTH;
+        cmd->clip_rects[0].top = cmd->bbox.top;
+        cmd->clip_rects[0].right = cmd->bbox.right - clipping_factor;
+        cmd->clip_rects[0].bottom = OVERLAY_HEIGHT;
+        cmd->clip_rects[1].left = cmd->bbox.left;
+        cmd->clip_rects[1].top = OVERLAY_HEIGHT;
+        cmd->clip_rects[1].right = cmd->bbox.right - clipping_factor;
+        cmd->clip_rects[1].bottom = cmd->bbox.bottom;
+    }
+}
+
+static void create_frame1(Test *test, Command *command)
+{
+    create_clipped_frame(test, command, 0);
+}
+
+void create_frame2(Test *test, Command *command)
+{
+    create_clipped_frame(test, command, 200);
+}
+
+typedef void (*create_frame_cb)(Test *test, Command *command);
+
+
+/*
+ * The test contains two types of streams. The first stream doesn't
+ * have a clipping besides the on that the display the overlay drawable.
+ * Expected result: If render_last_frame=false, the last frame should
+ * be sent losslessly. Otherwise, red_update_area should be called, and the
+ * stream is upgraded by a screenshot.
+ *
+ * In the second test, the stream clip changes in the middle (becomes smaller).
+ * Expected result: red_update_area should is, and the
+ * stream is upgraded by a screenshot (including lossy areas that belong to old frames
+ * and were never covered by a lossless drawable).
+ *
+ */
+static void get_stream_commands(Command *commands, int num_commands,
+                                create_frame_cb cb)
+{
+    int i;
+
+    commands[0].command = DESTROY_PRIMARY;
+    commands[1].command = CREATE_PRIMARY;
+    commands[1].create_primary.width = 1280;
+    commands[1].create_primary.height = 1024;
+    commands[num_commands - 1].command = SLEEP;
+    commands[num_commands - 1].sleep.secs = 20;
+
+    for (i = 2; i < num_commands - 1; i++) {
+        commands[i].command = SIMPLE_DRAW_BITMAP;
+        commands[i].cb = cb;
+    }
+    if (render_last_frame) {
+        commands[num_commands - 2].command = SIMPLE_UPDATE;
+    }
+}
+
+static void get_commands(Command **commands, int *num_commands)
+{
+    *num_commands = NUM_COMMANDS * 2;
+    *commands = calloc(sizeof(Command), *num_commands);
+
+    get_stream_commands(*commands, NUM_COMMANDS, create_frame1);
+    get_stream_commands((*commands) + NUM_COMMANDS, NUM_COMMANDS, create_frame2);
+}
+
+
+int main(int argc, char **argv)
+{
+    SpiceCoreInterface *core;
+    Command *commands;
+    int num_commands;
+    int i;
+    Test *test;
+
+    spice_test_config_parse_args(argc, argv);
+    sized = 0;
+    for (i = 1 ; i < argc; ++i) {
+        if (strcmp(argv[i], "sized") == 0) {
+            sized = 1;
+        }
+        /* render last frame */
+        if (strcmp(argv[i], "render") == 0) {
+            render_last_frame = 1;
+        }
+    }
+    srand(time(NULL));
+    // todo: add args list of test numbers with explenations
+    core = basic_event_loop_init();
+    test = test_new(core);
+    spice_server_set_streaming_video(test->server, SPICE_STREAM_VIDEO_ALL);
+    test_add_display_interface(test);
+    get_commands(&commands, &num_commands);
+    test_set_command_list(test, commands, num_commands);
+    basic_event_loop_mainloop();
+    free(commands);
+    return 0;
+}
diff --git a/server/tests/test-display-width-stride.c b/server/tests/test-display-width-stride.c
new file mode 100644
index 0000000..dc44282
--- /dev/null
+++ b/server/tests/test-display-width-stride.c
@@ -0,0 +1,121 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Recreate the primary surface endlessly.
+ */
+
+#include <config.h>
+#include <math.h>
+#include <stdlib.h>
+#include "test-display-base.h"
+
+SpiceTimer *ping_timer;
+
+void show_channels(SpiceServer *server);
+
+int ping_ms = 100;
+
+void pinger(void *opaque)
+{
+    Test *test = opaque;
+    // show_channels is not thread safe - fails if disconnections / connections occur
+    //show_channels(server);
+
+    test->core->timer_start(ping_timer, ping_ms);
+}
+
+static int g_surface_id = 1;
+static uint8_t *g_surface_data;
+
+void set_draw_parameters(SPICE_GNUC_UNUSED Test *test,
+                         Command *command)
+{
+    static int count = 17;
+    CommandDrawSolid *solid = &command->solid;
+
+    solid->bbox.top = 0;
+    solid->bbox.left = 0;
+    solid->bbox.bottom = 20;
+    solid->bbox.right = count;
+    solid->surface_id = g_surface_id;
+    count++;
+}
+
+void set_surface_params(SPICE_GNUC_UNUSED Test *test,
+                        Command *command)
+{
+    CommandCreateSurface *create = &command->create_surface;
+
+    // UGLY
+    if (g_surface_data) {
+        exit(0);
+    }
+    create->format = SPICE_SURFACE_FMT_8_A;
+    create->width = 128;
+    create->height = 128;
+    g_surface_data = realloc(g_surface_data, create->width * create->height * 1);
+    create->surface_id = g_surface_id;
+    create->data = g_surface_data;
+}
+
+void set_destroy_parameters(SPICE_GNUC_UNUSED Test *test,
+                            SPICE_GNUC_UNUSED Command *command)
+{
+    if (g_surface_data) {
+        free(g_surface_data);
+        g_surface_data = NULL;
+    }
+}
+
+static Command commands[] = {
+    {SIMPLE_CREATE_SURFACE, set_surface_params, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
+    {SIMPLE_DESTROY_SURFACE, set_destroy_parameters, .cb_opaque = NULL},
+};
+
+void on_client_connected(Test *test)
+{
+    test_set_command_list(test, commands, COUNT(commands));
+}
+
+int main(void)
+{
+    SpiceCoreInterface *core;
+    Test *test;
+
+    core = basic_event_loop_init();
+    test = test_new(core);
+    test->on_client_connected = on_client_connected;
+    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESSION_OFF);
+    test_add_display_interface(test);
+
+    ping_timer = core->timer_add(pinger, test);
+    core->timer_start(ping_timer, ping_ms);
+
+    basic_event_loop_mainloop();
+
+    return 0;
+}
diff --git a/server/tests/test-empty-success.c b/server/tests/test-empty-success.c
new file mode 100644
index 0000000..da98488
--- /dev/null
+++ b/server/tests/test-empty-success.c
@@ -0,0 +1,93 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <spice.h>
+
+struct SpiceTimer {
+    int a,b;
+};
+
+SpiceTimer* timer_add(SPICE_GNUC_UNUSED SpiceTimerFunc func,
+                      SPICE_GNUC_UNUSED void *opaque)
+{
+    static struct SpiceTimer t = {0,};
+
+    return &t;
+}
+
+void timer_start(SPICE_GNUC_UNUSED SpiceTimer *timer,
+                 SPICE_GNUC_UNUSED uint32_t ms)
+{
+}
+
+void timer_cancel(SPICE_GNUC_UNUSED SpiceTimer *timer)
+{
+}
+
+void timer_remove(SPICE_GNUC_UNUSED SpiceTimer *timer)
+{
+}
+
+SpiceWatch *watch_add(SPICE_GNUC_UNUSED int fd,
+                      SPICE_GNUC_UNUSED int event_mask,
+                      SPICE_GNUC_UNUSED SpiceWatchFunc func,
+                      SPICE_GNUC_UNUSED void *opaque)
+{
+    return NULL;
+}
+
+void watch_update_mask(SPICE_GNUC_UNUSED SpiceWatch *watch,
+                       SPICE_GNUC_UNUSED int event_mask)
+{
+}
+
+void watch_remove(SPICE_GNUC_UNUSED SpiceWatch *watch)
+{
+}
+
+void channel_event(SPICE_GNUC_UNUSED int event,
+                   SPICE_GNUC_UNUSED SpiceChannelEventInfo *info)
+{
+}
+
+int main(void)
+{
+    SpiceServer *server = spice_server_new();
+    SpiceCoreInterface core;
+
+    memset(&core, 0, sizeof(core));
+    core.base.major_version = SPICE_INTERFACE_CORE_MAJOR;
+    core.timer_add = timer_add;
+    core.timer_start = timer_start;
+    core.timer_cancel = timer_cancel;
+    core.timer_remove = timer_remove;
+    core.watch_add = watch_add;
+    core.watch_update_mask = watch_update_mask;
+    core.watch_remove = watch_remove;
+    core.channel_event = channel_event;
+
+    spice_server_set_port(server, 5911);
+    spice_server_init(server, &core);
+
+    spice_server_destroy(server);
+
+    return 0;
+}
diff --git a/server/tests/test-fail-on-null-core-interface.c b/server/tests/test-fail-on-null-core-interface.c
new file mode 100644
index 0000000..48e92db
--- /dev/null
+++ b/server/tests/test-fail-on-null-core-interface.c
@@ -0,0 +1,30 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <spice.h>
+
+int main(void)
+{
+    SpiceServer *server = spice_server_new();
+    SpiceCoreInterface core;
+
+    spice_server_init(server, &core);
+    spice_server_set_port(server, 5911);
+
+    return 0;
+}
diff --git a/server/tests/test-just-sockets-no-ssl.c b/server/tests/test-just-sockets-no-ssl.c
new file mode 100644
index 0000000..98def5a
--- /dev/null
+++ b/server/tests/test-just-sockets-no-ssl.c
@@ -0,0 +1,35 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <sys/select.h>
+#include <spice.h>
+#include "basic-event-loop.h"
+
+int main(void)
+{
+    SpiceServer *server = spice_server_new();
+    SpiceCoreInterface *core = basic_event_loop_init();
+
+    spice_server_set_port(server, 5912);
+    spice_server_set_noauth(server);
+    spice_server_init(server, core);
+
+    basic_event_loop_mainloop();
+
+    return 0;
+}
diff --git a/server/tests/test-loop.c b/server/tests/test-loop.c
index c8d3fb1..1e3b39e 100644
--- a/server/tests/test-loop.c
+++ b/server/tests/test-loop.c
@@ -30,7 +30,7 @@
 
 #include <spice/macros.h>
 #include <common/log.h>
-#include "basic_event_loop.h"
+#include "basic-event-loop.h"
 
 static SpiceCoreInterface *core = NULL;
 static GMainLoop *loop = NULL;
diff --git a/server/tests/test-multiple.py b/server/tests/test-multiple.py
new file mode 100755
index 0000000..2497d93
--- /dev/null
+++ b/server/tests/test-multiple.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+
+"""
+Example usage:
+./test-multiple.py test-display-no-ssl --log test.log
+
+Resulting test.log file (single test, stopped with Ctrl-C with 15 clients):
+
+0 162212
+1 154156
+2 154424
+3 154952
+4 155352
+5 155616
+6 156280
+7 222084
+8 222612
+9 230820
+10 230820
+11 230820
+12 230820
+13 296356
+14 296356
+
+"""
+
+import argparse
+import os
+import sys
+import subprocess
+import atexit
+import socket
+import time
+
+def killall(procs):
+    for p in procs:
+        print "killing %d" % p.pid
+        p.kill()
+        p.wait()
+
+def cleanup():
+    killall(clients + [test_process])
+
+def wait_for_port(port):
+    if not port:
+        return
+    # TODO: do this without actually opening the port - maybe just look at /proc/qemu_process_id/fd?
+    s = socket.socket(socket.AF_INET)
+    while True:
+        try:
+            s.connect(('localhost', port))
+            s.close()
+            break
+        except:
+            time.sleep(1)
+            pass
+
+def get_vm_size(pid):
+    """ read from /proc/<pid>/status, VmSize, in KiloBytes  """
+    return int([x for x in open('/proc/%s/status' % pid).readlines() if 'VmSize' in x][0].split()[1])
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--client', default='spicy')
+parser.add_argument('--start-count', default=1, type=int)
+parser.add_argument('--end-count', default=50, type=int)
+parser.add_argument('--log', default='-')
+parser.add_argument('--sleep', default=3, type=int)
+args, rest = parser.parse_known_args(sys.argv[1:])
+client = os.popen('which %s' % args.client).read().strip()
+if not os.path.exists(client):
+    print "supply a valid client. %s does not exist" % (args.client)
+    sys.exit(1)
+
+if not rest or len(rest) < 1 or not os.path.exists(rest[0]):
+    print "supply one argument that is the tester you wish to run"
+    sys.exit(1)
+
+prog = rest[0]
+port = {
+'test_display_no_ssl': 5912,
+'test_display_streaming': 5912,
+'test_just_sockets_no_ssl': 5912,
+'test_playback': 5701,
+}.get(prog, None)
+
+if args.log == '-':
+    log = sys.stdout
+else:
+    log = open(args.log, 'a+')
+
+log.write('#%s\n' % time.time())
+
+# kill leftovers from previous invocation
+os.system('killall lt-%s' % prog)
+
+if prog[0] != '/':
+    prog = os.path.join('.', prog)
+
+if not port:
+    print "unknown port for %r" % prog
+
+print "prog = %r" % prog
+print "client = %r" % client
+print "range = %d..%d" % (args.start_count, args.end_count)
+atexit.register(cleanup)
+os.environ['SPICE_DEBUG_ALLOW_MC'] = '1'
+test_process = subprocess.Popen([prog], executable=prog)
+wait_for_port(port)
+for count in xrange(args.start_count, args.end_count):
+    print "starting %d clients" % count
+    clients = [subprocess.Popen(args=[client, '-h', 'localhost', '-p', str(port)],
+                                executable=client) for i in xrange(count)]
+    print "sleeping %d" % (args.sleep * count)
+    time.sleep(args.sleep * count)
+    vmsize = "%d %d" % (i, get_vm_size(test_process.pid))
+    print vmsize
+    log.write(vmsize + '\n')
+    log.flush()
+    killall(clients)
+
+test_process.wait()
diff --git a/server/tests/test-options.c b/server/tests/test-options.c
new file mode 100644
index 0000000..0cfd4b3
--- /dev/null
+++ b/server/tests/test-options.c
@@ -0,0 +1,61 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2016 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <glib.h>
+#include <spice.h>
+
+#include "basic-event-loop.h"
+
+/* GLIB_CHECK_VERSION(2, 40, 0) */
+#ifndef g_assert_nonnull
+#define g_assert_nonnull g_assert
+#endif
+
+static void agent_options(void)
+{
+    SpiceCoreInterface *core ;
+    SpiceServer *server = spice_server_new();
+
+    g_assert_nonnull(server);
+
+    core = basic_event_loop_init();
+    g_assert_nonnull(core);
+
+    /* test before init */
+    spice_server_set_agent_mouse(server, 0);
+    spice_server_set_agent_copypaste(server, 0);
+    spice_server_set_agent_file_xfer(server, 0);
+
+    g_assert_cmpint(spice_server_init(server, core), ==, 0);
+
+    /* test after init */
+    spice_server_set_agent_mouse(server, 0);
+    spice_server_set_agent_copypaste(server, 0);
+    spice_server_set_agent_file_xfer(server, 0);
+
+    spice_server_destroy(server);
+}
+
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/server/agent options", agent_options);
+
+    return g_test_run();
+}
diff --git a/server/tests/test-playback.c b/server/tests/test-playback.c
new file mode 100644
index 0000000..7dab278
--- /dev/null
+++ b/server/tests/test-playback.c
@@ -0,0 +1,126 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <math.h>
+
+#include <spice.h>
+#include "basic-event-loop.h"
+
+/* test the audio playback interface. Really basic no frils test - create
+ * a single tone sinus sound (easy to hear clicks if it is generated badly
+ * or is transmitted badly).
+ *
+ * TODO: Was going to do white noise to test compression too.
+ *
+ * TODO: gstreamer based test (could be used to play music files so
+ * it has actual merit. Also possibly to simulate network effects?)
+ * */
+
+SpicePlaybackInstance playback_instance;
+
+static const SpiceBaseInterface base = {
+    .type          = SPICE_INTERFACE_PLAYBACK,
+    .description   = "test playback",
+    .major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
+    .minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
+};
+
+uint32_t *frame;
+uint32_t num_samples;
+SpiceTimer *playback_timer;
+int playback_timer_ms;
+SpiceCoreInterface *core;
+
+static void get_frame(void)
+{
+    if (frame) {
+        return;
+    }
+    spice_server_playback_get_buffer(&playback_instance, &frame, &num_samples);
+    playback_timer_ms = num_samples
+                        ? 1000 * num_samples / SPICE_INTERFACE_PLAYBACK_FREQ
+                        : 100;
+}
+
+void playback_timer_cb(SPICE_GNUC_UNUSED void *opaque)
+{
+    static int t = 0;
+    static uint64_t last_sent_usec = 0;
+    static uint64_t samples_to_send;
+    uint32_t i;
+    struct timeval cur;
+    uint64_t cur_usec;
+
+    get_frame();
+    if (!frame) {
+        /* continue waiting until there is a channel */
+        core->timer_start(playback_timer, 100);
+        return;
+    }
+
+    /* we have a channel */
+    gettimeofday(&cur, NULL);
+    cur_usec = cur.tv_usec + cur.tv_sec * 1e6;
+    if (last_sent_usec == 0) {
+        samples_to_send = num_samples;
+    } else {
+        samples_to_send += (cur_usec - last_sent_usec) * SPICE_INTERFACE_PLAYBACK_FREQ / 1e6;
+    }
+    last_sent_usec = cur_usec;
+    while (samples_to_send > num_samples && frame) {
+#if 0
+    printf("samples_to_send = %d\n", samples_to_send);
+#endif
+        samples_to_send -= num_samples;
+        for (i = 0 ; i < num_samples; ++i) {
+            frame[i] = (((uint16_t)((1<<14)*sin((t+i)/10))) << 16) + (((uint16_t)((1<<14)*sin((t+i)/10))));
+        }
+        t += num_samples;
+        if (frame) {
+            spice_server_playback_put_samples(&playback_instance, frame);
+            frame = NULL;
+        }
+        get_frame();
+    }
+    core->timer_start(playback_timer, playback_timer_ms);
+}
+
+int main(void)
+{
+    SpiceServer *server = spice_server_new();
+    core = basic_event_loop_init();
+
+    spice_server_set_port(server, 5701);
+    spice_server_set_noauth(server);
+    spice_server_init(server, core);
+
+    playback_instance.base.sif = &base;
+    spice_server_add_interface(server, &playback_instance.base);
+    spice_server_playback_start(&playback_instance);
+
+    playback_timer_ms = 100;
+    playback_timer = core->timer_add(playback_timer_cb, NULL);
+    core->timer_start(playback_timer, playback_timer_ms);
+
+    basic_event_loop_mainloop();
+
+    return 0;
+}
diff --git a/server/tests/test-stat-file.c b/server/tests/test-stat-file.c
new file mode 100644
index 0000000..09b0c7a
--- /dev/null
+++ b/server/tests/test-stat-file.c
@@ -0,0 +1,105 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2016 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glib.h>
+#include <spice.h>
+
+#include "stat-file.h"
+
+/* GLIB_CHECK_VERSION(2, 40, 0) */
+#ifndef g_assert_nonnull
+#define g_assert_nonnull g_assert
+#endif
+#ifndef g_assert_null
+#define g_assert_null(ptr) g_assert((ptr) == NULL)
+#endif
+
+static void stat_file(void)
+{
+    RedStatFile *stat_file;
+    StatNodeRef ref, refs[10];
+    uint64_t *counter, *counters[10] SPICE_GNUC_UNUSED;
+    int i;
+    char *filename = NULL;
+    char name[20];
+
+    /* create */
+    stat_file = stat_file_new(10);
+
+    g_assert_nonnull(stat_file);
+    g_assert_nonnull(stat_file_get_shm_name(stat_file));
+    filename = strdup(stat_file_get_shm_name(stat_file));
+    g_assert(access(filename, R_OK));
+
+    /* fill all nodes */
+    for (i = 0; i < 10; ++i) {
+        sprintf(name, "node %d", i);
+        ref = stat_file_add_node(stat_file, INVALID_STAT_REF, name, TRUE);
+        refs[i] = ref;
+        g_assert_cmpuint(ref,!=,INVALID_STAT_REF);
+    }
+
+    /* should fail */
+    ref = stat_file_add_node(stat_file, INVALID_STAT_REF, "invalid", TRUE);
+    g_assert_cmpuint(ref,==,INVALID_STAT_REF);
+
+    /* we should find already present nodes */
+    for (i = 0; i < 10; ++i) {
+        /* the formula used here is to take nodes here and there.
+         * As 17 and 10 are coprime numbers you'll get the same numbers
+         * after 10 iterations */
+        sprintf(name, "node %d", (i * 17 + 5) % 10);
+        ref = stat_file_add_node(stat_file, INVALID_STAT_REF, name, TRUE);
+        g_assert_cmpuint(ref,!=,INVALID_STAT_REF);
+    }
+
+    /* delete some nodes */
+    for (i = 0; i < 6; ++i) {
+        /* see above why the formula is used */
+        int n = (i * 23 + 3) % 10;
+        stat_file_remove_node(stat_file, refs[n]);
+        refs[n] = INVALID_STAT_REF;
+    }
+
+    /* now there should be some place for some counters */
+    for (i = 0; i < 6; ++i) {
+        sprintf(name, "counter %d", i);
+        counter = stat_file_add_counter(stat_file, INVALID_STAT_REF, name, TRUE);
+        counters[i] = counter;
+        g_assert_nonnull(counter);
+    }
+    counter = stat_file_add_counter(stat_file, INVALID_STAT_REF, "invalid", TRUE);
+    g_assert_null(counter);
+
+    stat_file_unlink(stat_file);
+    g_assert_null(stat_file_get_shm_name(stat_file));
+    g_assert_cmpint(access(filename, F_OK),==,-1);
+    free(filename);
+}
+
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/server/stat-file", stat_file);
+
+    return g_test_run();
+}
diff --git a/server/tests/test-stream.c b/server/tests/test-stream.c
new file mode 100644
index 0000000..8f653b2
--- /dev/null
+++ b/server/tests/test-stream.c
@@ -0,0 +1,157 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2016 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <common/log.h>
+#include "reds-stream.h"
+#include "basic-event-loop.h"
+
+static SpiceServer *server = NULL;
+
+static int server_init(void)
+{
+    SpiceCoreInterface *core = basic_event_loop_init();
+    server = spice_server_new();
+
+    return spice_server_init(server, core);
+}
+
+
+/*
+ * Based on code from Keith Packard:
+ * http://keithp.com/blogs/fd-passing/
+ */
+static ssize_t
+sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd)
+{
+    ssize_t size;
+
+    if (fd) {
+        struct msghdr msg;
+        struct iovec iov;
+        union {
+            struct cmsghdr cmsghdr;
+            char control[CMSG_SPACE(sizeof (int))];
+        } cmsgu;
+        struct cmsghdr *cmsg;
+
+        iov.iov_base = buf;
+        iov.iov_len = bufsize;
+
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+        msg.msg_control = cmsgu.control;
+        msg.msg_controllen = sizeof(cmsgu.control);
+        size = recvmsg(sock, &msg, 0);
+        if (size < 0) {
+            perror ("recvmsg");
+            exit(1);
+        }
+        cmsg = CMSG_FIRSTHDR(&msg);
+        if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+            if (cmsg->cmsg_level != SOL_SOCKET) {
+                fprintf(stderr, "invalid cmsg_level %d\n",
+                        cmsg->cmsg_level);
+                exit(1);
+            }
+            if (cmsg->cmsg_type != SCM_RIGHTS) {
+                fprintf(stderr, "invalid cmsg_type %d\n",
+                        cmsg->cmsg_type);
+                exit(1);
+            }
+
+            memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
+        } else
+            *fd = -1;
+    } else {
+        size = read(sock, buf, bufsize);
+        if (size < 0) {
+            perror("read");
+            exit(1);
+        }
+    }
+
+    return size;
+}
+
+int main(int argc, char *argv[])
+{
+    RedsStream *st[2];
+    int sv[2];
+    int ret, fd = -1;
+    char c;
+
+    spice_return_val_if_fail(server_init() == 0, -1);
+
+    if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) == -1) {
+        spice_error("socketpair failed %s", strerror(errno));
+        return -1;
+    }
+
+    st[0] = reds_stream_new(server, sv[0]);
+    spice_assert(reds_stream_is_plain_unix(st[0]));
+    st[1] = reds_stream_new(server, sv[1]);
+    spice_assert(reds_stream_is_plain_unix(st[1]));
+
+    /* send stdin, for the fun of it */
+    ret = reds_stream_send_msgfd(st[0], 0);
+    spice_assert(ret == 1);
+    ret = sock_fd_read(sv[1], &c, 1, &fd);
+    spice_assert(c == '@');
+    spice_assert(ret == 1);
+    spice_assert(fd != -1);
+    close(fd);
+
+    /* send invalid fd behaviour */
+    ret = reds_stream_send_msgfd(st[0], -1);
+    spice_assert(ret == 1);
+    ret = sock_fd_read(sv[1], &c, 1, &fd);
+    spice_assert(c == '@');
+    spice_assert(ret == 1);
+    spice_assert(fd == -1);
+
+    /* batch test */
+    ret = reds_stream_send_msgfd(st[0], 0);
+    spice_assert(ret == 1);
+    ret = reds_stream_send_msgfd(st[0], 0);
+    spice_assert(ret == 1);
+    ret = sock_fd_read(sv[1], &c, 1, &fd);
+    spice_assert(c == '@');
+    spice_assert(ret == 1);
+    spice_assert(fd != -1);
+    close(fd);
+    ret = sock_fd_read(sv[1], &c, 1, &fd);
+    spice_assert(c == '@');
+    spice_assert(ret == 1);
+    spice_assert(fd != -1);
+    close(fd);
+
+    reds_stream_free(st[0]);
+    reds_stream_free(st[1]);
+
+    return 0;
+}
diff --git a/server/tests/test-two-servers.c b/server/tests/test-two-servers.c
new file mode 100644
index 0000000..4cf451a
--- /dev/null
+++ b/server/tests/test-two-servers.c
@@ -0,0 +1,54 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Test two servers on one main loop.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include "test-display-base.h"
+
+SpiceCoreInterface *core;
+
+int simple_commands[] = {
+    //SIMPLE_CREATE_SURFACE,
+    //SIMPLE_DRAW,
+    //SIMPLE_DESTROY_SURFACE,
+    //PATH_PROGRESS,
+    SIMPLE_DRAW,
+    //SIMPLE_COPY_BITS,
+    SIMPLE_UPDATE,
+};
+
+int main(void)
+{
+    Test *t1;
+    Test *t2;
+
+    core = basic_event_loop_init();
+    t1 = test_new(core);
+    t2 = test_new(core);
+    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESSION_OFF);
+    test_add_display_interface(t1);
+    test_add_display_interface(t2);
+    test_set_simple_command_list(t1, simple_commands, COUNT(simple_commands));
+    test_set_simple_command_list(t2, simple_commands, COUNT(simple_commands));
+
+    basic_event_loop_mainloop();
+    return 0;
+}
diff --git a/server/tests/test-vdagent.c b/server/tests/test-vdagent.c
new file mode 100644
index 0000000..a3fa345
--- /dev/null
+++ b/server/tests/test-vdagent.c
@@ -0,0 +1,75 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Test vdagent guest to server messages
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <spice/vd_agent.h>
+
+#include "test-display-base.h"
+
+SpiceCoreInterface *core;
+SpiceTimer *ping_timer;
+
+int ping_ms = 100;
+
+#ifndef MIN
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+void pinger(SPICE_GNUC_UNUSED void *opaque)
+{
+    // show_channels is not thread safe - fails if disconnections / connections occur
+    //show_channels(server);
+
+    core->timer_start(ping_timer, ping_ms);
+}
+
+static SpiceBaseInterface base = {
+    .type          = SPICE_INTERFACE_CHAR_DEVICE,
+    .description   = "test spice virtual channel char device",
+    .major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
+    .minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
+};
+
+SpiceCharDeviceInstance vmc_instance = {
+    .subtype = "vdagent",
+};
+
+int main(void)
+{
+    Test *test;
+
+    core = basic_event_loop_init();
+    test = test_new(core);
+
+    vmc_instance.base.sif = &base;
+    spice_server_add_interface(test->server, &vmc_instance.base);
+
+    ping_timer = core->timer_add(pinger, NULL);
+    core->timer_start(ping_timer, ping_ms);
+
+    basic_event_loop_mainloop();
+
+    return 0;
+}
diff --git a/server/tests/test_display_base.c b/server/tests/test_display_base.c
deleted file mode 100644
index 8e577c9..0000000
--- a/server/tests/test_display_base.c
+++ /dev/null
@@ -1,932 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <signal.h>
-#include <wait.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <getopt.h>
-
-#include "spice.h"
-#include <spice/qxl_dev.h>
-
-#include "test_display_base.h"
-#include "red-channel.h"
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-#define MEM_SLOT_GROUP_ID 0
-
-#define NOTIFY_DISPLAY_BATCH (SINGLE_PART/2)
-#define NOTIFY_CURSOR_BATCH 10
-
-/* Parts cribbed from spice-display.h/.c/qxl.c */
-
-typedef struct SimpleSpiceUpdate {
-    QXLCommandExt ext; // first
-    QXLDrawable drawable;
-    QXLImage image;
-    uint8_t *bitmap;
-} SimpleSpiceUpdate;
-
-typedef struct SimpleSurfaceCmd {
-    QXLCommandExt ext; // first
-    QXLSurfaceCmd surface_cmd;
-} SimpleSurfaceCmd;
-
-static void test_spice_destroy_update(SimpleSpiceUpdate *update)
-{
-    if (!update) {
-        return;
-    }
-    if (update->drawable.clip.type != SPICE_CLIP_TYPE_NONE) {
-        uint8_t *ptr = (uint8_t*)update->drawable.clip.data;
-        free(ptr);
-    }
-    free(update->bitmap);
-    free(update);
-}
-
-#define DEFAULT_WIDTH 640
-#define DEFAULT_HEIGHT 320
-
-#define SINGLE_PART 4
-static const int angle_parts = 64 / SINGLE_PART;
-static int unique = 1;
-static int color = -1;
-static int c_i = 0;
-
-/* Used for automated tests */
-static int control = 3; //used to know when we can take a screenshot
-static int rects = 16; //number of rects that will be draw
-static int has_automated_tests = 0; //automated test flag
-
-__attribute__((noreturn))
-static void sigchld_handler(SPICE_GNUC_UNUSED int signal_num) // wait for the child process and exit
-{
-    int status;
-    wait(&status);
-    exit(0);
-}
-
-static void regression_test(void)
-{
-    pid_t pid;
-
-    if (--rects != 0) {
-        return;
-    }
-
-    rects = 16;
-
-    if (--control != 0) {
-        return;
-    }
-
-    pid = fork();
-    if (pid == 0) {
-        char buf[PATH_MAX];
-        char *argv[] = { NULL };
-        char *envp[] = {buf, NULL};
-
-        snprintf(buf, sizeof(buf), "PATH=%s", getenv("PATH"));
-        execve("regression_test.py", argv, envp);
-    } else if (pid > 0) {
-        return;
-    }
-}
-
-static void set_cmd(QXLCommandExt *ext, uint32_t type, QXLPHYSICAL data)
-{
-    ext->cmd.type = type;
-    ext->cmd.data = data;
-    ext->cmd.padding = 0;
-    ext->group_id = MEM_SLOT_GROUP_ID;
-    ext->flags = 0;
-}
-
-static void simple_set_release_info(QXLReleaseInfo *info, intptr_t ptr)
-{
-    info->id = ptr;
-    //info->group_id = MEM_SLOT_GROUP_ID;
-}
-
-typedef struct Path {
-    int t;
-    int min_t;
-    int max_t;
-} Path;
-
-static void path_init(Path *path, int min, int max)
-{
-    path->t = min;
-    path->min_t = min;
-    path->max_t = max;
-}
-
-static void path_progress(Path *path)
-{
-    path->t = (path->t+1)% (path->max_t - path->min_t) + path->min_t;
-}
-
-Path path;
-
-static void draw_pos(Test *test, int t, int *x, int *y)
-{
-#ifdef CIRCLE
-    *y = test->primary_height/2 + (test->primary_height/3)*cos(t*2*M_PI/angle_parts);
-    *x = test->primary_width/2 + (test->primary_width/3)*sin(t*2*M_PI/angle_parts);
-#else
-    *y = test->primary_height*(t % SINGLE_PART)/SINGLE_PART;
-    *x = ((test->primary_width/SINGLE_PART)*(t / SINGLE_PART)) % test->primary_width;
-#endif
-}
-
-/* bitmap and rects are freed, so they must be allocated with malloc */
-SimpleSpiceUpdate *test_spice_create_update_from_bitmap(uint32_t surface_id,
-                                                        QXLRect bbox,
-                                                        uint8_t *bitmap,
-                                                        uint32_t num_clip_rects,
-                                                        QXLRect *clip_rects)
-{
-    SimpleSpiceUpdate *update;
-    QXLDrawable *drawable;
-    QXLImage *image;
-    uint32_t bw, bh;
-
-    bh = bbox.bottom - bbox.top;
-    bw = bbox.right - bbox.left;
-
-    update   = calloc(sizeof(*update), 1);
-    update->bitmap = bitmap;
-    drawable = &update->drawable;
-    image    = &update->image;
-
-    drawable->surface_id      = surface_id;
-
-    drawable->bbox            = bbox;
-    if (num_clip_rects == 0) {
-        drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
-    } else {
-        QXLClipRects *cmd_clip;
-
-        cmd_clip = calloc(sizeof(QXLClipRects) + num_clip_rects*sizeof(QXLRect), 1);
-        cmd_clip->num_rects = num_clip_rects;
-        cmd_clip->chunk.data_size = num_clip_rects*sizeof(QXLRect);
-        cmd_clip->chunk.prev_chunk = cmd_clip->chunk.next_chunk = 0;
-        memcpy(cmd_clip + 1, clip_rects, cmd_clip->chunk.data_size);
-
-        drawable->clip.type = SPICE_CLIP_TYPE_RECTS;
-        drawable->clip.data = (intptr_t)cmd_clip;
-
-        free(clip_rects);
-    }
-    drawable->effect          = QXL_EFFECT_OPAQUE;
-    simple_set_release_info(&drawable->release_info, (intptr_t)update);
-    drawable->type            = QXL_DRAW_COPY;
-    drawable->surfaces_dest[0] = -1;
-    drawable->surfaces_dest[1] = -1;
-    drawable->surfaces_dest[2] = -1;
-
-    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
-    drawable->u.copy.src_bitmap      = (intptr_t)image;
-    drawable->u.copy.src_area.right  = bw;
-    drawable->u.copy.src_area.bottom = bh;
-
-    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, unique);
-    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
-    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
-    image->bitmap.stride     = bw * 4;
-    image->descriptor.width  = image->bitmap.x = bw;
-    image->descriptor.height = image->bitmap.y = bh;
-    image->bitmap.data = (intptr_t)bitmap;
-    image->bitmap.palette = 0;
-    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
-
-    set_cmd(&update->ext, QXL_CMD_DRAW, (intptr_t)drawable);
-
-    return update;
-}
-
-static SimpleSpiceUpdate *test_spice_create_update_solid(uint32_t surface_id, QXLRect bbox, uint32_t color)
-{
-    uint8_t *bitmap;
-    uint32_t *dst;
-    uint32_t bw;
-    uint32_t bh;
-    uint32_t i;
-
-    bw = bbox.right - bbox.left;
-    bh = bbox.bottom - bbox.top;
-
-    bitmap = malloc(bw * bh * 4);
-    dst = (uint32_t *)bitmap;
-
-    for (i = 0 ; i < bh * bw ; ++i, ++dst) {
-        *dst = color;
-    }
-
-    return test_spice_create_update_from_bitmap(surface_id, bbox, bitmap, 0, NULL);
-}
-
-static SimpleSpiceUpdate *test_spice_create_update_draw(Test *test, uint32_t surface_id, int t)
-{
-    int top, left;
-    uint8_t *dst;
-    uint8_t *bitmap;
-    int bw, bh;
-    int i;
-    QXLRect bbox;
-
-    draw_pos(test, t, &left, &top);
-    if ((t % angle_parts) == 0) {
-        c_i++;
-    }
-
-    if (surface_id != 0) {
-        color = (color + 1) % 2;
-    } else {
-        color = surface_id;
-    }
-
-    unique++;
-
-    bw       = test->primary_width/SINGLE_PART;
-    bh       = 48;
-
-    bitmap = dst = malloc(bw * bh * 4);
-    //printf("allocated %p\n", dst);
-
-    for (i = 0 ; i < bh * bw ; ++i, dst+=4) {
-        *dst = (color+i % 255);
-        *(dst+((1+c_i)%3)) = 255 - color;
-        *(dst+((2+c_i)%3)) = (color * (color + i)) & 0xff;
-        *(dst+((3+c_i)%3)) = 0;
-    }
-
-    bbox.left = left; bbox.top = top;
-    bbox.right = left + bw; bbox.bottom = top + bh;
-    return test_spice_create_update_from_bitmap(surface_id, bbox, bitmap, 0, NULL);
-}
-
-static SimpleSpiceUpdate *test_spice_create_update_copy_bits(Test *test, uint32_t surface_id)
-{
-    SimpleSpiceUpdate *update;
-    QXLDrawable *drawable;
-    int bw, bh;
-    QXLRect bbox = {
-        .left = 10,
-        .top = 0,
-    };
-
-    update   = calloc(sizeof(*update), 1);
-    drawable = &update->drawable;
-
-    bw       = test->primary_width/SINGLE_PART;
-    bh       = 48;
-    bbox.right = bbox.left + bw;
-    bbox.bottom = bbox.top + bh;
-    //printf("allocated %p, %p\n", update, update->bitmap);
-
-    drawable->surface_id      = surface_id;
-
-    drawable->bbox            = bbox;
-    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
-    drawable->effect          = QXL_EFFECT_OPAQUE;
-    simple_set_release_info(&drawable->release_info, (intptr_t)update);
-    drawable->type            = QXL_COPY_BITS;
-    drawable->surfaces_dest[0] = -1;
-    drawable->surfaces_dest[1] = -1;
-    drawable->surfaces_dest[2] = -1;
-
-    drawable->u.copy_bits.src_pos.x = 0;
-    drawable->u.copy_bits.src_pos.y = 0;
-
-    set_cmd(&update->ext, QXL_CMD_DRAW, (intptr_t)drawable);
-
-    return update;
-}
-
-static int format_to_bpp(int format)
-{
-    switch (format) {
-    case SPICE_SURFACE_FMT_8_A:
-        return 1;
-    case SPICE_SURFACE_FMT_16_555:
-    case SPICE_SURFACE_FMT_16_565:
-        return 2;
-    case SPICE_SURFACE_FMT_32_xRGB:
-    case SPICE_SURFACE_FMT_32_ARGB:
-        return 4;
-    }
-    abort();
-}
-
-static SimpleSurfaceCmd *create_surface(int surface_id, int format, int width, int height, uint8_t *data)
-{
-    SimpleSurfaceCmd *simple_cmd = calloc(sizeof(SimpleSurfaceCmd), 1);
-    QXLSurfaceCmd *surface_cmd = &simple_cmd->surface_cmd;
-    int bpp = format_to_bpp(format);
-
-    set_cmd(&simple_cmd->ext, QXL_CMD_SURFACE, (intptr_t)surface_cmd);
-    simple_set_release_info(&surface_cmd->release_info, (intptr_t)simple_cmd);
-    surface_cmd->type = QXL_SURFACE_CMD_CREATE;
-    surface_cmd->flags = 0; // ?
-    surface_cmd->surface_id = surface_id;
-    surface_cmd->u.surface_create.format = format;
-    surface_cmd->u.surface_create.width = width;
-    surface_cmd->u.surface_create.height = height;
-    surface_cmd->u.surface_create.stride = -width * bpp;
-    surface_cmd->u.surface_create.data = (intptr_t)data;
-    return simple_cmd;
-}
-
-static SimpleSurfaceCmd *destroy_surface(int surface_id)
-{
-    SimpleSurfaceCmd *simple_cmd = calloc(sizeof(SimpleSurfaceCmd), 1);
-    QXLSurfaceCmd *surface_cmd = &simple_cmd->surface_cmd;
-
-    set_cmd(&simple_cmd->ext, QXL_CMD_SURFACE, (intptr_t)surface_cmd);
-    simple_set_release_info(&surface_cmd->release_info, (intptr_t)simple_cmd);
-    surface_cmd->type = QXL_SURFACE_CMD_DESTROY;
-    surface_cmd->flags = 0; // ?
-    surface_cmd->surface_id = surface_id;
-    return simple_cmd;
-}
-
-static void create_primary_surface(Test *test, uint32_t width,
-                                   uint32_t height)
-{
-    QXLDevSurfaceCreate surface = { 0, };
-
-    spice_assert(height <= MAX_HEIGHT);
-    spice_assert(width <= MAX_WIDTH);
-    spice_assert(height > 0);
-    spice_assert(width > 0);
-
-    surface.format     = SPICE_SURFACE_FMT_32_xRGB;
-    surface.width      = test->primary_width = width;
-    surface.height     = test->primary_height = height;
-    surface.stride     = -width * 4; /* negative? */
-    surface.mouse_mode = TRUE; /* unused by red_worker */
-    surface.flags      = 0;
-    surface.type       = 0;    /* unused by red_worker */
-    surface.position   = 0;    /* unused by red_worker */
-    surface.mem        = (uint64_t)&test->primary_surface;
-    surface.group_id   = MEM_SLOT_GROUP_ID;
-
-    test->width = width;
-    test->height = height;
-
-    spice_qxl_create_primary_surface(&test->qxl_instance, 0, &surface);
-}
-
-QXLDevMemSlot slot = {
-.slot_group_id = MEM_SLOT_GROUP_ID,
-.slot_id = 0,
-.generation = 0,
-.virt_start = 0,
-.virt_end = ~0,
-.addr_delta = 0,
-.qxl_ram_size = ~0,
-};
-
-static void attache_worker(QXLInstance *qin, QXLWorker *_qxl_worker)
-{
-    Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance);
-
-    if (test->qxl_worker) {
-        if (test->qxl_worker != _qxl_worker)
-            printf("%s ignored, %p is set, ignoring new %p\n", __func__,
-                   test->qxl_worker, _qxl_worker);
-        else
-            printf("%s ignored, redundant\n", __func__);
-        return;
-    }
-    printf("%s\n", __func__);
-    test->qxl_worker = _qxl_worker;
-    spice_qxl_add_memslot(&test->qxl_instance, &slot);
-    create_primary_surface(test, DEFAULT_WIDTH, DEFAULT_HEIGHT);
-    spice_server_vm_start(test->server);
-}
-
-static void set_compression_level(SPICE_GNUC_UNUSED QXLInstance *qin,
-                                  SPICE_GNUC_UNUSED int level)
-{
-    printf("%s\n", __func__);
-}
-
-static void set_mm_time(SPICE_GNUC_UNUSED QXLInstance *qin,
-                        SPICE_GNUC_UNUSED uint32_t mm_time)
-{
-}
-
-// we now have a secondary surface
-#define MAX_SURFACE_NUM 2
-
-static void get_init_info(SPICE_GNUC_UNUSED QXLInstance *qin,
-                          QXLDevInitInfo *info)
-{
-    memset(info, 0, sizeof(*info));
-    info->num_memslots = 1;
-    info->num_memslots_groups = 1;
-    info->memslot_id_bits = 1;
-    info->memslot_gen_bits = 1;
-    info->n_surfaces = MAX_SURFACE_NUM;
-}
-
-// We shall now have a ring of commands, so that we can update
-// it from a separate thread - since get_command is called from
-// the worker thread, and we need to sometimes do an update_area,
-// which cannot be done from red_worker context (not via dispatcher,
-// since you get a deadlock, and it isn't designed to be done
-// any other way, so no point testing that).
-int commands_end = 0;
-int commands_start = 0;
-struct QXLCommandExt* commands[1024];
-
-#define COMMANDS_SIZE COUNT(commands)
-
-static void push_command(QXLCommandExt *ext)
-{
-    spice_assert(commands_end - commands_start < (int) COMMANDS_SIZE);
-    commands[commands_end % COMMANDS_SIZE] = ext;
-    commands_end++;
-}
-
-static struct QXLCommandExt *get_simple_command(void)
-{
-    struct QXLCommandExt *ret = commands[commands_start % COMMANDS_SIZE];
-    spice_assert(commands_start < commands_end);
-    commands_start++;
-    return ret;
-}
-
-static int get_num_commands(void)
-{
-    return commands_end - commands_start;
-}
-
-// called from spice_server thread (i.e. red_worker thread)
-static int get_command(SPICE_GNUC_UNUSED QXLInstance *qin,
-                       struct QXLCommandExt *ext)
-{
-    if (get_num_commands() == 0) {
-        return FALSE;
-    }
-    *ext = *get_simple_command();
-    return TRUE;
-}
-
-static void produce_command(Test *test)
-{
-    Command *command;
-    QXLWorker *qxl_worker = test->qxl_worker;
-
-    spice_assert(qxl_worker);
-
-    if (test->has_secondary)
-        test->target_surface = 1;
-
-    if (!test->num_commands) {
-        usleep(1000);
-        return;
-    }
-
-    command = &test->commands[test->cmd_index];
-    if (command->cb) {
-        command->cb(test, command);
-    }
-    switch (command->command) {
-        case SLEEP:
-             printf("sleep %u seconds\n", command->sleep.secs);
-             sleep(command->sleep.secs);
-             break;
-        case PATH_PROGRESS:
-            path_progress(&path);
-            break;
-        case SIMPLE_UPDATE: {
-            QXLRect rect = {
-                .left = 0,
-                .right = (test->target_surface == 0 ? test->primary_width : test->width),
-                .top = 0,
-                .bottom = (test->target_surface == 0 ? test->primary_height : test->height)
-            };
-            if (rect.right > 0 && rect.bottom > 0) {
-                spice_qxl_update_area(&test->qxl_instance, test->target_surface, &rect, NULL, 0, 1);
-            }
-            break;
-        }
-
-        /* Drawing commands, they all push a command to the command ring */
-        case SIMPLE_COPY_BITS:
-        case SIMPLE_DRAW_SOLID:
-        case SIMPLE_DRAW_BITMAP:
-        case SIMPLE_DRAW: {
-            SimpleSpiceUpdate *update;
-
-            if (has_automated_tests)
-            {
-                if (control == 0) {
-                     return;
-                }
-
-                regression_test();
-            }
-
-            switch (command->command) {
-            case SIMPLE_COPY_BITS:
-                update = test_spice_create_update_copy_bits(test, 0);
-                break;
-            case SIMPLE_DRAW:
-                update = test_spice_create_update_draw(test, 0, path.t);
-                break;
-            case SIMPLE_DRAW_BITMAP:
-                update = test_spice_create_update_from_bitmap(command->bitmap.surface_id,
-                        command->bitmap.bbox, command->bitmap.bitmap,
-                        command->bitmap.num_clip_rects, command->bitmap.clip_rects);
-                break;
-            case SIMPLE_DRAW_SOLID:
-                update = test_spice_create_update_solid(command->solid.surface_id,
-                        command->solid.bbox, command->solid.color);
-                break;
-            default: /* Just to shut up GCC warning (-Wswitch) */
-                break;
-            }
-            push_command(&update->ext);
-            break;
-        }
-
-        case SIMPLE_CREATE_SURFACE: {
-            SimpleSurfaceCmd *update;
-            if (command->create_surface.data) {
-                spice_assert(command->create_surface.surface_id > 0);
-                spice_assert(command->create_surface.surface_id < MAX_SURFACE_NUM);
-                spice_assert(command->create_surface.surface_id == 1);
-                update = create_surface(command->create_surface.surface_id,
-                                        command->create_surface.format,
-                                        command->create_surface.width,
-                                        command->create_surface.height,
-                                        command->create_surface.data);
-            } else {
-                update = create_surface(test->target_surface, SPICE_SURFACE_FMT_32_xRGB,
-                                        SURF_WIDTH, SURF_HEIGHT,
-                                        test->secondary_surface);
-            }
-            push_command(&update->ext);
-            test->has_secondary = 1;
-            break;
-        }
-
-        case SIMPLE_DESTROY_SURFACE: {
-            SimpleSurfaceCmd *update;
-            test->has_secondary = 0;
-            update = destroy_surface(test->target_surface);
-            test->target_surface = 0;
-            push_command(&update->ext);
-            break;
-        }
-
-        case DESTROY_PRIMARY:
-            spice_qxl_destroy_primary_surface(&test->qxl_instance, 0);
-            break;
-
-        case CREATE_PRIMARY:
-            create_primary_surface(test,
-                    command->create_primary.width, command->create_primary.height);
-            break;
-    }
-    test->cmd_index = (test->cmd_index + 1) % test->num_commands;
-}
-
-static int req_cmd_notification(QXLInstance *qin)
-{
-    Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance);
-
-    test->core->timer_start(test->wakeup_timer, test->wakeup_ms);
-    return TRUE;
-}
-
-static void do_wakeup(void *opaque)
-{
-    Test *test = opaque;
-    int notify;
-
-    test->cursor_notify = NOTIFY_CURSOR_BATCH;
-    for (notify = NOTIFY_DISPLAY_BATCH; notify > 0;--notify) {
-        produce_command(test);
-    }
-
-    test->core->timer_start(test->wakeup_timer, test->wakeup_ms);
-    spice_qxl_wakeup(&test->qxl_instance);
-}
-
-static void release_resource(SPICE_GNUC_UNUSED QXLInstance *qin,
-                             struct QXLReleaseInfoExt release_info)
-{
-    QXLCommandExt *ext = (QXLCommandExt*)(unsigned long)release_info.info->id;
-    //printf("%s\n", __func__);
-    spice_assert(release_info.group_id == MEM_SLOT_GROUP_ID);
-    switch (ext->cmd.type) {
-        case QXL_CMD_DRAW:
-            test_spice_destroy_update((void*)ext);
-            break;
-        case QXL_CMD_SURFACE:
-            free(ext);
-            break;
-        case QXL_CMD_CURSOR: {
-            QXLCursorCmd *cmd = (QXLCursorCmd *)(unsigned long)ext->cmd.data;
-            if (cmd->type == QXL_CURSOR_SET) {
-                free(cmd);
-            }
-            free(ext);
-            break;
-        }
-        default:
-            abort();
-    }
-}
-
-#define CURSOR_WIDTH 32
-#define CURSOR_HEIGHT 32
-
-static struct {
-    QXLCursor cursor;
-    uint8_t data[CURSOR_WIDTH * CURSOR_HEIGHT * 4]; // 32bit per pixel
-} cursor;
-
-static void cursor_init()
-{
-    cursor.cursor.header.unique = 0;
-    cursor.cursor.header.type = SPICE_CURSOR_TYPE_COLOR32;
-    cursor.cursor.header.width = CURSOR_WIDTH;
-    cursor.cursor.header.height = CURSOR_HEIGHT;
-    cursor.cursor.header.hot_spot_x = 0;
-    cursor.cursor.header.hot_spot_y = 0;
-    cursor.cursor.data_size = CURSOR_WIDTH * CURSOR_HEIGHT * 4;
-
-    // X drivers addes it to the cursor size because it could be
-    // cursor data information or another cursor related stuffs.
-    // Otherwise, the code will break in client/cursor.cpp side,
-    // that expect the data_size plus cursor information.
-    // Blame cursor protocol for this. :-)
-    cursor.cursor.data_size += 128;
-    cursor.cursor.chunk.data_size = cursor.cursor.data_size;
-    cursor.cursor.chunk.prev_chunk = cursor.cursor.chunk.next_chunk = 0;
-}
-
-static int get_cursor_command(QXLInstance *qin, struct QXLCommandExt *ext)
-{
-    Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance);
-    static int set = 1;
-    static int x = 0, y = 0;
-    QXLCursorCmd *cursor_cmd;
-    QXLCommandExt *cmd;
-
-    if (!test->cursor_notify) {
-        return FALSE;
-    }
-
-    test->cursor_notify--;
-    cmd = calloc(sizeof(QXLCommandExt), 1);
-    cursor_cmd = calloc(sizeof(QXLCursorCmd), 1);
-
-    cursor_cmd->release_info.id = (unsigned long)cmd;
-
-    if (set) {
-        cursor_cmd->type = QXL_CURSOR_SET;
-        cursor_cmd->u.set.position.x = 0;
-        cursor_cmd->u.set.position.y = 0;
-        cursor_cmd->u.set.visible = TRUE;
-        cursor_cmd->u.set.shape = (unsigned long)&cursor;
-        // Only a white rect (32x32) as cursor
-        memset(cursor.data, 255, sizeof(cursor.data));
-        set = 0;
-    } else {
-        cursor_cmd->type = QXL_CURSOR_MOVE;
-        cursor_cmd->u.position.x = x++ % test->primary_width;
-        cursor_cmd->u.position.y = y++ % test->primary_height;
-    }
-
-    cmd->cmd.data = (unsigned long)cursor_cmd;
-    cmd->cmd.type = QXL_CMD_CURSOR;
-    cmd->group_id = MEM_SLOT_GROUP_ID;
-    cmd->flags    = 0;
-    *ext = *cmd;
-    //printf("%s\n", __func__);
-    return TRUE;
-}
-
-static int req_cursor_notification(SPICE_GNUC_UNUSED QXLInstance *qin)
-{
-    printf("%s\n", __func__);
-    return TRUE;
-}
-
-static void notify_update(SPICE_GNUC_UNUSED QXLInstance *qin,
-                          SPICE_GNUC_UNUSED uint32_t update_id)
-{
-    printf("%s\n", __func__);
-}
-
-static int flush_resources(SPICE_GNUC_UNUSED QXLInstance *qin)
-{
-    printf("%s\n", __func__);
-    return TRUE;
-}
-
-static int client_monitors_config(SPICE_GNUC_UNUSED QXLInstance *qin,
-                                  VDAgentMonitorsConfig *monitors_config)
-{
-    if (!monitors_config) {
-        printf("%s: NULL monitors_config\n", __func__);
-    } else {
-        printf("%s: %d\n", __func__, monitors_config->num_of_monitors);
-    }
-    return 0;
-}
-
-static void set_client_capabilities(QXLInstance *qin,
-                                    uint8_t client_present,
-                                    uint8_t caps[58])
-{
-    Test *test = SPICE_CONTAINEROF(qin, Test, qxl_instance);
-
-    printf("%s: present %d caps %d\n", __func__, client_present, caps[0]);
-    if (test->on_client_connected && client_present) {
-        test->on_client_connected(test);
-    }
-    if (test->on_client_disconnected && !client_present) {
-        test->on_client_disconnected(test);
-    }
-}
-
-QXLInterface display_sif = {
-    .base = {
-        .type = SPICE_INTERFACE_QXL,
-        .description = "test",
-        .major_version = SPICE_INTERFACE_QXL_MAJOR,
-        .minor_version = SPICE_INTERFACE_QXL_MINOR
-    },
-    .attache_worker = attache_worker,
-    .set_compression_level = set_compression_level,
-    .set_mm_time = set_mm_time,
-    .get_init_info = get_init_info,
-
-    /* the callbacks below are called from spice server thread context */
-    .get_command = get_command,
-    .req_cmd_notification = req_cmd_notification,
-    .release_resource = release_resource,
-    .get_cursor_command = get_cursor_command,
-    .req_cursor_notification = req_cursor_notification,
-    .notify_update = notify_update,
-    .flush_resources = flush_resources,
-    .client_monitors_config = client_monitors_config,
-    .set_client_capabilities = set_client_capabilities,
-};
-
-/* interface for tests */
-void test_add_display_interface(Test* test)
-{
-    spice_server_add_interface(test->server, &test->qxl_instance.base);
-}
-
-static SpiceBaseInterface base = {
-    .type          = SPICE_INTERFACE_CHAR_DEVICE,
-    .description   = "test spice virtual channel char device",
-    .major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
-    .minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
-};
-
-SpiceCharDeviceInstance vdagent_sin = {
-    .base = {
-        .sif = &base,
-    },
-    .subtype = "vdagent",
-};
-
-void test_add_agent_interface(SpiceServer *server)
-{
-    spice_server_add_interface(server, &vdagent_sin.base);
-}
-
-void test_set_simple_command_list(Test *test, int *simple_commands, int num_commands)
-{
-    int i;
-
-    /* FIXME: leaks */
-    test->commands = malloc(sizeof(*test->commands) * num_commands);
-    memset(test->commands, 0, sizeof(*test->commands) * num_commands);
-    test->num_commands = num_commands;
-    for (i = 0 ; i < num_commands; ++i) {
-        test->commands[i].command = simple_commands[i];
-    }
-}
-
-void test_set_command_list(Test *test, Command *commands, int num_commands)
-{
-    test->commands = commands;
-    test->num_commands = num_commands;
-}
-
-
-Test *test_new(SpiceCoreInterface *core)
-{
-    int port = 5912;
-    Test *test = spice_new0(Test, 1);
-    SpiceServer* server = spice_server_new();
-
-    test->qxl_instance.base.sif = &display_sif.base;
-    test->qxl_instance.id = 0;
-
-    test->core = core;
-    test->server = server;
-    test->wakeup_ms = 1;
-    test->cursor_notify = NOTIFY_CURSOR_BATCH;
-    // some common initialization for all display tests
-    printf("TESTER: listening on port %d (unsecure)\n", port);
-    spice_server_set_port(server, port);
-    spice_server_set_noauth(server);
-    spice_server_init(server, core);
-
-    cursor_init();
-    path_init(&path, 0, angle_parts);
-    test->has_secondary = 0;
-    test->wakeup_timer = core->timer_add(do_wakeup, test);
-    return test;
-}
-
-void init_automated()
-{
-    struct sigaction sa;
-
-    memset(&sa, 0, sizeof sa);
-    sa.sa_handler = &sigchld_handler;
-    sigaction(SIGCHLD, &sa, NULL);
-}
-
-__attribute__((noreturn))
-void usage(const char *argv0, const int exitcode)
-{
-#ifdef AUTOMATED_TESTS
-    const char *autoopt=" [--automated-tests]";
-#else
-    const char *autoopt="";
-#endif
-
-    printf("usage: %s%s\n", argv0, autoopt);
-    exit(exitcode);
-}
-
-void spice_test_config_parse_args(int argc, char **argv)
-{
-    struct option options[] = {
-#ifdef AUTOMATED_TESTS
-        {"automated-tests", no_argument, &has_automated_tests, 1},
-#endif
-        {NULL, 0, NULL, 0},
-    };
-    int option_index;
-    int val;
-
-    while ((val = getopt_long(argc, argv, "", options, &option_index)) != -1) {
-        switch (val) {
-        case '?':
-            printf("unrecognized option '%s'\n", argv[optind - 1]);
-            usage(argv[0], EXIT_FAILURE);
-        case 0:
-            break;
-        }
-    }
-
-    if (argc > optind) {
-        printf("unknown argument '%s'\n", argv[optind]);
-        usage(argv[0], EXIT_FAILURE);
-    }
-    if (has_automated_tests) {
-        init_automated();
-    }
-    return;
-}
diff --git a/server/tests/test_display_base.h b/server/tests/test_display_base.h
deleted file mode 100644
index e5d7965..0000000
--- a/server/tests/test_display_base.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef __TEST_DISPLAY_BASE_H__
-#define __TEST_DISPLAY_BASE_H__
-
-#include <spice.h>
-#include "basic_event_loop.h"
-
-#define COUNT(x) ((sizeof(x)/sizeof(x[0])))
-
-/*
- * simple queue for commands.
- * each command can have up to two parameters (grow as needed)
- *
- * TODO: switch to gtk main loop. Then add gobject-introspection. then
- * write tests in python/guile/whatever.
- */
-typedef enum {
-    PATH_PROGRESS,
-    SIMPLE_CREATE_SURFACE,
-    SIMPLE_DRAW,
-    SIMPLE_DRAW_BITMAP,
-    SIMPLE_DRAW_SOLID,
-    SIMPLE_COPY_BITS,
-    SIMPLE_DESTROY_SURFACE,
-    SIMPLE_UPDATE,
-    DESTROY_PRIMARY,
-    CREATE_PRIMARY,
-    SLEEP
-} CommandType;
-
-typedef struct CommandCreatePrimary {
-    uint32_t width;
-    uint32_t height;
-} CommandCreatePrimary;
-
-typedef struct CommandCreateSurface {
-    uint32_t surface_id;
-    uint32_t format;
-    uint32_t width;
-    uint32_t height;
-    uint8_t *data;
-} CommandCreateSurface;
-
-typedef struct CommandDrawBitmap {
-    QXLRect bbox;
-    uint8_t *bitmap;
-    uint32_t surface_id;
-    uint32_t num_clip_rects;
-    QXLRect *clip_rects;
-} CommandDrawBitmap;
-
-typedef struct CommandDrawSolid {
-    QXLRect bbox;
-    uint32_t color;
-    uint32_t surface_id;
-} CommandDrawSolid;
-
-typedef struct CommandSleep {
-    uint32_t secs;
-} CommandSleep;
-
-typedef struct Command Command;
-typedef struct Test Test;
-
-struct Command {
-    CommandType command;
-    void (*cb)(Test *test, Command *command);
-    void *cb_opaque;
-    union {
-        CommandCreatePrimary create_primary;
-        CommandDrawBitmap bitmap;
-        CommandDrawSolid solid;
-        CommandSleep sleep;
-        CommandCreateSurface create_surface;
-    };
-};
-
-#define MAX_HEIGHT 2048
-#define MAX_WIDTH 2048
-
-#define SURF_WIDTH 320
-#define SURF_HEIGHT 240
-
-struct Test {
-    SpiceCoreInterface *core;
-    SpiceServer *server;
-
-    QXLInstance qxl_instance;
-    QXLWorker *qxl_worker;
-
-    uint8_t primary_surface[MAX_HEIGHT * MAX_WIDTH * 4];
-    int primary_height;
-    int primary_width;
-
-    SpiceTimer *wakeup_timer;
-    int wakeup_ms;
-
-    int cursor_notify;
-
-    uint8_t secondary_surface[SURF_WIDTH * SURF_HEIGHT * 4];
-    int has_secondary;
-
-    // Current mode (set by create_primary)
-    int width;
-    int height;
-
-    // qxl scripted rendering commands and io
-    Command *commands;
-    int num_commands;
-    int cmd_index;
-
-    int target_surface;
-
-    // callbacks
-    void (*on_client_connected)(Test *test);
-    void (*on_client_disconnected)(Test *test);
-};
-
-void test_set_simple_command_list(Test *test, int *command, int num_commands);
-void test_set_command_list(Test *test, Command *command, int num_commands);
-void test_add_display_interface(Test *test);
-void test_add_agent_interface(SpiceServer *server); // TODO - Test *test
-Test* test_new(SpiceCoreInterface* core);
-
-uint32_t test_get_width(void);
-uint32_t test_get_height(void);
-
-void spice_test_config_parse_args(int argc, char **argv);
-
-#endif /* __TEST_DISPLAY_BASE_H__ */
diff --git a/server/tests/test_display_no_ssl.c b/server/tests/test_display_no_ssl.c
deleted file mode 100644
index d861128..0000000
--- a/server/tests/test_display_no_ssl.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * Test ground for developing specific tests.
- *
- * Any specific test can start of from here and set the server to the
- * specific required state, and create specific operations or reuse
- * existing ones in the test_display_base supplied queue.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include "test_display_base.h"
-
-SpiceCoreInterface *core;
-SpiceTimer *ping_timer;
-
-void show_channels(SpiceServer *server);
-
-int ping_ms = 100;
-
-void pinger(SPICE_GNUC_UNUSED void *opaque)
-{
-    // show_channels is not thread safe - fails if disconnections / connections occur
-    //show_channels(server);
-
-    core->timer_start(ping_timer, ping_ms);
-}
-
-int simple_commands[] = {
-    //SIMPLE_CREATE_SURFACE,
-    //SIMPLE_DRAW,
-    //SIMPLE_DESTROY_SURFACE,
-    //PATH_PROGRESS,
-    SIMPLE_DRAW,
-    //SIMPLE_COPY_BITS,
-    SIMPLE_UPDATE,
-};
-
-int main(void)
-{
-    Test *test;
-
-    core = basic_event_loop_init();
-    test = test_new(core);
-    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESSION_OFF);
-    test_add_display_interface(test);
-    test_add_agent_interface(test->server);
-    test_set_simple_command_list(test, simple_commands, COUNT(simple_commands));
-
-    ping_timer = core->timer_add(pinger, NULL);
-    core->timer_start(ping_timer, ping_ms);
-
-    basic_event_loop_mainloop();
-
-    return 0;
-}
diff --git a/server/tests/test_display_resolution_changes.c b/server/tests/test_display_resolution_changes.c
deleted file mode 100644
index 069f460..0000000
--- a/server/tests/test_display_resolution_changes.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * Recreate the primary surface endlessly.
- */
-
-#include <config.h>
-#include <math.h>
-#include <stdlib.h>
-#include "test_display_base.h"
-
-SpiceTimer *ping_timer;
-
-void show_channels(SpiceServer *server);
-
-int ping_ms = 100;
-
-void pinger(void *opaque)
-{
-    Test *test = opaque;
-    // show_channels is not thread safe - fails if disconnections / connections occur
-    //show_channels(server);
-
-    test->core->timer_start(ping_timer, ping_ms);
-}
-
-void set_primary_params(SPICE_GNUC_UNUSED Test *test,
-                        Command *command)
-{
-#if 0
-    static int toggle = 0;
-
-    if (toggle) {
-        *arg1 = 800;
-        *arg2 = 600;
-    } else {
-        *arg1 = 1024;
-        *arg2 = 768;
-    }
-    toggle = 1 - toggle;
-#endif
-    static int count = 0;
-
-    command->create_primary.width = 800 + sin((float)count / 6) * 200;
-    command->create_primary.height = 600 + cos((float)count / 6) * 200;
-    count++;
-}
-
-static Command commands[] = {
-    {DESTROY_PRIMARY, NULL, .cb_opaque = NULL,},
-    {CREATE_PRIMARY, set_primary_params, .cb_opaque = NULL},
-};
-
-int main(void)
-{
-    SpiceCoreInterface *core;
-    Test *test;
-
-    core = basic_event_loop_init();
-    test = test_new(core);
-    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESSION_OFF);
-    test_add_display_interface(test);
-    test_set_command_list(test, commands, COUNT(commands));
-
-    ping_timer = core->timer_add(pinger, test);
-    core->timer_start(ping_timer, ping_ms);
-
-    basic_event_loop_mainloop();
-
-    return 0;
-}
diff --git a/server/tests/test_display_streaming.c b/server/tests/test_display_streaming.c
deleted file mode 100644
index 446bbf3..0000000
--- a/server/tests/test_display_streaming.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-/* Do repeated updates to the same rectangle to trigger stream creation.
- *
- * TODO: check that stream actually starts programatically (maybe stap?)
- * TODO: stop updating same rect, check (prog) that stream stops
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <time.h>
-
-#include <glib.h>
-
-#include "test_display_base.h"
-
-static int sized;
-static int render_last_frame;
-
-static void create_overlay(Command *command , int width, int height)
-{
-    CommandDrawBitmap *cmd = &command->bitmap;
-    uint32_t *dst;
-
-    cmd->surface_id = 0;
-
-    cmd->bbox.left = 0;
-    cmd->bbox.top = 0;
-    cmd->bbox.right = width;
-    cmd->bbox.bottom = height;
-
-    cmd->num_clip_rects = 0;
-    cmd->bitmap = g_malloc(width * height * 4 );
-    dst = (uint32_t *)cmd->bitmap;
-    for (int i = 0; i < width * height; i++, dst++) {
-        *dst = 0x8B008B;
-    }
-
-}
-
-#define NUM_COMMANDS 2000
-#define SIZED_INTERVAL 100
-#define OVERLAY_FRAME 500
-#define OVERLAY_WIDTH 200
-#define OVERLAY_HEIGHT 200
-
-/*
- * Create a frame in a stream that displays a row that moves
- * from the top to the bottom repeatedly.
- * Upon the OVERLAY_FRAME-th, a drawable is created on top of a part of the stream,
- * and from then on, all the stream frames has a clipping that keeps this drawable
- * visible, and in addition a clipping_factor is subtracted from the right limit of their clipping.
- * If sized=TRUE, a higher and wider frame than the original stream is created every SIZED_INTERVAL.
- * The sized frames can be distinguished by a change in the color of the top and bottom limits of the
- * surface.
- */
-static void create_clipped_frame(Test *test, Command *command, int clipping_factor)
-{
-    static int count = 0;
-    CommandDrawBitmap *cmd = &command->bitmap;
-    int max_height = test->height;
-    int max_width = test->width;
-    int width;
-    int height;
-    int cur_line, end_line;
-    uint32_t *dst;
-
-    count++;
-    if (count == NUM_COMMANDS) {
-        count = 0;
-    }
-    if (count == OVERLAY_FRAME) {
-        create_overlay(command, OVERLAY_WIDTH, OVERLAY_HEIGHT);
-        return;
-    }
-
-    cmd->surface_id = 0;
-
-    cmd->bbox.left = 0;
-    cmd->bbox.right = max_width - 50;
-    assert(max_height > 600);
-    cmd->bbox.top = 50;
-    cmd->bbox.bottom = max_height - 50;
-    height = cmd->bbox.bottom  - cmd->bbox.top;
-    width = cmd->bbox.right - cmd->bbox.left;
-    cur_line = (height/30)*(count % 30);
-    end_line = cur_line + (height/30);
-    if (end_line >= height || height - end_line < 8) {
-        end_line = height;
-    }
-
-    if (sized && count % SIZED_INTERVAL == 0) {
-
-        cmd->bbox.top = 0;
-        cmd->bbox.bottom = max_height;
-        cmd->bbox.left = 0;
-        cmd->bbox.right = max_width;
-        height = max_height;
-        width = max_width;
-        cur_line += 50;
-        end_line += 50;
-    }
-
-    cmd->bitmap = g_malloc(width*height*4);
-    memset(cmd->bitmap, 0xff, width*height*4);
-    dst = (uint32_t *)(cmd->bitmap + cur_line*width*4);
-    for (; cur_line < end_line; cur_line++) {
-        int col;
-        for (col = 0; col < width; col++, dst++) {
-            *dst = 0x00FF00;
-        }
-    }
-    if (sized && count % SIZED_INTERVAL == 0) {
-        int i;
-        uint32_t color = 0xffffff & rand();
-
-        dst = (uint32_t *)cmd->bitmap;
-
-        for (i = 0; i < 50*width; i++, dst++) {
-            *dst = color;
-        }
-
-        dst = ((uint32_t *)(cmd->bitmap + (height - 50)*4*width));
-
-        for (i = 0; i < 50*width; i++, dst++) {
-            *dst = color;
-        }
-    }
-
-    if (count < OVERLAY_FRAME) {
-        cmd->num_clip_rects = 0;
-    } else {
-        cmd->num_clip_rects = 2;
-        cmd->clip_rects = calloc(sizeof(QXLRect), 2);
-        cmd->clip_rects[0].left = OVERLAY_WIDTH;
-        cmd->clip_rects[0].top = cmd->bbox.top;
-        cmd->clip_rects[0].right = cmd->bbox.right - clipping_factor;
-        cmd->clip_rects[0].bottom = OVERLAY_HEIGHT;
-        cmd->clip_rects[1].left = cmd->bbox.left;
-        cmd->clip_rects[1].top = OVERLAY_HEIGHT;
-        cmd->clip_rects[1].right = cmd->bbox.right - clipping_factor;
-        cmd->clip_rects[1].bottom = cmd->bbox.bottom;
-    }
-}
-
-static void create_frame1(Test *test, Command *command)
-{
-    create_clipped_frame(test, command, 0);
-}
-
-void create_frame2(Test *test, Command *command)
-{
-    create_clipped_frame(test, command, 200);
-}
-
-typedef void (*create_frame_cb)(Test *test, Command *command);
-
-
-/*
- * The test contains two types of streams. The first stream doesn't
- * have a clipping besides the on that the display the overlay drawable.
- * Expected result: If render_last_frame=false, the last frame should
- * be sent losslessly. Otherwise, red_update_area should be called, and the
- * stream is upgraded by a screenshot.
- *
- * In the second test, the stream clip changes in the middle (becomes smaller).
- * Expected result: red_update_area should is, and the
- * stream is upgraded by a screenshot (including lossy areas that belong to old frames
- * and were never covered by a lossless drawable).
- *
- */
-static void get_stream_commands(Command *commands, int num_commands,
-                                create_frame_cb cb)
-{
-    int i;
-
-    commands[0].command = DESTROY_PRIMARY;
-    commands[1].command = CREATE_PRIMARY;
-    commands[1].create_primary.width = 1280;
-    commands[1].create_primary.height = 1024;
-    commands[num_commands - 1].command = SLEEP;
-    commands[num_commands - 1].sleep.secs = 20;
-
-    for (i = 2; i < num_commands - 1; i++) {
-        commands[i].command = SIMPLE_DRAW_BITMAP;
-        commands[i].cb = cb;
-    }
-    if (render_last_frame) {
-        commands[num_commands - 2].command = SIMPLE_UPDATE;
-    }
-}
-
-static void get_commands(Command **commands, int *num_commands)
-{
-    *num_commands = NUM_COMMANDS * 2;
-    *commands = calloc(sizeof(Command), *num_commands);
-
-    get_stream_commands(*commands, NUM_COMMANDS, create_frame1);
-    get_stream_commands((*commands) + NUM_COMMANDS, NUM_COMMANDS, create_frame2);
-}
-
-
-int main(int argc, char **argv)
-{
-    SpiceCoreInterface *core;
-    Command *commands;
-    int num_commands;
-    int i;
-    Test *test;
-
-    spice_test_config_parse_args(argc, argv);
-    sized = 0;
-    for (i = 1 ; i < argc; ++i) {
-        if (strcmp(argv[i], "sized") == 0) {
-            sized = 1;
-        }
-        /* render last frame */
-        if (strcmp(argv[i], "render") == 0) {
-            render_last_frame = 1;
-        }
-    }
-    srand(time(NULL));
-    // todo: add args list of test numbers with explenations
-    core = basic_event_loop_init();
-    test = test_new(core);
-    spice_server_set_streaming_video(test->server, SPICE_STREAM_VIDEO_ALL);
-    test_add_display_interface(test);
-    get_commands(&commands, &num_commands);
-    test_set_command_list(test, commands, num_commands);
-    basic_event_loop_mainloop();
-    free(commands);
-    return 0;
-}
diff --git a/server/tests/test_display_width_stride.c b/server/tests/test_display_width_stride.c
deleted file mode 100644
index bd27e60..0000000
--- a/server/tests/test_display_width_stride.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * Recreate the primary surface endlessly.
- */
-
-#include <config.h>
-#include <math.h>
-#include <stdlib.h>
-#include "test_display_base.h"
-
-SpiceTimer *ping_timer;
-
-void show_channels(SpiceServer *server);
-
-int ping_ms = 100;
-
-void pinger(void *opaque)
-{
-    Test *test = opaque;
-    // show_channels is not thread safe - fails if disconnections / connections occur
-    //show_channels(server);
-
-    test->core->timer_start(ping_timer, ping_ms);
-}
-
-static int g_surface_id = 1;
-static uint8_t *g_surface_data;
-
-void set_draw_parameters(SPICE_GNUC_UNUSED Test *test,
-                         Command *command)
-{
-    static int count = 17;
-    CommandDrawSolid *solid = &command->solid;
-
-    solid->bbox.top = 0;
-    solid->bbox.left = 0;
-    solid->bbox.bottom = 20;
-    solid->bbox.right = count;
-    solid->surface_id = g_surface_id;
-    count++;
-}
-
-void set_surface_params(SPICE_GNUC_UNUSED Test *test,
-                        Command *command)
-{
-    CommandCreateSurface *create = &command->create_surface;
-
-    // UGLY
-    if (g_surface_data) {
-        exit(0);
-    }
-    create->format = SPICE_SURFACE_FMT_8_A;
-    create->width = 128;
-    create->height = 128;
-    g_surface_data = realloc(g_surface_data, create->width * create->height * 1);
-    create->surface_id = g_surface_id;
-    create->data = g_surface_data;
-}
-
-void set_destroy_parameters(SPICE_GNUC_UNUSED Test *test,
-                            SPICE_GNUC_UNUSED Command *command)
-{
-    if (g_surface_data) {
-        free(g_surface_data);
-        g_surface_data = NULL;
-    }
-}
-
-static Command commands[] = {
-    {SIMPLE_CREATE_SURFACE, set_surface_params, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DRAW_SOLID, set_draw_parameters, .cb_opaque = NULL},
-    {SIMPLE_DESTROY_SURFACE, set_destroy_parameters, .cb_opaque = NULL},
-};
-
-void on_client_connected(Test *test)
-{
-    test_set_command_list(test, commands, COUNT(commands));
-}
-
-int main(void)
-{
-    SpiceCoreInterface *core;
-    Test *test;
-
-    core = basic_event_loop_init();
-    test = test_new(core);
-    test->on_client_connected = on_client_connected;
-    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESSION_OFF);
-    test_add_display_interface(test);
-
-    ping_timer = core->timer_add(pinger, test);
-    core->timer_start(ping_timer, ping_ms);
-
-    basic_event_loop_mainloop();
-
-    return 0;
-}
diff --git a/server/tests/test_empty_success.c b/server/tests/test_empty_success.c
deleted file mode 100644
index da98488..0000000
--- a/server/tests/test_empty_success.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <spice.h>
-
-struct SpiceTimer {
-    int a,b;
-};
-
-SpiceTimer* timer_add(SPICE_GNUC_UNUSED SpiceTimerFunc func,
-                      SPICE_GNUC_UNUSED void *opaque)
-{
-    static struct SpiceTimer t = {0,};
-
-    return &t;
-}
-
-void timer_start(SPICE_GNUC_UNUSED SpiceTimer *timer,
-                 SPICE_GNUC_UNUSED uint32_t ms)
-{
-}
-
-void timer_cancel(SPICE_GNUC_UNUSED SpiceTimer *timer)
-{
-}
-
-void timer_remove(SPICE_GNUC_UNUSED SpiceTimer *timer)
-{
-}
-
-SpiceWatch *watch_add(SPICE_GNUC_UNUSED int fd,
-                      SPICE_GNUC_UNUSED int event_mask,
-                      SPICE_GNUC_UNUSED SpiceWatchFunc func,
-                      SPICE_GNUC_UNUSED void *opaque)
-{
-    return NULL;
-}
-
-void watch_update_mask(SPICE_GNUC_UNUSED SpiceWatch *watch,
-                       SPICE_GNUC_UNUSED int event_mask)
-{
-}
-
-void watch_remove(SPICE_GNUC_UNUSED SpiceWatch *watch)
-{
-}
-
-void channel_event(SPICE_GNUC_UNUSED int event,
-                   SPICE_GNUC_UNUSED SpiceChannelEventInfo *info)
-{
-}
-
-int main(void)
-{
-    SpiceServer *server = spice_server_new();
-    SpiceCoreInterface core;
-
-    memset(&core, 0, sizeof(core));
-    core.base.major_version = SPICE_INTERFACE_CORE_MAJOR;
-    core.timer_add = timer_add;
-    core.timer_start = timer_start;
-    core.timer_cancel = timer_cancel;
-    core.timer_remove = timer_remove;
-    core.watch_add = watch_add;
-    core.watch_update_mask = watch_update_mask;
-    core.watch_remove = watch_remove;
-    core.channel_event = channel_event;
-
-    spice_server_set_port(server, 5911);
-    spice_server_init(server, &core);
-
-    spice_server_destroy(server);
-
-    return 0;
-}
diff --git a/server/tests/test_fail_on_null_core_interface.c b/server/tests/test_fail_on_null_core_interface.c
deleted file mode 100644
index 48e92db..0000000
--- a/server/tests/test_fail_on_null_core_interface.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <spice.h>
-
-int main(void)
-{
-    SpiceServer *server = spice_server_new();
-    SpiceCoreInterface core;
-
-    spice_server_init(server, &core);
-    spice_server_set_port(server, 5911);
-
-    return 0;
-}
diff --git a/server/tests/test_just_sockets_no_ssl.c b/server/tests/test_just_sockets_no_ssl.c
deleted file mode 100644
index 570903c..0000000
--- a/server/tests/test_just_sockets_no_ssl.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <sys/select.h>
-#include <spice.h>
-#include "basic_event_loop.h"
-
-int main(void)
-{
-    SpiceServer *server = spice_server_new();
-    SpiceCoreInterface *core = basic_event_loop_init();
-
-    spice_server_set_port(server, 5912);
-    spice_server_set_noauth(server);
-    spice_server_init(server, core);
-
-    basic_event_loop_mainloop();
-
-    return 0;
-}
diff --git a/server/tests/test_multiple.py b/server/tests/test_multiple.py
deleted file mode 100755
index ce03c94..0000000
--- a/server/tests/test_multiple.py
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/usr/bin/python
-
-"""
-Example usage:
-./test_multiple.py test_display_no_ssl --log test.log
-
-Resulting test.log file (single test, stopped with Ctrl-C with 15 clients):
-
-0 162212
-1 154156
-2 154424
-3 154952
-4 155352
-5 155616
-6 156280
-7 222084
-8 222612
-9 230820
-10 230820
-11 230820
-12 230820
-13 296356
-14 296356
-
-"""
-
-import argparse
-import os
-import sys
-import subprocess
-import atexit
-import socket
-import time
-
-def killall(procs):
-    for p in procs:
-        print "killing %d" % p.pid
-        p.kill()
-        p.wait()
-
-def cleanup():
-    killall(clients + [test_process])
-
-def wait_for_port(port):
-    if not port:
-        return
-    # TODO: do this without actually opening the port - maybe just look at /proc/qemu_process_id/fd?
-    s = socket.socket(socket.AF_INET)
-    while True:
-        try:
-            s.connect(('localhost', port))
-            s.close()
-            break
-        except:
-            time.sleep(1)
-            pass
-
-def get_vm_size(pid):
-    """ read from /proc/<pid>/status, VmSize, in KiloBytes  """
-    return int([x for x in open('/proc/%s/status' % pid).readlines() if 'VmSize' in x][0].split()[1])
-
-parser = argparse.ArgumentParser()
-parser.add_argument('--client', default='spicy')
-parser.add_argument('--start-count', default=1, type=int)
-parser.add_argument('--end-count', default=50, type=int)
-parser.add_argument('--log', default='-')
-parser.add_argument('--sleep', default=3, type=int)
-args, rest = parser.parse_known_args(sys.argv[1:])
-client = os.popen('which %s' % args.client).read().strip()
-if not os.path.exists(client):
-    print "supply a valid client. %s does not exist" % (args.client)
-    sys.exit(1)
-
-if not rest or len(rest) < 1 or not os.path.exists(rest[0]):
-    print "supply one argument that is the tester you wish to run"
-    sys.exit(1)
-
-prog = rest[0]
-port = {
-'test_display_no_ssl': 5912,
-'test_display_streaming': 5912,
-'test_just_sockets_no_ssl': 5912,
-'test_playback': 5701,
-}.get(prog, None)
-
-if args.log == '-':
-    log = sys.stdout
-else:
-    log = open(args.log, 'a+')
-
-log.write('#%s\n' % time.time())
-
-# kill leftovers from previous invocation
-os.system('killall lt-%s' % prog)
-
-if prog[0] != '/':
-    prog = os.path.join('.', prog)
-
-if not port:
-    print "unknown port for %r" % prog
-
-print "prog = %r" % prog
-print "client = %r" % client
-print "range = %d..%d" % (args.start_count, args.end_count)
-atexit.register(cleanup)
-os.environ['SPICE_DEBUG_ALLOW_MC'] = '1'
-test_process = subprocess.Popen([prog], executable=prog)
-wait_for_port(port)
-for count in xrange(args.start_count, args.end_count):
-    print "starting %d clients" % count
-    clients = [subprocess.Popen(args=[client, '-h', 'localhost', '-p', str(port)],
-                                executable=client) for i in xrange(count)]
-    print "sleeping %d" % (args.sleep * count)
-    time.sleep(args.sleep * count)
-    vmsize = "%d %d" % (i, get_vm_size(test_process.pid))
-    print vmsize
-    log.write(vmsize + '\n')
-    log.flush()
-    killall(clients)
-
-test_process.wait()
diff --git a/server/tests/test_playback.c b/server/tests/test_playback.c
deleted file mode 100644
index 1283427..0000000
--- a/server/tests/test_playback.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-#include <config.h>
-#include <stdio.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <math.h>
-
-#include <spice.h>
-#include "basic_event_loop.h"
-
-/* test the audio playback interface. Really basic no frils test - create
- * a single tone sinus sound (easy to hear clicks if it is generated badly
- * or is transmitted badly).
- *
- * TODO: Was going to do white noise to test compression too.
- *
- * TODO: gstreamer based test (could be used to play music files so
- * it has actual merit. Also possibly to simulate network effects?)
- * */
-
-SpicePlaybackInstance playback_instance;
-
-static const SpiceBaseInterface base = {
-    .type          = SPICE_INTERFACE_PLAYBACK,
-    .description   = "test playback",
-    .major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
-    .minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
-};
-
-uint32_t *frame;
-uint32_t num_samples;
-SpiceTimer *playback_timer;
-int playback_timer_ms;
-SpiceCoreInterface *core;
-
-static void get_frame(void)
-{
-    if (frame) {
-        return;
-    }
-    spice_server_playback_get_buffer(&playback_instance, &frame, &num_samples);
-    playback_timer_ms = num_samples
-                        ? 1000 * num_samples / SPICE_INTERFACE_PLAYBACK_FREQ
-                        : 100;
-}
-
-void playback_timer_cb(SPICE_GNUC_UNUSED void *opaque)
-{
-    static int t = 0;
-    static uint64_t last_sent_usec = 0;
-    static uint64_t samples_to_send;
-    uint32_t i;
-    struct timeval cur;
-    uint64_t cur_usec;
-
-    get_frame();
-    if (!frame) {
-        /* continue waiting until there is a channel */
-        core->timer_start(playback_timer, 100);
-        return;
-    }
-
-    /* we have a channel */
-    gettimeofday(&cur, NULL);
-    cur_usec = cur.tv_usec + cur.tv_sec * 1e6;
-    if (last_sent_usec == 0) {
-        samples_to_send = num_samples;
-    } else {
-        samples_to_send += (cur_usec - last_sent_usec) * SPICE_INTERFACE_PLAYBACK_FREQ / 1e6;
-    }
-    last_sent_usec = cur_usec;
-    while (samples_to_send > num_samples && frame) {
-#if 0
-    printf("samples_to_send = %d\n", samples_to_send);
-#endif
-        samples_to_send -= num_samples;
-        for (i = 0 ; i < num_samples; ++i) {
-            frame[i] = (((uint16_t)((1<<14)*sin((t+i)/10))) << 16) + (((uint16_t)((1<<14)*sin((t+i)/10))));
-        }
-        t += num_samples;
-        if (frame) {
-            spice_server_playback_put_samples(&playback_instance, frame);
-            frame = NULL;
-        }
-        get_frame();
-    }
-    core->timer_start(playback_timer, playback_timer_ms);
-}
-
-int main(void)
-{
-    SpiceServer *server = spice_server_new();
-    core = basic_event_loop_init();
-
-    spice_server_set_port(server, 5701);
-    spice_server_set_noauth(server);
-    spice_server_init(server, core);
-
-    playback_instance.base.sif = &base;
-    spice_server_add_interface(server, &playback_instance.base);
-    spice_server_playback_start(&playback_instance);
-
-    playback_timer_ms = 100;
-    playback_timer = core->timer_add(playback_timer_cb, NULL);
-    core->timer_start(playback_timer, playback_timer_ms);
-
-    basic_event_loop_mainloop();
-
-    return 0;
-}
diff --git a/server/tests/test_two_servers.c b/server/tests/test_two_servers.c
deleted file mode 100644
index e89909c..0000000
--- a/server/tests/test_two_servers.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * Test two servers on one main loop.
- */
-
-#include <config.h>
-#include <stdlib.h>
-#include "test_display_base.h"
-
-SpiceCoreInterface *core;
-
-int simple_commands[] = {
-    //SIMPLE_CREATE_SURFACE,
-    //SIMPLE_DRAW,
-    //SIMPLE_DESTROY_SURFACE,
-    //PATH_PROGRESS,
-    SIMPLE_DRAW,
-    //SIMPLE_COPY_BITS,
-    SIMPLE_UPDATE,
-};
-
-int main(void)
-{
-    Test *t1;
-    Test *t2;
-
-    core = basic_event_loop_init();
-    t1 = test_new(core);
-    t2 = test_new(core);
-    //spice_server_set_image_compression(server, SPICE_IMAGE_COMPRESSION_OFF);
-    test_add_display_interface(t1);
-    test_add_display_interface(t2);
-    test_set_simple_command_list(t1, simple_commands, COUNT(simple_commands));
-    test_set_simple_command_list(t2, simple_commands, COUNT(simple_commands));
-
-    basic_event_loop_mainloop();
-    return 0;
-}
diff --git a/server/tests/test_vdagent.c b/server/tests/test_vdagent.c
deleted file mode 100644
index bba3e64..0000000
--- a/server/tests/test_vdagent.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
-   Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-/**
- * Test vdagent guest to server messages
- */
-
-#include <config.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <spice/vd_agent.h>
-
-#include "test_display_base.h"
-
-SpiceCoreInterface *core;
-SpiceTimer *ping_timer;
-
-int ping_ms = 100;
-
-#ifndef MIN
-#define MIN(a, b) ((a) > (b) ? (b) : (a))
-#endif
-
-void pinger(SPICE_GNUC_UNUSED void *opaque)
-{
-    // show_channels is not thread safe - fails if disconnections / connections occur
-    //show_channels(server);
-
-    core->timer_start(ping_timer, ping_ms);
-}
-
-static SpiceBaseInterface base = {
-    .type          = SPICE_INTERFACE_CHAR_DEVICE,
-    .description   = "test spice virtual channel char device",
-    .major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
-    .minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
-};
-
-SpiceCharDeviceInstance vmc_instance = {
-    .subtype = "vdagent",
-};
-
-int main(void)
-{
-    Test *test;
-
-    core = basic_event_loop_init();
-    test = test_new(core);
-
-    vmc_instance.base.sif = &base;
-    spice_server_add_interface(test->server, &vmc_instance.base);
-
-    ping_timer = core->timer_add(pinger, NULL);
-    core->timer_start(ping_timer, ping_ms);
-
-    basic_event_loop_mainloop();
-
-    return 0;
-}


More information about the Spice-commits mailing list