Age Owner 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
5938 andrew 167 GIC 84 : unlimit_core_size(void)
168 : {
169 : struct rlimit lim;
170 :
5624 bruce 171 84 : getrlimit(RLIMIT_CORE, &lim);
5938 andrew 172 84 : if (lim.rlim_max == 0)
173 : {
9 dgustafsson 174 UNC 0 : diag("could not set core size: disallowed by hard limit");
5938 andrew 175 UIC 0 : return;
176 : }
5938 andrew 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;
5624 bruce 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
3260 190 3382 : add_stringlist_item(_stringlist **listhead, const char *str)
191 : {
2413 tgl 192 3382 : _stringlist *newentry = pg_malloc(sizeof(_stringlist));
193 : _stringlist *oldentry;
194 :
195 3382 : newentry->str = pg_strdup(str);
6108 196 3382 : newentry->next = NULL;
197 3382 : if (*listhead == NULL)
6108 tgl 198 CBC 2785 : *listhead = newentry;
199 : else
200 : {
6108 tgl 201 GIC 2607 : for (oldentry = *listhead; oldentry->next; oldentry = oldentry->next)
6031 bruce 202 ECB : /* skip */ ;
6108 tgl 203 CBC 597 : oldentry->next = newentry;
204 : }
6108 tgl 205 GBC 3382 : }
6108 tgl 206 EUB :
207 : /*
5780 magnus 208 ECB : * Free a stringlist.
209 : */
210 : static void
3260 bruce 211 CBC 2900 : free_stringlist(_stringlist **listhead)
212 : {
5780 magnus 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 : }
5780 magnus 221 ECB :
222 : /*
223 : * Split a delimited string into a stringlist
224 : */
225 : static void
3260 bruce 226 CBC 100 : split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
5780 magnus 227 ECB : {
2413 tgl 228 CBC 100 : char *sc = pg_strdup(s);
5624 bruce 229 100 : char *token = strtok(sc, delim);
230 :
5780 magnus 231 GIC 205 : while (token)
5780 magnus 232 ECB : {
5780 magnus 233 GIC 105 : add_stringlist_item(listhead, token);
5780 magnus 234 CBC 105 : token = strtok(NULL, delim);
235 : }
236 100 : free(sc);
5780 magnus 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 : */
6108 tgl 245 ECB : static void
9 dgustafsson 246 UNC 0 : bail_out(bool noatexit, const char *fmt,...)
6108 tgl 247 ECB : {
248 : va_list ap;
249 :
6108 tgl 250 LBC 0 : va_start(ap, fmt);
9 dgustafsson 251 UNC 0 : emit_tap_output_v(BAIL, fmt, ap);
6108 tgl 252 LBC 0 : va_end(ap);
253 :
9 dgustafsson 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 : */
6108 tgl 270 ECB : static void
9 dgustafsson 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 : }
6108 tgl 292 ECB :
293 : static void
9 dgustafsson 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);
6108 tgl 299 1110 : }
300 :
301 : static void
9 dgustafsson 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
9 dgustafsson 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)
9 dgustafsson 343 UNC 0 : fp = stderr;
344 : else
9 dgustafsson 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);
6108 tgl 375 GBC 2037 : if (logfile)
9 dgustafsson 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 : {
9 dgustafsson 392 UNC 0 : fprintf(stdout, "Bail out!");
393 0 : if (logfile)
394 0 : fprintf(logfile, "Bail out!");
395 : }
396 :
9 dgustafsson 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 : }
6108 tgl 407 EUB :
408 : /*
409 : * shut down temp postmaster
410 : */
411 : static void
6108 tgl 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",
2908 peter_e 422 82 : bindir ? bindir : "",
423 82 : bindir ? "/" : "",
424 : temp_instance);
223 tgl 425 GNC 82 : fflush(NULL);
5248 peter_e 426 GIC 82 : r = system(buf);
427 82 : if (r != 0)
5248 peter_e 428 ECB : {
429 : /* Not using the normal bail() as we want _exit */
9 dgustafsson 430 UNC 0 : bail_noatexit(_("could not stop postmaster: exit code was %d"), r);
431 : }
432 :
6108 tgl 433 GIC 82 : postmaster_running = false;
434 : }
435 385 : }
436 :
437 : /*
438 : * Remove the socket temporary directory. pg_regress never waits for a
3221 noah 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
1105 peter 444 : * on Windows, pg_regress does not use Unix sockets by default.
445 : */
446 : static void
3221 noah 447 GBC 82 : remove_temp(void)
448 : {
3221 noah 449 GIC 82 : Assert(temp_sockdir);
450 82 : unlink(sockself);
451 82 : unlink(socklock);
452 82 : rmdir(temp_sockdir);
3221 noah 453 GBC 82 : }
3221 noah 454 EUB :
455 : /*
456 : * Signal handler that calls remove_temp() and reraises the signal.
457 : */
458 : static void
207 tgl 459 UNC 0 : signal_remove_temp(SIGNAL_ARGS)
3221 noah 460 EUB : {
3221 noah 461 UIC 0 : remove_temp();
3221 noah 462 EUB :
207 tgl 463 UNC 0 : pqsignal(postgres_signal_arg, SIG_DFL);
464 0 : raise(postgres_signal_arg);
3221 noah 465 UIC 0 : }
466 :
3221 noah 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 *
3221 noah 480 GIC 82 : make_temp_sockdir(void)
481 : {
1106 peter 482 82 : char *template = psprintf("%s/pg_regress-XXXXXX",
483 82 : getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
484 :
3221 noah 485 82 : temp_sockdir = mkdtemp(template);
486 82 : if (temp_sockdir == NULL)
3221 noah 487 ECB : {
9 dgustafsson 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. */
3221 noah 493 GIC 82 : UNIXSOCK_PATH(sockself, port, temp_sockdir);
494 82 : snprintf(socklock, sizeof(socklock), "%s.lock", sockself);
3221 noah 495 ECB :
496 : /* Remove the directory during clean exit. */
3221 noah 497 CBC 82 : atexit(remove_temp);
3221 noah 498 ECB :
499 : /*
500 : * Remove the directory before dying to the usual signals. Omit SIGQUIT,
501 : * preserving it as a quick, untidy exit.
502 : */
3221 noah 503 GIC 82 : pqsignal(SIGHUP, signal_remove_temp);
504 82 : pqsignal(SIGINT, signal_remove_temp);
3221 noah 505 CBC 82 : pqsignal(SIGPIPE, signal_remove_temp);
3221 noah 506 GIC 82 : pqsignal(SIGTERM, signal_remove_temp);
507 :
508 82 : return temp_sockdir;
509 : }
3221 noah 510 ECB :
6108 tgl 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
6108 tgl 524 GIC 42 : string_matches_pattern(const char *str, const char *pattern)
525 : {
6108 tgl 526 CBC 78 : while (*str && *pattern)
6108 tgl 527 ECB : {
6108 tgl 528 GIC 78 : if (*pattern == '.' && pattern[1] == '*')
529 : {
530 24 : pattern += 2;
531 : /* Trailing .* matches everything. */
532 24 : if (*pattern == '\0')
6108 tgl 533 LBC 0 : return true;
534 :
6108 tgl 535 EUB : /*
536 : * Otherwise, scan for a text position at which we can match the
537 : * rest of the pattern.
538 : */
6108 tgl 539 GIC 282 : while (*str)
6108 tgl 540 ECB : {
541 : /*
542 : * Optimization to prevent most recursion: don't recurse
543 : * unless first pattern char might match this text char.
544 : */
6108 tgl 545 CBC 258 : if (*str == *pattern || *pattern == '.')
6108 tgl 546 ECB : {
6108 tgl 547 GIC 36 : if (string_matches_pattern(str, pattern))
6108 tgl 548 LBC 0 : return true;
549 : }
550 :
6108 tgl 551 GIC 258 : str++;
552 : }
553 :
554 : /*
6108 tgl 555 ECB : * End of text with no match.
556 : */
6108 tgl 557 CBC 24 : return false;
558 : }
6108 tgl 559 GIC 54 : else if (*pattern != '.' && *str != *pattern)
560 : {
561 : /*
562 : * Not the single-character wildcard and no explicit match? Then
6108 tgl 563 ECB : * time to quit...
564 : */
6108 tgl 565 CBC 18 : return false;
6108 tgl 566 ECB : }
567 :
6108 tgl 568 CBC 36 : str++;
569 36 : pattern++;
6108 tgl 570 ECB : }
571 :
6108 tgl 572 UIC 0 : if (*pattern == '\0')
6108 tgl 573 UBC 0 : return true; /* end of pattern, so declare match */
574 :
575 : /* End of input string. Do we have matching pattern remaining? */
6108 tgl 576 LBC 0 : while (*pattern == '.' && pattern[1] == '*')
6108 tgl 577 UIC 0 : pattern += 2;
6108 tgl 578 LBC 0 : if (*pattern == '\0')
6108 tgl 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),
6108 tgl 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
3260 bruce 593 : * matched against is the config.guess output. (In the shell-script version,
6108 tgl 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
6108 tgl 598 GIC 84 : load_resultmap(void)
599 : {
600 : char buf[MAXPGPATH];
601 : FILE *f;
6108 tgl 602 EUB :
603 : /* scan the file ... */
6108 tgl 604 GBC 84 : snprintf(buf, sizeof(buf), "%s/resultmap", inputdir);
6031 bruce 605 GIC 84 : f = fopen(buf, "r");
6108 tgl 606 GBC 84 : if (!f)
6108 tgl 607 EUB : {
608 : /* OK if it doesn't exist, else complain */
6108 tgl 609 GIC 81 : if (errno == ENOENT)
610 81 : return;
9 dgustafsson 611 UNC 0 : bail("could not open file \"%s\" for reading: %s",
612 : buf, strerror(errno));
613 : }
614 :
6108 tgl 615 GIC 12 : while (fgets(buf, sizeof(buf), f))
616 : {
617 : char *platform;
618 : char *file_type;
619 : char *expected;
620 : int i;
621 :
6108 tgl 622 ECB : /* strip trailing whitespace, especially the newline */
6108 tgl 623 GIC 6 : i = strlen(buf);
6031 bruce 624 CBC 12 : while (i > 0 && isspace((unsigned char) buf[i - 1]))
6108 tgl 625 6 : buf[--i] = '\0';
626 :
6108 tgl 627 ECB : /* parse out the line fields */
5780 magnus 628 CBC 6 : file_type = strchr(buf, ':');
5780 magnus 629 GIC 6 : if (!file_type)
5780 magnus 630 EUB : {
9 dgustafsson 631 UNC 0 : bail("incorrectly formatted resultmap entry: %s", buf);
632 : }
5780 magnus 633 CBC 6 : *file_type++ = '\0';
5780 magnus 634 ECB :
5780 magnus 635 GIC 6 : platform = strchr(file_type, ':');
6108 tgl 636 6 : if (!platform)
6108 tgl 637 ECB : {
9 dgustafsson 638 UNC 0 : bail("incorrectly formatted resultmap entry: %s", buf);
639 : }
6108 tgl 640 GIC 6 : *platform++ = '\0';
6108 tgl 641 CBC 6 : expected = strchr(platform, '=');
642 6 : if (!expected)
6108 tgl 643 ECB : {
9 dgustafsson 644 UNC 0 : bail("incorrectly formatted resultmap entry: %s", buf);
645 : }
6108 tgl 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 : {
2413 tgl 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);
2413 tgl 660 LBC 0 : entry->resultfile = pg_strdup(expected);
6108 tgl 661 UIC 0 : entry->next = resultmap;
6108 tgl 662 LBC 0 : resultmap = entry;
663 : }
6108 tgl 664 ECB : }
6108 tgl 665 GIC 3 : fclose(f);
6108 tgl 666 ECB : }
667 :
5780 magnus 668 : /*
5780 magnus 669 EUB : * Check in resultmap if we should be looking at a different file
670 : */
671 : static
672 : const char *
5624 bruce 673 GIC 1236 : get_expectfile(const char *testname, const char *file)
674 : {
5624 bruce 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.
5780 magnus 681 : */
5780 magnus 682 GIC 1236 : if (!file || !(file_type = strrchr(file, '.')))
5780 magnus 683 LBC 0 : return NULL;
5780 magnus 684 EUB :
5780 magnus 685 GIC 1236 : file_type++;
686 :
5780 magnus 687 CBC 1236 : for (rm = resultmap; rm != NULL; rm = rm->next)
688 : {
5780 magnus 689 UIC 0 : if (strcmp(testname, rm->test) == 0 && strcmp(file_type, rm->type) == 0)
690 : {
691 0 : return rm->resultfile;
692 : }
5780 magnus 693 ECB : }
694 :
5780 magnus 695 CBC 1236 : return NULL;
696 : }
697 :
698 : /*
699 : * Prepare environment variables for running regression tests
700 : */
6108 tgl 701 ECB : static void
6108 tgl 702 GIC 84 : initialize_environment(void)
703 : {
1321 tgl 704 ECB : /*
818 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 : */
830 tgl 708 GBC 84 : setenv("PGAPPNAME", "pg_regress", 1);
4065 peter_e 709 EUB :
710 : /*
711 : * Set variables that the test scripts may need to refer to.
475 tgl 712 : */
475 tgl 713 GBC 84 : setenv("PG_ABS_SRCDIR", inputdir, 1);
714 84 : setenv("PG_ABS_BUILDDIR", outputdir, 1);
715 84 : setenv("PG_LIBDIR", dlpath, 1);
475 tgl 716 GIC 84 : setenv("PG_DLSUFFIX", DLSUFFIX, 1);
475 tgl 717 EUB :
5170 peter_e 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.
3005 noah 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);
6108 tgl 740 : #endif
5170 peter_e 741 : }
6108 tgl 742 :
743 : /*
744 : * Set translation-related settings to English; otherwise psql will
5050 bruce 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
5050 bruce 747 EUB : * is actually called.)
748 : */
5169 peter_e 749 GIC 84 : unsetenv("LANGUAGE");
750 84 : unsetenv("LC_ALL");
830 tgl 751 CBC 84 : setenv("LC_MESSAGES", "C", 1);
752 :
753 : /*
754 : * Set encoding as requested
755 : */
6108 tgl 756 GIC 84 : if (encoding)
830 757 2 : setenv("PGCLIENTENCODING", encoding, 1);
758 : else
6108 tgl 759 CBC 82 : unsetenv("PGCLIENTENCODING");
6108 tgl 760 ECB :
761 : /*
762 : * Set timezone and datestyle for datetime-related tests
763 : */
830 tgl 764 CBC 84 : setenv("PGTZ", "PST8PDT", 1);
765 84 : setenv("PGDATESTYLE", "Postgres, MDY", 1);
766 :
5248 tgl 767 EUB : /*
768 : * Likewise set intervalstyle to ensure consistent results. This is a bit
5050 bruce 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.
5248 tgl 771 : */
772 : {
5247 tgl 773 GIC 84 : const char *my_pgoptions = "-c intervalstyle=postgres_verbose";
5248 tgl 774 GBC 84 : const char *old_pgoptions = getenv("PGOPTIONS");
775 : char *new_pgoptions;
5248 tgl 776 ECB :
5248 tgl 777 CBC 84 : if (!old_pgoptions)
778 84 : old_pgoptions = "";
830 tgl 779 GIC 84 : new_pgoptions = psprintf("%s %s",
3456 tgl 780 EUB : old_pgoptions, my_pgoptions);
830 tgl 781 GIC 84 : setenv("PGOPTIONS", new_pgoptions, 1);
830 tgl 782 CBC 84 : free(new_pgoptions);
783 : }
784 :
2908 peter_e 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
6031 bruce 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
3221 noah 792 EUB : * PGHOST depending on whether we are using TCP or Unix sockets.
793 : *
532 andrew 794 : * This list should be kept in sync with PostgreSQL/Test/Utils.pm.
6108 tgl 795 : */
665 michael 796 GBC 82 : unsetenv("PGCHANNELBINDING");
665 michael 797 EUB : /* PGCLIENTENCODING, see above */
665 michael 798 GBC 82 : unsetenv("PGCONNECT_TIMEOUT");
665 michael 799 GIC 82 : unsetenv("PGDATA");
6108 tgl 800 82 : unsetenv("PGDATABASE");
665 michael 801 CBC 82 : unsetenv("PGGSSENCMODE");
665 michael 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");
6108 tgl 809 CBC 82 : unsetenv("PGSERVICE");
665 michael 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");
6108 tgl 817 82 : unsetenv("PGSSLMODE");
665 michael 818 CBC 82 : unsetenv("PGSSLROOTCERT");
665 michael 819 GBC 82 : unsetenv("PGSSLSNI");
665 michael 820 GIC 82 : unsetenv("PGTARGETSESSIONATTRS");
665 michael 821 CBC 82 : unsetenv("PGUSER");
822 : /* PGPORT, see below */
665 michael 823 ECB : /* PGHOST, see below */
824 :
6108 tgl 825 GIC 82 : if (hostname != NULL)
830 tgl 826 UBC 0 : setenv("PGHOST", hostname, 1);
827 : else
828 : {
3221 noah 829 GIC 82 : sockdir = getenv("PG_REGRESS_SOCK_DIR");
3221 noah 830 CBC 82 : if (!sockdir)
3221 noah 831 GIC 82 : sockdir = make_temp_sockdir();
830 tgl 832 82 : setenv("PGHOST", sockdir, 1);
833 : }
6108 834 82 : unsetenv("PGHOSTADDR");
835 82 : if (port != -1)
836 : {
837 : char s[16];
838 :
6031 bruce 839 CBC 82 : sprintf(s, "%d", port);
830 tgl 840 GIC 82 : setenv("PGPORT", s, 1);
841 : }
842 : }
843 : else
6108 tgl 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 : */
6108 tgl 852 GIC 2 : if (hostname != NULL)
853 : {
830 tgl 854 CBC 2 : setenv("PGHOST", hostname, 1);
6108 855 2 : unsetenv("PGHOSTADDR");
6108 tgl 856 ECB : }
6108 tgl 857 CBC 2 : if (port != -1)
6108 tgl 858 ECB : {
6031 bruce 859 : char s[16];
860 :
6031 bruce 861 GIC 2 : sprintf(s, "%d", port);
830 tgl 862 2 : setenv("PGPORT", s, 1);
863 : }
6108 864 2 : if (user != NULL)
830 tgl 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 : */
1290 tgl 873 GIC 2 : unsetenv("PGDATABASE");
874 :
875 : /*
876 : * Report what we're connecting to
877 : */
6108 878 2 : pghost = getenv("PGHOST");
879 2 : pgport = getenv("PGPORT");
6108 tgl 880 CBC 2 : if (!pghost)
401 tgl 881 ECB : {
882 : /* Keep this bit in sync with libpq's default host location: */
401 tgl 883 UIC 0 : if (DEFAULT_PGSOCKET_DIR[0])
884 : /* do nothing, we'll print "Unix socket" below */ ;
885 : else
401 tgl 886 LBC 0 : pghost = "localhost"; /* DefaultHost in fe-connect.c */
887 : }
6108 tgl 888 ECB :
6108 tgl 889 GIC 2 : if (pghost && pgport)
9 dgustafsson 890 GNC 2 : note("using postmaster on %s, port %s", pghost, pgport);
6108 tgl 891 GIC 2 : if (pghost && !pgport)
9 dgustafsson 892 UNC 0 : note("using postmaster on %s, default port", pghost);
6108 tgl 893 CBC 2 : if (!pghost && pgport)
9 dgustafsson 894 UNC 0 : note("using postmaster on Unix socket, port %s", pgport);
6108 tgl 895 GIC 2 : if (!pghost && !pgport)
9 dgustafsson 896 UNC 0 : note("using postmaster on Unix socket, default port");
897 : }
898 :
6108 tgl 899 GIC 84 : load_resultmap();
900 84 : }
901 :
1442 tgl 902 ECB : #ifdef ENABLE_SSPI
903 :
904 : /* support for config_sspi_auth() */
905 : static const char *
2439 peter_e 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 :
3035 noah 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 : }
2413 tgl 953 : tokenuser = pg_malloc(retlen);
3035 noah 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.
1379 tgl 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 : */
3035 noah 981 : static void
1379 tgl 982 : config_sspi_auth(const char *pgdata, const char *superuser_name)
983 : {
3035 noah 984 : const char *accountname,
3035 noah 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;
3035 noah 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 */
1379 tgl 998 : if (superuser_name == NULL)
3035 noah 999 : {
1379 tgl 1000 : /*
1001 : * Compute the default superuser name the same way initdb does.
1002 : *
1379 tgl 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)
1379 tgl 1009 ECB : {
1010 : bail("%s", errstr);
1379 tgl 1011 EUB : }
3035 noah 1012 ECB : }
3035 noah 1013 EUB :
3027 noah 1014 ECB : /*
3027 noah 1015 EUB : * Like initdb.c:setup_config(), determine whether the platform recognizes
1016 : * ::1 (IPv6 loopback) as a numeric host address string.
1017 : */
3027 noah 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
536 tgl 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 (;;)
536 tgl 1126 UIC 0 : {
1127 : va_list args;
1128 : int needed;
1129 :
536 tgl 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 */
536 tgl 1135 UIC 0 : enlargeStringInfo(&cmdbuf, needed);
1136 : }
1137 :
1138 : /* Now escape any shell double-quote metacharacters */
536 tgl 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 */
223 tgl 1160 GNC 94 : fflush(NULL);
536 tgl 1161 GIC 94 : if (system(buf->data) != 0)
1162 : {
1163 : /* psql probably already reported the error */
9 dgustafsson 1164 UNC 0 : bail("command failed: %s", buf->data);
1165 : }
1166 :
1167 : /* Clean up */
536 tgl 1168 GIC 94 : pfree(buf->data);
1169 94 : pfree(buf);
6108 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 : */
223 tgl 1196 GNC 1192 : fflush(NULL);
1197 :
1198 : #ifdef EXEC_BACKEND
1199 : pg_disable_aslr();
1200 : #endif
1201 :
6108 tgl 1202 GIC 1192 : pid = fork();
1203 2384 : if (pid == -1)
1204 : {
9 dgustafsson 1205 UNC 0 : bail("could not fork: %s", strerror(errno));
1206 : }
6108 tgl 1207 GIC 2384 : if (pid == 0)
1208 : {
1209 : /*
1210 : * In child
1211 : *
6031 bruce 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 : */
3465 peter_e 1216 : char *cmdline2;
1217 :
3456 tgl 1218 CBC 1192 : cmdline2 = psprintf("exec %s", cmdline);
5744 alvherre 1219 1192 : execl(shellprog, shellprog, "-c", cmdline2, (char *) NULL);
1220 : /* Not using the normal bail() here as we want _exit */
9 dgustafsson 1221 GNC 1192 : bail_noatexit("could not exec \"%s\": %s", shellprog, strerror(errno));
1222 : }
6108 tgl 1223 ECB : /* in parent */
6108 tgl 1224 GIC 1192 : return pid;
1225 : #else
1226 : PROCESS_INFORMATION pi;
1227 : char *cmdline2;
1228 : HANDLE restrictedToken;
1259 tgl 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)
1259 tgl 1234 EUB : comspec = "CMD";
1235 :
1236 : memset(&pi, 0, sizeof(pi));
1237 : cmdline2 = psprintf("\"%s\" /c \"%s\"", comspec, cmdline);
6108 tgl 1238 ECB :
2878 bruce 1239 : if ((restrictedToken =
1469 peter 1240 : CreateRestrictedProcess(cmdline2, &pi)) == 0)
4115 peter_e 1241 : exit(2);
6108 tgl 1242 :
6108 tgl 1243 EUB : CloseHandle(pi.hThread);
1244 : return pi.hProcess;
1245 : #endif
1246 : }
6108 tgl 1247 ECB :
1248 : /*
1249 : * Count bytes in file
1250 : */
1251 : static long
6108 tgl 1252 GIC 84 : file_size(const char *file)
1253 : {
6031 bruce 1254 ECB : long r;
6031 bruce 1255 GIC 84 : FILE *f = fopen(file, "r");
6108 tgl 1256 ECB :
6108 tgl 1257 CBC 84 : if (!f)
1258 : {
9 dgustafsson 1259 UNC 0 : diag("could not open file \"%s\" for reading: %s",
1260 : file, strerror(errno));
6108 tgl 1261 UIC 0 : return -1;
1262 : }
6108 tgl 1263 CBC 84 : fseek(f, 0, SEEK_END);
6108 tgl 1264 GIC 84 : r = ftell(f);
1265 84 : fclose(f);
1266 84 : return r;
1267 : }
6108 tgl 1268 ECB :
1269 : /*
1270 : * Count lines in file
1271 : */
6108 tgl 1272 EUB : static int
6108 tgl 1273 GIC 21 : file_line_count(const char *file)
1274 : {
1275 : int c;
6031 bruce 1276 CBC 21 : int l = 0;
1277 21 : FILE *f = fopen(file, "r");
6108 tgl 1278 ECB :
6108 tgl 1279 GIC 21 : if (!f)
1280 : {
9 dgustafsson 1281 UNC 0 : diag("could not open file \"%s\" for reading: %s",
1282 : file, strerror(errno));
6108 tgl 1283 UIC 0 : return -1;
1284 : }
6108 tgl 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)
6108 tgl 1296 ECB : {
6031 bruce 1297 GIC 2141 : FILE *f = fopen(file, "r");
1298 :
6108 tgl 1299 2141 : if (!f)
1300 2120 : return false;
1301 21 : fclose(f);
1302 21 : return true;
1303 : }
6108 tgl 1304 ECB :
1305 : static bool
6108 tgl 1306 GIC 332 : directory_exists(const char *dir)
1307 : {
1308 : struct stat st;
1309 :
6108 tgl 1310 CBC 332 : if (stat(dir, &st) != 0)
1311 255 : return false;
5487 tgl 1312 GIC 77 : if (S_ISDIR(st.st_mode))
6108 tgl 1313 GBC 77 : return true;
6108 tgl 1314 UIC 0 : return false;
6108 tgl 1315 ECB : }
1316 :
1317 : /* Create a directory */
1318 : static void
6108 tgl 1319 GIC 255 : make_directory(const char *dir)
1320 : {
6100 1321 255 : if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
1322 : {
9 dgustafsson 1323 UNC 0 : bail("could not create directory \"%s\": %s", dir, strerror(errno));
6108 tgl 1324 ECB : }
6108 tgl 1325 CBC 255 : }
1326 :
5780 magnus 1327 ECB : /*
1328 : * In: filename.ext, Return: filename_i.ext, where 0 < i <= 9
1329 : */
1330 : static char *
5780 magnus 1331 GIC 47 : get_alternative_expectfile(const char *expectfile, int i)
1332 : {
1333 : char *last_dot;
5624 bruce 1334 47 : int ssize = strlen(expectfile) + 2 + 1;
1335 : char *tmp;
1336 : char *s;
1337 :
3260 1338 47 : if (!(tmp = (char *) malloc(ssize)))
3326 sfrost 1339 UIC 0 : return NULL;
1340 :
3260 bruce 1341 GIC 47 : if (!(s = (char *) malloc(ssize)))
1342 : {
3324 sfrost 1343 UIC 0 : free(tmp);
1344 0 : return NULL;
1345 : }
1346 :
5780 magnus 1347 GIC 47 : strcpy(tmp, expectfile);
5624 bruce 1348 47 : last_dot = strrchr(tmp, '.');
5780 magnus 1349 47 : if (!last_dot)
1350 : {
5204 bruce 1351 UIC 0 : free(tmp);
1352 0 : free(s);
5780 magnus 1353 0 : return NULL;
1354 : }
5780 magnus 1355 GIC 47 : *last_dot = '\0';
5624 bruce 1356 47 : snprintf(s, ssize, "%s_%d.%s", tmp, i, last_dot + 1);
5780 magnus 1357 47 : free(tmp);
5780 magnus 1358 CBC 47 : return s;
1359 : }
1360 :
6107 tgl 1361 ECB : /*
1362 : * Run a "diff" command and also check that it didn't crash
1363 : */
1364 : static int
6097 bruce 1365 GBC 1257 : run_diff(const char *cmd, const char *filename)
1366 : {
6031 bruce 1367 EUB : int r;
1368 :
223 tgl 1369 GNC 1257 : fflush(NULL);
6107 tgl 1370 CBC 1257 : r = system(cmd);
1371 1257 : if (!WIFEXITED(r) || WEXITSTATUS(r) > 1)
6107 tgl 1372 ECB : {
9 dgustafsson 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,
6031 bruce 1379 ECB : * but produces nothing to stdout, so we check for that here.
1380 : */
1381 : if (WEXITSTATUS(r) == 1 && file_size(filename) <= 0)
6097 1382 : {
1383 : bail("diff command not found: %s", cmd);
1384 : }
1385 : #endif
6031 bruce 1386 EUB :
6097 bruce 1387 GIC 1257 : return WEXITSTATUS(r);
6107 tgl 1388 EUB : }
1389 :
6108 tgl 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
5780 magnus 1397 GIC 1236 : results_differ(const char *testname, const char *resultsfile, const char *default_expectfile)
1398 : {
1399 : char expectfile[MAXPGPATH];
6031 bruce 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;
5780 magnus 1407 : const char *platform_expectfile;
1408 :
1409 : /*
1410 : * We can pass either the resultsfile or the expectfile, they should have
5624 bruce 1411 : * the same type (filename.type) anyway.
1412 : */
5780 magnus 1413 GIC 1236 : platform_expectfile = get_expectfile(testname, resultsfile);
1414 :
3338 tgl 1415 CBC 1236 : strlcpy(expectfile, default_expectfile, sizeof(expectfile));
5624 bruce 1416 1236 : if (platform_expectfile)
6108 tgl 1417 ECB : {
5780 magnus 1418 : /*
2563 sfrost 1419 EUB : * Replace everything after the last slash in expectfile with what the
1420 : * platform_expectfile contains.
1421 : */
5624 bruce 1422 UIC 0 : char *p = strrchr(expectfile, '/');
1423 :
5780 magnus 1424 LBC 0 : if (p)
5780 magnus 1425 UIC 0 : strcpy(++p, platform_expectfile);
6108 tgl 1426 ECB : }
1427 :
6108 tgl 1428 EUB : /* Name to use for temporary diff file */
5780 magnus 1429 GIC 1236 : snprintf(diff, sizeof(diff), "%s.diff", resultsfile);
6108 tgl 1430 ECB :
1431 : /* OK, run the diff */
6108 tgl 1432 GIC 1236 : snprintf(cmd, sizeof(cmd),
1433 : "diff %s \"%s\" \"%s\" > \"%s\"",
1434 : basic_diff_opts, expectfile, resultsfile, diff);
1435 :
6108 tgl 1436 ECB : /* Is the diff file empty? */
6097 bruce 1437 GIC 1236 : if (run_diff(cmd, diff) == 0)
1438 : {
6108 tgl 1439 CBC 1217 : unlink(diff);
6108 tgl 1440 GIC 1217 : return false;
1441 : }
1442 :
6108 tgl 1443 ECB : /* There may be secondary comparison files that match better */
6108 tgl 1444 GBC 19 : best_line_count = file_line_count(diff);
6108 tgl 1445 GIC 19 : strcpy(best_expect_file, expectfile);
6108 tgl 1446 ECB :
6108 tgl 1447 GIC 47 : for (i = 0; i <= 9; i++)
6108 tgl 1448 EUB : {
5624 bruce 1449 : char *alt_expectfile;
1450 :
5780 magnus 1451 GIC 47 : alt_expectfile = get_alternative_expectfile(expectfile, i);
3326 sfrost 1452 CBC 47 : if (!alt_expectfile)
3326 sfrost 1453 ECB : {
9 dgustafsson 1454 UNC 0 : bail("Unable to check secondary comparison files: %s",
1455 : strerror(errno));
3326 sfrost 1456 EUB : }
1457 :
5780 magnus 1458 GIC 47 : if (!file_exists(alt_expectfile))
3326 sfrost 1459 ECB : {
3326 sfrost 1460 CBC 26 : free(alt_expectfile);
6108 tgl 1461 26 : continue;
3326 sfrost 1462 ECB : }
1463 :
6108 tgl 1464 GIC 21 : snprintf(cmd, sizeof(cmd),
1465 : "diff %s \"%s\" \"%s\" > \"%s\"",
1466 : basic_diff_opts, alt_expectfile, resultsfile, diff);
1467 :
6097 bruce 1468 21 : if (run_diff(cmd, diff) == 0)
6108 tgl 1469 ECB : {
6108 tgl 1470 GIC 19 : unlink(diff);
3326 sfrost 1471 19 : free(alt_expectfile);
6108 tgl 1472 19 : return false;
6108 tgl 1473 ECB : }
1474 :
6108 tgl 1475 CBC 2 : l = file_line_count(diff);
6108 tgl 1476 GIC 2 : if (l < best_line_count)
6108 tgl 1477 EUB : {
1478 : /* This diff was a better match than the last one */
6108 tgl 1479 GIC 2 : best_line_count = l;
3338 1480 2 : strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
1481 : }
5780 magnus 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 :
5780 magnus 1490 UIC 0 : if (platform_expectfile)
6095 andrew 1491 ECB : {
6095 andrew 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;
6095 andrew 1501 ECB : }
1502 :
6095 andrew 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;
3338 tgl 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 :
1558 peter 1517 ECB : /* Write diff header */
6108 tgl 1518 UIC 0 : difffile = fopen(difffilename, "a");
6108 tgl 1519 LBC 0 : if (difffile)
6108 tgl 1520 ECB : {
6108 tgl 1521 UIC 0 : fprintf(difffile,
1522 : "diff %s %s %s\n",
1523 : pretty_diff_opts, best_expect_file, resultsfile);
1524 0 : fclose(difffile);
1525 : }
6108 tgl 1526 EUB :
1527 : /* Run diff */
1558 peter 1528 UBC 0 : snprintf(cmd, sizeof(cmd),
1558 peter 1529 EUB : "diff %s \"%s\" \"%s\" >> \"%s\"",
1530 : pretty_diff_opts, best_expect_file, resultsfile, difffilename);
1558 peter 1531 UIC 0 : run_diff(cmd, difffilename);
1532 :
6108 tgl 1533 LBC 0 : unlink(diff);
6108 tgl 1534 UIC 0 : return true;
1535 : }
6108 tgl 1536 ECB :
1537 : /*
1538 : * Wait for specified subprocesses to finish, and return their exit
1539 : * statuses into statuses[] and stop times into stoptimes[]
1540 : *
5440 1541 : * If names isn't NULL, print each subprocess's name as it finishes
1542 : *
6107 1543 : * Note: it's OK to scribble on the pids array, but not on the names array
6108 1544 : */
1545 : static void
1519 tgl 1546 GIC 543 : wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
1547 : char **names, int num_tests)
6108 tgl 1548 ECB : {
6031 bruce 1549 : int tests_left;
1550 : int i;
6108 tgl 1551 :
1552 : #ifdef WIN32
1553 : PID_TYPE *active_pids = pg_malloc(num_tests * sizeof(PID_TYPE));
1554 :
6107 1555 : memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
1556 : #endif
1557 :
6108 tgl 1558 GBC 543 : tests_left = num_tests;
6108 tgl 1559 GIC 1653 : while (tests_left > 0)
1560 : {
1561 : PID_TYPE p;
6107 tgl 1562 ECB :
1563 : #ifndef WIN32
5184 magnus 1564 : int exit_status;
5050 bruce 1565 :
5440 tgl 1566 GIC 1110 : p = wait(&exit_status);
1567 :
6107 tgl 1568 CBC 1110 : if (p == INVALID_PID)
1569 : {
9 dgustafsson 1570 UNC 0 : bail("failed to wait for subprocesses: %s", strerror(errno));
1571 : }
6107 tgl 1572 ECB : #else
5184 magnus 1573 : DWORD exit_status;
6031 bruce 1574 : int r;
1575 :
1576 : r = WaitForMultipleObjects(tests_left, active_pids, FALSE, INFINITE);
6107 tgl 1577 : if (r < WAIT_OBJECT_0 || r >= WAIT_OBJECT_0 + tests_left)
6108 1578 : {
1579 : bail("failed to wait for subprocesses: error code %lu",
1580 : GetLastError());
1581 : }
1582 : p = active_pids[r - WAIT_OBJECT_0];
6107 1583 : /* compact the active_pids array */
1584 : active_pids[r - WAIT_OBJECT_0] = active_pids[tests_left - 1];
1585 : #endif /* WIN32 */
1586 :
6031 bruce 1587 GIC 5613 : for (i = 0; i < num_tests; i++)
1588 : {
6108 tgl 1589 5613 : if (p == pids[i])
1590 : {
6107 tgl 1591 EUB : #ifdef WIN32
1592 : GetExitCodeProcess(pids[i], &exit_status);
1593 : CloseHandle(pids[i]);
1594 : #endif
6107 tgl 1595 GIC 1110 : pids[i] = INVALID_PID;
5184 magnus 1596 1110 : statuses[i] = (int) exit_status;
1519 tgl 1597 GBC 1110 : INSTR_TIME_SET_CURRENT(stoptimes[i]);
6107 tgl 1598 GIC 1110 : if (names)
9 dgustafsson 1599 GNC 621 : note_detail(" %s", names[i]);
6108 tgl 1600 GBC 1110 : tests_left--;
6107 1601 1110 : break;
1602 : }
1603 : }
6108 tgl 1604 EUB : }
1605 :
1606 : #ifdef WIN32
1607 : free(active_pids);
1608 : #endif
6108 tgl 1609 GBC 543 : }
1610 :
1611 : /*
1612 : * report nonzero exit code from a test process
1613 : */
1614 : static void
5440 tgl 1615 UIC 0 : log_child_failure(int exitstatus)
1616 : {
1617 0 : if (WIFEXITED(exitstatus))
9 dgustafsson 1618 UNC 0 : diag("(test process exited with exit code %d)",
1619 : WEXITSTATUS(exitstatus));
5440 tgl 1620 UBC 0 : else if (WIFSIGNALED(exitstatus))
1621 : {
5440 tgl 1622 EUB : #if defined(WIN32)
1623 : diag("(test process was terminated by exception 0x%X)",
1624 : WTERMSIG(exitstatus));
1625 : #else
9 dgustafsson 1626 UNC 0 : diag("(test process was terminated by signal %d: %s)",
1627 : WTERMSIG(exitstatus), pg_strsignal(WTERMSIG(exitstatus)));
1628 : #endif
5440 tgl 1629 EUB : }
1630 : else
9 dgustafsson 1631 UNC 0 : diag("(test process exited with unrecognized status %d)", exitstatus);
5440 tgl 1632 UIC 0 : }
5440 tgl 1633 EUB :
6108 1634 : /*
1635 : * Run all the tests specified in one schedule file
1636 : */
1637 : static void
818 tgl 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];
6031 bruce 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;
6031 bruce 1652 GIC 5 : int line_num = 0;
1653 :
2010 tgl 1654 5 : memset(tests, 0, sizeof(tests));
1655 5 : memset(resultfiles, 0, sizeof(resultfiles));
1656 5 : memset(expectfiles, 0, sizeof(expectfiles));
2010 tgl 1657 CBC 5 : memset(tags, 0, sizeof(tags));
5780 magnus 1658 ECB :
6108 tgl 1659 GIC 5 : scf = fopen(schedule, "r");
1660 5 : if (!scf)
1661 : {
9 dgustafsson 1662 UNC 0 : bail("could not open file \"%s\" for reading: %s",
1663 : schedule, strerror(errno));
6108 tgl 1664 ECB : }
1665 :
6108 tgl 1666 CBC 581 : while (fgets(scbuf, sizeof(scbuf), scf))
1667 : {
6031 bruce 1668 GBC 576 : char *test = NULL;
1669 : char *c;
1670 : int num_tests;
1671 : bool inword;
1672 : int i;
1673 :
6108 tgl 1674 GIC 576 : line_num++;
1675 :
1676 : /* strip trailing whitespace, especially the newline */
1677 576 : i = strlen(scbuf);
6031 bruce 1678 1152 : while (i > 0 && isspace((unsigned char) scbuf[i - 1]))
6108 tgl 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;
6108 tgl 1685 ECB : else
1686 : {
9 dgustafsson 1687 UNC 0 : bail("syntax error in schedule file \"%s\" line %d: %s",
1688 : schedule, line_num, scbuf);
1689 : }
1690 :
6108 tgl 1691 GIC 249 : num_tests = 0;
6108 tgl 1692 CBC 249 : inword = false;
2010 tgl 1693 GIC 9612 : for (c = test;; c++)
1694 : {
1695 9612 : if (*c == '\0' || isspace((unsigned char) *c))
1696 : {
1697 816 : if (inword)
2010 tgl 1698 EUB : {
1699 : /* Reached end of a test name */
1700 : char sav;
1701 :
2010 tgl 1702 GIC 816 : if (num_tests >= MAX_PARALLEL_TESTS)
2010 tgl 1703 EUB : {
9 dgustafsson 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 : }
2010 tgl 1707 GIC 816 : sav = *c;
2010 tgl 1708 GBC 816 : *c = '\0';
2010 tgl 1709 GIC 816 : tests[num_tests] = pg_strdup(test);
1710 816 : num_tests++;
1711 816 : *c = sav;
1712 816 : inword = false;
2010 tgl 1713 EUB : }
2010 tgl 1714 GBC 816 : if (*c == '\0')
2010 tgl 1715 GIC 249 : break; /* loop exit is here */
1716 : }
6108 1717 8796 : else if (!inword)
1718 : {
1719 : /* Start of a test name */
2010 tgl 1720 CBC 816 : test = c;
6108 tgl 1721 GIC 816 : inword = true;
1722 : }
1723 : }
1724 :
1725 249 : if (num_tests == 0)
1726 : {
9 dgustafsson 1727 UNC 0 : bail("syntax error in schedule file \"%s\" line %d: %s",
1728 : schedule, line_num, scbuf);
1729 : }
1730 :
6108 tgl 1731 GIC 249 : if (num_tests == 1)
1732 : {
818 1733 195 : pids[0] = (startfunc) (tests[0], &resultfiles[0], &expectfiles[0], &tags[0]);
1519 tgl 1734 CBC 195 : INSTR_TIME_SET_CURRENT(starttimes[0]);
1735 195 : wait_for_tests(pids, statuses, stoptimes, NULL, 1);
6108 tgl 1736 ECB : /* status line is finished below */
1737 : }
2010 tgl 1738 GIC 54 : else if (max_concurrent_tests > 0 && max_concurrent_tests < num_tests)
2010 tgl 1739 ECB : {
9 dgustafsson 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 : }
6108 tgl 1743 GIC 54 : else if (max_connections > 0 && max_connections < num_tests)
6108 tgl 1744 UIC 0 : {
6031 bruce 1745 LBC 0 : int oldest = 0;
1746 :
9 dgustafsson 1747 UNC 0 : note_detail("parallel group (%d tests, in groups of %d): ",
1748 : num_tests, max_connections);
6108 tgl 1749 UIC 0 : for (i = 0; i < num_tests; i++)
1750 : {
1751 0 : if (i - oldest >= max_connections)
1752 : {
5440 tgl 1753 LBC 0 : wait_for_tests(pids + oldest, statuses + oldest,
1519 tgl 1754 UIC 0 : stoptimes + oldest,
5440 1755 0 : tests + oldest, i - oldest);
6108 tgl 1756 LBC 0 : oldest = i;
6108 tgl 1757 ECB : }
818 tgl 1758 LBC 0 : pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1519 tgl 1759 UIC 0 : INSTR_TIME_SET_CURRENT(starttimes[i]);
6108 tgl 1760 ECB : }
5440 tgl 1761 LBC 0 : wait_for_tests(pids + oldest, statuses + oldest,
1519 1762 0 : stoptimes + oldest,
5440 1763 0 : tests + oldest, i - oldest);
9 dgustafsson 1764 UNC 0 : note_end();
1765 : }
6108 tgl 1766 EUB : else
1767 : {
9 dgustafsson 1768 GNC 54 : note_detail("parallel group (%d tests): ", num_tests);
6108 tgl 1769 GIC 675 : for (i = 0; i < num_tests; i++)
6108 tgl 1770 ECB : {
818 tgl 1771 CBC 621 : pids[i] = (startfunc) (tests[i], &resultfiles[i], &expectfiles[i], &tags[i]);
1519 1772 621 : INSTR_TIME_SET_CURRENT(starttimes[i]);
1773 : }
1774 54 : wait_for_tests(pids, statuses, stoptimes, tests, num_tests);
9 dgustafsson 1775 GNC 54 : note_end();
6108 tgl 1776 ECB : }
1777 :
1778 : /* Check results for all tests */
6108 tgl 1779 GIC 1065 : for (i = 0; i < num_tests; i++)
1780 : {
5624 bruce 1781 ECB : _stringlist *rl,
1782 : *el,
5624 bruce 1783 EUB : *tl;
5624 bruce 1784 GIC 816 : bool differ = false;
1785 :
9 dgustafsson 1786 GNC 816 : INSTR_TIME_SUBTRACT(stoptimes[i], starttimes[i]);
6108 tgl 1787 ECB :
5780 magnus 1788 : /*
1789 : * Advance over all three lists simultaneously.
1790 : *
1791 : * Compare resultfiles[j] with expectfiles[j] always. Tags are
5624 bruce 1792 : * optional but if there are tags, the tag list has the same
1793 : * length as the other two lists.
1794 : */
5780 magnus 1795 CBC 816 : for (rl = resultfiles[i], el = expectfiles[i], tl = tags[i];
5624 bruce 1796 GIC 1756 : rl != NULL; /* rl and el have the same length */
1806 tgl 1797 940 : rl = rl->next, el = el->next,
1806 tgl 1798 CBC 940 : tl = tl ? tl->next : NULL)
5780 magnus 1799 ECB : {
1800 : bool newdiff;
1801 :
818 tgl 1802 GIC 940 : if (postfunc)
818 tgl 1803 CBC 186 : (*postfunc) (rl->str);
5780 magnus 1804 GIC 940 : newdiff = results_differ(tests[i], rl->str, el->str);
5624 bruce 1805 GBC 940 : if (newdiff && tl)
1806 : {
9 dgustafsson 1807 UNC 0 : diag("tag: %s", tl->str);
1808 : }
5780 magnus 1809 CBC 940 : differ |= newdiff;
1810 : }
5780 magnus 1811 ECB :
45 dgustafsson 1812 GNC 816 : if (statuses[i] != 0)
6108 tgl 1813 ECB : {
9 dgustafsson 1814 UNC 0 : test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
45 1815 0 : log_child_failure(statuses[i]);
1816 : }
6108 tgl 1817 EUB : else
1818 : {
45 dgustafsson 1819 GNC 816 : if (differ)
1820 : {
9 dgustafsson 1821 UNC 0 : test_status_failed(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
1822 : }
1823 : else
1824 : {
9 dgustafsson 1825 GNC 816 : test_status_ok(tests[i], INSTR_TIME_GET_MILLISEC(stoptimes[i]), (num_tests > 1));
1826 : }
45 dgustafsson 1827 EUB : }
6108 tgl 1828 ECB : }
2010 1829 :
2010 tgl 1830 GIC 1065 : for (i = 0; i < num_tests; i++)
2010 tgl 1831 ECB : {
2010 tgl 1832 CBC 816 : pg_free(tests[i]);
2010 tgl 1833 GIC 816 : tests[i] = NULL;
1834 816 : free_stringlist(&resultfiles[i]);
1835 816 : free_stringlist(&expectfiles[i]);
2010 tgl 1836 CBC 816 : free_stringlist(&tags[i]);
1837 : }
1838 : }
1839 :
6108 tgl 1840 GIC 5 : fclose(scf);
6108 tgl 1841 CBC 5 : }
1842 :
1843 : /*
1844 : * Run a single test
1845 : */
1846 : static void
818 tgl 1847 GIC 294 : run_single_test(const char *test, test_start_function startfunc,
1848 : postprocess_result_function postfunc)
1849 : {
6031 bruce 1850 ECB : PID_TYPE pid;
1519 tgl 1851 : instr_time starttime;
1852 : instr_time stoptime;
5440 1853 : int exit_status;
5780 magnus 1854 GIC 294 : _stringlist *resultfiles = NULL;
1855 294 : _stringlist *expectfiles = NULL;
1856 294 : _stringlist *tags = NULL;
5624 bruce 1857 ECB : _stringlist *rl,
1858 : *el,
1859 : *tl;
5780 magnus 1860 CBC 294 : bool differ = false;
1861 :
818 tgl 1862 GIC 294 : pid = (startfunc) (test, &resultfiles, &expectfiles, &tags);
1519 tgl 1863 CBC 294 : INSTR_TIME_SET_CURRENT(starttime);
1519 tgl 1864 GIC 294 : wait_for_tests(&pid, &exit_status, &stoptime, NULL, 1);
1865 :
5780 magnus 1866 ECB : /*
1867 : * Advance over all three lists simultaneously.
5780 magnus 1868 EUB : *
5624 bruce 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 : */
5780 magnus 1873 CBC 294 : for (rl = resultfiles, el = expectfiles, tl = tags;
5624 bruce 1874 GIC 590 : rl != NULL; /* rl and el have the same length */
1806 tgl 1875 GBC 296 : rl = rl->next, el = el->next,
1806 tgl 1876 GIC 296 : tl = tl ? tl->next : NULL)
1877 : {
1878 : bool newdiff;
5624 bruce 1879 ECB :
818 tgl 1880 GIC 296 : if (postfunc)
1881 3 : (*postfunc) (rl->str);
5780 magnus 1882 296 : newdiff = results_differ(test, rl->str, el->str);
5624 bruce 1883 296 : if (newdiff && tl)
5780 magnus 1884 ECB : {
9 dgustafsson 1885 UNC 0 : diag("tag: %s", tl->str);
5780 magnus 1886 ECB : }
5780 magnus 1887 CBC 296 : differ |= newdiff;
5780 magnus 1888 ECB : }
1889 :
9 dgustafsson 1890 GNC 294 : INSTR_TIME_SUBTRACT(stoptime, starttime);
1891 :
45 1892 294 : if (exit_status != 0)
1893 : {
9 dgustafsson 1894 UNC 0 : test_status_failed(test, false, INSTR_TIME_GET_MILLISEC(stoptime));
45 1895 0 : log_child_failure(exit_status);
6108 tgl 1896 ECB : }
1897 : else
1898 : {
45 dgustafsson 1899 GNC 294 : if (differ)
1900 : {
9 dgustafsson 1901 UNC 0 : test_status_failed(test, false, INSTR_TIME_GET_MILLISEC(stoptime));
1902 : }
1903 : else
1904 : {
9 dgustafsson 1905 GNC 294 : test_status_ok(test, INSTR_TIME_GET_MILLISEC(stoptime), false);
1906 : }
1907 : }
6108 tgl 1908 CBC 294 : }
6108 tgl 1909 ECB :
1910 : /*
1911 : * Create the summary-output files (making them empty if already existing)
1912 : */
1913 : static void
6108 tgl 1914 CBC 84 : open_result_files(void)
1915 : {
6031 bruce 1916 ECB : char file[MAXPGPATH];
1917 : FILE *difffile;
6108 tgl 1918 :
1919 : /* create outputdir directory if not present */
2217 andres 1920 GIC 84 : if (!directory_exists(outputdir))
1921 7 : make_directory(outputdir);
1922 :
1923 : /* create the log file (copy of running status output) */
6108 tgl 1924 84 : snprintf(file, sizeof(file), "%s/regression.out", outputdir);
2413 1925 84 : logfilename = pg_strdup(file);
6108 1926 84 : logfile = fopen(logfilename, "w");
6108 tgl 1927 CBC 84 : if (!logfile)
6108 tgl 1928 ECB : {
9 dgustafsson 1929 UNC 0 : bail("could not open file \"%s\" for writing: %s",
1930 : logfilename, strerror(errno));
1931 : }
1932 :
6108 tgl 1933 ECB : /* create the diffs file as empty */
6108 tgl 1934 CBC 84 : snprintf(file, sizeof(file), "%s/regression.diffs", outputdir);
2413 1935 84 : difffilename = pg_strdup(file);
6108 1936 84 : difffile = fopen(difffilename, "w");
6108 tgl 1937 GIC 84 : if (!difffile)
6108 tgl 1938 EUB : {
9 dgustafsson 1939 UNC 0 : bail("could not open file \"%s\" for writing: %s",
1940 : difffilename, strerror(errno));
1941 : }
6108 tgl 1942 ECB : /* we don't keep the diffs file open continuously */
6108 tgl 1943 GIC 84 : fclose(difffile);
6108 tgl 1944 ECB :
1945 : /* also create the results directory if not present */
6108 tgl 1946 GBC 84 : snprintf(file, sizeof(file), "%s/results", outputdir);
1947 84 : if (!directory_exists(file))
6108 tgl 1948 GIC 84 : make_directory(file);
1949 84 : }
1950 :
5780 magnus 1951 ECB : static void
5780 magnus 1952 GIC 2 : drop_database_if_exists(const char *dbname)
5780 magnus 1953 EUB : {
536 tgl 1954 GIC 2 : StringInfo buf = psql_start_command();
1955 :
536 tgl 1956 ECB : /* Set warning level so we don't see chatter about nonexistent DB */
536 tgl 1957 GIC 2 : psql_add_command(buf, "SET client_min_messages = warning");
1958 2 : psql_add_command(buf, "DROP DATABASE IF EXISTS \"%s\"", dbname);
536 tgl 1959 CBC 2 : psql_end_command(buf, "postgres");
5780 magnus 1960 GIC 2 : }
1961 :
1962 : static void
1963 85 : create_database(const char *dbname)
1964 : {
536 tgl 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.
5780 magnus 1971 ECB : */
5780 magnus 1972 GIC 85 : if (encoding)
536 tgl 1973 2 : psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0 ENCODING='%s'%s", dbname, encoding,
536 tgl 1974 CBC 2 : (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
5780 magnus 1975 ECB : else
536 tgl 1976 CBC 83 : psql_add_command(buf, "CREATE DATABASE \"%s\" TEMPLATE=template0%s", dbname,
1977 83 : (nolocale) ? " LC_COLLATE='C' LC_CTYPE='C'" : "");
536 tgl 1978 GIC 85 : psql_add_command(buf,
536 tgl 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';"
536 tgl 1984 ECB : "ALTER DATABASE \"%s\" SET timezone_abbreviations TO 'Default';",
1985 : dbname, dbname, dbname, dbname, dbname, dbname);
536 tgl 1986 CBC 85 : psql_end_command(buf, "postgres");
5780 magnus 1987 ECB :
1988 : /*
4382 bruce 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 : */
4419 tgl 1992 GIC 90 : for (sl = loadextension; sl != NULL; sl = sl->next)
1993 5 : psql_command(dbname, "CREATE EXTENSION IF NOT EXISTS \"%s\"", sl->str);
5780 magnus 1994 CBC 85 : }
5780 magnus 1995 ECB :
1996 : static void
5780 magnus 1997 UIC 0 : drop_role_if_exists(const char *rolename)
1998 : {
536 tgl 1999 LBC 0 : StringInfo buf = psql_start_command();
2000 :
2001 : /* Set warning level so we don't see chatter about nonexistent role */
536 tgl 2002 UIC 0 : psql_add_command(buf, "SET client_min_messages = warning");
536 tgl 2003 LBC 0 : psql_add_command(buf, "DROP ROLE IF EXISTS \"%s\"", rolename);
2004 0 : psql_end_command(buf, "postgres");
5780 magnus 2005 0 : }
5780 magnus 2006 ECB :
2007 : static void
3260 bruce 2008 GIC 2 : create_role(const char *rolename, const _stringlist *granted_dbs)
5780 magnus 2009 ECB : {
536 tgl 2010 GIC 2 : StringInfo buf = psql_start_command();
536 tgl 2011 ECB :
536 tgl 2012 GIC 2 : psql_add_command(buf, "CREATE ROLE \"%s\" WITH LOGIN", rolename);
5780 magnus 2013 6 : for (; granted_dbs != NULL; granted_dbs = granted_dbs->next)
2014 : {
536 tgl 2015 4 : psql_add_command(buf, "GRANT ALL ON DATABASE \"%s\" TO \"%s\"",
2016 4 : granted_dbs->str, rolename);
5780 magnus 2017 ECB : }
536 tgl 2018 CBC 2 : psql_end_command(buf, "postgres");
5780 magnus 2019 2 : }
2020 :
6108 tgl 2021 ECB : static void
6108 tgl 2022 LBC 0 : help(void)
6108 tgl 2023 ECB : {
6108 tgl 2024 UIC 0 : printf(_("PostgreSQL regression test driver\n"));
2025 0 : printf(_("\n"));
4240 peter_e 2026 0 : printf(_("Usage:\n %s [OPTION]... [EXTRA-TEST]...\n"), progname);
6108 tgl 2027 0 : printf(_("\n"));
2028 0 : printf(_("Options:\n"));
2004 mail 2029 0 : printf(_(" --bindir=BINPATH use BINPATH for programs that are run;\n"));
2030 0 : printf(_(" if empty, use PATH from the environment\n"));
2004 mail 2031 LBC 0 : printf(_(" --config-auth=DATADIR update authentication settings for DATADIR\n"));
2004 mail 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"));
232 andres 2037 UNC 0 : printf(_(" --expecteddir=DIR take expected files from DIR (default \".\")\n"));
2004 mail 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"));
2004 mail 2041 UIC 0 : printf(_(" --load-extension=EXT load the named extension before running the\n"));
2042 0 : printf(_(" tests; can appear multiple times\n"));
2004 mail 2043 UBC 0 : printf(_(" --max-connections=N maximum number of concurrent connections\n"));
2004 mail 2044 UIC 0 : printf(_(" (default is 0, meaning unlimited)\n"));
2004 mail 2045 UBC 0 : printf(_(" --max-concurrent-tests=N maximum number of concurrent tests in schedule\n"));
2004 mail 2046 UIC 0 : printf(_(" (default is 0, meaning unlimited)\n"));
2047 0 : printf(_(" --outputdir=DIR place output files in DIR (default \".\")\n"));
2004 mail 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"));
2004 mail 2052 UIC 0 : printf(_(" -V, --version output version information, then exit\n"));
2865 tgl 2053 0 : printf(_("\n"));
2908 peter_e 2054 LBC 0 : printf(_("Options for \"temp-instance\" mode:\n"));
2004 mail 2055 UIC 0 : printf(_(" --no-locale use C locale\n"));
2004 mail 2056 LBC 0 : printf(_(" --port=PORT start postmaster on PORT\n"));
2004 mail 2057 UIC 0 : printf(_(" --temp-config=FILE append contents of FILE to temporary config\n"));
6108 tgl 2058 LBC 0 : printf(_("\n"));
2059 0 : printf(_("Options for using an existing installation:\n"));
2004 mail 2060 UIC 0 : printf(_(" --host=HOST use postmaster running on HOST\n"));
2004 mail 2061 LBC 0 : printf(_(" --port=PORT use postmaster running at PORT\n"));
2062 0 : printf(_(" --user=USER connect as USER\n"));
6108 tgl 2063 UIC 0 : printf(_("\n"));
6108 tgl 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"));
6108 tgl 2066 UIC 0 : printf(_("\n"));
1136 peter 2067 0 : printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1136 peter 2068 UBC 0 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
6108 tgl 2069 UIC 0 : }
6108 tgl 2070 EUB :
2071 : int
818 tgl 2072 GBC 303 : regression_main(int argc, char *argv[],
818 tgl 2073 EUB : init_function ifunc,
2074 : test_start_function startfunc,
2075 : postprocess_result_function postfunc)
6108 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},
4377 peter_e 2084 : {"encoding", required_argument, NULL, 6},
6108 tgl 2085 : {"outputdir", required_argument, NULL, 7},
2086 : {"schedule", required_argument, NULL, 8},
2908 peter_e 2087 : {"temp-instance", required_argument, NULL, 9},
6108 tgl 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},
2908 peter_e 2092 : {"bindir", required_argument, NULL, 16},
5303 2093 : {"dlpath", required_argument, NULL, 17},
5780 magnus 2094 : {"create-role", required_argument, NULL, 18},
5691 andrew 2095 : {"temp-config", required_argument, NULL, 19},
4859 simon 2096 : {"use-existing", no_argument, NULL, 20},
4459 rhaas 2097 : {"launcher", required_argument, NULL, 21},
4419 tgl 2098 : {"load-extension", required_argument, NULL, 22},
3035 noah 2099 : {"config-auth", required_argument, NULL, 24},
2010 tgl 2100 : {"max-concurrent-tests", required_argument, NULL, 25},
2101 : {"expecteddir", required_argument, NULL, 26},
6108 2102 : {NULL, 0, NULL, 0}
2103 : };
2104 :
1105 peter 2105 : bool use_unix_sockets;
3782 bruce 2106 : _stringlist *sl;
2107 : int c;
2108 : int i;
2109 : int option_index;
2110 : char buf[MAXPGPATH * 4];
2111 : char buf2[MAXPGPATH * 4];
2112 :
1469 peter 2113 GBC 303 : pg_logging_init(argv[0]);
6108 tgl 2114 303 : progname = get_progname(argv[0]);
5232 peter_e 2115 303 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
6108 tgl 2116 EUB :
1469 peter 2117 GIC 303 : get_restricted_token();
2118 :
4115 peter_e 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
1105 peter 2129 GIC 303 : use_unix_sockets = true;
2130 : #endif
2131 :
2132 303 : if (!use_unix_sockets)
1105 peter 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 : */
3439 rhaas 2139 GIC 303 : ifunc(argc, argv);
2140 :
3722 peter_e 2141 303 : if (getenv("PG_REGRESS_DIFF_OPTS"))
2142 303 : pretty_diff_opts = getenv("PG_REGRESS_DIFF_OPTS");
2143 :
6108 tgl 2144 920 : while ((c = getopt_long(argc, argv, "hV", long_options, &option_index)) != -1)
2145 : {
2146 617 : switch (c)
2147 : {
6108 tgl 2148 UIC 0 : case 'h':
2149 0 : help();
4115 peter_e 2150 0 : exit(0);
6108 tgl 2151 0 : case 'V':
5527 2152 0 : puts("pg_regress (PostgreSQL) " PG_VERSION);
4115 peter_e 2153 0 : exit(0);
6108 tgl 2154 GIC 80 : case 1:
2155 :
2156 : /*
5624 bruce 2157 ECB : * If a default database was specified, we need to remove it
2158 : * before we add the specified one.
5780 magnus 2159 : */
5780 magnus 2160 GIC 80 : free_stringlist(&dblist);
2439 peter_e 2161 CBC 80 : split_to_stringlist(optarg, ",", &dblist);
6108 tgl 2162 GIC 80 : break;
6108 tgl 2163 LBC 0 : case 2:
6108 tgl 2164 UIC 0 : debug = true;
2165 0 : break;
6108 tgl 2166 GIC 83 : case 3:
2413 2167 83 : inputdir = pg_strdup(optarg);
6108 2168 83 : break;
6108 tgl 2169 UIC 0 : case 5:
2170 0 : max_connections = atoi(optarg);
2171 0 : break;
6108 tgl 2172 GIC 2 : case 6:
2413 tgl 2173 CBC 2 : encoding = pg_strdup(optarg);
6108 tgl 2174 GIC 2 : break;
2175 9 : case 7:
2413 tgl 2176 CBC 9 : outputdir = pg_strdup(optarg);
6108 tgl 2177 GBC 9 : break;
6108 tgl 2178 GIC 5 : case 8:
2179 5 : add_stringlist_item(&schedulelist, optarg);
2180 5 : break;
2181 82 : case 9:
2908 peter_e 2182 82 : temp_instance = make_absolute_path(optarg);
6108 tgl 2183 CBC 82 : break;
6108 tgl 2184 GIC 3 : case 10:
6108 tgl 2185 CBC 3 : nolocale = true;
2186 3 : break;
6108 tgl 2187 GIC 2 : case 13:
2413 tgl 2188 CBC 2 : hostname = pg_strdup(optarg);
6108 tgl 2189 GIC 2 : break;
6108 tgl 2190 CBC 2 : case 14:
6108 tgl 2191 GIC 2 : port = atoi(optarg);
5245 peter_e 2192 GBC 2 : port_specified_by_user = true;
6108 tgl 2193 2 : break;
2194 3 : case 15:
2413 2195 3 : user = pg_strdup(optarg);
6108 2196 3 : break;
6106 2197 84 : case 16:
2908 peter_e 2198 ECB : /* "--bindir=" means to use PATH */
6106 tgl 2199 GIC 84 : if (strlen(optarg))
2413 tgl 2200 UIC 0 : bindir = pg_strdup(optarg);
2201 : else
2908 peter_e 2202 GIC 84 : bindir = NULL;
6106 tgl 2203 84 : break;
5924 alvherre 2204 CBC 4 : case 17:
2413 tgl 2205 4 : dlpath = pg_strdup(optarg);
5924 alvherre 2206 4 : break;
5780 magnus 2207 GBC 20 : case 18:
2439 peter_e 2208 20 : split_to_stringlist(optarg, ",", &extraroles);
5780 magnus 2209 20 : break;
5691 andrew 2210 CBC 10 : case 19:
2597 2211 10 : add_stringlist_item(&temp_configs, optarg);
5691 2212 10 : break;
4859 simon 2213 UBC 0 : case 20:
2214 0 : use_existing = true;
2215 0 : break;
4459 rhaas 2216 LBC 0 : case 21:
2413 tgl 2217 0 : launcher = pg_strdup(optarg);
4459 rhaas 2218 0 : break;
4419 tgl 2219 CBC 5 : case 22:
2220 5 : add_stringlist_item(&loadextension, optarg);
2221 5 : break;
3035 noah 2222 219 : case 24:
2413 tgl 2223 219 : config_auth_datadir = pg_strdup(optarg);
3035 noah 2224 219 : break;
2010 tgl 2225 3 : case 25:
2226 3 : max_concurrent_tests = atoi(optarg);
2227 3 : break;
232 andres 2228 GNC 1 : case 26:
2229 1 : expecteddir = pg_strdup(optarg);
2230 1 : break;
6108 tgl 2231 LBC 0 : default:
6108 tgl 2232 ECB : /* getopt_long already emitted a complaint */
9 dgustafsson 2233 UNC 0 : pg_log_error_hint("Try \"%s --help\" for more information.",
2234 : progname);
4115 peter_e 2235 LBC 0 : exit(2);
6108 tgl 2236 ECB : }
2237 : }
2238 :
2239 : /*
2240 : * if we still have arguments, they are extra tests to run
2241 : */
6108 tgl 2242 CBC 597 : while (argc - optind >= 1)
6108 tgl 2243 ECB : {
6108 tgl 2244 CBC 294 : add_stringlist_item(&extra_tests, argv[optind]);
6108 tgl 2245 GIC 294 : optind++;
6108 tgl 2246 ECB : }
6108 tgl 2247 EUB :
2248 : /*
130 tgl 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 : */
130 tgl 2252 CBC 303 : if (!(dblist && dblist->str && dblist->str[0]))
130 tgl 2253 ECB : {
9 dgustafsson 2254 UNC 0 : bail("no database name was specified");
130 tgl 2255 ECB : }
2256 :
3035 noah 2257 CBC 303 : if (config_auth_datadir)
3035 noah 2258 EUB : {
2259 : #ifdef ENABLE_SSPI
1105 peter 2260 : if (!use_unix_sockets)
2261 : config_sspi_auth(config_auth_datadir, user);
3035 noah 2262 : #endif
3035 noah 2263 GBC 219 : exit(0);
3035 noah 2264 ECB : }
2265 :
2908 peter_e 2266 CBC 84 : if (temp_instance && !port_specified_by_user)
5050 bruce 2267 ECB :
5245 peter_e 2268 : /*
5050 bruce 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
3221 noah 2272 : * systems; elsewhere, the use of a private socket directory already
2273 : * prevents interference.
5245 peter_e 2274 : */
5245 peter_e 2275 CBC 82 : port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
6108 tgl 2276 EUB :
1506 peter 2277 GIC 84 : inputdir = make_absolute_path(inputdir);
1506 peter 2278 GBC 84 : outputdir = make_absolute_path(outputdir);
232 andres 2279 GNC 84 : expecteddir = make_absolute_path(expecteddir);
1506 peter 2280 GIC 84 : dlpath = make_absolute_path(dlpath);
1506 peter 2281 EUB :
2282 : /*
2283 : * Initialization
2284 : */
6108 tgl 2285 GIC 84 : open_result_files();
2286 :
2287 84 : initialize_environment();
6108 tgl 2288 ECB :
2289 : #if defined(HAVE_GETRLIMIT)
5938 andrew 2290 CBC 84 : unlimit_core_size();
5938 andrew 2291 ECB : #endif
2292 :
2908 peter_e 2293 GIC 84 : if (temp_instance)
2294 : {
2295 : FILE *pg_conf;
2296 : const char *env_wait;
2297 : int wait_seconds;
5099 tgl 2298 ECB :
2299 : /*
2908 peter_e 2300 EUB : * Prepare the temp instance
2301 : */
2302 :
2908 peter_e 2303 CBC 82 : if (directory_exists(temp_instance))
2304 : {
2908 peter_e 2305 UIC 0 : if (!rmtree(temp_instance, true))
2306 : {
9 dgustafsson 2307 UNC 0 : bail("could not remove temp instance \"%s\"", temp_instance);
2308 : }
6108 tgl 2309 ECB : }
2310 :
2311 : /* make the temp instance top directory */
2908 peter_e 2312 GIC 82 : make_directory(temp_instance);
2313 :
2314 : /* and a directory for log files */
2819 andrew 2315 82 : snprintf(buf, sizeof(buf), "%s/log", outputdir);
6108 tgl 2316 CBC 82 : if (!directory_exists(buf))
6108 tgl 2317 GIC 82 : make_directory(buf);
6108 tgl 2318 ECB :
2319 : /* initdb */
6108 tgl 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",
2908 peter_e 2322 GIC 82 : bindir ? bindir : "",
2323 82 : bindir ? "/" : "",
2324 : temp_instance,
6107 tgl 2325 CBC 82 : debug ? " --debug" : "",
6107 tgl 2326 GIC 82 : nolocale ? " --no-locale" : "",
2819 andrew 2327 ECB : outputdir);
223 tgl 2328 GNC 82 : fflush(NULL);
6108 tgl 2329 GIC 82 : if (system(buf))
2330 : {
9 dgustafsson 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 : }
6108 tgl 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 : */
2908 peter_e 2345 GIC 82 : snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
5099 tgl 2346 CBC 82 : pg_conf = fopen(buf, "a");
5099 tgl 2347 GIC 82 : if (pg_conf == NULL)
5099 tgl 2348 EUB : {
9 dgustafsson 2349 UNC 0 : bail("could not open \"%s\" for adding extra config: %s",
2350 : buf, strerror(errno));
2351 : }
5099 tgl 2352 GIC 82 : fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
3003 noah 2353 82 : fputs("log_autovacuum_min_duration = 0\n", pg_conf);
2354 82 : fputs("log_checkpoints = on\n", pg_conf);
1120 peter 2355 CBC 82 : fputs("log_line_prefix = '%m %b[%p] %q%a '\n", pg_conf);
3003 noah 2356 GIC 82 : fputs("log_lock_waits = on\n", pg_conf);
2357 82 : fputs("log_temp_files = 128kB\n", pg_conf);
5099 tgl 2358 CBC 82 : fputs("max_prepared_transactions = 2\n", pg_conf);
5099 tgl 2359 ECB :
2597 andrew 2360 CBC 92 : for (sl = temp_configs; sl != NULL; sl = sl->next)
2361 : {
2597 andrew 2362 GIC 10 : char *temp_config = sl->str;
5624 bruce 2363 ECB : FILE *extra_conf;
2364 : char line_buf[1024];
5691 andrew 2365 :
5624 bruce 2366 CBC 10 : extra_conf = fopen(temp_config, "r");
5691 andrew 2367 GIC 10 : if (extra_conf == NULL)
5691 andrew 2368 ECB : {
9 dgustafsson 2369 UNC 0 : bail("could not open \"%s\" to read extra config: %s",
2370 : temp_config, strerror(errno));
5691 andrew 2371 ECB : }
5624 bruce 2372 CBC 32 : while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
5691 andrew 2373 GIC 22 : fputs(line_buf, pg_conf);
5691 andrew 2374 GBC 10 : fclose(extra_conf);
2375 : }
2376 :
5099 tgl 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);
1105 peter 2388 ECB : }
2389 : #endif
3035 noah 2390 EUB :
2391 : /*
2392 : * Check if there is a postmaster running already.
5245 peter_e 2393 ECB : */
5245 peter_e 2394 CBC 164 : snprintf(buf2, sizeof(buf2),
2908 peter_e 2395 ECB : "\"%s%spsql\" -X postgres <%s 2>%s",
2908 peter_e 2396 CBC 82 : bindir ? bindir : "",
2397 82 : bindir ? "/" : "",
2908 peter_e 2398 ECB : DEVNULL, DEVNULL);
5245 2399 :
5245 peter_e 2400 GIC 82 : for (i = 0; i < 16; i++)
5245 peter_e 2401 ECB : {
223 tgl 2402 GNC 82 : fflush(NULL);
5245 peter_e 2403 GIC 82 : if (system(buf2) == 0)
5245 peter_e 2404 ECB : {
2405 : char s[16];
2406 :
5245 peter_e 2407 UIC 0 : if (port_specified_by_user || i == 15)
5245 peter_e 2408 ECB : {
9 dgustafsson 2409 UNC 0 : note("port %d apparently in use", port);
5245 peter_e 2410 UIC 0 : if (!port_specified_by_user)
9 dgustafsson 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.");
5245 peter_e 2413 ECB : }
2414 :
9 dgustafsson 2415 UNC 0 : note("port %d apparently in use, trying %d", port, port + 1);
5245 peter_e 2416 UIC 0 : port++;
2417 0 : sprintf(s, "%d", port);
830 tgl 2418 LBC 0 : setenv("PGPORT", s, 1);
2419 : }
2420 : else
5245 peter_e 2421 GIC 82 : break;
2422 : }
2423 :
2424 : /*
2425 : * Start the temp postmaster
2426 : */
6108 tgl 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",
2908 peter_e 2431 82 : bindir ? bindir : "",
2432 82 : bindir ? "/" : "",
2433 82 : temp_instance, debug ? " -d 5" : "",
3221 noah 2434 CBC 164 : hostname ? hostname : "", sockdir ? sockdir : "",
2435 : outputdir);
6108 tgl 2436 82 : postmaster_pid = spawn_process(buf);
2437 82 : if (postmaster_pid == INVALID_PID)
9 dgustafsson 2438 UNC 0 : bail("could not spawn postmaster: %s", strerror(errno));
6108 tgl 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
2545 tgl 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.
6108 2446 : */
2545 tgl 2447 GBC 82 : env_wait = getenv("PGCTLTIMEOUT");
2448 82 : if (env_wait != NULL)
2449 : {
2545 tgl 2450 UIC 0 : wait_seconds = atoi(env_wait);
2545 tgl 2451 UBC 0 : if (wait_seconds <= 0)
2452 0 : wait_seconds = 60;
2545 tgl 2453 EUB : }
2454 : else
2545 tgl 2455 GIC 82 : wait_seconds = 60;
2456 :
2545 tgl 2457 CBC 164 : for (i = 0; i < wait_seconds; i++)
2458 : {
2459 : /* Done if psql succeeds */
223 tgl 2460 GNC 164 : fflush(NULL);
5245 peter_e 2461 GIC 164 : if (system(buf2) == 0)
6108 tgl 2462 82 : break;
2463 :
6108 tgl 2464 ECB : /*
2465 : * Fail immediately if postmaster has exited
2466 : */
2467 : #ifndef WIN32
1560 noah 2468 CBC 82 : if (waitpid(postmaster_pid, NULL, WNOHANG) == postmaster_pid)
6041 tgl 2469 ECB : #else
2470 : if (WaitForSingleObject(postmaster_pid, 0) == WAIT_OBJECT_0)
2471 : #endif
2472 : {
9 dgustafsson 2473 UNC 0 : bail("postmaster failed, examine \"%s/log/postmaster.log\" for the reason",
2474 : outputdir);
6108 tgl 2475 EUB : }
2476 :
6108 tgl 2477 GIC 82 : pg_usleep(1000000L);
2478 : }
2545 2479 82 : if (i >= wait_seconds)
2480 : {
9 dgustafsson 2481 UNC 0 : diag("postmaster did not respond within %d seconds, examine \"%s/log/postmaster.log\" for the reason",
2482 : wait_seconds, outputdir);
2483 :
6083 tgl 2484 ECB : /*
6031 bruce 2485 : * If we get here, the postmaster is probably wedged somewhere in
2486 : * startup. Try to kill it ungracefully rather than leaving a
6031 bruce 2487 EUB : * stuck postmaster that might interfere with subsequent test
6083 tgl 2488 : * attempts.
2489 : */
2490 : #ifndef WIN32
9 dgustafsson 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());
6083 tgl 2497 ECB : #endif
9 dgustafsson 2498 UNC 0 : bail("postmaster failed");
2499 : }
2500 :
6108 tgl 2501 GIC 82 : postmaster_running = true;
6108 tgl 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
4373 andrew 2507 EUB : #define ULONGPID(x) (unsigned long) (x)
2508 : #endif
9 dgustafsson 2509 GNC 82 : note("using temp instance on port %d with PID %lu",
2510 : port, ULONGPID(postmaster_pid));
6108 tgl 2511 ECB : }
2512 : else
2513 : {
2514 : /*
6108 tgl 2515 EUB : * Using an existing installation, so may need to get rid of
2516 : * pre-existing database(s) and role(s)
2517 : */
4859 simon 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)
4859 simon 2523 UIC 0 : drop_role_if_exists(sl->str);
2524 : }
6108 tgl 2525 EUB : }
2526 :
2527 : /*
2528 : * Create the test database(s) and role(s)
2529 : */
4859 simon 2530 GIC 84 : if (!use_existing)
2531 : {
4859 simon 2532 GBC 169 : for (sl = dblist; sl; sl = sl->next)
4859 simon 2533 GIC 85 : create_database(sl->str);
2534 86 : for (sl = extraroles; sl; sl = sl->next)
4859 simon 2535 CBC 2 : create_role(sl->str, dblist);
2536 : }
2537 :
2538 : /*
2539 : * Ready to run the tests
2540 : */
6108 tgl 2541 89 : for (sl = schedulelist; sl != NULL; sl = sl->next)
2542 : {
818 tgl 2543 GIC 5 : run_schedule(sl->str, startfunc, postfunc);
2544 : }
2545 :
6108 2546 378 : for (sl = extra_tests; sl != NULL; sl = sl->next)
2547 : {
818 2548 294 : run_single_test(sl->str, startfunc, postfunc);
2549 : }
6108 tgl 2550 ECB :
2551 : /*
2552 : * Shut down temp installation's postmaster
2553 : */
2908 peter_e 2554 CBC 84 : if (temp_instance)
6108 tgl 2555 EUB : {
6108 tgl 2556 GIC 82 : stop_postmaster();
2557 : }
2558 :
2559 : /*
2560 : * If there were no errors, remove the temp instance immediately to
2878 bruce 2561 ECB : * conserve disk space. (If there were errors, we leave the instance in
2562 : * place for possible manual investigation.)
3002 tgl 2563 : */
90 tgl 2564 GNC 84 : if (temp_instance && fail_count == 0)
3002 tgl 2565 ECB : {
2908 peter_e 2566 GIC 82 : if (!rmtree(temp_instance, true))
9 dgustafsson 2567 UNC 0 : diag("could not remove temp instance \"%s\"",
2568 : temp_instance);
2569 : }
2570 :
2571 : /*
2572 : * Emit a TAP compliant Plan
2573 : */
9 dgustafsson 2574 GNC 84 : plan(fail_count + success_count);
2575 :
6108 tgl 2576 ECB : /*
2577 : * Emit nice-looking summary message
2578 : */
90 tgl 2579 GNC 84 : if (fail_count == 0)
9 dgustafsson 2580 84 : note("All %d tests passed.", success_count);
2581 : else
9 dgustafsson 2582 UNC 0 : diag("%d of %d tests failed.", fail_count, success_count + fail_count);
2583 :
6108 tgl 2584 GIC 84 : if (file_size(difffilename) > 0)
6108 tgl 2585 ECB : {
9 dgustafsson 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);
6108 tgl 2590 ECB : }
2591 : else
6108 tgl 2592 EUB : {
6108 tgl 2593 GIC 84 : unlink(difffilename);
6108 tgl 2594 GBC 84 : unlink(logfilename);
2595 : }
2596 :
9 dgustafsson 2597 GNC 84 : fclose(logfile);
2598 84 : logfile = NULL;
2599 :
6108 tgl 2600 GIC 84 : if (fail_count != 0)
4115 peter_e 2601 UIC 0 : exit(1);
6108 tgl 2602 ECB :
6108 tgl 2603 CBC 84 : return 0;
2604 : }
|