diff options
Diffstat (limited to 'tests/tap')
| -rw-r--r-- | tests/tap/basic.c | 196 | ||||
| -rw-r--r-- | tests/tap/basic.h | 41 | ||||
| -rw-r--r-- | tests/tap/kerberos.c | 31 | ||||
| -rw-r--r-- | tests/tap/kerberos.sh | 32 | ||||
| -rw-r--r-- | tests/tap/libtap.sh | 32 | ||||
| -rw-r--r-- | tests/tap/remctl.sh | 18 | 
6 files changed, 254 insertions, 96 deletions
| diff --git a/tests/tap/basic.c b/tests/tap/basic.c index 5ca9ff4..829f91a 100644 --- a/tests/tap/basic.c +++ b/tests/tap/basic.c @@ -2,12 +2,13 @@   * Some utility routines for writing tests.   *   * Herein are a variety of utility routines for writing tests.  All routines - * of the form ok*() take a test number and some number of appropriate + * of the form ok() or is*() take a test number and some number of appropriate   * arguments, check to be sure the results match the expected output using the   * arguments, and print out something appropriate for that test number.  Other - * utility routines help in constructing more complex tests. + * utility routines help in constructing more complex tests, skipping tests, + * or setting up the TAP output format.   * - * Copyright 2009 Russ Allbery <rra@stanford.edu> + * Copyright 2009, 2010 Russ Allbery <rra@stanford.edu>   * Copyright 2006, 2007, 2008   *     Board of Trustees, Leland Stanford Jr. University   * Copyright (c) 2004, 2005, 2006 @@ -34,7 +35,7 @@   * The test count.  Always contains the number that will be used for the next   * test status.   */ -int testnum = 1; +unsigned long testnum = 1;  /*   * Status information stored so that we can give a test summary at the end of @@ -44,10 +45,14 @@ int testnum = 1;   * We also store the PID of the process that called plan() and only summarize   * results when that process exits, so as to not misreport results in forked   * processes. + * + * If _lazy is true, we're doing lazy planning and will print out the plan + * based on the last test number at the end of testing.   */ -static int _planned = 0; -static int _failed  = 0; +static unsigned long _planned = 0; +static unsigned long _failed  = 0;  static pid_t _process = 0; +static int _lazy = 0;  /* @@ -57,22 +62,28 @@ static pid_t _process = 0;  static void  finish(void)  { -    int highest = testnum - 1; - -    if (_process != 0 && getpid() == _process && _planned > 0) { +    unsigned long highest = testnum - 1; + +    if (_planned == 0 && !_lazy) +        return; +    if (_process != 0 && getpid() == _process) { +        if (_lazy) { +            printf("1..%lu\n", highest); +            _planned = highest; +        }          if (_planned > highest) -            printf("# Looks like you planned %d test%s but only ran %d\n", +            printf("# Looks like you planned %lu test%s but only ran %lu\n",                     _planned, (_planned > 1 ? "s" : ""), highest);          else if (_planned < highest) -            printf("# Looks like you planned %d test%s but ran %d extra\n", +            printf("# Looks like you planned %lu test%s but ran %lu extra\n",                     _planned, (_planned > 1 ? "s" : ""), highest - _planned);          else if (_failed > 0) -            printf("# Looks like you failed %d test%s of %d\n", _failed, +            printf("# Looks like you failed %lu test%s of %lu\n", _failed,                     (_failed > 1 ? "s" : ""), _planned);          else if (_planned > 1) -            printf("# All %d tests successful or skipped\n", _planned); +            printf("# All %lu tests successful or skipped\n", _planned);          else -            printf("# %d test successful or skipped\n", _planned); +            printf("# %lu test successful or skipped\n", _planned);      }  } @@ -82,12 +93,12 @@ finish(void)   * the number of tests in the test suite.   */  void -plan(int count) +plan(unsigned long count)  {      if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)          fprintf(stderr, "# cannot set stdout to line buffered: %s\n",                  strerror(errno)); -    printf("1..%d\n", count); +    printf("1..%lu\n", count);      testnum = 1;      _planned = count;      _process = getpid(); @@ -96,6 +107,23 @@ plan(int count)  /* + * Initialize things for lazy planning, where we'll automatically print out a + * plan at the end of the program.  Turns on line buffering on stdout as well. + */ +void +plan_lazy(void) +{ +    if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0) +        fprintf(stderr, "# cannot set stdout to line buffered: %s\n", +                strerror(errno)); +    testnum = 1; +    _process = getpid(); +    _lazy = 1; +    atexit(finish); +} + + +/*   * Skip the entire test suite and exits.  Should be called instead of plan(),   * not after it, since it prints out a special plan line.   */ @@ -134,7 +162,7 @@ print_desc(const char *format, va_list args)  void  ok(int success, const char *format, ...)  { -    printf("%sok %d", success ? "" : "not ", testnum++); +    printf("%sok %lu", success ? "" : "not ", testnum++);      if (!success)          _failed++;      if (format != NULL) { @@ -149,12 +177,27 @@ ok(int success, const char *format, ...)  /* + * Same as ok(), but takes the format arguments as a va_list. + */ +void +okv(int success, const char *format, va_list args) +{ +    printf("%sok %lu", success ? "" : "not ", testnum++); +    if (!success) +        _failed++; +    if (format != NULL) +        print_desc(format, args); +    putchar('\n'); +} + + +/*   * Skip a test.   */  void  skip(const char *reason, ...)  { -    printf("ok %d # skip", testnum++); +    printf("ok %lu # skip", testnum++);      if (reason != NULL) {          va_list args; @@ -171,12 +214,12 @@ skip(const char *reason, ...)   * Report the same status on the next count tests.   */  void -ok_block(int count, int status, const char *format, ...) +ok_block(unsigned long count, int status, const char *format, ...)  { -    int i; +    unsigned long i;      for (i = 0; i < count; i++) { -        printf("%sok %d", status ? "" : "not ", testnum++); +        printf("%sok %lu", status ? "" : "not ", testnum++);          if (!status)              _failed++;          if (format != NULL) { @@ -195,12 +238,12 @@ ok_block(int count, int status, const char *format, ...)   * Skip the next count tests.   */  void -skip_block(int count, const char *reason, ...) +skip_block(unsigned long count, const char *reason, ...)  { -    int i; +    unsigned long i;      for (i = 0; i < count; i++) { -        printf("ok %d # skip", testnum++); +        printf("ok %lu # skip", testnum++);          if (reason != NULL) {              va_list args; @@ -219,13 +262,13 @@ skip_block(int count, const char *reason, ...)   * if those two numbers match.   */  void -is_int(int wanted, int seen, const char *format, ...) +is_int(long wanted, long seen, const char *format, ...)  {      if (wanted == seen) -        printf("ok %d", testnum++); +        printf("ok %lu", testnum++);      else { -        printf("# wanted: %d\n#   seen: %d\n", wanted, seen); -        printf("not ok %d", testnum++); +        printf("# wanted: %ld\n#   seen: %ld\n", wanted, seen); +        printf("not ok %lu", testnum++);          _failed++;      }      if (format != NULL) { @@ -251,10 +294,10 @@ is_string(const char *wanted, const char *seen, const char *format, ...)      if (seen == NULL)          seen = "(null)";      if (strcmp(wanted, seen) == 0) -        printf("ok %d", testnum++); +        printf("ok %lu", testnum++);      else {          printf("# wanted: %s\n#   seen: %s\n", wanted, seen); -        printf("not ok %d", testnum++); +        printf("not ok %lu", testnum++);          _failed++;      }      if (format != NULL) { @@ -276,10 +319,10 @@ void  is_double(double wanted, double seen, const char *format, ...)  {      if (wanted == seen) -        printf("ok %d", testnum++); +        printf("ok %lu", testnum++);      else {          printf("# wanted: %g\n#   seen: %g\n", wanted, seen); -        printf("not ok %d", testnum++); +        printf("not ok %lu", testnum++);          _failed++;      }      if (format != NULL) { @@ -301,11 +344,11 @@ void  is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)  {      if (wanted == seen) -        printf("ok %d", testnum++); +        printf("ok %lu", testnum++);      else {          printf("# wanted: %lx\n#   seen: %lx\n", (unsigned long) wanted,                 (unsigned long) seen); -        printf("not ok %d", testnum++); +        printf("not ok %lu", testnum++);          _failed++;      }      if (format != NULL) { @@ -354,3 +397,88 @@ sysbail(const char *format, ...)      printf(": %s\n", strerror(oerrno));      exit(1);  } + + +/* + * Report a diagnostic to stderr. + */ +void +diag(const char *format, ...) +{ +    va_list args; + +    fflush(stdout); +    printf("# "); +    va_start(args, format); +    vprintf(format, args); +    va_end(args); +    printf("\n"); +} + + +/* + * Report a diagnostic to stderr, appending strerror(errno). + */ +void +sysdiag(const char *format, ...) +{ +    va_list args; +    int oerrno = errno; + +    fflush(stdout); +    printf("# "); +    va_start(args, format); +    vprintf(format, args); +    va_end(args); +    printf(": %s\n", strerror(oerrno)); +} + + +/* + * Locate a test file.  Given the partial path to a file, look under BUILD and + * then SOURCE for the file and return the full path to the file.  Returns + * NULL if the file doesn't exist.  A non-NULL return should be freed with + * test_file_path_free(). + * + * This function uses sprintf because it attempts to be independent of all + * other portability layers.  The use immediately after a memory allocation + * should be safe without using snprintf or strlcpy/strlcat. + */ +char * +test_file_path(const char *file) +{ +    char *base; +    char *path = NULL; +    size_t length; +    const char *envs[] = { "BUILD", "SOURCE", NULL }; +    int i; + +    for (i = 0; envs[i] != NULL; i++) { +        base = getenv(envs[i]); +        if (base == NULL) +            continue; +        length = strlen(base) + 1 + strlen(file) + 1; +        path = malloc(length); +        if (path == NULL) +            sysbail("cannot allocate memory"); +        sprintf(path, "%s/%s", base, file); +        if (access(path, R_OK) == 0) +            break; +        free(path); +        path = NULL; +    } +    return path; +} + + +/* + * Free a path returned from test_file_path().  This function exists primarily + * for Windows, where memory must be freed from the same library domain that + * it was allocated from. + */ +void +test_file_path_free(char *path) +{ +    if (path != NULL) +        free(path); +} diff --git a/tests/tap/basic.h b/tests/tap/basic.h index efe94ba..9602db4 100644 --- a/tests/tap/basic.h +++ b/tests/tap/basic.h @@ -1,6 +1,7 @@  /*   * Basic utility routines for the TAP protocol.   * + * Copyright 2009, 2010 Russ Allbery <rra@stanford.edu>   * Copyright 2006, 2007, 2008   *     Board of Trustees, Leland Stanford Jr. University   * Copyright (c) 2004, 2005, 2006 @@ -14,6 +15,7 @@  #ifndef TAP_BASIC_H  #define TAP_BASIC_H 1 +#include <stdarg.h>             /* va_list */  #include <sys/types.h>          /* pid_t */  /* @@ -56,29 +58,40 @@ BEGIN_DECLS   * The test count.  Always contains the number that will be used for the next   * test status.   */ -extern int testnum; +extern unsigned long testnum;  /* Print out the number of tests and set standard output to line buffered. */ -void plan(int count); +void plan(unsigned long count); + +/* + * Prepare for lazy planning, in which the plan will be  printed automatically + * at the end of the test program. + */ +void plan_lazy(void);  /* Skip the entire test suite.  Call instead of plan. */  void skip_all(const char *format, ...)      __attribute__((__noreturn__, __format__(printf, 1, 2))); -/* Basic reporting functions. */ +/* + * Basic reporting functions.  The okv() function is the same as ok() but + * takes the test description as a va_list to make it easier to reuse the + * reporting infrastructure when writing new tests. + */  void ok(int success, const char *format, ...)      __attribute__((__format__(printf, 2, 3))); +void okv(int success, const char *format, va_list args);  void skip(const char *reason, ...)      __attribute__((__format__(printf, 1, 2)));  /* Report the same status on, or skip, the next count tests. */ -void ok_block(int count, int success, const char *format, ...) +void ok_block(unsigned long count, int success, const char *format, ...)      __attribute__((__format__(printf, 3, 4))); -void skip_block(int count, const char *reason, ...) +void skip_block(unsigned long count, const char *reason, ...)      __attribute__((__format__(printf, 2, 3)));  /* Check an expected value against a seen value. */ -void is_int(int wanted, int seen, const char *format, ...) +void is_int(long wanted, long seen, const char *format, ...)      __attribute__((__format__(printf, 3, 4)));  void is_double(double wanted, double seen, const char *format, ...)      __attribute__((__format__(printf, 3, 4))); @@ -93,6 +106,20 @@ void bail(const char *format, ...)  void sysbail(const char *format, ...)      __attribute__((__noreturn__, __nonnull__, __format__(printf, 1, 2))); +/* Report a diagnostic to stderr prefixed with #. */ +void diag(const char *format, ...) +    __attribute__((__nonnull__, __format__(printf, 1, 2))); +void sysdiag(const char *format, ...) +    __attribute__((__nonnull__, __format__(printf, 1, 2))); + +/* + * Find a test file under BUILD or SOURCE, returning the full path.  The + * returned path should be freed with test_file_path_free(). + */ +char *test_file_path(const char *file) +    __attribute__((__malloc__, __nonnull__)); +void test_file_path_free(char *path); +  END_DECLS -#endif /* LIBTEST_H */ +#endif /* TAP_BASIC_H */ diff --git a/tests/tap/kerberos.c b/tests/tap/kerberos.c index 700212e..a17d980 100644 --- a/tests/tap/kerberos.c +++ b/tests/tap/kerberos.c @@ -23,33 +23,6 @@  /* - * Given the partial path to a file, look under BUILD and then SOURCE for the - * file and return the full path to the file in newly-allocated memory. - * Returns NULL if the file doesn't exist. - */ -static char * -find_file(const char *file) -{ -    char *base; -    char *path = NULL; -    const char *envs[] = { "BUILD", "SOURCE", NULL }; -    int i; - -    for (i = 0; envs[i] != NULL; i++) { -        base = getenv(envs[i]); -        if (base == NULL) -            continue; -        path = concatpath(base, file); -        if (access(path, R_OK) == 0) -            break; -        free(path); -        path = NULL; -    } -    return path; -} - - -/*   * Obtain Kerberos tickets for the principal specified in test.principal using   * the keytab specified in test.keytab, both of which are presumed to be in   * tests/data in either the build or the source tree. @@ -78,7 +51,7 @@ kerberos_setup(void)      krb5_creds creds;      /* Read the principal name and find the keytab file. */ -    path = find_file("data/test.principal"); +    path = test_file_path("data/test.principal");      if (path == NULL)          return NULL;      file = fopen(path, "r"); @@ -95,7 +68,7 @@ kerberos_setup(void)          bail("no newline in %s", path);      free(path);      principal[strlen(principal) - 1] = '\0'; -    path = find_file("data/test.keytab"); +    path = test_file_path("data/test.keytab");      if (path == NULL)          return NULL; diff --git a/tests/tap/kerberos.sh b/tests/tap/kerberos.sh index da07e66..904cae5 100644 --- a/tests/tap/kerberos.sh +++ b/tests/tap/kerberos.sh @@ -1,7 +1,7 @@  # Shell function library to initialize Kerberos credentials  #  # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2009 Board of Trustees, Leland Stanford Jr. University +# Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University  #  # See LICENSE for licensing terms. @@ -10,18 +10,9 @@  # configured.  Sets the global principal variable to the principal to use.  kerberos_setup () {      local keytab -    keytab='' -    for f in "$BUILD/data/test.keytab" "$SOURCE/data/test.keytab" ; do -        if [ -r "$f" ] ; then -            keytab="$f" -        fi -    done -    principal='' -    for f in "$BUILD/data/test.principal" "$SOURCE/data/test.principal" ; do -        if [ -r "$f" ] ; then -            principal=`cat "$BUILD/data/test.principal"` -        fi -    done +    keytab=`test_file_path data/test.keytab` +    principal=`test_file_path data/test.principal` +    principal=`cat "$principal" 2>/dev/null`      if [ -z "$keytab" ] || [ -z "$principal" ] ; then          return 1      fi @@ -46,3 +37,18 @@ kerberos_setup () {  kerberos_cleanup () {      rm -f "$BUILD/data/test.cache"  } + +# List the contents of a keytab with enctypes and keys.  This adjusts for the +# difference between MIT Kerberos (which uses klist) and Heimdal (which uses +# ktutil).  Be careful to try klist first, since the ktutil on MIT Kerberos +# may just hang.  Takes the keytab to list and the file into which to save the +# output, and strips off the header containing the file name. +ktutil_list () { +    if klist -keK "$1" > ktutil-tmp 2>/dev/null ; then +        : +    else +        ktutil -k "$1" list --keys > ktutil-tmp < /dev/null 2>/dev/null +    fi +    sed -e '/Keytab name:/d' -e "/^[^ ]*:/d" ktutil-tmp > "$2" +    rm -f ktutil-tmp +} diff --git a/tests/tap/libtap.sh b/tests/tap/libtap.sh index 1846840..a9b46d4 100644 --- a/tests/tap/libtap.sh +++ b/tests/tap/libtap.sh @@ -1,7 +1,7 @@  # Shell function library for test cases.  #  # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2009 Russ Allbery <rra@stanford.edu> +# Copyright 2009, 2010 Russ Allbery <rra@stanford.edu>  # Copyright 2006, 2007, 2008 Board of Trustees, Leland Stanford Jr. University  #  # See LICENSE for licensing terms. @@ -15,10 +15,22 @@ plan () {      trap finish 0  } +# Prepare for lazy planning. +plan_lazy () { +    count=1 +    planned=0 +    failed=0 +    trap finish 0 +} +  # Report the test status on exit.  finish () {      local highest looks      highest=`expr "$count" - 1` +    if [ "$planned" = 0 ] ; then +        echo "1..$highest" +        planned="$highest" +    fi      looks='# Looks like you'      if [ "$planned" -gt 0 ] ; then          if [ "$planned" -gt "$highest" ] ; then @@ -146,3 +158,21 @@ bail () {      echo 'Bail out!' "$@"      exit 1  } + +# Output a diagnostic on standard error, preceded by the required # mark. +diag () { +    echo '#' "$@" +} + +# Search for the given file first in $BUILD and then in $SOURCE and echo the +# path where the file was found, or the empty string if the file wasn't +# found. +test_file_path () { +    if [ -f "$BUILD/$1" ] ; then +        echo "$BUILD/$1" +    elif [ -f "$SOURCE/$1" ] ; then +        echo "$SOURCE/$1" +    else +        echo '' +    fi +} diff --git a/tests/tap/remctl.sh b/tests/tap/remctl.sh index b9667ef..9e01bcf 100644 --- a/tests/tap/remctl.sh +++ b/tests/tap/remctl.sh @@ -10,18 +10,12 @@  remctld_start () {      local keytab principal      rm -f "$BUILD/data/remctld.pid" -    keytab='' -    for f in "$BUILD/data/test.keytab" "$SOURCE/data/test.keytab" ; do -        if [ -r "$f" ] ; then -            keytab="$f" -        fi -    done -    principal='' -    for f in "$BUILD/data/test.principal" "$SOURCE/data/test.principal" ; do -        if [ -r "$f" ] ; then -            principal=`cat "$BUILD/data/test.principal"` -        fi -    done +    keytab=`test_file_path data/test.keytab` +    principal=`test_file_path data/test.principal` +    principal=`cat "$principal" 2>/dev/null` +    if [ -z "$keytab" ] || [ -z "$principal" ] ; then +        return 1 +    fi      if [ -n "$VALGRIND" ] ; then          ( "$VALGRIND" --log-file=valgrind.%p --leak-check=full "$1" -m \            -p 14373 -s "$principal" -P "$BUILD/data/remctld.pid" -f "$2" -d \ | 
