test-tool: Don't use static binary helper program, nor ISO.

This simplifies the libguestfs-test-tool program down to essentials.
Bugs most commonly occur when starting the appliance, so what we
should concentrate on test is just that.

Previously the test tool built a special static binary helper program,
packaged it up in an ISO, then ran this inside the appliance.  None of
this really tested useful failure modes, but they did make the test
tool itself harder to build, harder for users to run, and more
brittle.

This change also adds some more debugging of libguestfs state.
This commit is contained in:
Richard W.M. Jones
2011-04-06 19:45:46 +01:00
parent cbc6b720a4
commit 6ea263b1f1
6 changed files with 37 additions and 233 deletions

View File

@@ -142,7 +142,6 @@ src/launch.c
src/listfs.c
src/proto.c
src/virt.c
test-tool/helper.c
test-tool/test-tool.c
tools/virt-edit.pl
tools/virt-list-filesystems.pl

View File

@@ -1,5 +1,5 @@
# libguestfs
# Copyright (C) 2009 Red Hat Inc.
# Copyright (C) 2009-2011 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -22,23 +22,16 @@ EXTRA_DIST = libguestfs-test-tool.pod run-test-tool-locally
CLEANFILES =
bin_PROGRAMS = libguestfs-test-tool
libexec_PROGRAMS = libguestfs-test-tool-helper
man_MANS = libguestfs-test-tool.1
AM_CPPFLAGS = \
-DDEFAULT_HELPER='"$(libexecdir)/libguestfs-test-tool-helper"'
libguestfs_test_tool_SOURCES = test-tool.c
libguestfs_test_tool_CFLAGS = \
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
-I$(top_srcdir)/src -I$(top_builddir)/src \
-Wall
$(WARN_CFLAGS) $(WERROR_CFLAGS)
libguestfs_test_tool_LDADD = \
$(top_builddir)/src/libguestfs.la
libguestfs_test_tool_helper_SOURCES = helper.c
libguestfs_test_tool_helper_LDFLAGS = -all-static
libguestfs-test-tool.1: libguestfs-test-tool.pod
$(top_srcdir)/podwrapper.sh \
--man $@ \

View File

@@ -1,73 +0,0 @@
/* libguestfs-test-tool-helper
* Copyright (C) 2009 Red Hat Inc.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* NB. This program is intended to run inside the appliance. */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
char buffer[10 * 1024];
int
main (void)
{
int fd;
fprintf (stderr, "This is the libguestfs-test-tool helper program.\n");
/* This should fail immediately if we're not in the appliance. */
if (mkdir ("/tmp", 0700) == -1) {
perror ("mkdir");
fprintf (stderr, "This program should not be run directly. Use libguestfs-test-tool instead.\n");
exit (EXIT_FAILURE);
}
if (geteuid () != 0) {
fprintf (stderr, "helper: This program doesn't appear to be running as root.\n");
exit (EXIT_FAILURE);
}
if (mkdir ("/tmp/helper", 0700) == -1) {
perror ("/tmp/helper");
exit (EXIT_FAILURE);
}
fd = open ("/tmp/helper/a", O_CREAT|O_EXCL|O_WRONLY, 0600);
if (fd == -1) {
perror ("create /tmp/helper/a");
exit (EXIT_FAILURE);
}
if (write (fd, buffer, sizeof buffer) != sizeof buffer) {
perror ("write");
exit (EXIT_FAILURE);
}
if (close (fd) == -1) {
perror ("close");
exit (EXIT_FAILURE);
}
exit (EXIT_SUCCESS);
}

View File

@@ -42,12 +42,6 @@ L<http://libguestfs.org/> website.
Display short usage information and exit.
=item I<--helper /path/to/libguestfs-test-tool-helper>
Pass an alternate name for the helper program. libguestfs-test-tool
will normally look in the C<$libexec> directory that was configured
when the tool was built.
=item I<--qemu qemu_binary>
If you have downloaded another qemu binary, point this option at the
@@ -85,22 +79,6 @@ script when you use either of the I<--qemudir> or I<--qemu> options.
libguestfs-test-tool returns I<0> if the tests completed without
error, or I<1> if there was an error.
=head1 FILES
=over 4
=item /usr/libexec/libguestfs-test-tool-helper
This helper program is run inside the appliance and provides
additional tests.
=item /usr/bin/mkisofs
The C<mkisofs> command is required in order to construct a CD-ROM ISO
file which is used as part of the tests.
=back
=head1 ENVIRONMENT VARIABLES
For the full list of environment variables which may affect
@@ -118,7 +96,7 @@ Richard W.M. Jones (C<rjones at redhat dot com>)
=head1 COPYRIGHT
Copyright (C) 2009 Red Hat Inc.
Copyright (C) 2009-2011 Red Hat Inc.
L<http://libguestfs.org/>
This program is free software; you can redistribute it and/or modify

View File

