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