1 /*-------------------------------------------------------------------------
3 * pg_regress --- regression test driver
5 * This is a C implementation of the previous shell script for running
6 * the regression tests, and should be mostly compatible with it.
7 * Initial author of C translation: Magnus Hagander
9 * This code is released under the terms of the PostgreSQL License.
11 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
14 * $PostgreSQL: pgsql/src/test/regress/pg_regress.c,v 1.15 2006/07/25 03:51:22 tgl Exp $
16 *-------------------------------------------------------------------------
19 #include "postgres_fe.h"
27 #include "getopt_long.h"
28 #include "pg_config_paths.h"
31 #define PID_TYPE pid_t
32 #define INVALID_PID (-1)
34 #define PID_TYPE HANDLE
35 #define INVALID_PID INVALID_HANDLE_VALUE
39 /* simple list of strings */
40 typedef struct _stringlist
43 struct _stringlist *next;
46 /* for resultmap we need a list of pairs of strings */
47 typedef struct _resultmap
51 struct _resultmap *next;
55 * Values obtained from pg_config_paths.h and Makefile. The PG installation
56 * paths are only used in temp_install mode: we use these strings to find
57 * out where "make install" will put stuff under the temp_install directory.
58 * In non-temp_install mode, the only thing we need is the location of psql,
59 * which we expect to find in psqldir, or in the PATH if psqldir isn't given.
61 static char *bindir = PGBINDIR;
62 static char *libdir = LIBDIR;
63 static char *datadir = PGSHAREDIR;
64 static char *host_platform = HOST_TUPLE;
65 static char *makeprog = MAKEPROG;
66 #ifndef WIN32 /* not used in WIN32 case */
67 static char *shellprog = SHELLPROG;
70 /* currently we can use the same diff switches on all platforms */
71 static const char *basic_diff_opts = "-w";
72 static const char *pretty_diff_opts = "-w -C3";
74 /* options settable from command line */
75 static char *dbname = "regression";
76 static bool debug = false;
77 static char *inputdir = ".";
78 static char *outputdir = ".";
79 static _stringlist *loadlanguage = NULL;
80 static int max_connections = 0;
81 static char *encoding = NULL;
82 static _stringlist *schedulelist = NULL;
83 static _stringlist *extra_tests = NULL;
84 static char *temp_install = NULL;
85 static char *top_builddir = NULL;
86 static int temp_port = 65432;
87 static bool nolocale = false;
88 static char *psqldir = NULL;
89 static char *hostname = NULL;
91 static char *user = NULL;
93 /* internal variables */
94 static const char *progname;
95 static char *logfilename;
97 static char *difffilename;
99 static _resultmap *resultmap = NULL;
101 static PID_TYPE postmaster_pid = INVALID_PID;
102 static bool postmaster_running = false;
104 static int success_count = 0;
105 static int fail_count = 0;
106 static int fail_ignore_count = 0;
109 header(const char *fmt,...)
110 /* This extension allows gcc to check the format string for consistency with
111 the supplied arguments. */
112 __attribute__((format(printf, 1, 2)));
114 status(const char *fmt,...)
115 /* This extension allows gcc to check the format string for consistency with
116 the supplied arguments. */
117 __attribute__((format(printf, 1, 2)));
119 psql_command(const char *database, const char *query, ...)
120 /* This extension allows gcc to check the format string for consistency with
121 the supplied arguments. */
122 __attribute__((format(printf, 2, 3)));
126 * Add an item at the end of a stringlist.
129 add_stringlist_item(_stringlist **listhead, const char *str)
131 _stringlist *newentry = malloc(sizeof(_stringlist));
132 _stringlist *oldentry;
134 newentry->str = strdup(str);
135 newentry->next = NULL;
136 if (*listhead == NULL)
137 *listhead = newentry;
140 for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
142 oldentry->next = newentry;
147 * Print a progress banner on stdout.
150 header(const char *fmt,...)
156 vsnprintf(tmp, sizeof(tmp), fmt, ap);
159 fprintf(stdout, "============== %-38s ==============\n", tmp);
164 * Print "doing something ..." --- supplied text should not end with newline
167 status(const char *fmt,...)
172 vfprintf(stdout, fmt, ap);
179 vfprintf(logfile, fmt, ap);
185 * Done "doing something ..."
190 fprintf(stdout, "\n");
193 fprintf(logfile, "\n");
197 * shut down temp postmaster
200 stop_postmaster(void)
202 if (postmaster_running)
204 /* We use pg_ctl to issue the kill and wait for stop */
205 char buf[MAXPGPATH * 2];
207 /* On Windows, system() seems not to force fflush, so... */
211 snprintf(buf, sizeof(buf),
212 SYSTEMQUOTE "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast" SYSTEMQUOTE,
213 bindir, temp_install);
214 system(buf); /* ignore exit status */
215 postmaster_running = false;
220 * Always exit through here, not through plain exit(), to ensure we make
221 * an effort to shut down a temp postmaster
224 exit_nicely(int code)
231 * Check whether string matches pattern
233 * In the original shell script, this function was implemented using expr(1),
234 * which provides basic regular expressions restricted to match starting at
235 * the string start (in conventional regex terms, there's an implicit "^"
236 * at the start of the pattern --- but no implicit "$" at the end).
238 * For now, we only support "." and ".*" as non-literal metacharacters,
239 * because that's all that anyone has found use for in resultmap. This
240 * code could be extended if more functionality is needed.
243 string_matches_pattern(const char *str, const char *pattern)
245 while (*str && *pattern)
247 if (*pattern == '.' && pattern[1] == '*')
250 /* Trailing .* matches everything. */
251 if (*pattern == '\0')
255 * Otherwise, scan for a text position at which we can match the
256 * rest of the pattern.
261 * Optimization to prevent most recursion: don't recurse
262 * unless first pattern char might match this text char.
264 if (*str == *pattern || *pattern == '.')
266 if (string_matches_pattern(str, pattern))
274 * End of text with no match.
278 else if (*pattern != '.' && *str != *pattern)
281 * Not the single-character wildcard and no explicit match? Then
291 if (*pattern == '\0')
292 return true; /* end of pattern, so declare match */
294 /* End of input string. Do we have matching pattern remaining? */
295 while (*pattern == '.' && pattern[1] == '*')
297 if (*pattern == '\0')
298 return true; /* end of pattern, so declare match */
304 * Scan resultmap file to find which platform-specific expected files to use.
306 * The format of each line of the file is
307 * testname/hostplatformpattern=substitutefile
308 * where the hostplatformpattern is evaluated per the rules of expr(1),
309 * namely, it is a standard regular expression with an implicit ^ at the start.
310 * (We currently support only a very limited subset of regular expressions,
311 * see string_matches_pattern() above.) What hostplatformpattern will be
312 * matched against is the config.guess output. (In the shell-script version,
313 * we also provided an indication of whether gcc or another compiler was in
314 * use, but that facility isn't used anymore.)
322 /* scan the file ... */
323 snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
327 /* OK if it doesn't exist, else complain */
330 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
331 progname, buf, strerror(errno));
335 while (fgets(buf, sizeof(buf), f))
341 /* strip trailing whitespace, especially the newline */
343 while (i > 0 && isspace((unsigned char) buf[i-1]))
346 /* parse out the line fields */
347 platform = strchr(buf, '/');
350 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
355 expected = strchr(platform, '=');
358 fprintf(stderr, _("incorrectly formatted resultmap entry: %s\n"),
365 * if it's for current platform, save it in resultmap list.
366 * Note: by adding at the front of the list, we ensure that in
367 * ambiguous cases, the last match in the resultmap file is used.
368 * This mimics the behavior of the old shell script.
370 if (string_matches_pattern(host_platform, platform))
372 _resultmap *entry = malloc(sizeof(_resultmap));
374 entry->test = strdup(buf);
375 entry->resultfile = strdup(expected);
376 entry->next = resultmap;
384 * Handy subroutine for setting an environment variable "var" to "val"
387 doputenv(const char *var, const char *val)
389 char *s = malloc(strlen(var)+strlen(val)+2);
391 sprintf(s, "%s=%s", var, val);
396 * Set the environment variable "pathname", prepending "addval" to its
397 * old value (if any).
400 add_to_path(const char *pathname, char separator, const char *addval)
402 char *oldval = getenv(pathname);
405 if (!oldval || !oldval[0])
407 /* no previous value */
408 newval = malloc(strlen(pathname) + strlen(addval) + 2);
409 sprintf(newval, "%s=%s", pathname, addval);
413 newval = malloc(strlen(pathname) + strlen(addval) + strlen(oldval) + 3);
414 sprintf(newval,"%s=%s%c%s",pathname,addval,separator,oldval);
420 * Prepare environment variables for running regression tests
423 initialize_environment(void)
428 * Clear out any non-C locale settings
430 unsetenv("LC_COLLATE");
431 unsetenv("LC_CTYPE");
432 unsetenv("LC_MONETARY");
433 unsetenv("LC_MESSAGES");
434 unsetenv("LC_NUMERIC");
438 unsetenv("LANGUAGE");
439 /* On Windows the default locale may not be English, so force it */
440 #if defined(WIN32) || defined(__CYGWIN__)
445 * Set multibyte as requested
448 doputenv("PGCLIENTENCODING", encoding);
450 unsetenv("PGCLIENTENCODING");
453 * Set timezone and datestyle for datetime-related tests
455 putenv("PGTZ=PST8PDT");
456 putenv("PGDATESTYLE=Postgres, MDY");
461 * Clear out any environment vars that might cause psql to connect
462 * to the wrong postmaster, or otherwise behave in nondefault ways.
463 * (Note we also use psql's -X switch consistently, so that ~/.psqlrc
464 * files won't mess things up.) Also, set PGPORT to the temp port,
465 * and set or unset PGHOST depending on whether we are using TCP or
468 unsetenv("PGDATABASE");
470 unsetenv("PGSERVICE");
471 unsetenv("PGSSLMODE");
472 unsetenv("PGREQUIRESSL");
473 unsetenv("PGCONNECT_TIMEOUT");
475 if (hostname != NULL)
476 doputenv("PGHOST", hostname);
479 unsetenv("PGHOSTADDR");
484 sprintf(s,"%d",port);
485 doputenv("PGPORT",s);
489 * Adjust path variables to point into the temp-install tree
491 tmp = malloc(strlen(temp_install) + 32 + strlen(bindir));
492 sprintf(tmp, "%s/install/%s", temp_install, bindir);
495 tmp = malloc(strlen(temp_install) + 32 + strlen(libdir));
496 sprintf(tmp, "%s/install/%s", temp_install, libdir);
499 tmp = malloc(strlen(temp_install) + 32 + strlen(datadir));
500 sprintf(tmp, "%s/install/%s", temp_install, datadir);
503 /* psql will be installed into temp-install bindir */
507 * Set up shared library paths to include the temp install.
509 * LD_LIBRARY_PATH covers many platforms. DYLD_LIBRARY_PATH works on
510 * Darwin, and maybe other Mach-based systems. Windows needs shared
511 * libraries in PATH. (Only those linked into executables, not
512 * dlopen'ed ones) Feel free to account for others as well.
514 add_to_path("LD_LIBRARY_PATH", ':', libdir);
515 add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
516 #if defined(WIN32) || defined(__CYGWIN__)
517 add_to_path("PATH", ';', libdir);
526 * When testing an existing install, we honor existing environment
527 * variables, except if they're overridden by command line options.
529 if (hostname != NULL)
531 doputenv("PGHOST", hostname);
532 unsetenv("PGHOSTADDR");
538 sprintf(s,"%d",port);
539 doputenv("PGPORT",s);
542 doputenv("PGUSER", user);
545 * Report what we're connecting to
547 pghost = getenv("PGHOST");
548 pgport = getenv("PGPORT");
549 #ifndef HAVE_UNIX_SOCKETS
551 pghost = "localhost";
554 if (pghost && pgport)
555 printf(_("(using postmaster on %s, port %s)\n"), pghost, pgport);
556 if (pghost && !pgport)
557 printf(_("(using postmaster on %s, default port)\n"), pghost);
558 if (!pghost && pgport)
559 printf(_("(using postmaster on Unix socket, port %s)\n"), pgport);
560 if (!pghost && !pgport)
561 printf(_("(using postmaster on Unix socket, default port)\n"));
568 * Issue a command via psql, connecting to the specified database
570 * Since we use system(), this doesn't return until the operation finishes
573 psql_command(const char *database, const char *query, ...)
575 char query_formatted[1024];
576 char query_escaped[2048];
577 char psql_cmd[MAXPGPATH + 2048];
582 /* Generate the query with insertion of sprintf arguments */
583 va_start(args, query);
584 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
587 /* Now escape any shell double-quote metacharacters */
589 for (s = query_formatted; *s; s++)
591 if (strchr("\\\"$`", *s))
597 /* And now we can build and execute the shell command */
598 snprintf(psql_cmd, sizeof(psql_cmd),
599 SYSTEMQUOTE "\"%s%spsql\" -X -c \"%s\" \"%s\"" SYSTEMQUOTE,
600 psqldir ? psqldir : "",
605 if (system(psql_cmd) != 0)
607 /* psql probably already reported the error */
608 fprintf(stderr, _("command failed: %s\n"), psql_cmd);
614 * Spawn a process to execute the given shell command; don't wait for it
616 * Returns the process ID so we can wait for it later
619 spawn_process(const char *cmdline)
625 * Must flush I/O buffers before fork. Ideally we'd use fflush(NULL) here
626 * ... does anyone still care about systems where that doesn't work?
636 fprintf(stderr, _("%s: could not fork: %s\n"),
637 progname, strerror(errno));
645 * Instead of using system(), exec the shell directly, and tell it
646 * to "exec" the command too. This saves two useless processes
647 * per parallel test case.
649 char *cmdline2 = malloc(strlen(cmdline) + 6);
651 sprintf(cmdline2, "exec %s", cmdline);
652 execl(shellprog, shellprog, "-c", cmdline2, NULL);
653 fprintf(stderr, _("%s: could not exec \"%s\": %s\n"),
654 progname, shellprog, strerror(errno));
655 exit(1); /* not exit_nicely here... */
662 PROCESS_INFORMATION pi;
664 ZeroMemory(&si, sizeof(si));
667 cmdline2 = malloc(strlen(cmdline) + 8);
668 sprintf(cmdline2, "cmd /c %s", cmdline);
670 if (!CreateProcess(NULL, cmdline2, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
672 fprintf(stderr, _("could not start process for \"%s\": %lu\n"),
673 cmdline2, GetLastError());
678 CloseHandle(pi.hThread);
684 * start a psql test process for specified file (including redirection),
685 * and return process ID
688 psql_start_test(const char *testname)
691 char infile[MAXPGPATH];
692 char outfile[MAXPGPATH];
693 char psql_cmd[MAXPGPATH * 3];
695 snprintf(infile, sizeof(infile), "%s/sql/%s.sql",
697 snprintf(outfile, sizeof(outfile), "%s/results/%s.out",
698 outputdir, testname);
700 snprintf(psql_cmd, sizeof(psql_cmd),
701 SYSTEMQUOTE "\"%s%spsql\" -X -a -q -d \"%s\" < \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
702 psqldir ? psqldir : "",
708 pid = spawn_process(psql_cmd);
710 if (pid == INVALID_PID)
712 fprintf(stderr, _("could not start process for test %s\n"),
721 * Count bytes in file
724 file_size(const char *file)
727 FILE *f = fopen(file,"r");
731 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
732 progname, file, strerror(errno));
735 fseek(f, 0, SEEK_END);
742 * Count lines in file
745 file_line_count(const char *file)
749 FILE *f = fopen(file,"r");
753 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
754 progname, file, strerror(errno));
757 while ((c = fgetc(f)) != EOF)
767 file_exists(const char *file)
769 FILE *f = fopen(file, "r");
778 directory_exists(const char *dir)
782 if (stat(dir, &st) != 0)
784 if (st.st_mode & S_IFDIR)
789 /* Create a directory */
791 make_directory(const char *dir)
793 if (mkdir(dir, S_IRWXU) < 0)
795 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
796 progname, dir, strerror(errno));
802 * Run a "diff" command and check that it didn't crash
805 run_diff(const char *cmd)
811 * XXX FIXME: it appears that include/port/win32.h's definitions of
812 * WIFEXITED and related macros may be wrong. They certainly don't
813 * work for inspecting the results of system(). For the moment,
814 * hard-wire the check on Windows.
817 if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
819 if (r != 0 && r != 1)
822 fprintf(stderr, _("diff command failed with status %d: %s\n"), r, cmd);
828 * Check the actual result file for the given test against expected results
830 * Returns true if different (failure), false if correct match found.
831 * In the true case, the diff is appended to the diffs file.
834 results_differ(const char *testname)
836 const char *expectname;
837 char resultsfile[MAXPGPATH];
838 char expectfile[MAXPGPATH];
839 char diff[MAXPGPATH];
840 char cmd[MAXPGPATH * 3];
841 char best_expect_file[MAXPGPATH];
848 /* Check in resultmap if we should be looking at a different file */
849 expectname = testname;
850 for (rm = resultmap; rm != NULL; rm = rm->next)
852 if (strcmp(testname, rm->test) == 0)
854 expectname = rm->resultfile;
859 /* Name of test results file */
860 snprintf(resultsfile, sizeof(resultsfile), "%s/results/%s.out",
861 outputdir, testname);
863 /* Name of expected-results file */
864 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s.out",
865 inputdir, expectname);
867 /* Name to use for temporary diff file */
868 snprintf(diff, sizeof(diff), "%s/results/%s.diff",
869 outputdir, testname);
871 /* OK, run the diff */
872 snprintf(cmd, sizeof(cmd),
873 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
874 basic_diff_opts, expectfile, resultsfile, diff);
877 /* Is the diff file empty? */
878 if (file_size(diff) == 0)
880 /* No diff = no changes = good */
885 /* There may be secondary comparison files that match better */
886 best_line_count = file_line_count(diff);
887 strcpy(best_expect_file, expectfile);
889 for (i = 0; i <= 9; i++)
891 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s_%d.out",
892 inputdir, expectname, i);
893 if (!file_exists(expectfile))
896 snprintf(cmd, sizeof(cmd),
897 SYSTEMQUOTE "diff %s \"%s\" \"%s\" > \"%s\"" SYSTEMQUOTE,
898 basic_diff_opts, expectfile, resultsfile, diff);
901 if (file_size(diff) == 0)
903 /* No diff = no changes = good */
908 l = file_line_count(diff);
909 if (l < best_line_count)
911 /* This diff was a better match than the last one */
913 strcpy(best_expect_file, expectfile);
918 * Use the best comparison file to generate the "pretty" diff, which
919 * we append to the diffs summary file.
921 snprintf(cmd, sizeof(cmd),
922 SYSTEMQUOTE "diff %s \"%s\" \"%s\" >> \"%s\"" SYSTEMQUOTE,
923 pretty_diff_opts, best_expect_file, resultsfile, difffilename);
926 /* And append a separator */
927 difffile = fopen(difffilename, "a");
931 "\n======================================================================\n\n");
940 * Wait for specified subprocesses to finish
942 * If names isn't NULL, report each subprocess as it finishes
944 * Note: it's OK to scribble on the pids array, but not on the names array
947 wait_for_tests(PID_TYPE *pids, char **names, int num_tests)
953 PID_TYPE *active_pids = malloc(num_tests * sizeof(PID_TYPE));
955 memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
958 tests_left = num_tests;
959 while (tests_left > 0)
966 if (p == INVALID_PID)
968 fprintf(stderr, _("failed to wait for subprocesses: %s\n"),
975 r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
976 if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
978 fprintf(stderr, _("failed to wait for subprocesses: %lu\n"),
982 p = active_pids[r - WAIT_OBJECT_0];
983 /* compact the active_pids array */
984 active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
987 for (i=0; i < num_tests; i++)
992 CloseHandle(pids[i]);
994 pids[i] = INVALID_PID;
996 status(" %s", names[i]);
1009 * Run all the tests specified in one schedule file
1012 run_schedule(const char *schedule)
1014 #define MAX_PARALLEL_TESTS 100
1015 char *tests[MAX_PARALLEL_TESTS];
1016 PID_TYPE pids[MAX_PARALLEL_TESTS];
1017 _stringlist *ignorelist = NULL;
1022 scf = fopen(schedule, "r");
1025 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1026 progname, schedule, strerror(errno));
1030 while (fgets(scbuf, sizeof(scbuf), scf))
1040 /* strip trailing whitespace, especially the newline */
1042 while (i > 0 && isspace((unsigned char) scbuf[i-1]))
1045 if (scbuf[0] == '\0' || scbuf[0] == '#')
1047 if (strncmp(scbuf, "test: ", 6) == 0)
1049 else if (strncmp(scbuf, "ignore: ", 8) == 0)
1052 while (*c && isspace((unsigned char) *c))
1054 add_stringlist_item(&ignorelist, c);
1056 * Note: ignore: lines do not run the test, they just say that
1057 * failure of this test when run later on is to be ignored.
1058 * A bit odd but that's how the shell-script version did it.
1064 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1065 schedule, line_num, scbuf);
1071 for (c = test; *c; c++)
1073 if (isspace((unsigned char) *c))
1080 if (num_tests >= MAX_PARALLEL_TESTS)
1082 /* can't print scbuf here, it's already been trashed */
1083 fprintf(stderr, _("too many parallel tests in schedule file \"%s\", line %d\n"),
1084 schedule, line_num);
1087 tests[num_tests] = c;
1095 fprintf(stderr, _("syntax error in schedule file \"%s\" line %d: %s\n"),
1096 schedule, line_num, scbuf);
1102 status(_("test %-20s ... "), tests[0]);
1103 pids[0] = psql_start_test(tests[0]);
1104 wait_for_tests(pids, NULL, 1);
1105 /* status line is finished below */
1107 else if (max_connections > 0 && max_connections < num_tests)
1111 status(_("parallel group (%d tests, in groups of %d): "),
1112 num_tests, max_connections);
1113 for (i = 0; i < num_tests; i++)
1115 if (i - oldest >= max_connections)
1117 wait_for_tests(pids + oldest, tests + oldest, i - oldest);
1120 pids[i] = psql_start_test(tests[i]);
1122 wait_for_tests(pids + oldest, tests + oldest, i - oldest);
1127 status(_("parallel group (%d tests): "), num_tests);
1128 for (i = 0; i < num_tests; i++)
1130 pids[i] = psql_start_test(tests[i]);
1132 wait_for_tests(pids, tests, num_tests);
1136 /* Check results for all tests */
1137 for (i = 0; i < num_tests; i++)
1140 status(_(" %-20s ... "), tests[i]);
1142 if (results_differ(tests[i]))
1144 bool ignore = false;
1147 for (sl = ignorelist; sl != NULL; sl = sl->next)
1149 if (strcmp(tests[i], sl->str) == 0)
1157 status(_("failed (ignored)"));
1158 fail_ignore_count++;
1162 status(_("FAILED"));
1183 run_single_test(const char *test)
1187 status(_("test %-20s ... "), test);
1188 pid = psql_start_test(test);
1189 wait_for_tests(&pid, NULL, 1);
1191 if (results_differ(test))
1193 status(_("FAILED"));
1205 * Create the summary-output files (making them empty if already existing)
1208 open_result_files(void)
1210 char file[MAXPGPATH];
1213 /* create the log file (copy of running status output) */
1214 snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1215 logfilename = strdup(file);
1216 logfile = fopen(logfilename, "w");
1219 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1220 progname, logfilename, strerror(errno));
1224 /* create the diffs file as empty */
1225 snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
1226 difffilename = strdup(file);
1227 difffile = fopen(difffilename, "w");
1230 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1231 progname, difffilename, strerror(errno));
1234 /* we don't keep the diffs file open continuously */
1237 /* also create the output directory if not present */
1238 snprintf(file, sizeof(file), "%s/results", outputdir);
1239 if (!directory_exists(file))
1240 make_directory(file);
1246 printf(_("PostgreSQL regression test driver\n"));
1248 printf(_("Usage: %s [options...] [extra tests...]\n"), progname);
1250 printf(_("Options:\n"));
1251 printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
1252 printf(_(" --debug turn on debug mode in programs that are run\n"));
1253 printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
1254 printf(_(" --load-language=lang load the named language before running the\n"));
1255 printf(_(" tests; can appear multiple times\n"));
1256 printf(_(" --max-connections=N maximum number of concurrent connections\n"));
1257 printf(_(" (default is 0 meaning unlimited)\n"));
1258 printf(_(" --multibyte=ENCODING use ENCODING as the multibyte encoding\n"));
1259 printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
1260 printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
1261 printf(_(" (may be used multiple times to concatenate)\n"));
1262 printf(_(" --temp-install=DIR create a temporary installation in DIR\n"));
1263 printf(_(" --no-locale use C locale\n"));
1265 printf(_("Options for \"temp-install\" mode:\n"));
1266 printf(_(" --top-builddir=DIR (relative) path to top level build directory\n"));
1267 printf(_(" --temp-port=PORT port number to start temp postmaster on\n"));
1269 printf(_("Options for using an existing installation:\n"));
1270 printf(_(" --host=HOST use postmaster running on HOST\n"));
1271 printf(_(" --port=PORT use postmaster running at PORT\n"));
1272 printf(_(" --user=USER connect as USER\n"));
1273 printf(_(" --psqldir=DIR use psql in DIR (default: find in PATH)\n"));
1275 printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
1276 printf(_("if the tests could not be run for some reason.\n"));
1278 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1282 main(int argc, char *argv[])
1288 char buf[MAXPGPATH * 4];
1290 static struct option long_options[] = {
1291 {"help", no_argument, NULL, 'h'},
1292 {"version", no_argument, NULL, 'V'},
1293 {"dbname", required_argument, NULL, 1},
1294 {"debug", no_argument, NULL, 2},
1295 {"inputdir", required_argument, NULL, 3},
1296 {"load-language", required_argument, NULL, 4},
1297 {"max-connections", required_argument, NULL, 5},
1298 {"multibyte", required_argument, NULL, 6},
1299 {"outputdir", required_argument, NULL, 7},
1300 {"schedule", required_argument, NULL, 8},
1301 {"temp-install", required_argument, NULL, 9},
1302 {"no-locale", no_argument, NULL, 10},
1303 {"top-builddir", required_argument, NULL, 11},
1304 {"temp-port", required_argument, NULL, 12},
1305 {"host", required_argument, NULL, 13},
1306 {"port", required_argument, NULL, 14},
1307 {"user", required_argument, NULL, 15},
1308 {"psqldir", required_argument, NULL, 16},
1312 progname = get_progname(argv[0]);
1313 set_pglocale_pgservice(argv[0], "pg_regress");
1315 #ifndef HAVE_UNIX_SOCKETS
1316 /* no unix domain sockets available, so change default */
1317 hostname = "localhost";
1320 while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
1328 printf("pg_regress (PostgreSQL %s)\n", PG_VERSION);
1331 dbname = strdup(optarg);
1337 inputdir = strdup(optarg);
1340 add_stringlist_item(&loadlanguage, optarg);
1343 max_connections = atoi(optarg);
1346 encoding = strdup(optarg);
1349 outputdir = strdup(optarg);
1352 add_stringlist_item(&schedulelist, optarg);
1355 /* temp_install must be absolute path */
1356 if (is_absolute_path(optarg))
1357 temp_install = strdup(optarg);
1360 char cwdbuf[MAXPGPATH];
1362 if (!getcwd(cwdbuf, sizeof(cwdbuf)))
1364 fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
1367 temp_install = malloc(strlen(cwdbuf) + strlen(optarg) + 2);
1368 sprintf(temp_install,"%s/%s", cwdbuf, optarg);
1370 canonicalize_path(temp_install);
1376 top_builddir = strdup(optarg);
1380 int p = atoi(optarg);
1382 /* Since Makefile isn't very bright, check port range */
1383 if (p >= 1024 && p <= 65535)
1388 hostname = strdup(optarg);
1391 port = atoi(optarg);
1394 user = strdup(optarg);
1397 /* "--psqldir=" should mean to use PATH */
1399 psqldir = strdup(optarg);
1402 /* getopt_long already emitted a complaint */
1403 fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
1410 * if we still have arguments, they are extra tests to run
1412 while (argc - optind >= 1)
1414 add_stringlist_item(&extra_tests, argv[optind]);
1424 open_result_files();
1426 initialize_environment();
1431 * Prepare the temp installation
1435 fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
1439 if (directory_exists(temp_install))
1441 header(_("removing existing temp installation"));
1442 rmtree(temp_install,true);
1445 header(_("creating temporary installation"));
1447 /* make the temp install top directory */
1448 make_directory(temp_install);
1450 /* and a directory for log files */
1451 snprintf(buf, sizeof(buf), "%s/log", outputdir);
1452 if (!directory_exists(buf))
1453 make_directory(buf);
1455 /* "make install" */
1456 snprintf(buf, sizeof(buf),
1457 SYSTEMQUOTE "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install with_perl=no with_python=no > \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
1458 makeprog, top_builddir, temp_install, outputdir);
1461 fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
1466 header(_("initializing database system"));
1467 snprintf(buf, sizeof(buf),
1468 SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
1469 bindir, temp_install, datadir,
1470 debug ? " --debug" : "",
1471 nolocale ? " --no-locale" : "",
1475 fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
1480 * Start the temp postmaster
1482 header(_("starting postmaster"));
1483 snprintf(buf, sizeof(buf),
1484 SYSTEMQUOTE "\"%s/postmaster\" -D \"%s/data\" -F%s -c \"listen_addresses=%s\" > \"%s/log/postmaster.log\" 2>&1" SYSTEMQUOTE,
1485 bindir, temp_install,
1486 debug ? " -d 5" : "",
1487 hostname ? hostname : "",
1489 postmaster_pid = spawn_process(buf);
1490 if (postmaster_pid == INVALID_PID)
1492 fprintf(stderr, _("\n%s: could not spawn postmaster: %s\n"),
1493 progname, strerror(errno));
1498 * Wait till postmaster is able to accept connections (normally only
1499 * a second or so, but Cygwin is reportedly *much* slower). Don't
1500 * wait forever, however.
1502 snprintf(buf, sizeof(buf),
1503 SYSTEMQUOTE "\"%s/psql\" -X postgres <%s 2>%s" SYSTEMQUOTE,
1504 bindir, DEVNULL, DEVNULL);
1505 for (i = 0; i < 60; i++)
1507 /* Done if psql succeeds */
1508 if (system(buf) == 0)
1512 * Fail immediately if postmaster has exited
1514 * XXX is there a way to do this on Windows?
1517 if (kill(postmaster_pid, 0) != 0)
1519 fprintf(stderr, _("\n%s: postmaster failed\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
1524 pg_usleep(1000000L);
1528 fprintf(stderr, _("\n%s: postmaster did not start within 60 seconds\nExamine %s/log/postmaster.log for the reason\n"), progname, outputdir);
1532 postmaster_running = true;
1534 printf(_("running on port %d with pid %lu\n"),
1535 temp_port, (unsigned long) postmaster_pid);
1540 * Using an existing installation, so may need to get rid of
1541 * pre-existing database.
1543 header(_("dropping database \"%s\""), dbname);
1544 psql_command("postgres","DROP DATABASE IF EXISTS \"%s\"", dbname);
1548 * Create the test database
1550 * We use template0 so that any installation-local cruft in template1
1551 * will not mess up the tests.
1553 header(_("creating database \"%s\""), dbname);
1555 psql_command("postgres",
1556 "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'",
1558 else /* use installation default */
1559 psql_command("postgres",
1560 "CREATE DATABASE \"%s\" TEMPLATE=template0",
1563 psql_command(dbname,
1564 "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
1565 "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
1566 "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
1567 "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
1568 "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1569 dbname, dbname, dbname, dbname, dbname);
1572 * Install any requested PL languages
1574 for (sl = loadlanguage; sl != NULL; sl = sl->next)
1576 header(_("installing %s"), sl->str);
1577 psql_command(dbname, "CREATE LANGUAGE \"%s\"", sl->str);
1581 * Ready to run the tests
1583 header(_("running regression test queries"));
1585 for (sl = schedulelist; sl != NULL; sl = sl->next)
1587 run_schedule(sl->str);
1590 for (sl = extra_tests; sl != NULL; sl = sl->next)
1592 run_single_test(sl->str);
1596 * Shut down temp installation's postmaster
1600 header(_("shutting down postmaster"));
1607 * Emit nice-looking summary message
1609 if (fail_count == 0 && fail_ignore_count == 0)
1610 snprintf(buf, sizeof(buf),
1611 _(" All %d tests passed. "),
1613 else if (fail_count == 0) /* fail_count=0, fail_ignore_count>0 */
1614 snprintf(buf, sizeof(buf),
1615 _(" %d of %d tests passed, %d failed test(s) ignored. "),
1617 success_count + fail_ignore_count,
1619 else if (fail_ignore_count == 0) /* fail_count>0 && fail_ignore_count=0 */
1620 snprintf(buf, sizeof(buf),
1621 _(" %d of %d tests failed. "),
1623 success_count+fail_count);
1624 else /* fail_count>0 && fail_ignore_count>0 */
1625 snprintf(buf, sizeof(buf),
1626 _(" %d of %d tests failed, %d of these failures ignored. "),
1627 fail_count+fail_ignore_count,
1628 success_count + fail_count+fail_ignore_count,
1632 for (i = strlen(buf); i > 0; i--)
1634 printf("\n%s\n", buf);
1635 for (i = strlen(buf); i > 0; i--)
1640 if (file_size(difffilename) > 0)
1642 printf(_("The differences that caused some tests to fail can be viewed in the\n"
1643 "file \"%s\". A copy of the test summary that you see\n"
1644 "above is saved in the file \"%s\".\n\n"),
1645 difffilename, logfilename);
1649 unlink(difffilename);
1650 unlink(logfilename);
1653 if (fail_count != 0)