Commit 9af71717 authored by Jeremy White's avatar Jeremy White

Add a basic testing infrastructure.

parent d3cbf659
......@@ -18,3 +18,9 @@ Makefile.in
src/x11spice
config.guess
config.sub
test-driver
src/tests/run
*.log
*.trs
x11spice_test
......@@ -13,5 +13,5 @@ PKG_CHECK_MODULES(GLIB2, glib-2.0)
PKG_CHECK_MODULES(PIXMAN, pixman-1)
AC_PROG_CC
AC_CONFIG_FILES(Makefile src/Makefile)
AC_CONFIG_FILES(Makefile src/Makefile src/tests/Makefile)
AC_OUTPUT
......@@ -12,3 +12,6 @@ x11spice_SOURCES = \
spice.c \
scan.c \
main.c
SUBDIRS = tests
TESTS = x11spice_test
ALL_XCB_CFLAGS=$(XCB_CFLAGS) $(DAMAGE_CFLAGS) $(XTEST_CFLAGS) $(SHM_CFLAGS) $(UTIL_CFLAGS)
ALL_XCB_LIBS=$(XCB_LIBS) $(DAMAGE_LIBS) $(XTEST_LIBS) $(SHM_LIBS) $(UTIL_LIBS)
AM_CFLAGS = -Wall $(ALL_XCB_CFLAGS) $(GTK2_CFLAGS) $(SPICE_CFLAGS) $(SPICE_PROTOCOL_CFLAGS) $(GLIB2_CFLAGS) $(PIXMAN_CFLAGS)
AM_LDFLAGS = $(ALL_XCB_LIBS) $(GTK2_LIBS) $(SPICE_LIBS) $(GLIB2_LIBS) $(PIXMAN_LIBS)
x11spice_test_SOURCES = \
tests.c \
x11spice_test.c \
xcb.c \
xdummy.c \
main.c
noinst_PROGRAMS = $(TESTS)
/*
Copyright (C) 2016 Jeremy White <jwhite@codeweavers.com>
All rights reserved.
This file is part of x11spice
x11spice is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
x11spice 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with x11spice. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <locale.h>
#include "xdummy.h"
#include "tests.h"
int main(int argc, char *argv[])
{
setlocale (LC_ALL, "");
g_test_init (&argc, &argv, NULL);
// FIXME - g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id=");
g_test_add("/x11spice/basic", xdummy_t, "basic",
start_server, test_basic, stop_server);
return g_test_run ();
}
/*
Copyright (C) 2016 Jeremy White <jwhite@codeweavers.com>
All rights reserved.
This file is part of x11spice
x11spice is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
x11spice 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with x11spice. If not, see <http://www.gnu.org/licenses/>.
*/
#include "xdummy.h"
#include "tests.h"
#include "xcb.h"
#include "x11spice_test.h"
static int test_common_start(test_t *test, x11spice_server_t *server,
xdummy_t *xserver, gconstpointer user_data)
{
int rc;
if (! xserver->running)
{
g_test_skip("No server");
return -1;
}
test->xserver = xserver;
test->name = user_data;
test->logfile = g_test_build_filename(G_TEST_BUILT, "run", test->name, "test.log", NULL);
if (! test->logfile)
{
g_warning("Failed to create logfile");
g_test_fail();
return -1;
}
memset(server, 0, sizeof(*server));
rc = x11spice_start(server, test);
if (rc)
{
g_warning("Failed to start x11spice");
g_test_fail();
return rc;
}
return 0;
}
static void test_common_stop(test_t *test, x11spice_server_t *server)
{
x11spice_stop(server);
}
void test_basic(xdummy_t *xserver, gconstpointer user_data)
{
test_t test;
x11spice_server_t server;
int rc;
gchar *screencap;
char buf[4096];
int needs_prefix;
rc = test_common_start(&test, &server, xserver, user_data);
if (rc)
return;
snprintf(buf, sizeof(buf), ":%s", xserver->display);
xcb_draw_grid(buf);
screencap = g_test_build_filename(G_TEST_BUILT, "run", test.name, "screencap.ppm", NULL);
needs_prefix = 1;
if (strlen(server.uri) >= 8 && memcmp(server.uri, "spice://", 8) == 0)
needs_prefix = 0;
snprintf(buf, sizeof(buf), "spicy-screenshot --uri=%s%s --out-file=%s",
needs_prefix ? "spice://" : "", server.uri, screencap);
system(buf);
snprintf(buf, sizeof(buf), "md5sum basic.expected.ppm | "
"sed -e 's!basic.expected.ppm!%s!' |"
"md5sum -c", screencap);
if (system(buf))
{
g_warning("Captured screenshot does not match expected one.");
g_test_fail();
}
test_common_stop(&test, &server);
}
/*
Copyright (C) 2016 Jeremy White <jwhite@codeweavers.com>
All rights reserved.
This file is part of x11spice
x11spice is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
x11spice 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with x11spice. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TESTS_H_
#define TESTS_H_
#include <glib.h>
#include <string.h>
#include "xdummy.h"
/*----------------------------------------------------------------------------
** Structure definitions
**--------------------------------------------------------------------------*/
typedef struct
{
xdummy_t *xserver;
const gchar *logfile;
const gchar *name;
} test_t;
/*----------------------------------------------------------------------------
** Prototypes
**--------------------------------------------------------------------------*/
void test_basic(xdummy_t *server, gconstpointer user_data);
#endif
/*
Copyright (C) 2016 Jeremy White <jwhite@codeweavers.com>
All rights reserved.
This file is part of x11spice
x11spice is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
x11spice 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with x11spice. If not, see <http://www.gnu.org/licenses/>.
*/
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "xdummy.h"
#include "x11spice_test.h"
static char **duplicate_environment(void)
{
extern char **environ;
char **p;
int i;
for (i = 0, p = environ; *p; p++)
i++;
p = malloc((i + 1 + 1 ) * sizeof(*p));
memcpy(p + 1, environ, (i + 1) * sizeof(*p));
return p;
}
static int exec_x11spice(x11spice_server_t *server, gchar *display)
{
char buf[256];
char **env = duplicate_environment();
/* Redirect stderr and stdout to our pipe */
dup2(server->pipe, fileno(stdout));
dup2(server->pipe, fileno(stderr));
snprintf(buf, sizeof(buf), "DISPLAY=:%s", display);
*env = buf;
return execle("../x11spice", "x11spice", "--auto", "localhost:5900-5999", "--hide", NULL, env);
return -1;
}
static void * flush_output(void *opaque)
{
x11spice_server_t *server = (x11spice_server_t *) opaque;
int rc;
char buf[4096];
while (1)
{
rc = read(server->pipe, buf, sizeof(buf));
if (rc == -1 && errno == EINTR)
continue;
if (rc <= 0)
break;
write(server->logfd, buf, rc);
}
close(server->logfd);
close(server->pipe);
return NULL;
}
static int get_a_line(char *buf, int len, x11spice_server_t *server)
{
char *p;
for (p = buf; p < buf + len; p++)
if (*p == '\n')
{
if (p - buf > 4 && memcmp(buf, "URI=", 4) == 0)
{
server->uri = g_memdup(buf + 4, p - buf - 4 + 1);
server->uri[p - buf - 4] = '\0';
printf("JPW got [%*.*s]\n", (int) (p - buf - 4), (int) (p - buf - 4), server->uri);
return len;
}
return p - buf + 1;
}
return 0;
}
int x11spice_start(x11spice_server_t *server, test_t *test)
{
int fd[2];
char buf[4096];
int rc;
int pos = 0;
int flush;
server->running = FALSE;
if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd))
return -1;
server->pid = fork();
if (server->pid == 0)
{
close(fd[0]);
server->pipe = fd[1];
exec_x11spice(server, test->xserver->display);
g_warning("server exec failed.");
return -1;
}
else
{
server->pipe = fd[0];
close(fd[1]);
if (server->pid == -1)
return -1;
}
server->logfd = open(test->logfile, O_CREAT | O_WRONLY, S_IRUSR |S_IWUSR | S_IRGRP | S_IROTH);
if (server->logfd <= 0)
{
x11spice_stop(server);
return -1;
}
memset(buf, 0, sizeof(buf));
while (! server->uri)
{
rc = read(server->pipe, buf + pos, sizeof(buf) - pos);
if (rc == -1 && errno == EINTR)
continue;
if (rc <= 0)
{
g_warning("server failed to start.");
return -1;
}
pos += rc;
while ((flush = get_a_line(buf, pos, server)))
{
write(server->logfd, buf, flush);
if (flush < pos)
memmove(buf, buf + flush, pos - flush);
pos -= flush;
}
}
pthread_create(&server->flush_thread, NULL, flush_output, server);
server->running = TRUE;
g_message("x11spice started; pid %d", server->pid);
return 0;
}
void x11spice_stop(x11spice_server_t *server)
{
g_message("server stopping; pid %d", server->pid);
if (server->running)
{
if (still_alive(server->pid))
{
kill(server->pid, SIGTERM);
usleep(50 * 1000);
}
if (still_alive(server->pid))
{
sleep(1);
kill(server->pid, SIGKILL);
}
}
}
/*
Copyright (C) 2016 Jeremy White <jwhite@codeweavers.com>
All rights reserved.
This file is part of x11spice
x11spice is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
x11spice 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with x11spice. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef X11SPICE_TEST_H_
#define X11SPICE_TEST_H_
#include <glib.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include "tests.h"
/*----------------------------------------------------------------------------
** Structure definitions
**--------------------------------------------------------------------------*/
typedef struct
{
int pid;
int pipe;
int logfd;
pthread_t flush_thread;
gboolean running;
gchar *uri;
} x11spice_server_t;
/*----------------------------------------------------------------------------
** Prototypes
**--------------------------------------------------------------------------*/
int x11spice_start(x11spice_server_t *server, test_t *test);
void x11spice_stop(x11spice_server_t *server);
#endif
/*
Copyright (C) 2016 Jeremy White <jwhite@codeweavers.com>
All rights reserved.
This file is part of x11spice
x11spice is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
x11spice 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with x11spice. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <xcb/xcb.h>
static void lookup_color(xcb_connection_t *c, xcb_screen_t *screen, const char *color, uint32_t *pixel)
{
xcb_lookup_color_cookie_t cookie;
xcb_lookup_color_reply_t *r;
xcb_alloc_color_cookie_t acookie;
xcb_alloc_color_reply_t *ar;
cookie = xcb_lookup_color(c, screen->default_colormap, strlen(color), color);
r = xcb_lookup_color_reply(c, cookie, NULL);
acookie = xcb_alloc_color(c, screen->default_colormap, r->exact_red, r->exact_green, r->exact_blue);
free(r);
ar = xcb_alloc_color_reply(c, acookie, NULL);
*pixel = ar->pixel;
free(ar);
}
static void create_rectangles(xcb_rectangle_t *red, xcb_rectangle_t *green, int w, int h)
{
int x, y;
int r, g;
int i;
for (i = 0; i < 32; i++)
{
red[i].width = green[i].width = w / 8;
red[i].height = green[i].height = h / 8;
}
r = g = 0;
for (x = 0; x < 8; x++)
for (y = 0; y < 8; y++)
{
if (((y * 8) + x) % 2 == y % 2)
{
red[r].x = x * (w / 8);
red[r].y = y * (h / 8);
r++;
}
else
{
green[g].x = x * (w / 8);
green[g].y = y * (h / 8);
g++;
}
}
}
int xcb_draw_grid(const char *display)
{
uint32_t pixels[2];
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_gcontext_t red_fg;
xcb_gcontext_t green_fg;
xcb_rectangle_t red_rectangles[32];
xcb_rectangle_t green_rectangles[32];
/* Open the connection to the X server */
c = xcb_connect(display, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
red_fg = xcb_generate_id(c);
lookup_color(c, screen, "red", &pixels[0]);
pixels[1] = 0;
xcb_create_gc(c, red_fg, screen->root, XCB_GC_FOREGROUND, pixels);
green_fg = xcb_generate_id(c);
lookup_color(c, screen, "green", &pixels[0]);
pixels[1] = 0;
xcb_create_gc(c, green_fg, screen->root, XCB_GC_FOREGROUND, pixels);
create_rectangles(red_rectangles, green_rectangles, screen->width_in_pixels, screen->height_in_pixels);
/* We draw the rectangles */
xcb_poly_fill_rectangle_checked(c, screen->root, red_fg, 32, red_rectangles);
xcb_poly_fill_rectangle_checked(c, screen->root, green_fg, 32, green_rectangles);
/* We flush the request */
xcb_flush (c);
xcb_disconnect(c);
return 0;
}
/*
Copyright (C) 2016 Jeremy White <jwhite@codeweavers.com>
All rights reserved.
This file is part of x11spice
x11spice is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
x11spice 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with x11spice. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XCB_H_
#define XCB_H_
/*----------------------------------------------------------------------------
** Prototypes
**--------------------------------------------------------------------------*/
int xcb_draw_grid(const char *display);
#endif
/*
Copyright (C) 2016 Jeremy White <jwhite@codeweavers.com>
All rights reserved.
This file is part of x11spice
x11spice is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
x11spice 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with x11spice. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>