diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/c-api/Makefile.am | 152 | ||||
-rw-r--r-- | tests/c-api/test-add-drive-opts.c | 58 | ||||
-rw-r--r-- | tests/c-api/test-add-libvirt-dom.c | 151 | ||||
-rw-r--r-- | tests/c-api/test-command.c | 67 | ||||
-rw-r--r-- | tests/c-api/test-config.c | 68 | ||||
-rw-r--r-- | tests/c-api/test-create-handle.c | 42 | ||||
-rw-r--r-- | tests/c-api/test-debug-to-file.c | 91 | ||||
-rw-r--r-- | tests/c-api/test-just-header.c | 30 | ||||
-rw-r--r-- | tests/c-api/test-last-errno.c | 142 | ||||
-rw-r--r-- | tests/c-api/test-private-data.c | 120 | ||||
-rw-r--r-- | tests/c-api/test-user-cancel.c | 371 | ||||
-rw-r--r-- | tests/qemu/Makefile.am | 2 |
12 files changed, 1292 insertions, 2 deletions
diff --git a/tests/c-api/Makefile.am b/tests/c-api/Makefile.am new file mode 100644 index 00000000..0b6c6838 --- /dev/null +++ b/tests/c-api/Makefile.am @@ -0,0 +1,152 @@ +# libguestfs +# Copyright (C) 2009-2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +include $(top_srcdir)/subdir-rules.mk + +generator_built = tests.c + +BUILT_SOURCES = $(generator_built) + +EXTRA_DIST = $(BUILT_SOURCES) + +check_PROGRAMS = \ + tests \ + test-command \ + test-just-header \ + test-create-handle \ + test-config \ + test-add-drive-opts \ + test-last-errno \ + test-private-data \ + test-user-cancel \ + test-debug-to-file + +TESTS = \ + tests \ + test-just-header \ + test-create-handle \ + test-config \ + test-add-drive-opts \ + test-last-errno \ + test-private-data \ + test-user-cancel \ + test-debug-to-file + +# The API behind this test is not baked yet. +#if HAVE_LIBVIRT +#check_PROGRAMS += test-add-libvirt-dom +#TESTS += test-add-libvirt-dom +#endif +EXTRA_DIST += test-add-libvirt-dom.c + +TESTS_ENVIRONMENT = \ + SKIP_TEST_COMMAND=$(shell ldd test-command | grep -sq 'not a dynamic executable' || echo 1) \ + SKIP_TEST_COMMAND_LINES=$(shell ldd test-command | grep -sq 'not a dynamic executable' || echo 1) \ + LIBGUESTFS_PATH=$(top_builddir)/appliance \ + TMPDIR=$(top_builddir) \ + $(VG) + +#SKIP_TEST_CHECKSUM_8=$(shell if test `find ../initramfs -name squashfs.ko | wc -l` -eq 0; then echo 1; fi) + +tests_SOURCES = tests.c +tests_CFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +tests_LDADD = $(top_builddir)/src/libguestfs.la + +# This binary must be statically linked. It is used for testing +# the "guestfs_command" and "guestfs_command_lines" functions. + +test_command_SOURCES = test-command.c +test_command_LDFLAGS = -all-static + +# Hand-written C API tests. + +test_just_header_SOURCES = test-just-header.c +test_just_header_CFLAGS = \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +test_just_header_LDADD = \ + $(top_builddir)/src/libguestfs.la + +test_create_handle_SOURCES = test-create-handle.c +test_create_handle_CFLAGS = \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +test_create_handle_LDADD = \ + $(top_builddir)/src/libguestfs.la + +test_config_SOURCES = test-config.c +test_config_CFLAGS = \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +test_config_LDADD = \ + $(top_builddir)/src/libguestfs.la + +test_add_drive_opts_SOURCES = test-add-drive-opts.c +test_add_drive_opts_CFLAGS = \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +test_add_drive_opts_LDADD = \ + $(top_builddir)/src/libguestfs.la + +test_last_errno_SOURCES = test-last-errno.c +test_last_errno_CFLAGS = \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +test_last_errno_LDADD = \ + $(top_builddir)/src/libguestfs.la + +test_private_data_SOURCES = test-private-data.c +test_private_data_CFLAGS = \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +test_private_data_LDADD = \ + $(top_builddir)/src/libguestfs.la + +test_user_cancel_SOURCES = test-user-cancel.c +test_user_cancel_CFLAGS = \ + -pthread \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +test_user_cancel_LDADD = \ + $(top_builddir)/src/libguestfs.la -lm + +test_debug_to_file_SOURCES = test-debug-to-file.c +test_debug_to_file_CFLAGS = \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + -I$(top_srcdir)/gnulib/lib \ + -I$(top_builddir)/gnulib/lib \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) +test_debug_to_file_LDADD = \ + $(top_builddir)/src/libguestfs.la \ + $(top_builddir)/gnulib/lib/libgnu.la + +#if HAVE_LIBVIRT +#test_add_libvirt_dom_SOURCES = test-add-libvirt-dom.c +#test_add_libvirt_dom_CFLAGS = \ +# -I$(top_srcdir)/src -I$(top_builddir)/src -I$(top_srcdir)/gnulib/lib \ +# $(LIBVIRT_CFLAGS) \ +# $(WARN_CFLAGS) $(WERROR_CFLAGS) +#test_add_libvirt_dom_LDADD = \ +# $(top_builddir)/src/libguestfs.la $(LIBVIRT_LIBS) \ +# $(LTLIBTHREAD) $(top_builddir)/gnulib/lib/libgnu.la +#endif + +# Run the tests under valgrind. + +valgrind: + $(MAKE) check VG="valgrind --quiet --leak-check=full" diff --git a/tests/c-api/test-add-drive-opts.c b/tests/c-api/test-add-drive-opts.c new file mode 100644 index 00000000..897c6fac --- /dev/null +++ b/tests/c-api/test-add-drive-opts.c @@ -0,0 +1,58 @@ +/* libguestfs + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "guestfs.h" + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + int r; + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, "failed to create handle\n"); + exit (EXIT_FAILURE); + } + + r = guestfs_add_drive_opts (g, "/dev/null", -1); + if (r == -1) + exit (EXIT_FAILURE); + r = guestfs_add_drive_opts (g, "/dev/null", + GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, + -1); + if (r == -1) + exit (EXIT_FAILURE); + r = guestfs_add_drive_opts (g, "/dev/null", + GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, + GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", + -1); + if (r == -1) + exit (EXIT_FAILURE); + + guestfs_close (g); + + exit (EXIT_SUCCESS); +} diff --git a/tests/c-api/test-add-libvirt-dom.c b/tests/c-api/test-add-libvirt-dom.c new file mode 100644 index 00000000..6f994056 --- /dev/null +++ b/tests/c-api/test-add-libvirt-dom.c @@ -0,0 +1,151 @@ +/* libguestfs + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "xgetcwd.h" + +#include <libvirt/libvirt.h> +#include <libvirt/virterror.h> + +#include "guestfs.h" + +static void +make_test_xml (FILE *fp, const char *cwd) +{ + fprintf (fp, + "<?xml version=\"1.0\"?>\n" + "<node>\n" + " <domain type='test'>\n" + " <name>guest</name>\n" + " <os>\n" + " <type>hvm</type>\n" + " <boot dev='hd'/>\n" + " </os>\n" + " <memory>524288</memory>\n" + " <devices>\n" + " <disk type='file'>\n" + " <source file='%s/test1.img'/>\n" + " <target dev='hda'/>\n" + " </disk>\n" + " <disk type='file'>\n" + " <driver name='qemu' type='raw'/>\n" + " <source file='%s/test2.img'/>\n" + " <target dev='hdb'/>\n" + " </disk>\n" + " <disk type='file'>\n" + " <driver name='qemu' type='qcow2'/>\n" + " <source file='%s/test3.img'/>\n" + " <target dev='hdc'/>\n" + " </disk>\n" + " </devices>\n" + " </domain>\n" + "</node>", + cwd, cwd, cwd); +} + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + virConnectPtr conn; + virDomainPtr dom; + virErrorPtr err; + int r; + const char *test_xml; + char *cwd; + FILE *fp; + char libvirt_uri[1024]; + + cwd = xgetcwd (); + + /* Create the libvirt XML and test images in the current directory. */ + fp = fopen ("test.xml", "w"); + if (fp == NULL) { + perror ("test.xml"); + exit (EXIT_FAILURE); + } + make_test_xml (fp, cwd); + fclose (fp); + + fp = fopen ("test1.img", "w"); + if (fp == NULL) { + perror ("test1.img"); + exit (EXIT_FAILURE); + } + fclose (fp); + + fp = fopen ("test2.img", "w"); + if (fp == NULL) { + perror ("test2.img"); + exit (EXIT_FAILURE); + } + fclose (fp); + + fp = fopen ("test3.img", "w"); + if (fp == NULL) { + perror ("test3.img"); + exit (EXIT_FAILURE); + } + fclose (fp); + + /* Create the guestfs handle. */ + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, "failed to create handle\n"); + exit (EXIT_FAILURE); + } + + /* Create the libvirt connection. */ + snprintf (libvirt_uri, sizeof libvirt_uri, "test://%s/test.xml", cwd); + conn = virConnectOpenReadOnly (libvirt_uri); + if (!conn) { + err = virGetLastError (); + fprintf (stderr, "could not connect to libvirt (code %d, domain %d): %s\n", + err->code, err->domain, err->message); + exit (EXIT_FAILURE); + } + + dom = virDomainLookupByName (conn, "guest"); + if (!dom) { + err = virGetLastError (); + fprintf (stderr, + "no libvirt domain called '%s': %s\n", "guest", err->message); + exit (EXIT_FAILURE); + } + + r = guestfs_add_libvirt_dom (g, dom, + GUESTFS_ADD_LIBVIRT_DOM_READONLY, 1, + -1); + if (r == -1) + exit (EXIT_FAILURE); + + guestfs_close (g); + + unlink ("test.xml"); + unlink ("test1.img"); + unlink ("test2.img"); + unlink ("test3.img"); + + exit (EXIT_SUCCESS); +} diff --git a/tests/c-api/test-command.c b/tests/c-api/test-command.c new file mode 100644 index 00000000..c23b7d17 --- /dev/null +++ b/tests/c-api/test-command.c @@ -0,0 +1,67 @@ +/* libguestfs + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* This program, which must be statically linked, is used to test the + * guestfs_command and guestfs_command_lines functions. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define STREQ(a,b) (strcmp((a),(b)) == 0) + +int +main (int argc, char *argv[]) +{ + if (argc > 1) { + if (STREQ (argv[1], "1")) { + printf ("Result1"); + } else if (STREQ (argv[1], "2")) { + printf ("Result2\n"); + } else if (STREQ (argv[1], "3")) { + printf ("\nResult3"); + } else if (STREQ (argv[1], "4")) { + printf ("\nResult4\n"); + } else if (STREQ (argv[1], "5")) { + printf ("\nResult5\n\n"); + } else if (STREQ (argv[1], "6")) { + printf ("\n\nResult6\n\n"); + } else if (STREQ (argv[1], "7")) { + /* nothing */ + } else if (STREQ (argv[1], "8")) { + printf ("\n"); + } else if (STREQ (argv[1], "9")) { + printf ("\n\n"); + } else if (STREQ (argv[1], "10")) { + printf ("Result10-1\nResult10-2\n"); + } else if (STREQ (argv[1], "11")) { + printf ("Result11-1\nResult11-2"); + } else { + fprintf (stderr, "unknown parameter: %s\n", argv[1]); + exit (EXIT_FAILURE); + } + } else { + fprintf (stderr, "missing parameter\n"); + exit (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); +} diff --git a/tests/c-api/test-config.c b/tests/c-api/test-config.c new file mode 100644 index 00000000..c5411232 --- /dev/null +++ b/tests/c-api/test-config.c @@ -0,0 +1,68 @@ +/* libguestfs + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "guestfs.h" + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + int r; + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, "failed to create handle\n"); + exit (EXIT_FAILURE); + } + + /* If these fail, the default error handler will print an error + * message to stderr, so we don't need to print anything. This code + * is very pedantic, but after all we are testing the details of the + * C API. + */ + + if (guestfs_set_verbose (g, 1) == -1) + exit (EXIT_FAILURE); + r = guestfs_get_verbose (g); + if (r == -1) + exit (EXIT_FAILURE); + if (!r) { + fprintf (stderr, "set_verbose not true\n"); + exit (EXIT_FAILURE); + } + if (guestfs_set_verbose (g, 0) == -1) + exit (EXIT_FAILURE); + r = guestfs_get_verbose (g); + if (r == -1) + exit (EXIT_FAILURE); + if (r) { + fprintf (stderr, "set_verbose not false\n"); + exit (EXIT_FAILURE); + } + + guestfs_close (g); + + exit (EXIT_SUCCESS); +} diff --git a/tests/c-api/test-create-handle.c b/tests/c-api/test-create-handle.c new file mode 100644 index 00000000..edea19f6 --- /dev/null +++ b/tests/c-api/test-create-handle.c @@ -0,0 +1,42 @@ +/* libguestfs + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "guestfs.h" + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, "failed to create handle\n"); + exit (EXIT_FAILURE); + } + + guestfs_close (g); + + exit (EXIT_SUCCESS); +} diff --git a/tests/c-api/test-debug-to-file.c b/tests/c-api/test-debug-to-file.c new file mode 100644 index 00000000..5eb56104 --- /dev/null +++ b/tests/c-api/test-debug-to-file.c @@ -0,0 +1,91 @@ +/* libguestfs + * Copyright (C) 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 + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Test that we can use the new event API to capture all debugging + * messages to a file. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ignore-value.h" + +#include "guestfs.h" + +static void +debug_to_file (guestfs_h *g, + void *opaque, + uint64_t event, + int event_handle, + int flags, + const char *buf, size_t buf_len, + const uint64_t *array, size_t array_len) +{ + FILE *fp = opaque; + + ignore_value (fwrite (buf, 1, buf_len, fp)); +} + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + const char *filename = "test.log"; + FILE *debugfp; + + debugfp = fopen (filename, "w"); + if (debugfp == NULL) { + perror (filename); + exit (EXIT_FAILURE); + } + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, "failed to create handle\n"); + exit (EXIT_FAILURE); + } + + if (guestfs_set_event_callback + (g, debug_to_file, + GUESTFS_EVENT_LIBRARY|GUESTFS_EVENT_APPLIANCE|GUESTFS_EVENT_TRACE, + 0, debugfp) == -1) + exit (EXIT_FAILURE); + + if (guestfs_set_verbose (g, 1) == -1) + exit (EXIT_FAILURE); + + if (guestfs_set_trace (g, 1) == -1) + exit (EXIT_FAILURE); + + if (guestfs_add_drive_opts (g, "/dev/null", + GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", + GUESTFS_ADD_DRIVE_OPTS_READONLY, 1, + -1) == -1) + exit (EXIT_FAILURE); + + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + guestfs_close (g); + + exit (EXIT_SUCCESS); +} diff --git a/tests/c-api/test-just-header.c b/tests/c-api/test-just-header.c new file mode 100644 index 00000000..57551f53 --- /dev/null +++ b/tests/c-api/test-just-header.c @@ -0,0 +1,30 @@ +/* libguestfs + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Check that just including the header and nothing else works, ie. + * that there are no implicit dependencies in the header file. + */ + +#include "guestfs.h" + +int +main (int argc, char *argv[]) +{ + guestfs_h *g = guestfs_create (); + return 0; +} diff --git a/tests/c-api/test-last-errno.c b/tests/c-api/test-last-errno.c new file mode 100644 index 00000000..31a5c4de --- /dev/null +++ b/tests/c-api/test-last-errno.c @@ -0,0 +1,142 @@ +/* libguestfs + * Copyright (C) 2010 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Test that we can get correct errnos all the way back from the + * appliance, translated to the local operating system. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include "guestfs.h" + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + int fd, r, err; + struct guestfs_stat *stat; + const char *filename = "test1.img"; + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, "failed to create handle\n"); + exit (EXIT_FAILURE); + } + + fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666); + if (fd == -1) { + perror (filename); + exit (EXIT_FAILURE); + } + if (ftruncate (fd, 524288000) == -1) { + perror (filename); + close (fd); + unlink (filename); + exit (EXIT_FAILURE); + } + if (close (fd) == -1) { + perror (filename); + unlink (filename); + exit (EXIT_FAILURE); + } + + if (guestfs_add_drive_opts (g, filename, + GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", + -1) == -1) + exit (EXIT_FAILURE); + + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1) + exit (EXIT_FAILURE); + + if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1) + exit (EXIT_FAILURE); + + /* Mount read-only, and check that errno == EROFS is passed back when + * we create a file. + */ + if (guestfs_mount_ro (g, "/dev/sda1", "/") == -1) + exit (EXIT_FAILURE); + + r = guestfs_touch (g, "/test"); + if (r != -1) { + fprintf (stderr, + "guestfs_touch: expected error for read-only filesystem\n"); + exit (EXIT_FAILURE); + } + + err = guestfs_last_errno (g); + if (err != EROFS) { + fprintf (stderr, + "guestfs_touch: expected errno == EROFS, but got %d\n", err); + exit (EXIT_FAILURE); + } + + if (guestfs_umount (g, "/") == -1) + exit (EXIT_FAILURE); + + /* Mount it writable and test some other errors. */ + if (guestfs_mount_options (g, "", "/dev/sda1", "/") == -1) + exit (EXIT_FAILURE); + + stat = guestfs_lstat (g, "/nosuchfile"); + if (stat != NULL) { + fprintf (stderr, + "guestfs_lstat: expected error for missing file\n"); + exit (EXIT_FAILURE); + } + + err = guestfs_last_errno (g); + if (err != ENOENT) { + fprintf (stderr, + "guestfs_lstat: expected errno == ENOENT, but got %d\n", err); + exit (EXIT_FAILURE); + } + + if (guestfs_touch (g, "/test") == -1) + exit (EXIT_FAILURE); + + r = guestfs_mkdir (g, "/test"); + if (r != -1) { + fprintf (stderr, + "guestfs_mkdir: expected error for file which exists\n"); + exit (EXIT_FAILURE); + } + + err = guestfs_last_errno (g); + if (err != EEXIST) { + fprintf (stderr, + "guestfs_mkdir: expected errno == EEXIST, but got %d\n", err); + exit (EXIT_FAILURE); + } + + guestfs_close (g); + + unlink (filename); + + exit (EXIT_SUCCESS); +} diff --git a/tests/c-api/test-private-data.c b/tests/c-api/test-private-data.c new file mode 100644 index 00000000..f2ff647b --- /dev/null +++ b/tests/c-api/test-private-data.c @@ -0,0 +1,120 @@ +/* libguestfs + * Copyright (C) 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 + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Test aspects of the private data area API. */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include "guestfs.h" + +#define PREFIX "test_" + +static size_t close_callback_called = 0; + +/* This callback deletes all test keys in the handle. */ +static void +close_callback (guestfs_h *g, + void *opaque, + uint64_t event, + int event_handle, + int flags, + const char *buf, size_t buf_len, + const uint64_t *array, size_t array_len) +{ + const char *key; + void *data; + + close_callback_called++; + + again: + data = guestfs_first_private (g, &key); + while (data != NULL) { + if (strncmp (key, PREFIX, strlen (PREFIX)) == 0) { + guestfs_set_private (g, key, NULL); + goto again; + } + data = guestfs_next_private (g, &key); + } +} + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + const char *key; + void *data; + size_t count; + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, "failed to create handle\n"); + exit (EXIT_FAILURE); + } + + if (guestfs_set_event_callback (g, close_callback, GUESTFS_EVENT_CLOSE, + 0, NULL) == -1) + exit (EXIT_FAILURE); + + guestfs_set_private (g, PREFIX "a", (void *) 1); + guestfs_set_private (g, PREFIX "b", (void *) 2); + guestfs_set_private (g, PREFIX "c", (void *) 3); + guestfs_set_private (g, PREFIX "a", (void *) 4); /* overwrites previous */ + + /* Check we can fetch keys. */ + assert (guestfs_get_private (g, PREFIX "a") == (void *) 4); + assert (guestfs_get_private (g, PREFIX "b") == (void *) 2); + assert (guestfs_get_private (g, PREFIX "c") == (void *) 3); + assert (guestfs_get_private (g, PREFIX "d") == NULL); + + /* Check we can count keys by iterating. */ + count = 0; + data = guestfs_first_private (g, &key); + while (data != NULL) { + if (strncmp (key, PREFIX, strlen (PREFIX)) == 0) + count++; + data = guestfs_next_private (g, &key); + } + assert (count == 3); + + /* Delete some keys. */ + guestfs_set_private (g, PREFIX "a", NULL); + guestfs_set_private (g, PREFIX "b", NULL); + + /* Count them again. */ + count = 0; + data = guestfs_first_private (g, &key); + while (data != NULL) { + if (strncmp (key, PREFIX, strlen (PREFIX)) == 0) + count++; + data = guestfs_next_private (g, &key); + } + assert (count == 1); + + /* Closing should implicitly call the close_callback function. */ + guestfs_close (g); + + assert (close_callback_called == 1); + + exit (EXIT_SUCCESS); +} diff --git a/tests/c-api/test-user-cancel.c b/tests/c-api/test-user-cancel.c new file mode 100644 index 00000000..0cc049a0 --- /dev/null +++ b/tests/c-api/test-user-cancel.c @@ -0,0 +1,371 @@ +/* libguestfs + * Copyright (C) 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 + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Test user cancellation. + * + * We perform the test using two threads. The main thread issues + * guestfs commands to download and upload large files. Uploads and + * downloads are done to/from a pipe which is connected back to the + * current process. The second test thread sits on the other end of + * the pipe, feeding or consuming data slowly, and injecting the user + * cancel events at a particular place in the transfer. + * + * It is important to test both download and upload separately, since + * these exercise different code paths in the library. However this + * adds complexity here because these tests are symmetric-but-opposite + * cases. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/time.h> +#include <math.h> + +#include <pthread.h> + +#include "guestfs.h" + +static const char *filename = "test.img"; +static const off_t filesize = 1024*1024*1024; + +static void remove_test_img (void); +static void *start_test_thread (void *); +static off_t random_cancel_posn (void); + +struct test_thread_data { + guestfs_h *g; /* handle */ + int direction; /* direction of transfer */ +#define DIRECTION_UP 1 /* upload (test thread is writing) */ +#define DIRECTION_DOWN 2 /* download (test thread is reading) */ + int fd; /* pipe to read/write */ + off_t cancel_posn; /* position at which to cancel */ + off_t transfer_size; /* how much data thread wrote/read */ +}; + +int +main (int argc, char *argv[]) +{ + guestfs_h *g; + int fd; + char c = 0; + pthread_t test_thread; + struct test_thread_data data; + int fds[2], r, op_error, op_errno, errors = 0; + char dev_fd[64]; + + srand48 (time (NULL)); + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, "failed to create handle\n"); + exit (EXIT_FAILURE); + } + + /* Create a test image and test data. */ + fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666); + if (fd == -1) { + perror (filename); + exit (EXIT_FAILURE); + } + + atexit (remove_test_img); + + if (lseek (fd, filesize - 1, SEEK_SET) == (off_t) -1) { + perror ("lseek"); + close (fd); + exit (EXIT_FAILURE); + } + + if (write (fd, &c, 1) != 1) { + perror ("write"); + close (fd); + exit (EXIT_FAILURE); + } + + if (close (fd) == -1) { + perror ("test.img"); + exit (EXIT_FAILURE); + } + + if (guestfs_add_drive_opts (g, filename, + GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", + -1) == -1) + exit (EXIT_FAILURE); + + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1) + exit (EXIT_FAILURE); + + if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1) + exit (EXIT_FAILURE); + + if (guestfs_mount_options (g, "", "/dev/sda1", "/") == -1) + exit (EXIT_FAILURE); + + /*----- Upload cancellation test -----*/ + + data.g = g; + data.direction = DIRECTION_UP; + + if (pipe (fds) == -1) { + perror ("pipe"); + exit (EXIT_FAILURE); + } + + data.fd = fds[1]; + snprintf (dev_fd, sizeof dev_fd, "/dev/fd/%d", fds[0]); + + data.cancel_posn = random_cancel_posn (); + + /* Create the test thread. */ + r = pthread_create (&test_thread, NULL, start_test_thread, &data); + if (r != 0) { + fprintf (stderr, "pthread_create: %s", strerror (r)); + exit (EXIT_FAILURE); + } + + /* Do the upload. */ + op_error = guestfs_upload (g, dev_fd, "/upload"); + op_errno = guestfs_last_errno (g); + + /* Kill the test thread and clean up. */ + r = pthread_cancel (test_thread); + if (r != 0) { + fprintf (stderr, "pthread_cancel: %s", strerror (r)); + exit (EXIT_FAILURE); + } + r = pthread_join (test_thread, NULL); + if (r != 0) { + fprintf (stderr, "pthread_join: %s", strerror (r)); + exit (EXIT_FAILURE); + } + + close (fds[0]); + close (fds[1]); + + /* We expect to get an error, with errno == EINTR. */ + if (op_error == -1 && op_errno == EINTR) + printf ("test-user-cancel: upload cancellation test passed (%ld/%ld)\n", + (long) data.cancel_posn, (long) data.transfer_size); + else { + fprintf (stderr, "test-user-cancel: upload cancellation test FAILED\n"); + fprintf (stderr, "cancel_posn %ld, upload returned %d, errno = %d (%s)\n", + (long) data.cancel_posn, op_error, op_errno, strerror (op_errno)); + errors++; + } + + if (guestfs_rm (g, "/upload") == -1) + exit (EXIT_FAILURE); + + /*----- Download cancellation test -----*/ + + if (guestfs_touch (g, "/download") == -1) + exit (EXIT_FAILURE); + + if (guestfs_truncate_size (g, "/download", filesize/4) == -1) + exit (EXIT_FAILURE); + + data.g = g; + data.direction = DIRECTION_DOWN; + + if (pipe (fds) == -1) { + perror ("pipe"); + exit (EXIT_FAILURE); + } + + data.fd = fds[0]; + snprintf (dev_fd, sizeof dev_fd, "/dev/fd/%d", fds[1]); + + data.cancel_posn = random_cancel_posn (); + + /* Create the test thread. */ + r = pthread_create (&test_thread, NULL, start_test_thread, &data); + if (r != 0) { + fprintf (stderr, "pthread_create: %s", strerror (r)); + exit (EXIT_FAILURE); + } + + /* Do the download. */ + op_error = guestfs_download (g, "/download", dev_fd); + op_errno = guestfs_last_errno (g); + + /* Kill the test thread and clean up. */ + r = pthread_cancel (test_thread); + if (r != 0) { + fprintf (stderr, "pthread_cancel: %s", strerror (r)); + exit (EXIT_FAILURE); + } + r = pthread_join (test_thread, NULL); + if (r != 0) { + fprintf (stderr, "pthread_join: %s", strerror (r)); + exit (EXIT_FAILURE); + } + + close (fds[0]); + close (fds[1]); + + /* We expect to get an error, with errno == EINTR. */ + if (op_error == -1 && op_errno == EINTR) + printf ("test-user-cancel: download cancellation test passed (%ld/%ld)\n", + (long) data.cancel_posn, (long) data.transfer_size); + else { + fprintf (stderr, "test-user-cancel: download cancellation test FAILED\n"); + fprintf (stderr, "cancel_posn %ld, upload returned %d, errno = %d (%s)\n", + (long) data.cancel_posn, op_error, op_errno, strerror (op_errno)); + errors++; + } + + exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void +remove_test_img (void) +{ + unlink (filename); +} + +static char buffer[BUFSIZ]; + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +static void * +start_test_thread (void *datav) +{ + struct test_thread_data *data = datav; + ssize_t r; + size_t n; + + data->transfer_size = 0; + + if (data->direction == DIRECTION_UP) { /* thread is writing */ + /* Feed data in, up to the cancellation point. */ + while (data->transfer_size < data->cancel_posn) { + n = MIN (sizeof buffer, + (size_t) (data->cancel_posn - data->transfer_size)); + r = write (data->fd, buffer, n); + if (r == -1) { + perror ("test thread: write to pipe before user cancel"); + exit (EXIT_FAILURE); + } + data->transfer_size += r; + } + + /* Keep feeding data after the cancellation point for as long as + * the main thread wants it. + */ + while (1) { + /* Repeatedly assert the cancel flag. We have to do this because + * the guestfs_upload command in the main thread may not have + * started yet. + */ + guestfs_user_cancel (data->g); + + r = write (data->fd, buffer, sizeof buffer); + if (r == -1) { + perror ("test thread: write to pipe after user cancel"); + exit (EXIT_FAILURE); + } + data->transfer_size += r; + } + } else { /* thread is reading */ + /* Sink data, up to the cancellation point. */ + while (data->transfer_size < data->cancel_posn) { + n = MIN (sizeof buffer, + (size_t) (data->cancel_posn - data->transfer_size)); + r = read (data->fd, buffer, n); + if (r == -1) { + perror ("test thread: read from pipe before user cancel"); + exit (EXIT_FAILURE); + } + if (r == 0) { + perror ("test thread: unexpected end of file before user cancel"); + exit (EXIT_FAILURE); + } + data->transfer_size += r; + } + + /* Do user cancellation. */ + guestfs_user_cancel (data->g); + + /* Keep sinking data as long as the main thread is writing. */ + while (1) { + r = read (data->fd, buffer, sizeof buffer); + if (r == -1) { + perror ("test thread: read from pipe after user cancel"); + exit (EXIT_FAILURE); + } + if (r == 0) + break; + data->transfer_size += r; + } + + while (1) + pause (); + } + + return NULL; +} + +static double random_gauss (double mu, double sd); + +/* Generate a random cancellation position, but skew it towards + * smaller numbers. + */ +static off_t +random_cancel_posn (void) +{ + const double mu = 65536; + const double sd = 65536 * 4; + double r; + + do { + r = random_gauss (mu, sd); + } while (r <= 0); + + return (off_t) r; +} + +/* Generate a random Gaussian distributed number using the Box-Muller + * transformation. (http://www.taygeta.com/random/gaussian.html) + */ +static double +random_gauss (double mu, double sd) +{ + double x1, x2, w, y1; + + do { + x1 = 2. * drand48 () - 1.; + x2 = 2. * drand48 () - 1.; + w = x1 * x1 + x2 * x2; + } while (w >= 1.); + + w = sqrt ((-2. * log (w)) / w); + y1 = x1 * w; + //y2 = x2 * w; + return mu + y1 * sd; +} diff --git a/tests/qemu/Makefile.am b/tests/qemu/Makefile.am index fb95a747..ad735101 100644 --- a/tests/qemu/Makefile.am +++ b/tests/qemu/Makefile.am @@ -17,8 +17,6 @@ # Safety and liveness tests of components that libguestfs depends upon # (not of libguestfs itself). Mainly this is for qemu and the kernel. -# -# See also capitests and regressions directories. include $(top_srcdir)/subdir-rules.mk |