2073{
2074 static struct option long_options[] = {
2099 {NULL, 0, NULL, 0}
2100 };
2101
2102 bool use_unix_sockets;
2106 int option_index;
2108
2112
2114
2116
2117#if defined(WIN32)
2118
2119 /*
2120 * We don't use Unix-domain sockets on Windows by default (see comment at
2121 * remove_temp() for a reason). Override at your own risk.
2122 */
2123 use_unix_sockets = getenv(
"PG_TEST_USE_UNIX_SOCKETS") ?
true :
false;
2124#else
2125 use_unix_sockets = true;
2126#endif
2127
2128 if (!use_unix_sockets)
2130
2131 /*
2132 * We call the initialization function here because that way we can set
2133 * default parameters and let them be overwritten by the commandline.
2134 */
2135 ifunc(argc, argv);
2136
2137 if (getenv("PG_REGRESS_DIFF_OPTS"))
2139
2140 while ((
c =
getopt_long(argc, argv,
"hV", long_options, &option_index)) != -1)
2141 {
2143 {
2144 case 'h':
2146 exit(0);
2147 case 'V':
2148 puts("pg_regress (PostgreSQL) " PG_VERSION);
2149 exit(0);
2150 case 1:
2151
2152 /*
2153 * If a default database was specified, we need to remove it
2154 * before we add the specified one.
2155 */
2158 break;
2159 case 2:
2161 break;
2162 case 3:
2164 break;
2165 case 5:
2167 break;
2168 case 6:
2170 break;
2171 case 7:
2173 break;
2174 case 8:
2176 break;
2177 case 9:
2179 break;
2180 case 10:
2182 break;
2183 case 13:
2185 break;
2186 case 14:
2189 break;
2190 case 15:
2192 break;
2193 case 16:
2194 /* "--bindir=" means to use PATH */
2197 else
2199 break;
2200 case 17:
2202 break;
2203 case 18:
2205 break;
2206 case 19:
2208 break;
2209 case 20:
2211 break;
2212 case 21:
2214 break;
2215 case 22:
2217 break;
2218 case 24:
2220 break;
2221 case 25:
2223 break;
2224 case 26:
2226 break;
2227 default:
2228 /* getopt_long already emitted a complaint */
2231 exit(2);
2232 }
2233 }
2234
2235 /*
2236 * if we still have arguments, they are extra tests to run
2237 */
2238 while (argc -
optind >= 1)
2239 {
2242 }
2243
2244 /*
2245 * We must have a database to run the tests in; either a default name, or
2246 * one supplied by the --dbname switch.
2247 */
2249 {
2250 bail(
"no database name was specified");
2251 }
2252
2254 {
2255#ifdef ENABLE_SSPI
2256 if (!use_unix_sockets)
2258#endif
2259 exit(0);
2260 }
2261
2263
2264 /*
2265 * To reduce chances of interference with parallel installations, use
2266 * a port number starting in the private range (49152-65535)
2267 * calculated from the version number. This aids non-Unix socket mode
2268 * systems; elsewhere, the use of a private socket directory already
2269 * prevents interference.
2270 */
2271 port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
2272
2277
2278 /*
2279 * Initialization
2280 */
2282
2284
2285#if defined(HAVE_GETRLIMIT)
2287#endif
2288
2290 {
2292 FILE *pg_conf;
2293 const char *env_wait;
2295 const char *initdb_template_dir;
2299 const char *initdb_extra_opts_env;
2300
2301 /*
2302 * Prepare the temp instance
2303 */
2304
2306 {
2308 {
2310 }
2311 }
2312
2313 /* make the temp instance top directory */
2315
2316 /* and a directory for log files */
2320
2321 initdb_extra_opts_env = getenv("PG_TEST_INITDB_EXTRA_OPTS");
2322
2324
2325 /*
2326 * Create data directory.
2327 *
2328 * If available, use a previously initdb'd cluster as a template by
2329 * copying it. For a lot of tests, that's substantially cheaper.
2330 *
2331 * There's very similar code in Cluster.pm, but we can't easily de
2332 * duplicate it until we require perl at build time.
2333 */
2334 initdb_template_dir = getenv("INITDB_TEMPLATE");
2335 if (initdb_template_dir == NULL ||
nolocale ||
debug || initdb_extra_opts_env)
2336 {
2337 note(
"initializing database system by running initdb");
2338
2340 "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync",
2348 if (initdb_extra_opts_env)
2351 fflush(NULL);
2352 if (system(cmd.
data))
2353 {
2354 bail(
"initdb failed\n"
2355 "# Examine \"%s/log/initdb.log\" for the reason.\n"
2356 "# Command was: %s",
2358 }
2359 }
2360 else
2361 {
2362#ifndef WIN32
2363 const char *copycmd = "cp -RPp \"%s\" \"%s/data\"";
2364 int expected_exitcode = 0;
2365#else
2366 const char *copycmd = "robocopy /E /NJS /NJH /NFL /NDL /NP \"%s\" \"%s/data\"";
2367 int expected_exitcode = 1; /* 1 denotes files were copied */
2368#endif
2369
2370 note(
"initializing database system by copying initdb template");
2371
2373 copycmd,
2374 initdb_template_dir,
2377 fflush(NULL);
2378 if (system(cmd.
data) != expected_exitcode)
2379 {
2380 bail(
"copying of initdb template failed\n"
2381 "# Examine \"%s/log/initdb.log\" for the reason.\n"
2382 "# Command was: %s",
2384 }
2385 }
2386
2388
2389 /*
2390 * Adjust the default postgresql.conf for regression testing. The user
2391 * can specify a file to be appended; in any case we expand logging
2392 * and set max_prepared_transactions to enable testing of prepared
2393 * xacts. (Note: to reduce the probability of unexpected shmmax
2394 * failures, don't set max_prepared_transactions any higher than
2395 * actually needed by the prepared_xacts regression test.)
2396 */
2398 pg_conf = fopen(
buf,
"a");
2399 if (pg_conf == NULL)
2400 bail(
"could not open \"%s\" for adding extra config: %m",
buf);
2401
2402 fputs("\n# Configuration added by pg_regress\n\n", pg_conf);
2403 fputs("log_autovacuum_min_duration = 0\n", pg_conf);
2404 fputs("log_checkpoints = on\n", pg_conf);
2405 fputs("log_line_prefix = '%m %b[%p] %q%a '\n", pg_conf);
2406 fputs("log_lock_waits = on\n", pg_conf);
2407 fputs("log_temp_files = 128kB\n", pg_conf);
2408 fputs("max_prepared_transactions = 2\n", pg_conf);
2409
2411 {
2412 char *temp_config = sl->
str;
2413 FILE *extra_conf;
2414 char line_buf[1024];
2415
2416 extra_conf = fopen(temp_config, "r");
2417 if (extra_conf == NULL)
2418 {
2419 bail(
"could not open \"%s\" to read extra config: %m",
2420 temp_config);
2421 }
2422 while (fgets(line_buf, sizeof(line_buf), extra_conf) != NULL)
2423 fputs(line_buf, pg_conf);
2424 fclose(extra_conf);
2425 }
2426
2427 fclose(pg_conf);
2428
2429#ifdef ENABLE_SSPI
2430 if (!use_unix_sockets)
2431 {
2432 /*
2433 * Since we successfully used the same buffer for the much-longer
2434 * "initdb" command, this can't truncate.
2435 */
2437 config_sspi_auth(
buf, NULL);
2438 }
2439#endif
2440
2441 /*
2442 * Prepare the connection params for checking the state of the server
2443 * before starting the tests.
2444 */
2454
2455 /*
2456 * Check if there is a postmaster running already.
2457 */
2458 for (
i = 0;
i < 16;
i++)
2459 {
2461
2463 {
2465 {
2466 note(
"port %d apparently in use",
port);
2468 note(
"could not determine an available port");
2469 bail(
"Specify an unused port using the --port option or shut down any conflicting PostgreSQL servers.");
2470 }
2471
2472 note(
"port %d apparently in use, trying %d",
port,
port + 1);
2476 }
2477 else
2478 break;
2479 }
2480
2481 /*
2482 * Start the temp postmaster
2483 */
2485 "\"%s%spostgres\" -D \"%s/data\" -F%s "
2486 "-c \"listen_addresses=%s\" -k \"%s\" "
2487 "> \"%s/log/postmaster.log\" 2>&1",
2495 bail(
"could not spawn postmaster: %m");
2496
2497 /*
2498 * Wait till postmaster is able to accept connections; normally takes
2499 * only a fraction of a second or so, but Cygwin is reportedly *much*
2500 * slower, and test builds using Valgrind or similar tools might be
2501 * too. Hence, allow the default timeout of 60 seconds to be
2502 * overridden from the PGCTLTIMEOUT environment variable.
2503 */
2504 env_wait = getenv("PGCTLTIMEOUT");
2505 if (env_wait != NULL)
2506 {
2510 }
2511 else
2513
2515 {
2516 /*
2517 * It's fairly unlikely that the server is responding immediately
2518 * so we start with sleeping before checking instead of the other
2519 * way around.
2520 */
2522
2524
2525 /* Done if the server is running and accepts connections */
2527 break;
2528
2530 bail(
"attempting to connect to postmaster failed");
2531
2532 /*
2533 * Fail immediately if postmaster has exited
2534 */
2535#ifndef WIN32
2537#else
2539#endif
2540 {
2541 bail(
"postmaster failed, examine \"%s/log/postmaster.log\" for the reason",
2543 }
2544 }
2546 {
2547 diag(
"postmaster did not respond within %d seconds, examine \"%s/log/postmaster.log\" for the reason",
2549
2550 /*
2551 * If we get here, the postmaster is probably wedged somewhere in
2552 * startup. Try to kill it ungracefully rather than leaving a
2553 * stuck postmaster that might interfere with subsequent test
2554 * attempts.
2555 */
2556#ifndef WIN32
2558 bail(
"could not kill failed postmaster: %m");
2559#else
2561 bail(
"could not kill failed postmaster: error code %lu",
2562 GetLastError());
2563#endif
2564 bail(
"postmaster failed");
2565 }
2566
2568
2569#ifdef _WIN64
2570/* need a series of two casts to convert HANDLE without compiler warning */
2571#define ULONGPID(x) (unsigned long) (unsigned long long) (x)
2572#else
2573#define ULONGPID(x) (unsigned long) (x)
2574#endif
2575 note(
"using temp instance on port %d with PID %lu",
2577 }
2578 else
2579 {
2580 /*
2581 * Using an existing installation, so may need to get rid of
2582 * pre-existing database(s) and role(s)
2583 */
2585 {
2590 }
2591 }
2592
2593 /*
2594 * Create the test database(s) and role(s)
2595 */
2597 {
2602 }
2603
2604 /*
2605 * Ready to run the tests
2606 */
2608 {
2610 }
2611
2613 {
2615 }
2616
2617 /*
2618 * Shut down temp installation's postmaster
2619 */
2621 {
2623 }
2624
2625 /*
2626 * If there were no errors, remove the temp instance immediately to
2627 * conserve disk space. (If there were errors, we leave the instance in
2628 * place for possible manual investigation.)
2629 */
2631 {
2633 diag(
"could not remove temp instance \"%s\"",
2635 }
2636
2637 /*
2638 * Emit a TAP compliant Plan
2639 */
2641
2642 /*
2643 * Emit nice-looking summary message
2644 */
2647 else
2649
2651 {
2652 diag(
"The differences that caused some tests to fail can be viewed in the file \"%s\".",
2654 diag(
"A copy of the test summary that you see above is saved in the file \"%s\".",
2656 }
2657 else
2658 {
2661 }
2662
2665
2667 exit(1);
2668
2669 return 0;
2670}
static Datum values[MAXATTR]
#define PG_TEXTDOMAIN(domain)
void set_pglocale_pgservice(const char *argv0, const char *app)
PGPing PQpingParams(const char *const *keywords, const char *const *values, int expand_dbname)
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
#define required_argument
static const JsonPathKeyword keywords[]
void pg_logging_init(const char *argv0)
#define pg_log_error_hint(...)
void pfree(void *pointer)
PGDLLIMPORT char * optarg
static void open_result_files(void)
static int max_connections
static bool port_specified_by_user
static void stop_postmaster(void)
static int max_concurrent_tests
static void create_database(const char *dbname)
static void free_stringlist(_stringlist **listhead)
static void drop_role_if_exists(const char *rolename)
static void unlimit_core_size(void)
static bool directory_exists(const char *dir)
static _stringlist * schedulelist
#define WAIT_TICKS_PER_SECOND
static _stringlist * loadextension
static char * logfilename
static _stringlist * temp_configs
static _stringlist * extra_tests
static void make_directory(const char *dir)
static void split_to_stringlist(const char *s, const char *delim, _stringlist **listhead)
static void run_single_test(const char *test, test_start_function startfunc, postprocess_result_function postfunc)
const char * pretty_diff_opts
static char * difffilename
static char * config_auth_datadir
static void drop_database_if_exists(const char *dbname)
static void initialize_environment(void)
static char * temp_instance
static const char * sockdir
static long file_size(const char *file)
static bool postmaster_running
static const char * progname
static _stringlist * extraroles
PID_TYPE spawn_process(const char *cmdline)
static void create_role(const char *rolename, const _stringlist *granted_dbs)
static void run_schedule(const char *schedule, test_start_function startfunc, postprocess_result_function postfunc)
void add_stringlist_item(_stringlist **listhead, const char *str)
static PID_TYPE postmaster_pid
char * make_absolute_path(const char *path)
const char * get_progname(const char *argv0)
void get_restricted_token(void)
bool rmtree(const char *path, bool rmtopdir)
void pg_usleep(long microsec)
void appendStringInfo(StringInfo str, const char *fmt,...)
void appendStringInfoString(StringInfo str, const char *s)
void initStringInfo(StringInfo str)