1 /*-------------------------------------------------------------------------
2 *
3 * isolation_main --- pg_regress test launcher for isolation tests
4 *
5 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
7 *
8 * src/test/isolation/isolation_main.c
9 *
10 *-------------------------------------------------------------------------
11 */
12
13 #include "pg_regress.h"
14
15 char saved_argv0[MAXPGPATH];
16 char isolation_exec[MAXPGPATH];
17 bool looked_up_isolation_exec = false;
18
19 #define PG_ISOLATION_VERSIONSTR "isolationtester (PostgreSQL) " PG_VERSION "\n"
20
21 /*
22 * start an isolation tester process for specified file (including
23 * redirection), and return process ID
24 */
25 static PID_TYPE
isolation_start_test(const char * testname,_stringlist ** resultfiles,_stringlist ** expectfiles,_stringlist ** tags)26 isolation_start_test(const char *testname,
27 _stringlist **resultfiles,
28 _stringlist **expectfiles,
29 _stringlist **tags)
30 {
31 PID_TYPE pid;
32 char infile[MAXPGPATH];
33 char outfile[MAXPGPATH];
34 char expectfile[MAXPGPATH];
35 char psql_cmd[MAXPGPATH * 3];
36 size_t offset = 0;
37
38 /* need to do the path lookup here, check isolation_init() for details */
39 if (!looked_up_isolation_exec)
40 {
41 /* look for isolationtester binary */
42 if (find_other_exec(saved_argv0, "isolationtester",
43 PG_ISOLATION_VERSIONSTR, isolation_exec) != 0)
44 {
45 fprintf(stderr, _("could not find proper isolationtester binary\n"));
46 exit(2);
47 }
48 looked_up_isolation_exec = true;
49 }
50
51 /*
52 * Look for files in the output dir first, consistent with a vpath search.
53 * This is mainly to create more reasonable error messages if the file is
54 * not found. It also allows local test overrides when running pg_regress
55 * outside of the source tree.
56 */
57 snprintf(infile, sizeof(infile), "%s/specs/%s.spec",
58 outputdir, testname);
59 if (!file_exists(infile))
60 snprintf(infile, sizeof(infile), "%s/specs/%s.spec",
61 inputdir, testname);
62
63 snprintf(outfile, sizeof(outfile), "%s/results/%s.out",
64 outputdir, testname);
65
66 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s.out",
67 outputdir, testname);
68 if (!file_exists(expectfile))
69 snprintf(expectfile, sizeof(expectfile), "%s/expected/%s.out",
70 inputdir, testname);
71
72 add_stringlist_item(resultfiles, outfile);
73 add_stringlist_item(expectfiles, expectfile);
74
75 if (launcher)
76 {
77 offset += snprintf(psql_cmd + offset, sizeof(psql_cmd) - offset,
78 "%s ", launcher);
79 if (offset >= sizeof(psql_cmd))
80 {
81 fprintf(stderr, _("command too long\n"));
82 exit(2);
83 }
84 }
85
86 offset += snprintf(psql_cmd + offset, sizeof(psql_cmd) - offset,
87 "\"%s\" \"dbname=%s\" < \"%s\" > \"%s\" 2>&1",
88 isolation_exec,
89 dblist->str,
90 infile,
91 outfile);
92 if (offset >= sizeof(psql_cmd))
93 {
94 fprintf(stderr, _("command too long\n"));
95 exit(2);
96 }
97
98 pid = spawn_process(psql_cmd);
99
100 if (pid == INVALID_PID)
101 {
102 fprintf(stderr, _("could not start process for test %s\n"),
103 testname);
104 exit(2);
105 }
106
107 return pid;
108 }
109
110 static void
isolation_init(int argc,char ** argv)111 isolation_init(int argc, char **argv)
112 {
113 size_t argv0_len;
114
115 /*
116 * We unfortunately cannot do the find_other_exec() lookup to find the
117 * "isolationtester" binary here. regression_main() calls the
118 * initialization functions before parsing the commandline arguments and
119 * thus hasn't changed the library search path at this point which in turn
120 * can cause the "isolationtester -V" invocation that find_other_exec()
121 * does to fail since it's linked to libpq. So we instead copy argv[0]
122 * and do the lookup the first time through isolation_start_test().
123 */
124 argv0_len = strlcpy(saved_argv0, argv[0], MAXPGPATH);
125 if (argv0_len >= MAXPGPATH)
126 {
127 fprintf(stderr, _("path for isolationtester executable is longer than %d bytes\n"),
128 (int) (MAXPGPATH - 1));
129 exit(2);
130 }
131
132 /* set default regression database name */
133 add_stringlist_item(&dblist, "isolation_regression");
134 }
135
136 int
main(int argc,char * argv[])137 main(int argc, char *argv[])
138 {
139 return regression_main(argc, argv, isolation_init, isolation_start_test);
140 }
141