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