On Fri, Feb 03, 2012 at 02:10:03AM -0200, Fabiano FidĂȘncio wrote: > As suggested by Alon, a simple automated test to try to find > regressions in Spice code. > To use this, compile Spice with --enable-automated-tests and > run test_display_streaming passing --automated-tests as parameter.
Hmm, actually calling the parameter "--automated-tests" is surely too broad, but nm for now. > --- > Makefile.am | 2 +- > configure.ac | 19 +++++ > server/tests/Makefile.am | 4 + > server/tests/README | 6 ++ > server/tests/regression_test.py | 25 +++++++ > server/tests/test_display_base.c | 119 ++++++++++++++++++++++++++++++-- > server/tests/test_display_base.h | 3 + > server/tests/test_display_streaming.c | 8 ++- > 8 files changed, 176 insertions(+), 10 deletions(-) > create mode 100755 server/tests/regression_test.py > > diff --git a/Makefile.am b/Makefile.am > index f8cfe25..c807359 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -12,4 +12,4 @@ DISTCLEANFILES = \ > > EXTRA_DIST = spice.proto spice1.proto spice_codegen.py > > -DISTCHECK_CONFIGURE_FLAGS=--enable-opengl --enable-gui --enable-tunnel > --enable-smartcard --with-sasl > +DISTCHECK_CONFIGURE_FLAGS=--enable-opengl --enable-gui --enable-tunnel > --enable-smartcard --with-sasl --enable-automated-tests > diff --git a/configure.ac b/configure.ac > index 0f8ad7d..3166eb3 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -129,6 +129,13 @@ AC_ARG_ENABLE(client, > AS_IF([test x"$enable_client" != "xno"], [enable_client="yes"]) > AM_CONDITIONAL(SUPPORT_CLIENT, test "x$enable_client" = "xyes") > > +AC_ARG_ENABLE(automated_tests, > +[ --enable-automated-tests Enable automated tests using snappy (part of > spice--gtk)],, > +[enable_automated_tests="no"]) > +AS_IF([test x"$enable_automated_tests" != "xno"], > [enable_automated_tests="yes"]) > +AM_CONDITIONAL(SUPPORT_AUTOMATED_TESTS, test "x$enable_automated_tests" != > "xno") > + > + > dnl ========================================================================= > dnl Check deps > > @@ -372,6 +379,16 @@ AM_CONDITIONAL([HAVE_SASL], [test "x$with_sasl2" = > "xyes" || test "x$with_sasl" > AC_SUBST([SASL_CFLAGS]) > AC_SUBST([SASL_LIBS]) > > +if test "x$enable_automated_tests" = "xyes"; then > + AC_MSG_CHECKING([for snappy]) > + snappy --help >/dev/null 2>&1 > + if test $? -ne 0 ; then > + AC_MSG_RESULT([not found]) > + AC_MSG_ERROR([snappy was not found, this module is part of spice-gtk > andis required to compile this package]) > + fi > + AC_MSG_RESULT([found]) > +fi > + > dnl > =========================================================================== > dnl check compiler flags > > @@ -550,6 +567,8 @@ echo " > Smartcard: ${enable_smartcard} > > SASL support: ${enable_sasl} > + > + Automated tests: ${enable_automated_tests} > " > > if test $os_win32 == "yes" ; then > diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am > index 4513322..bc4e00e 100644 > --- a/server/tests/Makefile.am > +++ b/server/tests/Makefile.am > @@ -9,6 +9,10 @@ INCLUDES = \ > $(SPICE_NONPKGCONFIG_CFLAGS) \ > $(NULL) > > +if SUPPORT_AUTOMATED_TESTS > +INCLUDES += -DAUTOMATED_TESTS > +endif > + > AM_LDFLAGS = $(top_builddir)/server/libspice-server.la > > COMMON_BASE=basic_event_loop.c basic_event_loop.h test_util.h > ../../common/backtrace.c > diff --git a/server/tests/README b/server/tests/README > index e44251d..2724853 100644 > --- a/server/tests/README > +++ b/server/tests/README > @@ -21,3 +21,9 @@ test_fail_on_null_core_interface > > basic_event_loop.c > used by test_just_sockets_no_ssl, can be used by other tests. very crude > event loop. Should probably use libevent for better tests, but this is self > contained. > + > +Automated tests > +=============== > + > +test_display_streaming.c > + this test can be used to check regressions. For this, Spice needs to be > compiled with --enable-automated-tests and test_display_streaming needs to be > called passing --automated-tests as parameter > diff --git a/server/tests/regression_test.py b/server/tests/regression_test.py > new file mode 100755 > index 0000000..e53bf87 > --- /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 snappy(): > + cmd = "snappy -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__": > + snappy() > + 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/test_display_base.c > b/server/tests/test_display_base.c > index ef5a543..48f59d2 100644 > --- a/server/tests/test_display_base.c > +++ b/server/tests/test_display_base.c > @@ -1,9 +1,14 @@ > + > #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 <spice/qxl_dev.h> > #include "test_display_base.h" > #include "red_channel.h" > @@ -34,15 +39,53 @@ static void test_spice_destroy_update(SimpleSpiceUpdate > *update) > free(update); > } > > -#define WIDTH 320 > +#define WIDTH 640 > #define HEIGHT 320 > > -#define SINGLE_PART 8 > +#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 > + > +static void sigchld_handler(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 *envp[] = {buf, NULL}; > + > + snprintf(buf, sizeof(buf), "PATH=%s", getenv("PATH")); > + execve("regression_test.py", NULL, envp); > + } else if (pid > 0) { > + return; > + } > +} > + > static void set_cmd(QXLCommandExt *ext, uint32_t type, QXLPHYSICAL data) > { > ext->cmd.type = type; > @@ -107,7 +150,13 @@ static SimpleSpiceUpdate > *test_spice_create_update_draw(uint32_t surface_id, int > if ((t % angle_parts) == 0) { > c_i++; > } > - color = (color + 1) % 2; > + > + if(surface_id != 0) { > + color = (color + 1) % 2; > + } else { > + color = surface_id; > + } > + > unique++; > > update = calloc(sizeof(*update), 1); > @@ -116,6 +165,7 @@ static SimpleSpiceUpdate > *test_spice_create_update_draw(uint32_t surface_id, int > > bw = WIDTH/SINGLE_PART; > bh = 48; > + > bbox.right = bbox.left + bw; > bbox.bottom = bbox.top + bh; > update->bitmap = malloc(bw * bh * 4); > @@ -303,6 +353,7 @@ int cursor_notify = NOTIFY_CURSOR_BATCH; > #define SURF_WIDTH 320 > #define SURF_HEIGHT 240 > uint8_t secondary_surface[SURF_WIDTH * SURF_HEIGHT * 4]; > +int has_secondary; > > // We shall now have a ring of commands, so that we can update > // it from a separate thread - since get_command is called from > @@ -354,6 +405,10 @@ static void produce_command(void) > static int target_surface = 0; > static int cmd_index = 0; > > + > + if (has_secondary) > + target_surface = 1; > + > ASSERT(num_simple_commands); > > switch (simple_commands[cmd_index]) { > @@ -361,35 +416,50 @@ static void produce_command(void) > path_progress(&path); > break; > case SIMPLE_UPDATE: { > - QXLRect rect = {.left = 0, .right = WIDTH, > - .top = 0, .bottom = HEIGHT}; > - qxl_worker->update_area(qxl_worker, 0, &rect, NULL, 0, 1); > + QXLRect rect = {.left = 0, .right = SURF_WIDTH, > + .top = 0, .bottom = SURF_HEIGHT}; > + qxl_worker->update_area(qxl_worker, target_surface, &rect, NULL, > 0, 1); > break; > } > + > case SIMPLE_COPY_BITS: > case SIMPLE_DRAW: { > SimpleSpiceUpdate *update; > + > + if (has_automated_tests) > + { > + if (control == 0) { > + return; > + } > + > + regression_test(); > + } > + > switch (simple_commands[cmd_index]) { > case SIMPLE_COPY_BITS: > - update = > test_spice_create_update_copy_bits(target_surface); > + update = test_spice_create_update_copy_bits(0); > break; > case SIMPLE_DRAW: > - update = test_spice_create_update_draw(target_surface, > path.t); > + update = test_spice_create_update_draw(0, path.t); > break; > } > push_command(&update->ext); > break; > } > + > case SIMPLE_CREATE_SURFACE: { > SimpleSurfaceCmd *update; > target_surface = MAX_SURFACE_NUM - 1; > update = create_surface(target_surface, SURF_WIDTH, SURF_HEIGHT, > secondary_surface); > push_command(&update->ext); > + has_secondary = 1; > break; > } > + > case SIMPLE_DESTROY_SURFACE: { > SimpleSurfaceCmd *update; > + has_secondary = 0; > update = destroy_surface(target_surface); > target_surface = 0; > push_command(&update->ext); > @@ -529,6 +599,8 @@ QXLInterface display_sif = { > .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, > @@ -572,6 +644,37 @@ SpiceServer* test_init(SpiceCoreInterface *core) > path_init(&path, 0, angle_parts); > bzero(primary_surface, sizeof(primary_surface)); > bzero(secondary_surface, sizeof(secondary_surface)); > + has_secondary = 0; > wakeup_timer = core->timer_add(do_wakeup, NULL); > return server; > } > + > +void check_automated(int argc, char **argv) > +{ > + struct sigaction sa; > + > + if (argc == 1) { > + return; > + } > + > + if (argc > 2) { > + goto invalid_option; > + } > + > + if (strcmp(argv[1], "--automated-tests") != 0) { > + goto invalid_option; > + } > + > + has_automated_tests = 1; > + > + memset(&sa, 0, sizeof sa); > + sa.sa_handler = &sigchld_handler; > + sigaction(SIGCHLD, &sa, NULL); > + > + return; > + > +invalid_option: > + printf("Invalid option!\n" > + "Please, check README before run tests!\n" ); > + exit(0); > +} > diff --git a/server/tests/test_display_base.h > b/server/tests/test_display_base.h > index ca94057..4aeaf5f 100644 > --- a/server/tests/test_display_base.h > +++ b/server/tests/test_display_base.h > @@ -10,6 +10,9 @@ void test_set_simple_command_list(int* commands, int > num_commands); > void test_add_display_interface(SpiceServer *server); > SpiceServer* test_init(SpiceCoreInterface* core); > > +/* Used for automated tests */ > +void check_automated(int argc, char **argv); > + > // simple queue for commands > enum { > PATH_PROGRESS, > diff --git a/server/tests/test_display_streaming.c > b/server/tests/test_display_streaming.c > index 025541d..5052991 100644 > --- a/server/tests/test_display_streaming.c > +++ b/server/tests/test_display_streaming.c > @@ -10,13 +10,19 @@ > int simple_commands[] = { > SIMPLE_DRAW, > SIMPLE_UPDATE, > + PATH_PROGRESS, > + SIMPLE_CREATE_SURFACE, > + SIMPLE_DESTROY_SURFACE, > }; > > SpiceCoreInterface *core; > SpiceServer *server; > > -int main(void) > +int main(int argc, char **argv) > { > +#ifdef AUTOMATED_TESTS > + check_automated(argc, argv); > +#endif > core = basic_event_loop_init(); > server = test_init(core); > spice_server_set_streaming_video(server, SPICE_STREAM_VIDEO_ALL); > -- > 1.7.9 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/spice-devel _______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel