Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_regress --- regression test driver
4 : *
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
8 : *
9 : * This code is released under the terms of the PostgreSQL License.
10 : *
11 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
12 : * Portions Copyright (c) 1994, Regents of the University of California
13 : *
14 : * src/test/regress/pg_regress.c
15 : *
16 : *-------------------------------------------------------------------------
17 : */
18 :
19 : #include "postgres_fe.h"
20 :
21 : #include <ctype.h>
22 : #include <sys/resource.h>
23 : #include <sys/stat.h>
24 : #include <sys/time.h>
25 : #include <sys/wait.h>
26 : #include <signal.h>
27 : #include <unistd.h>
28 :
29 : #include "common/logging.h"
30 : #include "common/restricted_token.h"
31 : #include "common/username.h"
32 : #include "getopt_long.h"
33 : #include "lib/stringinfo.h"
34 : #include "libpq-fe.h"
35 : #include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
36 : #include "pg_config_paths.h"
37 : #include "pg_regress.h"
38 : #include "portability/instr_time.h"
39 :
40 : /* for resultmap we need a list of pairs of strings */
41 : typedef struct _resultmap
42 : {
43 : char *test;
44 : char *type;
45 : char *resultfile;
46 : struct _resultmap *next;
47 : } _resultmap;
48 :
49 : /*
50 : * Values obtained from Makefile.
51 : */
52 : char *host_platform = HOST_TUPLE;
53 :
54 : #ifndef WIN32 /* not used in WIN32 case */
55 : static char *shellprog = SHELLPROG;
56 : #endif
57 :
58 : /*
59 : * On Windows we use -w in diff switches to avoid problems with inconsistent
60 : * newline representation. The actual result files will generally have
61 : * Windows-style newlines, but the comparison files might or might not.
62 : */
63 : #ifndef WIN32
64 : const char *basic_diff_opts = "";
65 : const char *pretty_diff_opts = "-U3";
66 : #else
67 : const char *basic_diff_opts = "--strip-trailing-cr";
68 : const char *pretty_diff_opts = "--strip-trailing-cr -U3";
69 : #endif
70 :
71 : /*
72 : * The width of the testname field when printing to ensure vertical alignment
73 : * of test runtimes. This number is somewhat arbitrarily chosen to match the
74 : * older pre-TAP output format.
75 : */
76 : #define TESTNAME_WIDTH 36
77 :
78 : /*
79 : * The number times per second that pg_regress checks to see if the test
80 : * instance server has started and is available for connection.
81 : */
82 : #define WAIT_TICKS_PER_SECOND 20
83 :
84 : typedef enum TAPtype
85 : {
86 : DIAG = 0,
87 : DIAG_DETAIL,
88 : DIAG_END,
89 : BAIL,
90 : NOTE,
91 : NOTE_DETAIL,
92 : NOTE_END,
93 : TEST_STATUS,
94 : PLAN,
95 : NONE,
96 : } TAPtype;
97 :
98 : /* options settable from command line */
99 : _stringlist *dblist = NULL;
100 : bool debug = false;
101 : char *inputdir = ".";
102 : char *outputdir = ".";
103 : char *expecteddir = ".";
104 : char *bindir = PGBINDIR;
105 : char *launcher = NULL;
106 : static _stringlist *loadextension = NULL;
107 : static int max_connections = 0;
108 : static int max_concurrent_tests = 0;
109 : static char *encoding = NULL;
110 : static _stringlist *schedulelist = NULL;
111 : static _stringlist *extra_tests = NULL;
112 : static char *temp_instance = NULL;
113 : static _stringlist *temp_configs = NULL;
114 : static bool nolocale = false;
115 : static bool use_existing = false;
116 : static char *hostname = NULL;
117 : static int port = -1;
118 : static char portstr[16];
119 : static bool port_specified_by_user = false;
120 : static char *dlpath = PKGLIBDIR;
121 : static char *user = NULL;
122 : static _stringlist *extraroles = NULL;
123 : static char *config_auth_datadir = NULL;
124 :
125 : /* internal variables */
126 : static const char *progname;
127 : static char *logfilename;
128 : static FILE *logfile;
129 : static char *difffilename;
130 : static const char *sockdir;
131 : static const char *temp_sockdir;
132 : static char sockself[MAXPGPATH];
133 : static char socklock[MAXPGPATH];
134 : static StringInfo failed_tests = NULL;
135 : static bool in_note = false;
136 : static bool in_diag = false;
137 :
138 : static _resultmap *resultmap = NULL;
139 :
140 : static PID_TYPE postmaster_pid = INVALID_PID;
141 : static bool postmaster_running = false;
142 :
143 : static int success_count = 0;
144 : static int fail_count = 0;
145 :
146 : static bool directory_exists(const char *dir);
147 : static void make_directory(const char *dir);
148 :
149 : static void test_status_print(bool ok, const char *testname, double runtime, bool parallel);
150 : static void test_status_ok(const char *testname, double runtime, bool parallel);
151 : static void test_status_failed(const char *testname, double runtime, bool parallel);
152 : static void bail_out(bool noatexit, const char *fmt,...) pg_attribute_printf(2, 3);
153 : static void emit_tap_output(TAPtype type, const char *fmt,...) pg_attribute_printf(2, 3);
154 : static void emit_tap_output_v(TAPtype type, const char *fmt, va_list argp) pg_attribute_printf(2, 0);
155 :
156 : static StringInfo psql_start_command(void);
157 : static void psql_add_command(StringInfo buf, const char *query,...) pg_attribute_printf(2, 3);
158 : static void psql_end_command(StringInfo buf, const char *database);
159 :
160 : /*
161 : * Convenience macros for printing TAP output with a more shorthand syntax
162 : * aimed at making the code more readable.
163 : */
164 : #define plan(x) emit_tap_output(PLAN, "1..%i", (x))
165 : #define note(...) emit_tap_output(NOTE, __VA_ARGS__)
166 : #define note_detail(...) emit_tap_output(NOTE_DETAIL, __VA_ARGS__)
167 : #define diag(...) emit_tap_output(DIAG, __VA_ARGS__)
168 : #define diag_detail(...) emit_tap_output(DIAG_DETAIL, __VA_ARGS__)
169 : #define diag_end() emit_tap_output(DIAG_END, "\n");
170 : #define note_end() emit_tap_output(NOTE_END, "\n");
171 : #define bail_noatexit(...) bail_out(true, __VA_ARGS__)
172 : #define bail(...) bail_out(false, __VA_ARGS__)
173 :
174 : /*
175 : * allow core files if possible.
176 : */
177 : #if defined(HAVE_GETRLIMIT)
178 : static void
179 106 : unlimit_core_size(void)
180 : {
181 : struct rlimit lim;
182 :
183 106 : getrlimit(RLIMIT_CORE, &lim);
184 106 : if (lim.rlim_max == 0)
185 : {
186 0 : diag("could not set core size: disallowed by hard limit");
187 0 : return;
188 : }
189 106 : else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
190 : {
191 106 : lim.rlim_cur = lim.rlim_max;
192 106 : setrlimit(RLIMIT_CORE, &lim);
193 : }
194 : }
195 : #endif
196 :
197 :
198 : /*
199 : * Add an item at the end of a stringlist.
200 : */
201 : void
202 5135 : add_stringlist_item(_stringlist **listhead, const char *str)
203 : {
204 5135 : _stringlist *newentry = pg_malloc_object(_stringlist);
205 : _stringlist *oldentry;
206 :
207 5135 : newentry->str = pg_strdup(str);
208 5135 : newentry->next = NULL;
209 5135 : if (*listhead == NULL)
210 4066 : *listhead = newentry;
211 : else
212 : {
213 3644 : for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
214 : /* skip */ ;
215 1069 : oldentry->next = newentry;
216 : }
217 5135 : }
218 :
219 : /*
220 : * Free a stringlist.
221 : */
222 : static void
223 4619 : free_stringlist(_stringlist **listhead)
224 : {
225 4619 : if (listhead == NULL || *listhead == NULL)
226 1118 : return;
227 3501 : if ((*listhead)->next != NULL)
228 780 : free_stringlist(&((*listhead)->next));
229 3501 : free((*listhead)->str);
230 3501 : free(*listhead);
231 3501 : *listhead = NULL;
232 : }
233 :
234 : /*
235 : * Split a delimited string into a stringlist
236 : */
237 : static void
238 134 : split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
239 : {
240 : char *token;
241 : char *sc;
242 : char *tofree;
243 :
244 134 : tofree = sc = pg_strdup(s);
245 :
246 277 : while ((token = strsep(&sc, delim)))
247 : {
248 143 : add_stringlist_item(listhead, token);
249 : }
250 134 : free(tofree);
251 134 : }
252 :
253 : /*
254 : * Bailing out is for unrecoverable errors which prevents further testing to
255 : * occur and after which the test run should be aborted. By passing noatexit
256 : * as true the process will terminate with _exit(2) and skipping registered
257 : * exit handlers, thus avoid any risk of bottomless recursion calls to exit.
258 : */
259 : static void
260 0 : bail_out(bool noatexit, const char *fmt,...)
261 : {
262 : va_list ap;
263 :
264 0 : va_start(ap, fmt);
265 0 : emit_tap_output_v(BAIL, fmt, ap);
266 0 : va_end(ap);
267 :
268 0 : if (noatexit)
269 0 : _exit(2);
270 :
271 0 : exit(2);
272 : }
273 :
274 : /*
275 : * Print the result of a test run and associated metadata like runtime. Care
276 : * is taken to align testnames and runtimes vertically to ensure the output
277 : * is human readable while still TAP compliant. Tests run in parallel are
278 : * prefixed with a '+' and sequential tests with a '-'. This distinction was
279 : * previously indicated by 'test' prefixing sequential tests while parallel
280 : * tests were indented by four leading spaces. The meson TAP parser consumes
281 : * leading space however, so a non-whitespace prefix of the same length is
282 : * required for both.
283 : */
284 : static void
285 1606 : test_status_print(bool ok, const char *testname, double runtime, bool parallel)
286 : {
287 1606 : int testnumber = fail_count + success_count;
288 :
289 : /*
290 : * Testnumbers are padded to 5 characters to ensure that testnames align
291 : * vertically (assuming at most 9999 tests). Testnames are prefixed with
292 : * a leading character to indicate being run in parallel or not. A leading
293 : * '+' indicates a parallel test, '-' indicates a single test.
294 : */
295 1606 : emit_tap_output(TEST_STATUS, "%sok %-5i%*s %c %-*s %8.0f ms",
296 : (ok ? "" : "not "),
297 : testnumber,
298 : /* If ok, indent with four spaces matching "not " */
299 : (ok ? (int) strlen("not ") : 0), "",
300 : /* Prefix a parallel test '+' and a single test with '-' */
301 : (parallel ? '+' : '-'),
302 : /* Testnames are padded to align runtimes */
303 : TESTNAME_WIDTH, testname,
304 : runtime);
305 1606 : }
306 :
307 : static void
308 1606 : test_status_ok(const char *testname, double runtime, bool parallel)
309 : {
310 1606 : success_count++;
311 :
312 1606 : test_status_print(true, testname, runtime, parallel);
313 1606 : }
314 :
315 : static void
316 0 : test_status_failed(const char *testname, double runtime, bool parallel)
317 : {
318 : /*
319 : * Save failed tests in a buffer such that we can print a summary at the
320 : * end with diag() to ensure it's shown even under test harnesses.
321 : */
322 0 : if (!failed_tests)
323 0 : failed_tests = makeStringInfo();
324 : else
325 0 : appendStringInfoChar(failed_tests, ',');
326 :
327 0 : appendStringInfo(failed_tests, " %s", testname);
328 :
329 0 : fail_count++;
330 :
331 0 : test_status_print(false, testname, runtime, parallel);
332 0 : }
333 :
334 :
335 : static void
336 3131 : emit_tap_output(TAPtype type, const char *fmt,...)
337 : {
338 : va_list argp;
339 :
340 3131 : va_start(argp, fmt);
341 3131 : emit_tap_output_v(type, fmt, argp);
342 3131 : va_end(argp);
343 3131 : }
344 :
345 : static void
346 3131 : emit_tap_output_v(TAPtype type, const char *fmt, va_list argp)
347 : {
348 : va_list argp_logfile;
349 : FILE *fp;
350 : int save_errno;
351 :
352 : /*
353 : * The fprintf() calls used to output TAP-protocol elements might clobber
354 : * errno, so save it here and restore it before vfprintf()-ing the user's
355 : * format string, in case it contains %m placeholders.
356 : */
357 3131 : save_errno = errno;
358 :
359 : /*
360 : * Diagnostic output will be hidden by prove unless printed to stderr. The
361 : * Bail message is also printed to stderr to aid debugging under a harness
362 : * which might otherwise not emit such an important message.
363 : */
364 3131 : if (type == DIAG || type == DIAG_DETAIL || type == DIAG_END || type == BAIL)
365 0 : fp = stderr;
366 : else
367 3131 : fp = stdout;
368 :
369 : /*
370 : * If we are ending a note_detail line we can avoid further processing and
371 : * immediately return following a newline.
372 : */
373 3131 : if (type == NOTE_END || type == DIAG_END)
374 : {
375 76 : if (type == NOTE_END)
376 76 : in_note = false;
377 : else
378 0 : in_diag = false;
379 76 : fprintf(fp, "\n");
380 76 : if (logfile)
381 76 : fprintf(logfile, "\n");
382 76 : return;
383 : }
384 :
385 : /* Make a copy of the va args for printing to the logfile */
386 3055 : va_copy(argp_logfile, argp);
387 :
388 : /*
389 : * Non-protocol output such as diagnostics or notes must be prefixed by a
390 : * '#' character. We print the Bail message like this too.
391 : */
392 3055 : if ((type == NOTE || type == DIAG || type == BAIL)
393 2740 : || (type == NOTE_DETAIL && !in_note)
394 2664 : || (type == DIAG_DETAIL && !in_diag))
395 : {
396 391 : fprintf(fp, "# ");
397 391 : if (logfile)
398 391 : fprintf(logfile, "# ");
399 : }
400 3055 : errno = save_errno;
401 3055 : vfprintf(fp, fmt, argp);
402 3055 : if (logfile)
403 : {
404 3055 : errno = save_errno;
405 3055 : vfprintf(logfile, fmt, argp_logfile);
406 : }
407 :
408 : /*
409 : * If we are entering into a note with more details to follow, register
410 : * that the leading '#' has been printed such that subsequent details
411 : * aren't prefixed as well.
412 : */
413 3055 : if (type == NOTE_DETAIL)
414 1028 : in_note = true;
415 3055 : if (type == DIAG_DETAIL)
416 0 : in_diag = true;
417 :
418 : /*
419 : * If this was a Bail message, the bail protocol message must go to stdout
420 : * separately.
421 : */
422 3055 : if (type == BAIL)
423 : {
424 0 : fprintf(stdout, "Bail out!");
425 0 : if (logfile)
426 0 : fprintf(logfile, "Bail out!");
427 : }
428 :
429 3055 : va_end(argp_logfile);
430 :
431 3055 : if (type != NOTE_DETAIL && type != DIAG_DETAIL)
432 : {
433 2027 : fprintf(fp, "\n");
434 2027 : if (logfile)
435 2027 : fprintf(logfile, "\n");
436 : }
437 3055 : fflush(NULL);
438 : }
439 :
440 : /*
441 : * shut down temp postmaster
442 : */
443 : static void
444 570 : stop_postmaster(void)
445 : {
446 570 : if (postmaster_running)
447 : {
448 : /* We use pg_ctl to issue the kill and wait for stop */
449 : char buf[MAXPGPATH * 2];
450 : int r;
451 :
452 206 : snprintf(buf, sizeof(buf),
453 : "\"%s%spg_ctl\" stop -D \"%s/data\" -s",
454 103 : bindir ? bindir : "",
455 103 : bindir ? "/" : "",
456 : temp_instance);
457 103 : fflush(NULL);
458 103 : r = system(buf);
459 103 : if (r != 0)
460 : {
461 : /* Not using the normal bail() as we want _exit */
462 0 : bail_noatexit(_("could not stop postmaster: exit code was %d"), r);
463 : }
464 :
465 103 : postmaster_running = false;
466 : }
467 570 : }
468 :
469 : /*
470 : * Remove the socket temporary directory. pg_regress never waits for a
471 : * postmaster exit, so it is indeterminate whether the postmaster has yet to
472 : * unlink the socket and lock file. Unlink them here so we can proceed to
473 : * remove the directory. Ignore errors; leaking a temporary directory is
474 : * unimportant. This can run from a signal handler. The code is not
475 : * acceptable in a Windows signal handler (see initdb.c:trapsig()), but
476 : * on Windows, pg_regress does not use Unix sockets by default.
477 : */
478 : static void
479 102 : remove_temp(void)
480 : {
481 : Assert(temp_sockdir);
482 102 : unlink(sockself);
483 102 : unlink(socklock);
484 102 : rmdir(temp_sockdir);
485 102 : }
486 :
487 : /*
488 : * Signal handler that calls remove_temp() and reraises the signal.
489 : */
490 : static void
491 0 : signal_remove_temp(SIGNAL_ARGS)
492 : {
493 0 : remove_temp();
494 :
495 0 : pqsignal(postgres_signal_arg, SIG_DFL);
496 0 : raise(postgres_signal_arg);
497 0 : }
498 :
499 : /*
500 : * Create a temporary directory suitable for the server's Unix-domain socket.
501 : * The directory will have mode 0700 or stricter, so no other OS user can open
502 : * our socket to exploit our use of trust authentication. Most systems
503 : * constrain the length of socket paths well below _POSIX_PATH_MAX, so we
504 : * place the directory under /tmp rather than relative to the possibly-deep
505 : * current working directory.
506 : *
507 : * Compared to using the compiled-in DEFAULT_PGSOCKET_DIR, this also permits
508 : * testing to work in builds that relocate it to a directory not writable to
509 : * the build/test user.
510 : */
511 : static const char *
512 102 : make_temp_sockdir(void)
513 : {
514 102 : char *template = psprintf("%s/pg_regress-XXXXXX",
515 102 : getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
516 :
517 102 : temp_sockdir = mkdtemp(template);
518 102 : if (temp_sockdir == NULL)
519 0 : bail("could not create directory \"%s\": %m", template);
520 :
521 : /* Stage file names for remove_temp(). Unsafe in a signal handler. */
522 102 : UNIXSOCK_PATH(sockself, port, temp_sockdir);
523 102 : snprintf(socklock, sizeof(socklock), "%s.lock", sockself);
524 :
525 : /* Remove the directory during clean exit. */
526 102 : atexit(remove_temp);
527 :
528 : /*
529 : * Remove the directory before dying to the usual signals. Omit SIGQUIT,
530 : * preserving it as a quick, untidy exit.
531 : */
532 102 : pqsignal(SIGINT, signal_remove_temp);
533 102 : pqsignal(SIGTERM, signal_remove_temp);
534 :
535 : /* the following are not valid on Windows */
536 : #ifndef WIN32
537 102 : pqsignal(SIGHUP, signal_remove_temp);
538 102 : pqsignal(SIGPIPE, signal_remove_temp);
539 : #endif
540 :
541 102 : return temp_sockdir;
542 : }
543 :
544 : /*
545 : * Check whether string matches pattern
546 : *
547 : * In the original shell script, this function was implemented using expr(1),
548 : * which provides basic regular expressions restricted to match starting at
549 : * the string start (in conventional regex terms, there's an implicit "^"
550 : * at the start of the pattern --- but no implicit "$" at the end).
551 : *
552 : * For now, we only support "." and ".*" as non-literal metacharacters,
553 : * because that's all that anyone has found use for in resultmap. This
554 : * code could be extended if more functionality is needed.
555 : */
556 : static bool
557 56 : string_matches_pattern(const char *str, const char *pattern)
558 : {
559 104 : while (*str && *pattern)
560 : {
561 104 : if (*pattern == '.' && pattern[1] == '*')
562 : {
563 32 : pattern += 2;
564 : /* Trailing .* matches everything. */
565 32 : if (*pattern == '\0')
566 0 : return true;
567 :
568 : /*
569 : * Otherwise, scan for a text position at which we can match the
570 : * rest of the pattern.
571 : */
572 376 : while (*str)
573 : {
574 : /*
575 : * Optimization to prevent most recursion: don't recurse
576 : * unless first pattern char might match this text char.
577 : */
578 344 : if (*str == *pattern || *pattern == '.')
579 : {
580 48 : if (string_matches_pattern(str, pattern))
581 0 : return true;
582 : }
583 :
584 344 : str++;
585 : }
586 :
587 : /*
588 : * End of text with no match.
589 : */
590 32 : return false;
591 : }
592 72 : else if (*pattern != '.' && *str != *pattern)
593 : {
594 : /*
595 : * Not the single-character wildcard and no explicit match? Then
596 : * time to quit...
597 : */
598 24 : return false;
599 : }
600 :
601 48 : str++;
602 48 : pattern++;
603 : }
604 :
605 0 : if (*pattern == '\0')
606 0 : return true; /* end of pattern, so declare match */
607 :
608 : /* End of input string. Do we have matching pattern remaining? */
609 0 : while (*pattern == '.' && pattern[1] == '*')
610 0 : pattern += 2;
611 0 : if (*pattern == '\0')
612 0 : return true; /* end of pattern, so declare match */
613 :
614 0 : return false;
615 : }
616 :
617 : /*
618 : * Scan resultmap file to find which platform-specific expected files to use.
619 : *
620 : * The format of each line of the file is
621 : * testname/hostplatformpattern=substitutefile
622 : * where the hostplatformpattern is evaluated per the rules of expr(1),
623 : * namely, it is a standard regular expression with an implicit ^ at the start.
624 : * (We currently support only a very limited subset of regular expressions,
625 : * see string_matches_pattern() above.) What hostplatformpattern will be
626 : * matched against is the config.guess output. (In the shell-script version,
627 : * we also provided an indication of whether gcc or another compiler was in
628 : * use, but that facility isn't used anymore.)
629 : */
630 : static void
631 106 : load_resultmap(void)
632 : {
633 : char buf[MAXPGPATH];
634 : FILE *f;
635 :
636 : /* scan the file ... */
637 106 : snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
638 106 : f = fopen(buf, "r");
639 106 : if (!f)
640 : {
641 : /* OK if it doesn't exist, else complain */
642 102 : if (errno == ENOENT)
643 102 : return;
644 0 : bail("could not open file \"%s\" for reading: %m", buf);
645 : }
646 :
647 16 : while (fgets(buf, sizeof(buf), f))
648 : {
649 : char *platform;
650 : char *file_type;
651 : char *expected;
652 : int i;
653 :
654 : /* strip trailing whitespace, especially the newline */
655 8 : i = strlen(buf);
656 16 : while (i > 0 && isspace((unsigned char) buf[i - 1]))
657 8 : buf[--i] = '\0';
658 :
659 : /* parse out the line fields */
660 8 : file_type = strchr(buf, ':');
661 8 : if (!file_type)
662 : {
663 0 : bail("incorrectly formatted resultmap entry: %s", buf);
664 : }
665 8 : *file_type++ = '\0';
666 :
667 8 : platform = strchr(file_type, ':');
668 8 : if (!platform)
669 : {
670 0 : bail("incorrectly formatted resultmap entry: %s", buf);
671 : }
672 8 : *platform++ = '\0';
673 8 : expected = strchr(platform, '=');
674 8 : if (!expected)
675 : {
676 0 : bail("incorrectly formatted resultmap entry: %s", buf);
677 : }
678 8 : *expected++ = '\0';
679 :
680 : /*
681 : * if it's for current platform, save it in resultmap list. Note: by
682 : * adding at the front of the list, we ensure that in ambiguous cases,
683 : * the last match in the resultmap file is used. This mimics the
684 : * behavior of the old shell script.
685 : */
686 8 : if (string_matches_pattern(host_platform, platform))
687 : {
688 0 : _resultmap *entry = pg_malloc_object(_resultmap);
689 :
690 0 : entry->test = pg_strdup(buf);
691 0 : entry->type = pg_strdup(file_type);
692 0 : entry->resultfile = pg_strdup(expected);
693 0 : entry->next = resultmap;
694 0 : resultmap = entry;
695 : }
696 : }
697 4 : fclose(f);
698 : }
699 :
700 : /*
701 : * Check in resultmap if we should be looking at a different file
702 : */
703 : static
704 : const char *
705 1872 : get_expectfile(const char *testname, const char *file)
706 : {
707 : const char *file_type;
708 : _resultmap *rm;
709 :
710 : /*
711 : * Determine the file type from the file name. This is just what is
712 : * following the last dot in the file name.
713 : */
714 1872 : if (!file || !(file_type = strrchr(file, '.')))
715 0 : return NULL;
716 :
717 1872 : file_type++;
718 :
719 1872 : for (rm = resultmap; rm != NULL; rm = rm->next)
720 : {
721 0 : if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
722 : {
723 0 : return rm->resultfile;
724 : }
725 : }
726 :
727 1872 : return NULL;
728 : }
729 :
730 : /*
731 : * Prepare environment variables for running regression tests
732 : */
733 : static void
734 106 : initialize_environment(void)
735 : {
736 : /*
737 : * Set default application_name. (The test_start_function may choose to
738 : * override this, but if it doesn't, we have something useful in place.)
739 : */
740 106 : setenv("PGAPPNAME", "pg_regress", 1);
741 :
742 : /*
743 : * Set variables that the test scripts may need to refer to.
744 : */
745 106 : setenv("PG_ABS_SRCDIR", inputdir, 1);
746 106 : setenv("PG_ABS_BUILDDIR", outputdir, 1);
747 106 : setenv("PG_LIBDIR", dlpath, 1);
748 106 : setenv("PG_DLSUFFIX", DLSUFFIX, 1);
749 :
750 106 : if (nolocale)
751 : {
752 : /*
753 : * Clear out any non-C locale settings
754 : */
755 2 : unsetenv("LC_COLLATE");
756 2 : unsetenv("LC_CTYPE");
757 2 : unsetenv("LC_MONETARY");
758 2 : unsetenv("LC_NUMERIC");
759 2 : unsetenv("LC_TIME");
760 2 : unsetenv("LANG");
761 :
762 : /*
763 : * Most platforms have adopted the POSIX locale as their
764 : * implementation-defined default locale. Exceptions include native
765 : * Windows, macOS with --enable-nls, and Cygwin with --enable-nls.
766 : * (Use of --enable-nls matters because libintl replaces setlocale().)
767 : * Also, PostgreSQL does not support macOS with locale environment
768 : * variables unset; see PostmasterMain().
769 : */
770 : #if defined(WIN32) || defined(__CYGWIN__) || defined(__darwin__)
771 : setenv("LANG", "C", 1);
772 : #endif
773 : }
774 :
775 : /*
776 : * Set translation-related settings to English; otherwise psql will
777 : * produce translated messages and produce diffs. (XXX If we ever support
778 : * translation of pg_regress, this needs to be moved elsewhere, where psql
779 : * is actually called.)
780 : */
781 106 : unsetenv("LANGUAGE");
782 106 : unsetenv("LC_ALL");
783 106 : setenv("LC_MESSAGES", "C", 1);
784 :
785 : /*
786 : * Set encoding as requested
787 : */
788 106 : if (encoding)
789 1 : setenv("PGCLIENTENCODING", encoding, 1);
790 : else
791 105 : unsetenv("PGCLIENTENCODING");
792 :
793 : /*
794 : * Set timezone and datestyle for datetime-related tests
795 : */
796 106 : setenv("PGTZ", "America/Los_Angeles", 1);
797 106 : setenv("PGDATESTYLE", "Postgres, MDY", 1);
798 :
799 : /*
800 : * Likewise set intervalstyle to ensure consistent results. This is a bit
801 : * more painful because we must use PGOPTIONS, and we want to preserve the
802 : * user's ability to set other variables through that.
803 : */
804 : {
805 106 : const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
806 106 : const char *old_pgoptions = getenv("PGOPTIONS");
807 : char *new_pgoptions;
808 :
809 106 : if (!old_pgoptions)
810 106 : old_pgoptions = "";
811 106 : new_pgoptions = psprintf("%s %s",
812 : old_pgoptions, my_pgoptions);
813 106 : setenv("PGOPTIONS", new_pgoptions, 1);
814 106 : free(new_pgoptions);
815 : }
816 :
817 106 : if (temp_instance)
818 : {
819 : /*
820 : * Clear out any environment vars that might cause psql to connect to
821 : * the wrong postmaster, or otherwise behave in nondefault ways. (Note
822 : * we also use psql's -X switch consistently, so that ~/.psqlrc files
823 : * won't mess things up.) Also, set PGPORT to the temp port, and set
824 : * PGHOST depending on whether we are using TCP or Unix sockets.
825 : *
826 : * This list should be kept in sync with PostgreSQL/Test/Utils.pm.
827 : */
828 103 : unsetenv("PGCHANNELBINDING");
829 : /* PGCLIENTENCODING, see above */
830 103 : unsetenv("PGCONNECT_TIMEOUT");
831 103 : unsetenv("PGDATA");
832 103 : unsetenv("PGDATABASE");
833 103 : unsetenv("PGGSSDELEGATION");
834 103 : unsetenv("PGGSSENCMODE");
835 103 : unsetenv("PGGSSLIB");
836 : /* PGHOSTADDR, see below */
837 103 : unsetenv("PGKRBSRVNAME");
838 103 : unsetenv("PGPASSFILE");
839 103 : unsetenv("PGPASSWORD");
840 103 : unsetenv("PGREQUIREPEER");
841 103 : unsetenv("PGREQUIRESSL");
842 103 : unsetenv("PGSERVICE");
843 103 : unsetenv("PGSERVICEFILE");
844 103 : unsetenv("PGSSLCERT");
845 103 : unsetenv("PGSSLCRL");
846 103 : unsetenv("PGSSLCRLDIR");
847 103 : unsetenv("PGSSLKEY");
848 103 : unsetenv("PGSSLMAXPROTOCOLVERSION");
849 103 : unsetenv("PGSSLMINPROTOCOLVERSION");
850 103 : unsetenv("PGSSLMODE");
851 103 : unsetenv("PGSSLROOTCERT");
852 103 : unsetenv("PGSSLSNI");
853 103 : unsetenv("PGTARGETSESSIONATTRS");
854 103 : unsetenv("PGUSER");
855 : /* PGPORT, see below */
856 : /* PGHOST, see below */
857 :
858 103 : if (hostname != NULL)
859 1 : setenv("PGHOST", hostname, 1);
860 : else
861 : {
862 102 : sockdir = getenv("PG_REGRESS_SOCK_DIR");
863 102 : if (!sockdir)
864 102 : sockdir = make_temp_sockdir();
865 102 : setenv("PGHOST", sockdir, 1);
866 : }
867 103 : unsetenv("PGHOSTADDR");
868 103 : if (port != -1)
869 : {
870 : char s[16];
871 :
872 103 : snprintf(s, sizeof(s), "%d", port);
873 103 : setenv("PGPORT", s, 1);
874 : }
875 : }
876 : else
877 : {
878 : const char *pghost;
879 : const char *pgport;
880 :
881 : /*
882 : * When testing an existing install, we honor existing environment
883 : * variables, except if they're overridden by command line options.
884 : */
885 3 : if (hostname != NULL)
886 : {
887 3 : setenv("PGHOST", hostname, 1);
888 3 : unsetenv("PGHOSTADDR");
889 : }
890 3 : if (port != -1)
891 : {
892 : char s[16];
893 :
894 3 : snprintf(s, sizeof(s), "%d", port);
895 3 : setenv("PGPORT", s, 1);
896 : }
897 3 : if (user != NULL)
898 0 : setenv("PGUSER", user, 1);
899 :
900 : /*
901 : * However, we *don't* honor PGDATABASE, since we certainly don't wish
902 : * to connect to whatever database the user might like as default.
903 : * (Most tests override PGDATABASE anyway, but there are some ECPG
904 : * test cases that don't.)
905 : */
906 3 : unsetenv("PGDATABASE");
907 :
908 : /*
909 : * Report what we're connecting to
910 : */
911 3 : pghost = getenv("PGHOST");
912 3 : pgport = getenv("PGPORT");
913 3 : if (!pghost)
914 : {
915 : /* Keep this bit in sync with libpq's default host location: */
916 0 : if (DEFAULT_PGSOCKET_DIR[0])
917 : /* do nothing, we'll print "Unix socket" below */ ;
918 : else
919 0 : pghost = "localhost"; /* DefaultHost in fe-connect.c */
920 : }
921 :
922 3 : if (pghost && pgport)
923 3 : note("using postmaster on %s, port %s", pghost, pgport);
924 3 : if (pghost && !pgport)
925 0 : note("using postmaster on %s, default port", pghost);
926 3 : if (!pghost && pgport)
927 0 : note("using postmaster on Unix socket, port %s", pgport);
928 3 : if (!pghost && !pgport)
929 0 : note("using postmaster on Unix socket, default port");
930 : }
931 :
932 106 : load_resultmap();
933 106 : }
934 :
935 : #ifdef ENABLE_SSPI
936 :
937 : /* support for config_sspi_auth() */
938 : static const char *
939 : fmtHba(const char *raw)
940 : {
941 : static char *ret;
942 : const char *rp;
943 : char *wp;
944 :
945 : wp = ret = pg_realloc(ret, 3 + strlen(raw) * 2);
946 :
947 : *wp++ = '"';
948 : for (rp = raw; *rp; rp++)
949 : {
950 : if (*rp == '"')
951 : *wp++ = '"';
952 : *wp++ = *rp;
953 : }
954 : *wp++ = '"';
955 : *wp++ = '\0';
956 :
957 : return ret;
958 : }
959 :
960 : /*
961 : * Get account and domain/realm names for the current user. This is based on
962 : * pg_SSPI_recvauth(). The returned strings use static storage.
963 : */
964 : static void
965 : current_windows_user(const char **acct, const char **dom)
966 : {
967 : static char accountname[MAXPGPATH];
968 : static char domainname[MAXPGPATH];
969 : HANDLE token;
970 : TOKEN_USER *tokenuser;
971 : DWORD retlen;
972 : DWORD accountnamesize = sizeof(accountname);
973 : DWORD domainnamesize = sizeof(domainname);
974 : SID_NAME_USE accountnameuse;
975 :
976 : if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token))
977 : {
978 : bail("could not open process token: error code %lu", GetLastError());
979 : }
980 :
981 : if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
982 : {
983 : bail("could not get token information buffer size: error code %lu",
984 : GetLastError());
985 : }
986 : tokenuser = pg_malloc(retlen);
987 : if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
988 : {
989 : bail("could not get token information: error code %lu",
990 : GetLastError());
991 : }
992 :
993 : if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize,
994 : domainname, &domainnamesize, &accountnameuse))
995 : {
996 : bail("could not look up account SID: error code %lu",
997 : GetLastError());
998 : }
999 :
1000 : free(tokenuser);
1001 :
1002 : *acct = accountname;
1003 : *dom = domainname;
1004 : }
1005 :
1006 : /*
1007 : * Rewrite pg_hba.conf and pg_ident.conf to use SSPI authentication. Permit
1008 : * the current OS user to authenticate as the bootstrap superuser and as any
1009 : * user named in a --create-role option.
1010 : *
1011 : * In --config-auth mode, the --user switch can be used to specify the
1012 : * bootstrap superuser's name, otherwise we assume it is the default.
1013 : */
1014 : static void
1015 : config_sspi_auth(const char *pgdata, const char *superuser_name)
1016 : {
1017 : const char *accountname,
1018 : *domainname;
1019 : char *errstr;
1020 : bool have_ipv6;
1021 : char fname[MAXPGPATH];
1022 : int res;
1023 : FILE *hba,
1024 : *ident;
1025 : _stringlist *sl;
1026 :
1027 : /* Find out the name of the current OS user */
1028 : current_windows_user(&accountname, &domainname);
1029 :
1030 : /* Determine the bootstrap superuser's name */
1031 : if (superuser_name == NULL)
1032 : {
1033 : /*
1034 : * Compute the default superuser name the same way initdb does.
1035 : *
1036 : * It's possible that this result always matches "accountname", the
1037 : * value SSPI authentication discovers. But the underlying system
1038 : * functions do not clearly guarantee that.
1039 : */
1040 : superuser_name = get_user_name(&errstr);
1041 : if (superuser_name == NULL)
1042 : {
1043 : bail("%s", errstr);
1044 : }
1045 : }
1046 :
1047 : /*
1048 : * Like initdb.c:setup_config(), determine whether the platform recognizes
1049 : * ::1 (IPv6 loopback) as a numeric host address string.
1050 : */
1051 : {
1052 : struct addrinfo *gai_result;
1053 : struct addrinfo hints;
1054 : WSADATA wsaData;
1055 :
1056 : hints.ai_flags = AI_NUMERICHOST;
1057 : hints.ai_family = AF_UNSPEC;
1058 : hints.ai_socktype = 0;
1059 : hints.ai_protocol = 0;
1060 : hints.ai_addrlen = 0;
1061 : hints.ai_canonname = NULL;
1062 : hints.ai_addr = NULL;
1063 : hints.ai_next = NULL;
1064 :
1065 : have_ipv6 = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0 &&
1066 : getaddrinfo("::1", NULL, &hints, &gai_result) == 0);
1067 : }
1068 :
1069 : /* Check a Write outcome and report any error. */
1070 : #define CW(cond) \
1071 : do { \
1072 : if (!(cond)) \
1073 : bail("could not write to file \"%s\": %m", fname); \
1074 : } while (0)
1075 :
1076 : res = snprintf(fname, sizeof(fname), "%s/pg_hba.conf", pgdata);
1077 : if (res < 0 || res >= sizeof(fname))
1078 : {
1079 : /*
1080 : * Truncating this name is a fatal error, because we must not fail to
1081 : * overwrite an original trust-authentication pg_hba.conf.
1082 : */
1083 : bail("directory name too long");
1084 : }
1085 : hba = fopen(fname, "w");
1086 : if (hba == NULL)
1087 : {
1088 : bail("could not open file \"%s\" for writing: %m", fname);
1089 : }
1090 : CW(fputs("# Configuration written by config_sspi_auth()\n", hba) >= 0);
1091 : CW(fputs("host all all 127.0.0.1/32 sspi include_realm=1 map=regress\n",
1092 : hba) >= 0);
1093 : if (have_ipv6)
1094 : CW(fputs("host all all ::1/128 sspi include_realm=1 map=regress\n",
1095 : hba) >= 0);
1096 : CW(fclose(hba) == 0);
1097 :
1098 : snprintf(fname, sizeof(fname), "%s/pg_ident.conf", pgdata);
1099 : ident = fopen(fname, "w");
1100 : if (ident == NULL)
1101 : {
1102 : bail("could not open file \"%s\" for writing: %m", fname);
1103 : }
1104 : CW(fputs("# Configuration written by config_sspi_auth()\n", ident) >= 0);
1105 :
1106 : /*
1107 : * Double-quote for the benefit of account names containing whitespace or
1108 : * '#'. Windows forbids the double-quote character itself, so don't
1109 : * bother escaping embedded double-quote characters.
1110 : */
1111 : CW(fprintf(ident, "regress \"%s@%s\" %s\n",
1112 : accountname, domainname, fmtHba(superuser_name)) >= 0);
1113 : for (sl = extraroles; sl; sl = sl->next)
1114 : CW(fprintf(ident, "regress \"%s@%s\" %s\n",
1115 : accountname, domainname, fmtHba(sl->str)) >= 0);
1116 : CW(fclose(ident) == 0);
1117 : }
1118 :
1119 : #endif /* ENABLE_SSPI */
1120 :
1121 : /*
1122 : * psql_start_command, psql_add_command, psql_end_command
1123 : *
1124 : * Issue one or more commands within one psql call.
1125 : * Set up with psql_start_command, then add commands one at a time
1126 : * with psql_add_command, and finally execute with psql_end_command.
1127 : *
1128 : * Since we use system(), this doesn't return until the operation finishes
1129 : */
1130 : static StringInfo
1131 125 : psql_start_command(void)
1132 : {
1133 125 : StringInfo buf = makeStringInfo();
1134 :
1135 250 : appendStringInfo(buf,
1136 : "\"%s%spsql\" -X -q",
1137 125 : bindir ? bindir : "",
1138 125 : bindir ? "/" : "");
1139 125 : return buf;
1140 : }
1141 :
1142 : static void
1143 248 : psql_add_command(StringInfo buf, const char *query,...)
1144 : {
1145 : StringInfoData cmdbuf;
1146 : const char *cmdptr;
1147 :
1148 : /* Add each command as a -c argument in the psql call */
1149 248 : appendStringInfoString(buf, " -c \"");
1150 :
1151 : /* Generate the query with insertion of sprintf arguments */
1152 248 : initStringInfo(&cmdbuf);
1153 : for (;;)
1154 0 : {
1155 : va_list args;
1156 : int needed;
1157 :
1158 248 : va_start(args, query);
1159 248 : needed = appendStringInfoVA(&cmdbuf, query, args);
1160 248 : va_end(args);
1161 248 : if (needed == 0)
1162 248 : break; /* success */
1163 0 : enlargeStringInfo(&cmdbuf, needed);
1164 : }
1165 :
1166 : /* Now escape any shell double-quote metacharacters */
1167 47520 : for (cmdptr = cmdbuf.data; *cmdptr; cmdptr++)
1168 : {
1169 47272 : if (strchr("\\\"$`", *cmdptr))
1170 1594 : appendStringInfoChar(buf, '\\');
1171 47272 : appendStringInfoChar(buf, *cmdptr);
1172 : }
1173 :
1174 248 : appendStringInfoChar(buf, '"');
1175 :
1176 248 : pfree(cmdbuf.data);
1177 248 : }
1178 :
1179 : static void
1180 125 : psql_end_command(StringInfo buf, const char *database)
1181 : {
1182 : /* Add the database name --- assume it needs no extra escaping */
1183 125 : appendStringInfo(buf,
1184 : " \"%s\"",
1185 : database);
1186 :
1187 : /* And now we can execute the shell command */
1188 125 : fflush(NULL);
1189 125 : if (system(buf->data) != 0)
1190 : {
1191 : /* psql probably already reported the error */
1192 0 : bail("command failed: %s", buf->data);
1193 : }
1194 :
1195 : /* Clean up */
1196 125 : destroyStringInfo(buf);
1197 125 : }
1198 :
1199 : /*
1200 : * Shorthand macro for the common case of a single command
1201 : */
1202 : #define psql_command(database, ...) \
1203 : do { \
1204 : StringInfo cmdbuf = psql_start_command(); \
1205 : psql_add_command(cmdbuf, __VA_ARGS__); \
1206 : psql_end_command(cmdbuf, database); \
1207 : } while (0)
1208 :
1209 : /*
1210 : * Spawn a process to execute the given shell command; don't wait for it
1211 : *
1212 : * Returns the process ID (or HANDLE) so we can wait for it later
1213 : */
1214 : PID_TYPE
1215 1709 : spawn_process(const char *cmdline)
1216 : {
1217 : #ifndef WIN32
1218 : pid_t pid;
1219 :
1220 : /*
1221 : * Must flush I/O buffers before fork.
1222 : */
1223 1709 : fflush(NULL);
1224 :
1225 : #ifdef EXEC_BACKEND
1226 : pg_disable_aslr();
1227 : #endif
1228 :
1229 1709 : pid = fork();
1230 3418 : if (pid == -1)
1231 : {
1232 0 : bail("could not fork: %m");
1233 : }
1234 3418 : if (pid == 0)
1235 : {
1236 : /*
1237 : * In child
1238 : *
1239 : * Instead of using system(), exec the shell directly, and tell it to
1240 : * "exec" the command too. This saves two useless processes per
1241 : * parallel test case.
1242 : */
1243 : char *cmdline2;
1244 :
1245 1709 : cmdline2 = psprintf("exec %s", cmdline);
1246 1709 : execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
1247 : /* Not using the normal bail() here as we want _exit */
1248 1709 : bail_noatexit("could not exec \"%s\": %m", shellprog);
1249 : }
1250 : /* in parent */
1251 1709 : return pid;
1252 : #else
1253 : PROCESS_INFORMATION pi;
1254 : char *cmdline2;
1255 : const char *comspec;
1256 :
1257 : /* Find CMD.EXE location using COMSPEC, if it's set */
1258 : comspec = getenv("COMSPEC");
1259 : if (comspec == NULL)
1260 : comspec = "CMD";
1261 :
1262 : memset(&pi, 0, sizeof(pi));
1263 : cmdline2 = psprintf("\"%s\" /c \"%s\"", comspec, cmdline);
1264 :
1265 : if (!CreateRestrictedProcess(cmdline2, &pi))
1266 : exit(2);
1267 :
1268 : CloseHandle(pi.hThread);
1269 : return pi.hProcess;
1270 : #endif
1271 : }
1272 :
1273 : /*
1274 : * Count bytes in file
1275 : */
1276 : static long
1277 106 : file_size(const char *file)
1278 : {
1279 : long r;
1280 106 : FILE *f = fopen(file, "r");
1281 :
1282 106 : if (!f)
1283 : {
1284 0 : diag("could not open file \"%s\" for reading: %m", file);
1285 0 : return -1;
1286 : }
1287 106 : fseek(f, 0, SEEK_END);
1288 106 : r = ftell(f);
1289 106 : fclose(f);
1290 106 : return r;
1291 : }
1292 :
1293 : /*
1294 : * Count lines in file
1295 : */
1296 : static int
1297 57 : file_line_count(const char *file)
1298 : {
1299 : int c;
1300 57 : int l = 0;
1301 57 : FILE *f = fopen(file, "r");
1302 :
1303 57 : if (!f)
1304 : {
1305 0 : diag("could not open file \"%s\" for reading: %m", file);
1306 0 : return -1;
1307 : }
1308 288612 : while ((c = fgetc(f)) != EOF)
1309 : {
1310 288555 : if (c == '\n')
1311 10356 : l++;
1312 : }
1313 57 : fclose(f);
1314 57 : return l;
1315 : }
1316 :
1317 : bool
1318 3056 : file_exists(const char *file)
1319 : {
1320 3056 : FILE *f = fopen(file, "r");
1321 :
1322 3056 : if (!f)
1323 1847 : return false;
1324 1209 : fclose(f);
1325 1209 : return true;
1326 : }
1327 :
1328 : static bool
1329 418 : directory_exists(const char *dir)
1330 : {
1331 : struct stat st;
1332 :
1333 418 : if (stat(dir, &st) != 0)
1334 320 : return false;
1335 98 : if (S_ISDIR(st.st_mode))
1336 98 : return true;
1337 0 : return false;
1338 : }
1339 :
1340 : /* Create a directory */
1341 : static void
1342 320 : make_directory(const char *dir)
1343 : {
1344 320 : if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1345 0 : bail("could not create directory \"%s\": %m", dir);
1346 320 : }
1347 :
1348 : /*
1349 : * In: filename.ext, Return: filename_i.ext, where 0 <= i <= 9
1350 : */
1351 : static char *
1352 110 : get_alternative_expectfile(const char *expectfile, int i)
1353 : {
1354 : char *last_dot;
1355 110 : int ssize = strlen(expectfile) + 2 + 1;
1356 : char *tmp;
1357 : char *s;
1358 :
1359 110 : if (!(tmp = (char *) malloc(ssize)))
1360 0 : return NULL;
1361 :
1362 110 : if (!(s = (char *) malloc(ssize)))
1363 : {
1364 0 : free(tmp);
1365 0 : return NULL;
1366 : }
1367 :
1368 110 : strcpy(tmp, expectfile);
1369 110 : last_dot = strrchr(tmp, '.');
1370 110 : if (!last_dot)
1371 : {
1372 0 : free(tmp);
1373 0 : free(s);
1374 0 : return NULL;
1375 : }
1376 110 : *last_dot = '\0';
1377 110 : snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
1378 110 : free(tmp);
1379 110 : return s;
1380 : }
1381 :
1382 : /*
1383 : * Run a "diff" command and also check that it didn't crash
1384 : */
1385 : static int
1386 1929 : run_diff(const char *cmd, const char *filename)
1387 : {
1388 : int r;
1389 :
1390 1929 : fflush(NULL);
1391 1929 : r = system(cmd);
1392 1929 : if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
1393 : {
1394 0 : bail("diff command failed with status %d: %s", r, cmd);
1395 : }
1396 : #ifdef WIN32
1397 :
1398 : /*
1399 : * On WIN32, if the 'diff' command cannot be found, system() returns 1,
1400 : * but produces nothing to stdout, so we check for that here.
1401 : */
1402 : if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
1403 : {
1404 : bail("diff command not found: %s", cmd);
1405 : }
1406 : #endif
1407 :
1408 1929 : return WEXITSTATUS(r);
1409 : }
1410 :
1411 : /*
1412 : * Check the actual result file for the given test against expected results
1413 : *
1414 : * Returns true if different (failure), false if correct match found.
1415 : * In the true case, the diff is appended to the diffs file.
1416 : */
1417 : static bool
1418 1872 : results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
1419 : {
1420 : char expectfile[MAXPGPATH];
1421 : char diff[MAXPGPATH];
1422 : char cmd[MAXPGPATH * 3];
1423 : char best_expect_file[MAXPGPATH];
1424 : FILE *difffile;
1425 : int best_line_count;
1426 : int i;
1427 : int l;
1428 : long startpos;
1429 : const char *platform_expectfile;
1430 :
1431 : /*
1432 : * We can pass either the resultsfile or the expectfile, they should have
1433 : * the same type (filename.type) anyway.
1434 : */
1435 1872 : platform_expectfile = get_expectfile(testname, resultsfile);
1436 :
1437 1872 : strlcpy(expectfile, default_expectfile, sizeof(expectfile));
1438 1872 : if (platform_expectfile)
1439 : {
1440 : /*
1441 : * Replace everything after the last slash in expectfile with what the
1442 : * platform_expectfile contains.
1443 : */
1444 0 : char *p = strrchr(expectfile, '/');
1445 :
1446 0 : if (p)
1447 0 : strcpy(++p, platform_expectfile);
1448 : }
1449 :
1450 : /* Name to use for temporary diff file */
1451 1872 : snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
1452 :
1453 : /* OK, run the diff */
1454 1872 : snprintf(cmd, sizeof(cmd),
1455 : "diff %s \"%s\" \"%s\" > \"%s\"",
1456 : basic_diff_opts, expectfile, resultsfile, diff);
1457 :
1458 : /* Is the diff file empty? */
1459 1872 : if (run_diff(cmd, diff) == 0)
1460 : {
1461 1825 : unlink(diff);
1462 1825 : return false;
1463 : }
1464 :
1465 : /* There may be secondary comparison files that match better */
1466 47 : best_line_count = file_line_count(diff);
1467 47 : strcpy(best_expect_file, expectfile);
1468 :
1469 110 : for (i = 0; i <= 9; i++)
1470 : {
1471 : char *alt_expectfile;
1472 :
1473 110 : alt_expectfile = get_alternative_expectfile(expectfile, i);
1474 110 : if (!alt_expectfile)
1475 0 : bail("Unable to check secondary comparison files: %m");
1476 :
1477 110 : if (!file_exists(alt_expectfile))
1478 : {
1479 53 : free(alt_expectfile);
1480 53 : continue;
1481 : }
1482 :
1483 57 : snprintf(cmd, sizeof(cmd),
1484 : "diff %s \"%s\" \"%s\" > \"%s\"",
1485 : basic_diff_opts, alt_expectfile, resultsfile, diff);
1486 :
1487 57 : if (run_diff(cmd, diff) == 0)
1488 : {
1489 47 : unlink(diff);
1490 47 : free(alt_expectfile);
1491 47 : return false;
1492 : }
1493 :
1494 10 : l = file_line_count(diff);
1495 10 : if (l < best_line_count)
1496 : {
1497 : /* This diff was a better match than the last one */
1498 10 : best_line_count = l;
1499 10 : strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
1500 : }
1501 10 : free(alt_expectfile);
1502 : }
1503 :
1504 : /*
1505 : * fall back on the canonical results file if we haven't tried it yet and
1506 : * haven't found a complete match yet.
1507 : */
1508 :
1509 0 : if (platform_expectfile)
1510 : {
1511 0 : snprintf(cmd, sizeof(cmd),
1512 : "diff %s \"%s\" \"%s\" > \"%s\"",
1513 : basic_diff_opts, default_expectfile, resultsfile, diff);
1514 :
1515 0 : if (run_diff(cmd, diff) == 0)
1516 : {
1517 : /* No diff = no changes = good */
1518 0 : unlink(diff);
1519 0 : return false;
1520 : }
1521 :
1522 0 : l = file_line_count(diff);
1523 0 : if (l < best_line_count)
1524 : {
1525 : /* This diff was a better match than the last one */
1526 0 : best_line_count = l;
1527 0 : strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
1528 : }
1529 : }
1530 :
1531 : /*
1532 : * Use the best comparison file to generate the "pretty" diff, which we
1533 : * append to the diffs summary file.
1534 : */
1535 :
1536 0 : difffile = fopen(difffilename, "a");
1537 0 : if (difffile)
1538 : {
1539 0 : startpos = ftell(difffile);
1540 :
1541 : /* Write diff header */
1542 0 : fprintf(difffile,
1543 : "diff %s %s %s\n",
1544 : pretty_diff_opts, best_expect_file, resultsfile);
1545 0 : fclose(difffile);
1546 :
1547 : /* Run diff */
1548 0 : snprintf(cmd, sizeof(cmd),
1549 : "diff %s \"%s\" \"%s\" >> \"%s\"",
1550 : pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1551 0 : run_diff(cmd, difffilename);
1552 :
1553 : /*
1554 : * Reopen the file for reading to emit the diff as TAP diagnostics. We
1555 : * can't keep the file open while diff appends to it, because on
1556 : * Windows the file lock prevents diff from writing.
1557 : */
1558 0 : difffile = fopen(difffilename, "r");
1559 : }
1560 :
1561 0 : if (difffile)
1562 : {
1563 : /*
1564 : * In case of a crash the diff can be huge and all of the subsequent
1565 : * tests will fail with essentially useless diffs too. So to avoid
1566 : * flooding the output, while still providing useful info in most
1567 : * cases we output only the first 80 lines of the *combined* diff. The
1568 : * number 80 is chosen so that we output less than 100 lines of
1569 : * diagnostics per pg_regress run. Otherwise if meson is run with the
1570 : * --quiet flag only the last 100 lines are shown and usually the most
1571 : * useful information is actually in the first few lines.
1572 : */
1573 : static int nlines = 0;
1574 0 : const int max_diff_lines = 80;
1575 : char line[1024];
1576 :
1577 0 : fseek(difffile, startpos, SEEK_SET);
1578 0 : while (nlines < max_diff_lines &&
1579 0 : fgets(line, sizeof(line), difffile))
1580 : {
1581 0 : size_t len = strlen(line);
1582 0 : bool newline_found = (len > 0 && line[len - 1] == '\n');
1583 :
1584 0 : if (newline_found)
1585 0 : line[len - 1] = '\0';
1586 :
1587 0 : diag_detail("%s", line);
1588 0 : if (newline_found)
1589 : {
1590 0 : diag_end();
1591 0 : nlines++;
1592 : }
1593 : }
1594 :
1595 0 : if (in_diag)
1596 : {
1597 : /*
1598 : * If there was no final newline for some reason, we should still
1599 : * end the diagnostic.
1600 : */
1601 0 : diag_end();
1602 0 : nlines++;
1603 : }
1604 :
1605 0 : if (nlines >= max_diff_lines)
1606 0 : diag("(diff output truncated and silencing output for further failing tests...)");
1607 :
1608 0 : fclose(difffile);
1609 : }
1610 :
1611 0 : unlink(diff);
1612 0 : return true;
1613 : }
1614 :
1615 : /*
1616 : * Wait for specified subprocesses to finish, and return their exit
1617 : * statuses into statuses[] and stop times into stoptimes[]
1618 : *
1619 : * If names isn't NULL, print each subprocess's name as it finishes
1620 : *
1621 : * Note: it's OK to scribble on the pids array, but not on the names array
1622 : */
1623 : static void
1624 730 : wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
1625 : char **names, int num_tests)
1626 : {
1627 : int tests_left;
1628 : int i;
1629 :
1630 : #ifdef WIN32
1631 : PID_TYPE *active_pids = pg_malloc_array(PID_TYPE, num_tests);
1632 :
1633 : memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1634 : #endif
1635 :
1636 730 : tests_left = num_tests;
1637 2336 : while (tests_left > 0)
1638 : {
1639 : PID_TYPE p;
1640 :
1641 : #ifndef WIN32
1642 : int exit_status;
1643 :
1644 1606 : p = wait(&exit_status);
1645 :
1646 1606 : if (p == INVALID_PID)
1647 0 : bail("failed to wait for subprocesses: %m");
1648 : #else
1649 : DWORD exit_status;
1650 : int r;
1651 :
1652 : r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
1653 : if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
1654 : {
1655 : bail("failed to wait for subprocesses: error code %lu",
1656 : GetLastError());
1657 : }
1658 : p = active_pids[r - WAIT_OBJECT_0];
1659 : /* compact the active_pids array */
1660 : active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1661 : #endif /* WIN32 */
1662 :
1663 9222 : for (i = 0; i < num_tests; i++)
1664 : {
1665 9222 : if (p == pids[i])
1666 : {
1667 : #ifdef WIN32
1668 : GetExitCodeProcess(pids[i], &exit_status);
1669 : CloseHandle(pids[i]);
1670 : #endif
1671 1606 : pids[i] = INVALID_PID;
1672 1606 : statuses[i] = (int) exit_status;
1673 1606 : INSTR_TIME_SET_CURRENT(stoptimes[i]);
1674 1606 : if (names)
1675 952 : note_detail(" %s", names[i]);
1676 1606 : tests_left--;
1677 1606 : break;
1678 : }
1679 : }
1680 : }
1681 :
1682 : #ifdef WIN32
1683 : free(active_pids);
1684 : #endif
1685 730 : }
1686 :
1687 : /*
1688 : * report nonzero exit code from a test process
1689 : */
1690 : static void
1691 0 : log_child_failure(int exitstatus)
1692 : {
1693 0 : if (WIFEXITED(exitstatus))
1694 0 : diag("(test process exited with exit code %d)",
1695 : WEXITSTATUS(exitstatus));
1696 0 : else if (WIFSIGNALED(exitstatus))
1697 : {
1698 : #if defined(WIN32)
1699 : diag("(test process was terminated by exception 0x%X)",
1700 : WTERMSIG(exitstatus));
1701 : #else
1702 0 : diag("(test process was terminated by signal %d: %s)",
1703 : WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
1704 : #endif
1705 : }
1706 : else
1707 0 : diag("(test process exited with unrecognized status %d)", exitstatus);
1708 0 : }
1709 :
1710 : /*
1711 : * Run all the tests specified in one schedule file
1712 : */
1713 : static void
1714 7 : run_schedule(const char *schedule, test_start_function startfunc,
1715 : postprocess_result_function postfunc)
1716 : {
1717 : #define MAX_PARALLEL_TESTS 100
1718 : char *tests[MAX_PARALLEL_TESTS];
1719 : _stringlist *resultfiles[MAX_PARALLEL_TESTS];
1720 : _stringlist *expectfiles[MAX_PARALLEL_TESTS];
1721 : _stringlist *tags[MAX_PARALLEL_TESTS];
1722 : PID_TYPE pids[MAX_PARALLEL_TESTS];
1723 : instr_time starttimes[MAX_PARALLEL_TESTS];
1724 : instr_time stoptimes[MAX_PARALLEL_TESTS];
1725 : int statuses[MAX_PARALLEL_TESTS];
1726 : char scbuf[1024];
1727 : FILE *scf;
1728 7 : int line_num = 0;
1729 :
1730 7 : memset(tests, 0, sizeof(tests));
1731 7 : memset(resultfiles, 0, sizeof(resultfiles));
1732 7 : memset(expectfiles, 0, sizeof(expectfiles));
1733 7 : memset(tags, 0, sizeof(tags));
1734 :
1735 7 : scf = fopen(schedule, "r");
1736 7 : if (!scf)
1737 0 : bail("could not open file \"%s\" for reading: %m", schedule);
1738 :
1739 841 : while (fgets(scbuf, sizeof(scbuf), scf))
1740 : {
1741 834 : char *test = NULL;
1742 : char *c;
1743 : int num_tests;
1744 : bool inword;
1745 : int i;
1746 :
1747 834 : line_num++;
1748 :
1749 : /* strip trailing whitespace, especially the newline */
1750 834 : i = strlen(scbuf);
1751 1668 : while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
1752 834 : scbuf[--i] = '\0';
1753 :
1754 834 : if (scbuf[0] == '\0' || scbuf[0] == '#')
1755 464 : continue;
1756 370 : if (strncmp(scbuf, "test: ", 6) == 0)
1757 370 : test = scbuf + 6;
1758 : else
1759 : {
1760 0 : bail("syntax error in schedule file \"%s\" line %d: %s",
1761 : schedule, line_num, scbuf);
1762 : }
1763 :
1764 370 : num_tests = 0;
1765 370 : inword = false;
1766 15016 : for (c = test;; c++)
1767 : {
1768 15016 : if (*c == '\0' || isspace((unsigned char) *c))
1769 : {
1770 1246 : if (inword)
1771 : {
1772 : /* Reached end of a test name */
1773 : char sav;
1774 :
1775 1246 : if (num_tests >= MAX_PARALLEL_TESTS)
1776 : {
1777 0 : bail("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s",
1778 : MAX_PARALLEL_TESTS, schedule, line_num, scbuf);
1779 : }
1780 1246 : sav = *c;
1781 1246 : *c = '\0';
1782 1246 : tests[num_tests] = pg_strdup(test);
1783 1246 : num_tests++;
1784 1246 : *c = sav;
1785 1246 : inword = false;
1786 : }
1787 1246 : if (*c == '\0')
1788 370 : break; /* loop exit is here */
1789 : }
1790 13770 : else if (!inword)
1791 : {
1792 : /* Start of a test name */
1793 1246 : test = c;
1794 1246 : inword = true;
1795 : }
1796 : }
1797 :
1798 370 : if (num_tests == 0)
1799 : {
1800 0 : bail("syntax error in schedule file \"%s\" line %d: %s",
1801 : schedule, line_num, scbuf);
1802 : }
1803 :
1804 370 : if (num_tests == 1)
1805 : {
1806 294 : pids[0] = (startfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1807 294 : INSTR_TIME_SET_CURRENT(starttimes[0]);
1808 294 : wait_for_tests(pids, statuses, stoptimes, NULL, 1);
1809 : /* status line is finished below */
1810 : }
1811 76 : else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
1812 : {
1813 0 : bail("too many parallel tests (more than %d) in schedule file \"%s\" line %d: %s",
1814 : max_concurrent_tests, schedule, line_num, scbuf);
1815 : }
1816 76 : else if (max_connections > 0 && max_connections < num_tests)
1817 0 : {
1818 0 : int oldest = 0;
1819 :
1820 0 : note_detail("parallel group (%d tests, in groups of %d): ",
1821 : num_tests, max_connections);
1822 0 : for (i = 0; i < num_tests; i++)
1823 : {
1824 0 : if (i - oldest >= max_connections)
1825 : {
1826 0 : wait_for_tests(pids + oldest, statuses + oldest,
1827 0 : stoptimes + oldest,
1828 0 : tests + oldest, i - oldest);
1829 0 : oldest = i;
1830 : }
1831 0 : pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1832 0 : INSTR_TIME_SET_CURRENT(starttimes[i]);
1833 : }
1834 0 : wait_for_tests(pids + oldest, statuses + oldest,
1835 0 : stoptimes + oldest,
1836 0 : tests + oldest, i - oldest);
1837 0 : note_end();
1838 : }
1839 : else
1840 : {
1841 76 : note_detail("parallel group (%d tests): ", num_tests);
1842 1028 : for (i = 0; i < num_tests; i++)
1843 : {
1844 952 : pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1845 952 : INSTR_TIME_SET_CURRENT(starttimes[i]);
1846 : }
1847 76 : wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
1848 76 : note_end();
1849 : }
1850 :
1851 : /* Check results for all tests */
1852 1616 : for (i = 0; i < num_tests; i++)
1853 : {
1854 : _stringlist *rl,
1855 : *el,
1856 : *tl;
1857 1246 : bool differ = false;
1858 :
1859 1246 : INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
1860 :
1861 : /*
1862 : * Advance over all three lists simultaneously.
1863 : *
1864 : * Compare resultfiles[j] with expectfiles[j] always. Tags are
1865 : * optional but if there are tags, the tag list has the same
1866 : * length as the other two lists.
1867 : */
1868 1246 : for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
1869 2752 : rl != NULL; /* rl and el have the same length */
1870 1506 : rl = rl->next, el = el->next,
1871 1506 : tl = tl ? tl->next : NULL)
1872 : {
1873 : bool newdiff;
1874 :
1875 1506 : if (postfunc)
1876 390 : (*postfunc) (rl->str);
1877 1506 : newdiff = results_differ(tests[i], rl->str, el->str);
1878 1506 : if (newdiff && tl)
1879 : {
1880 0 : diag("tag: %s", tl->str);
1881 : }
1882 1506 : differ |= newdiff;
1883 : }
1884 :
1885 1246 : if (statuses[i] != 0)
1886 : {
1887 0 : test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
1888 0 : log_child_failure(statuses[i]);
1889 : }
1890 : else
1891 : {
1892 1246 : if (differ)
1893 : {
1894 0 : test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
1895 : }
1896 : else
1897 : {
1898 1246 : test_status_ok(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
1899 : }
1900 : }
1901 : }
1902 :
1903 1616 : for (i = 0; i < num_tests; i++)
1904 : {
1905 1246 : pg_free(tests[i]);
1906 1246 : tests[i] = NULL;
1907 1246 : free_stringlist(&resultfiles[i]);
1908 1246 : free_stringlist(&expectfiles[i]);
1909 1246 : free_stringlist(&tags[i]);
1910 : }
1911 : }
1912 :
1913 7 : fclose(scf);
1914 7 : }
1915 :
1916 : /*
1917 : * Run a single test
1918 : */
1919 : static void
1920 360 : run_single_test(const char *test, test_start_function startfunc,
1921 : postprocess_result_function postfunc)
1922 : {
1923 : PID_TYPE pid;
1924 : instr_time starttime;
1925 : instr_time stoptime;
1926 : int exit_status;
1927 360 : _stringlist *resultfiles = NULL;
1928 360 : _stringlist *expectfiles = NULL;
1929 360 : _stringlist *tags = NULL;
1930 : _stringlist *rl,
1931 : *el,
1932 : *tl;
1933 360 : bool differ = false;
1934 :
1935 360 : pid = (startfunc) (test, &resultfiles, &expectfiles, &tags);
1936 360 : INSTR_TIME_SET_CURRENT(starttime);
1937 360 : wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
1938 :
1939 : /*
1940 : * Advance over all three lists simultaneously.
1941 : *
1942 : * Compare resultfiles[j] with expectfiles[j] always. Tags are optional
1943 : * but if there are tags, the tag list has the same length as the other
1944 : * two lists.
1945 : */
1946 360 : for (rl = resultfiles, el = expectfiles, tl = tags;
1947 726 : rl != NULL; /* rl and el have the same length */
1948 366 : rl = rl->next, el = el->next,
1949 366 : tl = tl ? tl->next : NULL)
1950 : {
1951 : bool newdiff;
1952 :
1953 366 : if (postfunc)
1954 9 : (*postfunc) (rl->str);
1955 366 : newdiff = results_differ(test, rl->str, el->str);
1956 366 : if (newdiff && tl)
1957 : {
1958 0 : diag("tag: %s", tl->str);
1959 : }
1960 366 : differ |= newdiff;
1961 : }
1962 :
1963 360 : INSTR_TIME_SUBTRACT(stoptime, starttime);
1964 :
1965 360 : if (exit_status != 0)
1966 : {
1967 0 : test_status_failed(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
1968 0 : log_child_failure(exit_status);
1969 : }
1970 : else
1971 : {
1972 360 : if (differ)
1973 : {
1974 0 : test_status_failed(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
1975 : }
1976 : else
1977 : {
1978 360 : test_status_ok(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
1979 : }
1980 : }
1981 360 : }
1982 :
1983 : /*
1984 : * Create the summary-output files (making them empty if already existing)
1985 : */
1986 : static void
1987 106 : open_result_files(void)
1988 : {
1989 : char file[MAXPGPATH];
1990 : FILE *difffile;
1991 :
1992 : /* create outputdir directory if not present */
1993 106 : if (!directory_exists(outputdir))
1994 10 : make_directory(outputdir);
1995 :
1996 : /* create the log file (copy of running status output) */
1997 106 : snprintf(file, sizeof(file), "%s/regression.out", outputdir);
1998 106 : logfilename = pg_strdup(file);
1999 106 : logfile = fopen(logfilename, "w");
2000 106 : if (!logfile)
2001 0 : bail("could not open file \"%s\" for writing: %m", logfilename);
2002 :
2003 : /* create the diffs file as empty */
2004 106 : snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
2005 106 : difffilename = pg_strdup(file);
2006 106 : difffile = fopen(difffilename, "w");
2007 106 : if (!difffile)
2008 0 : bail("could not open file \"%s\" for writing: %m", difffilename);
2009 :
2010 : /* we don't keep the diffs file open continuously */
2011 106 : fclose(difffile);
2012 :
2013 : /* also create the results directory if not present */
2014 106 : snprintf(file, sizeof(file), "%s/results", outputdir);
2015 106 : if (!directory_exists(file))
2016 105 : make_directory(file);
2017 106 : }
2018 :
2019 : static void
2020 3 : drop_database_if_exists(const char *dbname)
2021 : {
2022 3 : StringInfo buf = psql_start_command();
2023 :
2024 : /* Set warning level so we don't see chatter about nonexistent DB */
2025 3 : psql_add_command(buf, "SET client_min_messages = warning");
2026 3 : psql_add_command(buf, "DROP DATABASE IF EXISTS \"%s\"", dbname);
2027 3 : psql_end_command(buf, "postgres");
2028 3 : }
2029 :
2030 : static void
2031 108 : create_database(const char *dbname)
2032 : {
2033 108 : StringInfo buf = psql_start_command();
2034 : _stringlist *sl;
2035 :
2036 : /*
2037 : * We use template0 so that any installation-local cruft in template1 will
2038 : * not mess up the tests.
2039 : */
2040 108 : if (encoding)
2041 1 : psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
2042 1 : (nolocale) ? " LOCALE='C' LOCALE_PROVIDER='builtin'" : "");
2043 : else
2044 107 : psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
2045 107 : (nolocale) ? " LOCALE='C' LOCALE_PROVIDER='builtin'" : "");
2046 108 : psql_add_command(buf,
2047 : "ALTER DATABASE \"%s\" SET lc_messages TO 'C';"
2048 : "ALTER DATABASE \"%s\" SET lc_monetary TO 'C';"
2049 : "ALTER DATABASE \"%s\" SET lc_numeric TO 'C';"
2050 : "ALTER DATABASE \"%s\" SET lc_time TO 'C';"
2051 : "ALTER DATABASE \"%s\" SET bytea_output TO 'hex';"
2052 : "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
2053 : dbname, dbname, dbname, dbname, dbname, dbname);
2054 108 : psql_end_command(buf, "postgres");
2055 :
2056 : /*
2057 : * Install any requested extensions. We use CREATE IF NOT EXISTS so that
2058 : * this will work whether or not the extension is preinstalled.
2059 : */
2060 114 : for (sl = loadextension; sl != NULL; sl = sl->next)
2061 6 : psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
2062 108 : }
2063 :
2064 : static void
2065 0 : drop_role_if_exists(const char *rolename)
2066 : {
2067 0 : StringInfo buf = psql_start_command();
2068 :
2069 : /* Set warning level so we don't see chatter about nonexistent role */
2070 0 : psql_add_command(buf, "SET client_min_messages = warning");
2071 0 : psql_add_command(buf, "DROP ROLE IF EXISTS \"%s\"", rolename);
2072 0 : psql_end_command(buf, "postgres");
2073 0 : }
2074 :
2075 : static void
2076 8 : create_role(const char *rolename, const _stringlist *granted_dbs)
2077 : {
2078 8 : StringInfo buf = psql_start_command();
2079 :
2080 8 : psql_add_command(buf, "CREATE ROLE \"%s\" WITH LOGIN", rolename);
2081 20 : for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
2082 : {
2083 12 : psql_add_command(buf, "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
2084 12 : granted_dbs->str, rolename);
2085 : }
2086 8 : psql_end_command(buf, "postgres");
2087 8 : }
2088 :
2089 : static void
2090 0 : help(void)
2091 : {
2092 0 : printf(_("PostgreSQL regression test driver\n"));
2093 0 : printf(_("\n"));
2094 0 : printf(_("Usage:\n %s [OPTION]... [EXTRA-TEST]...\n"), progname);
2095 0 : printf(_("\n"));
2096 0 : printf(_("Options:\n"));
2097 0 : printf(_(" --bindir=BINPATH use BINPATH for programs that are run;\n"));
2098 0 : printf(_(" if empty, use PATH from the environment\n"));
2099 0 : printf(_(" --config-auth=DATADIR update authentication settings for DATADIR\n"));
2100 0 : printf(_(" --create-role=ROLE create the specified role before testing\n"));
2101 0 : printf(_(" --dbname=DB use database DB (default \"regression\")\n"));
2102 0 : printf(_(" --debug turn on debug mode in programs that are run\n"));
2103 0 : printf(_(" --dlpath=DIR look for dynamic libraries in DIR\n"));
2104 0 : printf(_(" --encoding=ENCODING use ENCODING as the encoding\n"));
2105 0 : printf(_(" --expecteddir=DIR take expected files from DIR (default \".\")\n"));
2106 0 : printf(_(" -h, --help show this help, then exit\n"));
2107 0 : printf(_(" --inputdir=DIR take input files from DIR (default \".\")\n"));
2108 0 : printf(_(" --launcher=CMD use CMD as launcher of psql\n"));
2109 0 : printf(_(" --load-extension=EXT load the named extension before running the\n"));
2110 0 : printf(_(" tests; can appear multiple times\n"));
2111 0 : printf(_(" --max-connections=N maximum number of concurrent connections\n"));
2112 0 : printf(_(" (default is 0, meaning unlimited)\n"));
2113 0 : printf(_(" --max-concurrent-tests=N maximum number of concurrent tests in schedule\n"));
2114 0 : printf(_(" (default is 0, meaning unlimited)\n"));
2115 0 : printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
2116 0 : printf(_(" --schedule=FILE use test ordering schedule from FILE\n"));
2117 0 : printf(_(" (can be used multiple times to concatenate)\n"));
2118 0 : printf(_(" --temp-instance=DIR create a temporary instance in DIR\n"));
2119 0 : printf(_(" --use-existing use an existing installation\n"));
2120 0 : printf(_(" -V, --version output version information, then exit\n"));
2121 0 : printf(_("\n"));
2122 0 : printf(_("Options for \"temp-instance\" mode:\n"));
2123 0 : printf(_(" --no-locale use C locale\n"));
2124 0 : printf(_(" --port=PORT start postmaster on PORT\n"));
2125 0 : printf(_(" --temp-config=FILE append contents of FILE to temporary config\n"));
2126 0 : printf(_("\n"));
2127 0 : printf(_("Options for using an existing installation:\n"));
2128 0 : printf(_(" --host=HOST use postmaster running on HOST\n"));
2129 0 : printf(_(" --port=PORT use postmaster running at PORT\n"));
2130 0 : printf(_(" --user=USER connect as USER\n"));
2131 0 : printf(_("\n"));
2132 0 : printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
2133 0 : printf(_("if the tests could not be run for some reason.\n"));
2134 0 : printf(_("\n"));
2135 0 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
2136 0 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
2137 0 : }
2138 :
2139 : int
2140 467 : regression_main(int argc, char *argv[],
2141 : init_function ifunc,
2142 : test_start_function startfunc,
2143 : postprocess_result_function postfunc)
2144 : {
2145 : static struct option long_options[] = {
2146 : {"help", no_argument, NULL, 'h'},
2147 : {"version", no_argument, NULL, 'V'},
2148 : {"dbname", required_argument, NULL, 1},
2149 : {"debug", no_argument, NULL, 2},
2150 : {"inputdir", required_argument, NULL, 3},
2151 : {"max-connections", required_argument, NULL, 5},
2152 : {"encoding", required_argument, NULL, 6},
2153 : {"outputdir", required_argument, NULL, 7},
2154 : {"schedule", required_argument, NULL, 8},
2155 : {"temp-instance", required_argument, NULL, 9},
2156 : {"no-locale", no_argument, NULL, 10},
2157 : {"host", required_argument, NULL, 13},
2158 : {"port", required_argument, NULL, 14},
2159 : {"user", required_argument, NULL, 15},
2160 : {"bindir", required_argument, NULL, 16},
2161 : {"dlpath", required_argument, NULL, 17},
2162 : {"create-role", required_argument, NULL, 18},
2163 : {"temp-config", required_argument, NULL, 19},
2164 : {"use-existing", no_argument, NULL, 20},
2165 : {"launcher", required_argument, NULL, 21},
2166 : {"load-extension", required_argument, NULL, 22},
2167 : {"config-auth", required_argument, NULL, 24},
2168 : {"max-concurrent-tests", required_argument, NULL, 25},
2169 : {"expecteddir", required_argument, NULL, 26},
2170 : {NULL, 0, NULL, 0}
2171 : };
2172 :
2173 : bool use_unix_sockets;
2174 : _stringlist *sl;
2175 : int c;
2176 : int i;
2177 : int option_index;
2178 : char buf[MAXPGPATH * 4];
2179 :
2180 467 : pg_logging_init(argv[0]);
2181 467 : progname = get_progname(argv[0]);
2182 467 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
2183 :
2184 467 : get_restricted_token();
2185 :
2186 467 : atexit(stop_postmaster);
2187 :
2188 : #if defined(WIN32)
2189 :
2190 : /*
2191 : * We don't use Unix-domain sockets on Windows by default (see comment at
2192 : * remove_temp() for a reason). Override at your own risk.
2193 : */
2194 : use_unix_sockets = getenv("PG_TEST_USE_UNIX_SOCKETS") ? true : false;
2195 : #else
2196 467 : use_unix_sockets = true;
2197 : #endif
2198 :
2199 467 : if (!use_unix_sockets)
2200 0 : hostname = "localhost";
2201 :
2202 : /*
2203 : * We call the initialization function here because that way we can set
2204 : * default parameters and let them be overwritten by the commandline.
2205 : */
2206 467 : ifunc(argc, argv);
2207 :
2208 467 : if (getenv("PG_REGRESS_DIFF_OPTS"))
2209 0 : pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
2210 :
2211 1338 : while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
2212 : {
2213 871 : switch (c)
2214 : {
2215 0 : case 'h':
2216 0 : help();
2217 0 : exit(0);
2218 0 : case 'V':
2219 0 : puts("pg_regress (PostgreSQL) " PG_VERSION);
2220 0 : exit(0);
2221 101 : case 1:
2222 :
2223 : /*
2224 : * If a default database was specified, we need to remove it
2225 : * before we add the specified one.
2226 : */
2227 101 : free_stringlist(&dblist);
2228 101 : split_to_stringlist(optarg, ",", &dblist);
2229 101 : break;
2230 0 : case 2:
2231 0 : debug = true;
2232 0 : break;
2233 104 : case 3:
2234 104 : inputdir = pg_strdup(optarg);
2235 104 : break;
2236 0 : case 5:
2237 0 : max_connections = atoi(optarg);
2238 0 : break;
2239 1 : case 6:
2240 1 : encoding = pg_strdup(optarg);
2241 1 : break;
2242 13 : case 7:
2243 13 : outputdir = pg_strdup(optarg);
2244 13 : break;
2245 7 : case 8:
2246 7 : add_stringlist_item(&schedulelist, optarg);
2247 7 : break;
2248 103 : case 9:
2249 103 : temp_instance = make_absolute_path(optarg);
2250 103 : break;
2251 2 : case 10:
2252 2 : nolocale = true;
2253 2 : break;
2254 4 : case 13:
2255 4 : hostname = pg_strdup(optarg);
2256 4 : break;
2257 3 : case 14:
2258 3 : port = atoi(optarg);
2259 3 : port_specified_by_user = true;
2260 3 : break;
2261 3 : case 15:
2262 3 : user = pg_strdup(optarg);
2263 3 : break;
2264 106 : case 16:
2265 : /* "--bindir=" means to use PATH */
2266 106 : if (strlen(optarg))
2267 0 : bindir = pg_strdup(optarg);
2268 : else
2269 106 : bindir = NULL;
2270 106 : break;
2271 7 : case 17:
2272 7 : dlpath = pg_strdup(optarg);
2273 7 : break;
2274 33 : case 18:
2275 33 : split_to_stringlist(optarg, ",", &extraroles);
2276 33 : break;
2277 11 : case 19:
2278 11 : add_stringlist_item(&temp_configs, optarg);
2279 11 : break;
2280 0 : case 20:
2281 0 : use_existing = true;
2282 0 : break;
2283 0 : case 21:
2284 0 : launcher = pg_strdup(optarg);
2285 0 : break;
2286 6 : case 22:
2287 6 : add_stringlist_item(&loadextension, optarg);
2288 6 : break;
2289 361 : case 24:
2290 361 : config_auth_datadir = pg_strdup(optarg);
2291 361 : break;
2292 4 : case 25:
2293 4 : max_concurrent_tests = atoi(optarg);
2294 4 : break;
2295 2 : case 26:
2296 2 : expecteddir = pg_strdup(optarg);
2297 2 : break;
2298 0 : default:
2299 : /* getopt_long already emitted a complaint */
2300 0 : pg_log_error_hint("Try \"%s --help\" for more information.",
2301 : progname);
2302 0 : exit(2);
2303 : }
2304 : }
2305 :
2306 : /*
2307 : * if we still have arguments, they are extra tests to run
2308 : */
2309 827 : while (argc - optind >= 1)
2310 : {
2311 360 : add_stringlist_item(&extra_tests, argv[optind]);
2312 360 : optind++;
2313 : }
2314 :
2315 : /*
2316 : * We must have a database to run the tests in; either a default name, or
2317 : * one supplied by the --dbname switch.
2318 : */
2319 467 : if (!(dblist && dblist->str && dblist->str[0]))
2320 : {
2321 0 : bail("no database name was specified");
2322 : }
2323 :
2324 467 : if (config_auth_datadir)
2325 : {
2326 : #ifdef ENABLE_SSPI
2327 : if (!use_unix_sockets)
2328 : config_sspi_auth(config_auth_datadir, user);
2329 : #endif
2330 361 : exit(0);
2331 : }
2332 :
2333 106 : if (temp_instance && !port_specified_by_user)
2334 :
2335 : /*
2336 : * To reduce chances of interference with parallel installations, use
2337 : * a port number starting in the private range (49152-65535)
2338 : * calculated from the version number. This aids non-Unix socket mode
2339 : * systems; elsewhere, the use of a private socket directory already
2340 : * prevents interference.
2341 : */
2342 103 : port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
2343 :
2344 106 : inputdir = make_absolute_path(inputdir);
2345 106 : outputdir = make_absolute_path(outputdir);
2346 106 : expecteddir = make_absolute_path(expecteddir);
2347 106 : dlpath = make_absolute_path(dlpath);
2348 :
2349 : /*
2350 : * Initialization
2351 : */
2352 106 : open_result_files();
2353 :
2354 106 : initialize_environment();
2355 :
2356 : #if defined(HAVE_GETRLIMIT)
2357 106 : unlimit_core_size();
2358 : #endif
2359 :
2360 106 : if (temp_instance)
2361 : {
2362 : StringInfoData cmd;
2363 : FILE *pg_conf;
2364 : const char *env_wait;
2365 : int wait_seconds;
2366 : const char *initdb_template_dir;
2367 : const char *keywords[4];
2368 : const char *values[4];
2369 : PGPing rv;
2370 : const char *initdb_extra_opts_env;
2371 :
2372 : /*
2373 : * Prepare the temp instance
2374 : */
2375 :
2376 103 : if (directory_exists(temp_instance))
2377 : {
2378 0 : if (!rmtree(temp_instance, true))
2379 : {
2380 0 : bail("could not remove temp instance \"%s\"", temp_instance);
2381 : }
2382 : }
2383 :
2384 : /* make the temp instance top directory */
2385 103 : make_directory(temp_instance);
2386 :
2387 : /* and a directory for log files */
2388 103 : snprintf(buf, sizeof(buf), "%s/log", outputdir);
2389 103 : if (!directory_exists(buf))
2390 102 : make_directory(buf);
2391 :
2392 103 : initdb_extra_opts_env = getenv("PG_TEST_INITDB_EXTRA_OPTS");
2393 :
2394 103 : initStringInfo(&cmd);
2395 :
2396 : /*
2397 : * Create data directory.
2398 : *
2399 : * If available, use a previously initdb'd cluster as a template by
2400 : * copying it. For a lot of tests, that's substantially cheaper.
2401 : *
2402 : * There's very similar code in Cluster.pm, but we can't easily de
2403 : * duplicate it until we require perl at build time.
2404 : */
2405 103 : initdb_template_dir = getenv("INITDB_TEMPLATE");
2406 103 : if (initdb_template_dir == NULL || nolocale || debug || initdb_extra_opts_env)
2407 : {
2408 2 : note("initializing database system by running initdb");
2409 :
2410 4 : appendStringInfo(&cmd,
2411 : "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync",
2412 2 : bindir ? bindir : "",
2413 2 : bindir ? "/" : "",
2414 : temp_instance);
2415 2 : if (debug)
2416 0 : appendStringInfoString(&cmd, " --debug");
2417 2 : if (nolocale)
2418 2 : appendStringInfoString(&cmd, " --no-locale");
2419 2 : if (initdb_extra_opts_env)
2420 0 : appendStringInfo(&cmd, " %s", initdb_extra_opts_env);
2421 2 : appendStringInfo(&cmd, " > \"%s/log/initdb.log\" 2>&1", outputdir);
2422 2 : fflush(NULL);
2423 2 : if (system(cmd.data))
2424 : {
2425 0 : bail("initdb failed\n"
2426 : "# Examine \"%s/log/initdb.log\" for the reason.\n"
2427 : "# Command was: %s",
2428 : outputdir, cmd.data);
2429 : }
2430 : }
2431 : else
2432 : {
2433 : #ifndef WIN32
2434 101 : const char *copycmd = "cp -RPp \"%s\" \"%s/data\"";
2435 101 : int expected_exitcode = 0;
2436 : #else
2437 : const char *copycmd = "robocopy /E /NJS /NJH /NFL /NDL /NP \"%s\" \"%s/data\"";
2438 : int expected_exitcode = 1; /* 1 denotes files were copied */
2439 : #endif
2440 :
2441 101 : note("initializing database system by copying initdb template");
2442 :
2443 101 : appendStringInfo(&cmd,
2444 : copycmd,
2445 : initdb_template_dir,
2446 : temp_instance);
2447 101 : appendStringInfo(&cmd, " > \"%s/log/initdb.log\" 2>&1", outputdir);
2448 101 : fflush(NULL);
2449 101 : if (system(cmd.data) != expected_exitcode)
2450 : {
2451 0 : bail("copying of initdb template failed\n"
2452 : "# Examine \"%s/log/initdb.log\" for the reason.\n"
2453 : "# Command was: %s",
2454 : outputdir, cmd.data);
2455 : }
2456 : }
2457 :
2458 103 : pfree(cmd.data);
2459 :
2460 : /*
2461 : * Adjust the default postgresql.conf for regression testing. The user
2462 : * can specify a file to be appended; in any case we expand logging
2463 : * and set max_prepared_transactions to enable testing of prepared
2464 : * xacts. (Note: to reduce the probability of unexpected shmmax
2465 : * failures, don't set max_prepared_transactions any higher than
2466 : * actually needed by the prepared_xacts regression test.)
2467 : */
2468 103 : snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
2469 103 : pg_conf = fopen(buf, "a");
2470 103 : if (pg_conf == NULL)
2471 0 : bail("could not open \"%s\" for adding extra config: %m", buf);
2472 :
2473 103 : fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
2474 103 : fputs("log_autovacuum_min_duration = 0\n", pg_conf);
2475 103 : fputs("log_autoanalyze_min_duration = 0\n", pg_conf);
2476 103 : fputs("log_checkpoints = on\n", pg_conf);
2477 103 : fputs("log_line_prefix = '%m %b[%p] %q%a '\n", pg_conf);
2478 103 : fputs("log_lock_waits = on\n", pg_conf);
2479 103 : fputs("log_temp_files = 128kB\n", pg_conf);
2480 103 : fputs("max_prepared_transactions = 2\n", pg_conf);
2481 :
2482 114 : for (sl = temp_configs; sl != NULL; sl = sl->next)
2483 : {
2484 11 : char *temp_config = sl->str;
2485 : FILE *extra_conf;
2486 : char line_buf[1024];
2487 :
2488 11 : extra_conf = fopen(temp_config, "r");
2489 11 : if (extra_conf == NULL)
2490 : {
2491 0 : bail("could not open \"%s\" to read extra config: %m",
2492 : temp_config);
2493 : }
2494 33 : while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2495 22 : fputs(line_buf, pg_conf);
2496 11 : fclose(extra_conf);
2497 : }
2498 :
2499 103 : fclose(pg_conf);
2500 :
2501 : #ifdef ENABLE_SSPI
2502 : if (!use_unix_sockets)
2503 : {
2504 : /*
2505 : * Since we successfully used the same buffer for the much-longer
2506 : * "initdb" command, this can't truncate.
2507 : */
2508 : snprintf(buf, sizeof(buf), "%s/data", temp_instance);
2509 : config_sspi_auth(buf, NULL);
2510 : }
2511 : #endif
2512 :
2513 : /*
2514 : * Prepare the connection params for checking the state of the server
2515 : * before starting the tests.
2516 : */
2517 103 : sprintf(portstr, "%d", port);
2518 103 : keywords[0] = "dbname";
2519 103 : values[0] = "postgres";
2520 103 : keywords[1] = "port";
2521 103 : values[1] = portstr;
2522 103 : keywords[2] = "host";
2523 103 : values[2] = hostname ? hostname : sockdir;
2524 103 : keywords[3] = NULL;
2525 103 : values[3] = NULL;
2526 :
2527 : /*
2528 : * Check if there is a postmaster running already.
2529 : */
2530 103 : for (i = 0; i < 16; i++)
2531 : {
2532 103 : rv = PQpingParams(keywords, values, 1);
2533 :
2534 103 : if (rv == PQPING_OK)
2535 : {
2536 0 : if (port_specified_by_user || i == 15)
2537 : {
2538 0 : note("port %d apparently in use", port);
2539 0 : if (!port_specified_by_user)
2540 0 : note("could not determine an available port");
2541 0 : bail("Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.");
2542 : }
2543 :
2544 0 : note("port %d apparently in use, trying %d", port, port + 1);
2545 0 : port++;
2546 0 : sprintf(portstr, "%d", port);
2547 0 : setenv("PGPORT", portstr, 1);
2548 : }
2549 : else
2550 103 : break;
2551 : }
2552 :
2553 : /*
2554 : * Start the temp postmaster
2555 : */
2556 515 : snprintf(buf, sizeof(buf),
2557 : "\"%s%spostgres\" -D \"%s/data\" -F%s "
2558 : "-c \"listen_addresses=%s\" -k \"%s\" "
2559 : "> \"%s/log/postmaster.log\" 2>&1",
2560 103 : bindir ? bindir : "",
2561 103 : bindir ? "/" : "",
2562 103 : temp_instance, debug ? " -d 5" : "",
2563 206 : hostname ? hostname : "", sockdir ? sockdir : "",
2564 : outputdir);
2565 103 : postmaster_pid = spawn_process(buf);
2566 103 : if (postmaster_pid == INVALID_PID)
2567 0 : bail("could not spawn postmaster: %m");
2568 :
2569 : /*
2570 : * Wait till postmaster is able to accept connections; normally takes
2571 : * only a fraction of a second or so, but Cygwin is reportedly *much*
2572 : * slower, and test builds using Valgrind or similar tools might be
2573 : * too. Hence, allow the default timeout of 60 seconds to be
2574 : * overridden from the PGCTLTIMEOUT environment variable.
2575 : */
2576 103 : env_wait = getenv("PGCTLTIMEOUT");
2577 103 : if (env_wait != NULL)
2578 : {
2579 0 : wait_seconds = atoi(env_wait);
2580 0 : if (wait_seconds <= 0)
2581 0 : wait_seconds = 60;
2582 : }
2583 : else
2584 103 : wait_seconds = 60;
2585 :
2586 446 : for (i = 0; i < wait_seconds * WAIT_TICKS_PER_SECOND; i++)
2587 : {
2588 : /*
2589 : * It's fairly unlikely that the server is responding immediately
2590 : * so we start with sleeping before checking instead of the other
2591 : * way around.
2592 : */
2593 446 : pg_usleep(1000000L / WAIT_TICKS_PER_SECOND);
2594 :
2595 446 : rv = PQpingParams(keywords, values, 1);
2596 :
2597 : /* Done if the server is running and accepts connections */
2598 446 : if (rv == PQPING_OK)
2599 103 : break;
2600 :
2601 343 : if (rv == PQPING_NO_ATTEMPT)
2602 0 : bail("attempting to connect to postmaster failed");
2603 :
2604 : /*
2605 : * Fail immediately if postmaster has exited
2606 : */
2607 : #ifndef WIN32
2608 343 : if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
2609 : #else
2610 : if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2611 : #endif
2612 : {
2613 0 : bail("postmaster failed, examine \"%s/log/postmaster.log\" for the reason",
2614 : outputdir);
2615 : }
2616 : }
2617 103 : if (i >= wait_seconds * WAIT_TICKS_PER_SECOND)
2618 : {
2619 0 : diag("postmaster did not respond within %d seconds, examine \"%s/log/postmaster.log\" for the reason",
2620 : wait_seconds, outputdir);
2621 :
2622 : /*
2623 : * If we get here, the postmaster is probably wedged somewhere in
2624 : * startup. Try to kill it ungracefully rather than leaving a
2625 : * stuck postmaster that might interfere with subsequent test
2626 : * attempts.
2627 : */
2628 : #ifndef WIN32
2629 0 : if (kill(postmaster_pid, SIGKILL) != 0 && errno != ESRCH)
2630 0 : bail("could not kill failed postmaster: %m");
2631 : #else
2632 : if (TerminateProcess(postmaster_pid, 255) == 0)
2633 : bail("could not kill failed postmaster: error code %lu",
2634 : GetLastError());
2635 : #endif
2636 0 : bail("postmaster failed");
2637 : }
2638 :
2639 103 : postmaster_running = true;
2640 :
2641 : #ifdef _WIN64
2642 : /* need a series of two casts to convert HANDLE without compiler warning */
2643 : #define ULONGPID(x) (unsigned long) (unsigned long long) (x)
2644 : #else
2645 : #define ULONGPID(x) (unsigned long) (x)
2646 : #endif
2647 103 : note("using temp instance on port %d with PID %lu",
2648 : port, ULONGPID(postmaster_pid));
2649 : }
2650 : else
2651 : {
2652 : /*
2653 : * Using an existing installation, so may need to get rid of
2654 : * pre-existing database(s) and role(s)
2655 : */
2656 3 : if (!use_existing)
2657 : {
2658 6 : for (sl = dblist; sl; sl = sl->next)
2659 3 : drop_database_if_exists(sl->str);
2660 3 : for (sl = extraroles; sl; sl = sl->next)
2661 0 : drop_role_if_exists(sl->str);
2662 : }
2663 : }
2664 :
2665 : /*
2666 : * Create the test database(s) and role(s)
2667 : */
2668 106 : if (!use_existing)
2669 : {
2670 214 : for (sl = dblist; sl; sl = sl->next)
2671 108 : create_database(sl->str);
2672 114 : for (sl = extraroles; sl; sl = sl->next)
2673 8 : create_role(sl->str, dblist);
2674 : }
2675 :
2676 : /*
2677 : * Ready to run the tests
2678 : */
2679 113 : for (sl = schedulelist; sl != NULL; sl = sl->next)
2680 : {
2681 7 : run_schedule(sl->str, startfunc, postfunc);
2682 : }
2683 :
2684 466 : for (sl = extra_tests; sl != NULL; sl = sl->next)
2685 : {
2686 360 : run_single_test(sl->str, startfunc, postfunc);
2687 : }
2688 :
2689 : /*
2690 : * Shut down temp installation's postmaster
2691 : */
2692 106 : if (temp_instance)
2693 : {
2694 103 : stop_postmaster();
2695 : }
2696 :
2697 : /*
2698 : * If there were no errors, remove the temp instance immediately to
2699 : * conserve disk space. (If there were errors, we leave the instance in
2700 : * place for possible manual investigation.)
2701 : */
2702 106 : if (temp_instance && fail_count == 0)
2703 : {
2704 103 : if (!rmtree(temp_instance, true))
2705 0 : diag("could not remove temp instance \"%s\"",
2706 : temp_instance);
2707 : }
2708 :
2709 : /*
2710 : * Emit a TAP compliant Plan
2711 : */
2712 106 : plan(fail_count + success_count);
2713 :
2714 : /*
2715 : * Emit nice-looking summary message
2716 : */
2717 106 : if (fail_count == 0)
2718 106 : note("All %d tests passed.", success_count);
2719 : else
2720 0 : diag("%d of %d tests failed.", fail_count, success_count + fail_count);
2721 :
2722 106 : if (file_size(difffilename) > 0)
2723 : {
2724 0 : diag("The differences that caused some tests to fail can be viewed in the file \"%s\".",
2725 : difffilename);
2726 0 : diag("A copy of the test summary that you see above is saved in the file \"%s\".",
2727 : logfilename);
2728 : }
2729 : else
2730 : {
2731 106 : unlink(difffilename);
2732 106 : unlink(logfilename);
2733 : }
2734 :
2735 106 : fclose(logfile);
2736 106 : logfile = NULL;
2737 :
2738 106 : if (fail_count != 0)
2739 0 : exit(1);
2740 :
2741 106 : return 0;
2742 : }
|