Print this page
5293 desire symbol visibility test
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: TBD
@@ -8,27 +8,35 @@
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
- * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2015 Garrett D'Amore <garrett@damore.org>
*/
/*
* Common handling for test programs.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
#include <pthread.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/param.h>
#include "test_common.h"
static int debug = 0;
static int force = 0;
static pthread_mutex_t lk;
+static int passes;
+static int tests;
+
struct test {
char *name;
int ntids;
pthread_t *tids;
int fails;
@@ -74,22 +82,34 @@
test_debugf(t, NULL);
test_failed(t, NULL);
test_passed(t);
test_set_debug();
test_set_force();
+ test_summary();
+ (void) test_load_config(t, NULL, NULL);
#endif
+ tests++;
return (t);
-
}
void
test_failed(test_t t, const char *format, ...)
{
va_list args;
(void) pthread_mutex_lock(&lk);
+ if (t == NULL) {
+ (void) printf("FAILURE: ");
+ va_start(args, format);
+ (void) vprintf(format, args);
+ va_end(args);
+ (void) printf("\n");
+ (void) fflush(stdout);
+ (void) pthread_mutex_unlock(&lk);
+ return;
+ }
if (force || (t->ntids > 0)) {
(void) printf("TEST FAILING %s: ", t->name);
} else {
(void) printf("TEST FAILED %s: ", t->name);
}
@@ -112,10 +132,13 @@
}
void
test_passed(test_t t)
{
+ if (t == NULL) {
+ return;
+ }
if (t->ntids > 0) {
if (debug) {
(void) pthread_mutex_lock(&lk);
(void) printf("TEST PASSING: %s\n", t->name);
(void) pthread_mutex_unlock(&lk);
@@ -122,10 +145,11 @@
}
return;
}
(void) pthread_mutex_lock(&lk);
if (t->fails == 0) {
+ passes++;
(void) printf("TEST PASS: %s\n", t->name);
} else {
(void) printf("TEST FAILED: %d failures\n", t->fails);
}
(void) fflush(stdout);
@@ -136,20 +160,34 @@
}
free(t);
}
void
+test_summary(void)
+{
+ if (passes == tests) {
+ (void) printf("TEST SUMMARY: %d / %d (ok)\n", passes, tests);
+ } else {
+ (void) printf("TEST SUMMARY: %d / %d (%d failing)\n",
+ passes, tests, tests - passes);
+ }
+}
+
+void
test_debugf(test_t t, const char *format, ...)
{
va_list args;
if (!debug)
return;
(void) pthread_mutex_lock(&lk);
+ if (t) {
(void) printf("TEST DEBUG %s: ", t->name);
-
+ } else {
+ (void) printf("TEST DEBUG: ");
+ }
va_start(args, format);
(void) vprintf(format, args);
va_end(args);
(void) printf("\n");
(void) fflush(stdout);
@@ -201,6 +239,168 @@
(void) pthread_join(t->tids[i], NULL);
test_debugf(t, "thread %d joined", i);
t->ntids--;
}
test_passed(t);
+}
+
+void
+test_trim(char **ptr)
+{
+ char *p = *ptr;
+ while (isspace(*p)) {
+ p++;
+ }
+ *ptr = p;
+ p += strlen(p);
+ while ((--p >= *ptr) && (isspace(*p))) {
+ *p = 0;
+ }
+}
+
+#define MAXCB 20
+#define MAXFIELD 20
+
+int
+test_load_config(test_t t, const char *fname, ...)
+{
+ va_list va;
+ const char *keyws[MAXCB];
+ test_cfg_func_t callbs[MAXCB];
+ char *fields[MAXFIELD];
+ int nfields;
+
+ FILE *cfg;
+ char line[1024];
+ char buf[1024];
+ int done;
+ char *ptr;
+ char *tok;
+ char *err;
+ int lineno;
+ int rv;
+ int found;
+ char path[MAXPATHLEN];
+ int i;
+
+ va_start(va, fname);
+ for (i = 0; i < MAXCB; i++) {
+ keyws[i] = (const char *)va_arg(va, const char *);
+ if (keyws[i] == NULL)
+ break;
+ callbs[i] = (test_cfg_func_t)va_arg(va, test_cfg_func_t);
+ }
+ va_end(va);
+ if (i == MAXCB) {
+ test_debugf(t, "too many arguments to function >= %d", MAXCB);
+ }
+
+ found = 0;
+
+ if (access(fname, F_OK) == 0) {
+ found++;
+ }
+ if (!found && fname[0] != '/') {
+ char *stf = getenv("STF_SUITE");
+ if (stf == NULL) {
+ stf = "../..";
+ }
+ (void) snprintf(path, sizeof (path), "%s/cfg/%s", stf, fname);
+ if (access(path, F_OK) == 0) {
+ fname = path;
+ found++;
+ } else {
+ (void) snprintf(path, sizeof (path), "cfg/%s", fname);
+ if (access(path, F_OK) == 0) {
+ fname = path;
+ found++;
+ }
+ }
+ }
+
+ if ((cfg = fopen(fname, "r")) == NULL) {
+ test_failed(t, "open(%s): %s", fname, strerror(errno));
+ return (-1);
+ }
+
+ line[0] = 0;
+ done = 0;
+ lineno = 0;
+
+ while (!done) {
+
+ lineno++;
+
+ if (fgets(buf, sizeof (buf), cfg) == NULL) {
+ done++;
+ } else {
+ (void) strtok(buf, "\n");
+ if ((*buf != 0) && (buf[strlen(buf)-1] == '\\')) {
+ /*
+ * Continuation. This isn't quite right,
+ * as it doesn't allow for a "\" at the
+ * end of line (no escaping).
+ */
+ buf[strlen(buf)-1] = 0;
+ (void) strlcat(line, buf, sizeof (line));
+ continue;
+ }
+ (void) strlcat(line, buf, sizeof (line));
+ }
+
+ /* got a line */
+ ptr = line;
+ test_trim(&ptr);
+
+ /* skip comments and empty lines */
+ if (ptr[0] == 0 || ptr[0] == '#') {
+ line[0] = 0;
+ continue;
+ }
+
+ tok = strsep(&ptr, "|");
+ if (tok == NULL) {
+ break;
+ }
+ test_trim(&tok);
+
+ for (nfields = 0; nfields < MAXFIELD; nfields++) {
+ fields[nfields] = strsep(&ptr, "|");
+ if (fields[nfields] == NULL) {
+ break;
+ }
+ test_trim(&fields[nfields]);
+ }
+
+ found = 0;
+ rv = 0;
+
+ for (int i = 0; keyws[i] != NULL; i++) {
+ if (strcmp(tok, keyws[i]) == 0) {
+ found++;
+ err = NULL;
+ rv = callbs[i](fields, nfields, &err);
+ }
+ }
+ if (!found) {
+ rv = -1;
+ err = NULL;
+ (void) asprintf(&err, "unknown keyword %s", tok);
+ }
+ if (rv != 0) {
+ if (err) {
+ test_failed(t, "%s:%d: %s", fname,
+ lineno, err);
+ free(err);
+ } else {
+ test_failed(t, "%s:%d: unknown error",
+ fname, lineno);
+ }
+ (void) fclose(cfg);
+ return (rv);
+ }
+
+ line[0] = 0;
+ }
+ (void) fclose(cfg);
+ return (0);
}