diff --git a/ChangeLog b/ChangeLog index 57375128327617001197cab8f4a85d145162ce57..dab533b6081df911e1c85bf5a8c7ce22e0080da9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Thu Aug 24 16:43:47 EDT 2006 Daniel Berrange + + * tests/virshtest.c: Test suite for validating output / operation + of various virsh commands. + * tests/virshdata/*.txt: Known good output for validating results + during testing + * tests/testutils.h, tests/testutils.c: Added convenience method + for forking a child process & capturing its output. + * tests/Makefile.am: Enable POSIX / XOpen standards + Thu Aug 24 11:03:42 EDT 2006 Daniel Berrange * tests/Makefile.am: Added a 'valgrind' target which simply diff --git a/configure.in b/configure.in index e29b8cf1c06d1ee9da141dc733a5348baa2ba665..0891cc87c3b64deb7697316f73a127745e6fc8ef 100644 --- a/configure.in +++ b/configure.in @@ -256,4 +256,5 @@ AC_OUTPUT(Makefile src/Makefile include/Makefile docs/Makefile \ libvirt.pc libvirt.spec \ include/libvirt/Makefile include/libvirt/libvirt.h \ python/Makefile python/tests/Makefile \ - tests/Makefile proxy/Makefile) + tests/Makefile proxy/Makefile \ + tests/virshdata/Makefile) diff --git a/tests/.cvsignore b/tests/.cvsignore index fe457ec66ad57bd8e023a180c26cc309e6ed3a53..456b182f9d25eacf5bd6099c5bade8d04bd86e91 100644 --- a/tests/.cvsignore +++ b/tests/.cvsignore @@ -5,3 +5,4 @@ Makefile.in xmlrpctest sexpr2xmltest xml2sexprtest +virshtest diff --git a/tests/Makefile.am b/tests/Makefile.am index 480af533a3537955c0591f868b98ec63ffbf9d25..ef5af65470259c6998306684987df7cf34d63aa6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,7 @@ ## Process this file with automake to produce Makefile.in +SUBDIRS = virshdata + LIBVIRT = $(top_builddir)/src/.libs/libvirt.a INCLUDES = \ @@ -7,7 +9,8 @@ INCLUDES = \ -I$(top_builddir)/src \ -I$(top_srcdir)/include \ -I$(top_srcdir)/src \ - @LIBXML_CFLAGS@ + @LIBXML_CFLAGS@ \ + -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=199506L LDADDS = \ @STATIC_BINARIES@ \ @@ -16,9 +19,9 @@ LDADDS = \ EXTRA_DIST = xmlrpcserver.py -noinst_PROGRAMS = xmlrpctest xml2sexprtest sexpr2xmltest +noinst_PROGRAMS = xmlrpctest xml2sexprtest sexpr2xmltest virshtest -TESTS = xml2sexprtest sexpr2xmltest +TESTS = xml2sexprtest sexpr2xmltest virshtest valgrind: $(MAKE) check TESTS_ENVIRONMENT="valgrind --quiet" @@ -45,5 +48,11 @@ sexpr2xmltest_SOURCES = \ sexpr2xmltest_LDFLAGS = sexpr2xmltest_LDADD = $(LDADDS) +virshtest_SOURCES = \ + virshtest.c \ + testutils.c testutils.h +virshtest_LDFLAGS = +virshtest_LDADD = $(LDADDS) + $(LIBVIRT): -@(cd $(top_builddir)/src && $(MAKE) MAKEFLAGS+=--silent) diff --git a/tests/testutils.c b/tests/testutils.c index 4da6c7dc08f1f8c104634e097052702030a2b3b3..d6af4965cbd92b89e6b0418af04423ab775b9a82 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -15,8 +15,11 @@ #include #include #include +#include #include - +#include +#include +#include #include "testutils.h" #define GETTIMEOFDAY(T) gettimeofday(T, NULL) @@ -105,3 +108,91 @@ int virtTestLoadFile(const char *name, return st.st_size; } +static +void virtTestCaptureProgramExecChild(const char *const argv[], + int pipefd) { + int i; + int open_max; + int stdinfd = -1; + int stderrfd = -1; + const char *const env[] = { + "LANG=C", + NULL + }; + + if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0) + goto cleanup; + if ((stderrfd = open(_PATH_DEVNULL, O_WRONLY)) < 0) + goto cleanup; + + open_max = sysconf (_SC_OPEN_MAX); + for (i = 0; i < open_max; i++) { + if (i != stdinfd && + i != stderrfd && + i != pipefd) + close(i); + } + + if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO) + goto cleanup; + if (dup2(pipefd, STDOUT_FILENO) != STDOUT_FILENO) + goto cleanup; + if (dup2(stderrfd, STDERR_FILENO) != STDERR_FILENO) + goto cleanup; + + /* SUS is crazy here, hence the cast */ + execve(argv[0], (char *const*)argv, (char *const*)env); + + cleanup: + if (stdinfd != -1) + close(stdinfd); + if (stderrfd != -1) + close(stderrfd); +} + + +int virtTestCaptureProgramOutput(const char *const argv[], + char **buf, + int buflen) { + int pipefd[2]; + + if (pipe(pipefd) < 0) + return -1; + + int pid = fork(); + switch (pid) { + case 0: + close(pipefd[0]); + virtTestCaptureProgramExecChild(argv, pipefd[1]); + + close(pipefd[1]); + _exit(1); + + case -1: + return -1; + + default: + { + int got = 0; + int ret = -1; + int want = buflen-1; + + close(pipefd[1]); + + while (want) { + if ((ret = read(pipefd[0], (*buf)+got, want)) <= 0) + break; + got += ret; + want -= ret; + } + close(pipefd[0]); + + if (!ret) + (*buf)[got] = '\0'; + + waitpid(pid, NULL, 0); + + return ret; + } + } +} diff --git a/tests/testutils.h b/tests/testutils.h index 4cad281cc41e66f5845f828f237c0290d8085119..fd29ed6853928c4e066a58a35ed36ad23266e17b 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -28,6 +28,9 @@ int virtTestRun (const char *title, int virtTestLoadFile(const char *name, char **buf, int buflen); +int virtTestCaptureProgramOutput(const char *const argv[], + char **buf, + int buflen); #ifdef __cplusplus } diff --git a/tests/virshdata/.cvsignore b/tests/virshdata/.cvsignore new file mode 100644 index 0000000000000000000000000000000000000000..282522db0342d8750454b3dc162493b5fc709cc8 --- /dev/null +++ b/tests/virshdata/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/tests/virshdata/Makefile.am b/tests/virshdata/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..c46fc93e207c4e778e4005a020de1b6fe35f68ad --- /dev/null +++ b/tests/virshdata/Makefile.am @@ -0,0 +1,2 @@ + +EXTRA_DIST = $(wildcard *.txt) diff --git a/tests/virshdata/domid-fc4.txt b/tests/virshdata/domid-fc4.txt new file mode 100644 index 0000000000000000000000000000000000000000..d474e1b4d626dbf09a9776c778e9f8691bc8b406 --- /dev/null +++ b/tests/virshdata/domid-fc4.txt @@ -0,0 +1,2 @@ +1 + diff --git a/tests/virshdata/dominfo-fc4.txt b/tests/virshdata/dominfo-fc4.txt new file mode 100644 index 0000000000000000000000000000000000000000..97fbe3f14931996674b72b8ad0b34f2426cc03f6 --- /dev/null +++ b/tests/virshdata/dominfo-fc4.txt @@ -0,0 +1,9 @@ +Id: 1 +Name: fc4 +UUID: ef861801-45b9-11cb-88e3-afbfe5370493 +OS Type: linux +State: running +CPU(s): 1 +Max memory: 131072 kB +Used memory: 131072 kB + diff --git a/tests/virshdata/domname-fc4.txt b/tests/virshdata/domname-fc4.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd55058b4ca1fd7b0f4bc718e9a3b611c5d10ba4 --- /dev/null +++ b/tests/virshdata/domname-fc4.txt @@ -0,0 +1,2 @@ +fc4 + diff --git a/tests/virshdata/domstate-fc4.txt b/tests/virshdata/domstate-fc4.txt new file mode 100644 index 0000000000000000000000000000000000000000..511622fad3158ef7ef954ccbc022dd9d89cba3af --- /dev/null +++ b/tests/virshdata/domstate-fc4.txt @@ -0,0 +1,2 @@ +running + diff --git a/tests/virshdata/domuuid-fc4.txt b/tests/virshdata/domuuid-fc4.txt new file mode 100644 index 0000000000000000000000000000000000000000..face70eb649a1a28b7f3dbd9fd87e9f8f87dcab9 --- /dev/null +++ b/tests/virshdata/domuuid-fc4.txt @@ -0,0 +1,2 @@ +ef861801-45b9-11cb-88e3-afbfe5370493 + diff --git a/tests/virshdata/list-custom.txt b/tests/virshdata/list-custom.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb1adb39d9086ee1720d27feef4e4faa254836d9 --- /dev/null +++ b/tests/virshdata/list-custom.txt @@ -0,0 +1,5 @@ + Id Name State +---------------------------------- + 0 fv0 running + 1 fc4 running + diff --git a/tests/virshdata/list-default.txt b/tests/virshdata/list-default.txt new file mode 100644 index 0000000000000000000000000000000000000000..df496fe55c165a3cacfe3cae66636b5892ee37a3 --- /dev/null +++ b/tests/virshdata/list-default.txt @@ -0,0 +1,4 @@ + Id Name State +---------------------------------- + 0 Domain-0 running + diff --git a/tests/virshdata/nodeinfo-custom.txt b/tests/virshdata/nodeinfo-custom.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b31765fc33506fba8d818db287f18d09a2adf95 --- /dev/null +++ b/tests/virshdata/nodeinfo-custom.txt @@ -0,0 +1,9 @@ +CPU model: i986 +CPU(s): 50 +CPU frequency: 6000 MHz +CPU socket(s): 4 +Core(s) per socket: 4 +Thread(s) per core: 2 +NUMA cell(s): 4 +Memory size: 137438953472 kB + diff --git a/tests/virshdata/nodeinfo-default.txt b/tests/virshdata/nodeinfo-default.txt new file mode 100644 index 0000000000000000000000000000000000000000..99d9754d20a09d9740df90e4b63382241493b493 --- /dev/null +++ b/tests/virshdata/nodeinfo-default.txt @@ -0,0 +1,9 @@ +CPU model: i686 +CPU(s): 16 +CPU frequency: 1400 MHz +CPU socket(s): 2 +Core(s) per socket: 2 +Thread(s) per core: 2 +NUMA cell(s): 2 +Memory size: 3145728 kB + diff --git a/tests/virshtest.c b/tests/virshtest.c new file mode 100644 index 0000000000000000000000000000000000000000..90209577bd97bbfe53e7e04cd3503a9c2fcd7c3b --- /dev/null +++ b/tests/virshtest.c @@ -0,0 +1,351 @@ + +#include +#include +#include + +#include "xml.h" +#include "testutils.h" +#include "internal.h" + +static char *progname; +#define MAX_FILE 4096 + +static int testFilterLine(char *buffer, + const char *toRemove) { + char *start; + char *end; + + if (!(start = strstr(buffer, toRemove))) + return -1; + + if (!(end = strstr(start+1, "\n"))) { + *start = '\0'; + } else { + memmove(start, end, strlen(end)+1); + } + return 0; +} + +static int testCompareOutput(const char *expect, const char *filter, const char *const argv[]) { + char expectData[MAX_FILE]; + char actualData[MAX_FILE]; + char *expectPtr = &(expectData[0]); + char *actualPtr = &(actualData[0]); + + if (virtTestLoadFile(expect, &expectPtr, MAX_FILE) < 0) + return -1; + + if (virtTestCaptureProgramOutput(argv, &actualPtr, MAX_FILE) < 0) + return -1; + + if (filter) + if (testFilterLine(actualData, filter) < 0) + return -1; + + if (getenv("DEBUG_TESTS")) { + printf("Expect %d '%s'\n", strlen(expectData), expectData); + printf("Actual %d '%s'\n", strlen(actualData), actualData); + } + if (strcmp(expectData, actualData)) + return -1; + + return 0; +} + + +#define VIRSH_DEFAULT "../src/virsh", \ + "--connect", \ + "test:///default" + +static char *custom_uri; + +#define VIRSH_CUSTOM "../src/virsh", \ + "--connect", \ + custom_uri + + + +static int testCompareListDefault(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_DEFAULT, + "list", + NULL + }; + return testCompareOutput("virshdata/list-default.txt", + NULL, + argv); +} + +static int testCompareListCustom(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "list", + NULL + }; + return testCompareOutput("virshdata/list-custom.txt", + NULL, + argv); +} + + +static int testCompareNodeinfoDefault(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_DEFAULT, + "nodeinfo", + NULL + }; + return testCompareOutput("virshdata/nodeinfo-default.txt", + NULL, + argv); +} + +static int testCompareNodeinfoCustom(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "nodeinfo", + NULL + }; + return testCompareOutput("virshdata/nodeinfo-custom.txt", + NULL, + argv); +} + +static int testCompareDominfoByID(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "dominfo", + "1", + NULL + }; + return testCompareOutput("virshdata/dominfo-fc4.txt", + "\nCPU time:", + argv); +} + + +static int testCompareDominfoByUUID(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "dominfo", + "ef861801-45b9-11cb-88e3-afbfe5370493", + NULL + }; + return testCompareOutput("virshdata/dominfo-fc4.txt", + "\nCPU time:", + argv); +} + + +static int testCompareDominfoByName(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "dominfo", + "fc4", + NULL + }; + return testCompareOutput("virshdata/dominfo-fc4.txt", + "\nCPU time:", + argv); +} + + +static int testCompareDomuuidByID(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domuuid", + "1", + NULL + }; + return testCompareOutput("virshdata/domuuid-fc4.txt", + NULL, + argv); +} + +static int testCompareDomuuidByName(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domuuid", + "fc4", + NULL + }; + return testCompareOutput("virshdata/domuuid-fc4.txt", + NULL, + argv); +} + +static int testCompareDomidByName(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domid", + "fc4", + NULL + }; + return testCompareOutput("virshdata/domid-fc4.txt", + NULL, + argv); +} + + +static int testCompareDomidByUUID(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domid", + "ef861801-45b9-11cb-88e3-afbfe5370493", + NULL + }; + return testCompareOutput("virshdata/domid-fc4.txt", + NULL, + argv); +} + + +static int testCompareDomnameByID(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domname", + "1", + NULL + }; + return testCompareOutput("virshdata/domname-fc4.txt", + NULL, + argv); +} + + +static int testCompareDomnameByUUID(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domname", + "ef861801-45b9-11cb-88e3-afbfe5370493", + NULL + }; + return testCompareOutput("virshdata/domname-fc4.txt", + NULL, + argv); +} + +static int testCompareDomstateByID(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domstate", + "1", + NULL + }; + return testCompareOutput("virshdata/domstate-fc4.txt", + NULL, + argv); +} + + +static int testCompareDomstateByUUID(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domstate", + "ef861801-45b9-11cb-88e3-afbfe5370493", + NULL + }; + return testCompareOutput("virshdata/domstate-fc4.txt", + NULL, + argv); +} + +static int testCompareDomstateByName(void *data ATTRIBUTE_UNUSED) { + const char *const argv[] = { + VIRSH_CUSTOM, + "domstate", + "fc4", + NULL + }; + return testCompareOutput("virshdata/domstate-fc4.txt", + NULL, + argv); +} + + + +int +main(int argc, char **argv) +{ + int ret = 0; + char cwd[PATH_MAX]; + char buffer[PATH_MAX]; + + if (!getcwd(cwd, PATH_MAX-1)) + return 1; + + snprintf(buffer, PATH_MAX-1, "test://%s/../docs/testnode.xml", cwd); + buffer[PATH_MAX-1] = '\0'; + progname = argv[0]; + custom_uri = buffer; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", progname); + exit(EXIT_FAILURE); + } + + if (virtTestRun("virsh list (default)", + 1, testCompareListDefault, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh list (custom)", + 1, testCompareListCustom, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh nodeinfo (default)", + 1, testCompareNodeinfoDefault, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh nodeinfo (custom)", + 1, testCompareNodeinfoCustom, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh dominfo (by id)", + 1, testCompareDominfoByID, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh dominfo (by uuid)", + 1, testCompareDominfoByUUID, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh dominfo (by name)", + 1, testCompareDominfoByName, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domid (by name)", + 1, testCompareDomidByName, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domid (by uuid)", + 1, testCompareDomidByUUID, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domuuid (by id)", + 1, testCompareDomuuidByID, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domuuid (by name)", + 1, testCompareDomuuidByName, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domname (by id)", + 1, testCompareDomnameByID, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domname (by uuid)", + 1, testCompareDomnameByUUID, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domstate (by id)", + 1, testCompareDomstateByID, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domstate (by uuid)", + 1, testCompareDomstateByUUID, NULL) != 0) + ret = -1; + + if (virtTestRun("virsh domstate (by name)", + 1, testCompareDomstateByName, NULL) != 0) + ret = -1; + + exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); +}