@@ -1,5 +1,5 @@
#!/usr/bin/perl
# Copyright (C) 2010 Red Hat Inc.
# Copyright (C) 2010-2011 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -51,6 +51,4 @@ $ENV{LIBGUESTFS_PATH} = $path.'/appliance';
exec("$path/test-tool/libguestfs-test-tool",
"$path/test-tool/libguestfs-test-tool",
"--helper",
"$path/test-tool/libguestfs-test-tool-helper",
@ARGV);

View File

@@ -1,5 +1,5 @@
/* libguestfs-test-tool
* Copyright (C) 2009 Red Hat Inc.
* Copyright (C) 2009-2011 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,10 +37,10 @@
#ifdef HAVE_GETTEXT
#include "gettext.h"
#define _(str) dgettext(PACKAGE, (str))
#define N_(str) dgettext(PACKAGE, (str))
//#define N_(str) dgettext(PACKAGE, (str))
#else
#define _(str) str
#define N_(str) str
//#define N_(str) str
#endif
#if !ENABLE_NLS
@@ -51,14 +51,14 @@
#endif
#define STREQ(a,b) (strcmp((a),(b)) == 0)
#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
#define STRNEQ(a,b) (strcmp((a),(b)) != 0)
#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0)
//#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
//#define STRNEQ(a,b) (strcmp((a),(b)) != 0)
//#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0)
#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0)
#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0)
#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
//#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0)
//#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
//#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
//#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
#ifndef P_tmpdir
#define P_tmpdir "/tmp"
@@ -66,13 +66,10 @@
#define DEFAULT_TIMEOUT 120
static const char *helper = DEFAULT_HELPER;
static int timeout = DEFAULT_TIMEOUT;
static char tmpf[] = P_tmpdir "/libguestfs-test-tool-sda-XXXXXX";
static char isof[] = P_tmpdir "/libguestfs-test-tool-iso-XXXXXX";
static guestfs_h *g;
static void preruncheck (void);
static void make_files (void);
static void set_qemu (const char *path, int use_wrapper);
@@ -80,21 +77,21 @@ static void
usage (void)
{
printf (_("libguestfs-test-tool: interactive test tool\n"
"Copyright (C) 2009 Red Hat Inc.\n"
"Copyright (C) 2009-2011 Red Hat Inc.\n"
"Usage:\n"
" libguestfs-test-tool [--options]\n"
"Options:\n"
" --help Display usage\n"
" --helper libguestfs-test-tool-helper\n"
" Helper program (default: %s)\n"
" --qemudir dir Specify QEMU source directory\n"
" --qemu qemu Specify QEMU binary\n"
" --timeout n\n"
" -t n Set launch timeout (default: %d seconds)\n"
),
DEFAULT_HELPER, DEFAULT_TIMEOUT);
DEFAULT_TIMEOUT);
}
extern char **environ;
int
main (int argc, char *argv[])
{
@@ -105,7 +102,6 @@ main (int argc, char *argv[])
static const char *options = "t:?";
static const struct option long_options[] = {
{ "help", 0, 0, '?' },
{ "helper", 1, 0, 0 },
{ "qemu", 1, 0, 0 },
{ "qemudir", 1, 0, 0 },
{ "timeout", 1, 0, 't' },
@@ -113,13 +109,8 @@ main (int argc, char *argv[])
};
int c;
int option_index;
extern char **environ;
int i;
struct guestfs_version *vers;
char *sfdisk_lines[] = { ",", NULL };
char *str;
/* XXX This is wrong if the user renames the helper. */
char *helper_args[] = { "/iso/libguestfs-test-tool-helper", NULL };
for (;;) {
c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -127,9 +118,7 @@ main (int argc, char *argv[])
switch (c) {
case 0: /* options which are long only */
if (STREQ (long_options[option_index].name, "helper"))
helper = optarg;
else if (STREQ (long_options[option_index].name, "qemu"))
if (STREQ (long_options[option_index].name, "qemu"))
set_qemu (optarg, 0);
else if (STREQ (long_options[option_index].name, "qemudir"))
set_qemu (optarg, 1);
@@ -162,7 +151,6 @@ main (int argc, char *argv[])
}
}
preruncheck ();
make_files ();
printf ("===== Test starts here =====\n");
@@ -190,15 +178,6 @@ main (int argc, char *argv[])
tmpf);
exit (EXIT_FAILURE);
}
if (guestfs_add_drive_opts (g, isof,
GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
-1) == -1) {
fprintf (stderr,
_("libguestfs-test-tool: failed to add drive '%s'\n"),
isof);
exit (EXIT_FAILURE);
}
/* Print any version info etc. */
vers = guestfs_version (g);
@@ -211,12 +190,22 @@ main (int argc, char *argv[])
guestfs_free_version (vers);
printf ("guestfs_get_append: %s\n", guestfs_get_append (g) ? : "(null)");
printf ("guestfs_get_attach_method: %s\n",
guestfs_get_attach_method (g) ? : "(null)");
printf ("guestfs_get_autosync: %d\n", guestfs_get_autosync (g));
printf ("guestfs_get_direct: %d\n", guestfs_get_direct (g));
printf ("guestfs_get_memsize: %d\n", guestfs_get_memsize (g));
printf ("guestfs_get_network: %d\n", guestfs_get_network (g));
printf ("guestfs_get_path: %s\n", guestfs_get_path (g));
printf ("guestfs_get_qemu: %s\n", guestfs_get_qemu (g));
printf ("guestfs_get_recovery_proc: %d\n",
guestfs_get_recovery_proc (g));
printf ("guestfs_get_selinux: %d\n", guestfs_get_selinux (g));
printf ("guestfs_get_trace: %d\n", guestfs_get_trace (g));
printf ("guestfs_get_verbose: %d\n", guestfs_get_verbose (g));
printf ("host_cpu: %s\n", host_cpu);
/* Launch the guest handle. */
printf ("Launching appliance, timeout set to %d seconds.\n", timeout);
fflush (stdout);
@@ -235,9 +224,9 @@ main (int argc, char *argv[])
fflush (stdout);
/* Create the filesystem and mount everything. */
if (guestfs_sfdiskM (g, "/dev/sda", sfdisk_lines) == -1) {
if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1) {
fprintf (stderr,
_("libguestfs-test-tool: failed to run sfdisk\n"));
_("libguestfs-test-tool: failed to run part-disk\n"));
exit (EXIT_FAILURE);
}
@@ -253,27 +242,14 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
if (guestfs_mkdir (g, "/iso") == -1) {
/* Touch a file. */
if (guestfs_touch (g, "/hello") == -1) {
fprintf (stderr,
_("libguestfs-test-tool: failed to mkdir /iso\n"));
_("libguestfs-test-tool: failed to touch file\n"));
exit (EXIT_FAILURE);
}
if (guestfs_mount (g, "/dev/sdb", "/iso") == -1) {
fprintf (stderr,
_("libguestfs-test-tool: failed to mount /dev/sdb on /iso\n"));
exit (EXIT_FAILURE);
}
/* Let's now run some simple tests using the helper program. */
str = guestfs_command (g, helper_args);
if (str == NULL) {
fprintf (stderr,
_("libguestfs-test-tool: could not run helper program, or helper failed\n"));
exit (EXIT_FAILURE);
}
free (str);
/* Booted and performed some simple operations -- success! */
printf ("===== TEST FINISHED OK =====\n");
exit (EXIT_SUCCESS);
}
@@ -358,86 +334,21 @@ set_qemu (const char *path, int use_wrapper)
atexit (cleanup_wrapper);
}
/* After getting the command line args, but before running
* anything, we check everything is in place to do the tests.
*/
static void
preruncheck (void)
{
int r;
FILE *fp;
char cmd[256];
char buffer[1024];
if (access (helper, R_OK) == -1) {
fprintf (stderr,
_("Test tool helper program 'libguestfs-test-tool-helper' is not\n"
"available. Expected to find it in '%s'\n"
"\n"
"Use the --helper option to specify the location of this program.\n"),
helper);
exit (EXIT_FAILURE);
}
snprintf (cmd, sizeof cmd, "file '%s'", helper);
fp = popen (cmd, "r");
if (fp == NULL) {
perror (cmd);
exit (EXIT_FAILURE);
}
r = fread (buffer, 1, sizeof buffer - 1, fp);
if (r == 0) {
fprintf (stderr, _("command failed: %s"), cmd);
exit (EXIT_FAILURE);
}
pclose (fp);
buffer[r] = '\0';
if (strstr (buffer, "statically linked") == NULL) {
fprintf (stderr,
_("Test tool helper program %s\n"
"is not statically linked. This is a build error when this test tool\n"
"was built.\n"),
helper);
exit (EXIT_FAILURE);
}
}
static void
cleanup_tmpfiles (void)
{
unlink (tmpf);
unlink (isof);
}
static void
make_files (void)
{
int fd, r;
char cmd[256];
/* Make the ISO which will contain the helper program. */
fd = mkstemp (isof);
if (fd == -1) {
perror (isof);
exit (EXIT_FAILURE);
}
close (fd);
snprintf (cmd, sizeof cmd, "mkisofs -quiet -rJT -o '%s' '%s'",
isof, helper);
r = system (cmd);
if (r == -1 || WEXITSTATUS(r) != 0) {
fprintf (stderr,
_("mkisofs command failed: %s\n"), cmd);
exit (EXIT_FAILURE);
}
int fd;
/* Allocate the sparse file for /dev/sda. */
fd = mkstemp (tmpf);
if (fd == -1) {
perror (tmpf);
unlink (isof);
exit (EXIT_FAILURE);
}
@@ -445,7 +356,6 @@ make_files (void)
perror ("lseek");
close (fd);
unlink (tmpf);
unlink (isof);
exit (EXIT_FAILURE);
}
@@ -453,11 +363,10 @@ make_files (void)
perror ("write");
close (fd);
unlink (tmpf);
unlink (isof);
exit (EXIT_FAILURE);
}
close (fd);
atexit (cleanup_tmpfiles); /* Removes tmpf and isof. */
atexit (cleanup_tmpfiles); /* Removes tmpf. */
}