>From dc4f937e1d7bd9ebabef056fb9b702e8fac06e40 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <daniel@yesql.se>
Date: Wed, 2 Aug 2017 23:02:24 +0200
Subject: [PATCH 1/2] Allow running SSL tests against different binaries

In order to be able to test work on SSL frontends, or backends,
against a stock installation, allow a pgpath setting to override
the path to the binaries. The SSLTEST_SERVER_BIN environment var
will be used, if set, for which set of server binaries to run.

  SSLTEST_SERVER_BIN=/path/bin/ make -C src/test/ssl/ check

This is for testing during development in order to test a new
frontend against a known backend for example.
---
 src/test/perl/PostgresNode.pm  | 77 ++++++++++++++++++++++++++++++++----------
 src/test/ssl/t/001_ssltests.pl |  2 +-
 2 files changed, 60 insertions(+), 19 deletions(-)

diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index bf982101a5..86236bbd91 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -132,7 +132,7 @@ INIT
 
 =over
 
-=item PostgresNode::new($class, $name, $pghost, $pgport)
+=item PostgresNode::new($class, $name, $pghost, $pgport, $pgpath)
 
 Create a new PostgresNode instance. Does not initdb or start it.
 
@@ -143,12 +143,14 @@ of finding port numbers, registering instances for cleanup, etc.
 
 sub new
 {
-	my ($class, $name, $pghost, $pgport) = @_;
+	my ($class, $name, $pghost, $pgport, $pgpath) = @_;
 	my $testname = basename($0);
 	$testname =~ s/\.[^.]+$//;
+	$pgpath = '' unless defined $pgpath;
 	my $self = {
 		_port    => $pgport,
 		_host    => $pghost,
+		_pgpath  => $pgpath,
 		_basedir => TestLib::tempdir("data_" . $name),
 		_name    => $name,
 		_logfile => "$TestLib::log_path/${testname}_${name}.log" };
@@ -223,6 +225,21 @@ sub name
 
 =pod
 
+=item $node->pgpath()
+
+Path to the PostgreSQL binaries to run, if empty then the installation in PATH
+is assumed.
+
+=cut
+
+sub pgpath
+{
+	my ($self) = @_;
+	return $self->{_pgpath};
+}
+
+=pod
+
 =item $node->logfile()
 
 Path to the PostgreSQL log file for this instance.
@@ -323,6 +340,7 @@ sub info
 	my $_info = '';
 	open my $fh, '>', \$_info or die;
 	print $fh "Name: " . $self->name . "\n";
+	print $fh "Binary directory: " . $self->pgpath . "\n";
 	print $fh "Data directory: " . $self->data_dir . "\n";
 	print $fh "Backup directory: " . $self->backup_dir . "\n";
 	print $fh "Archive directory: " . $self->archive_dir . "\n";
@@ -398,6 +416,7 @@ sub init
 	my $port   = $self->port;
 	my $pgdata = $self->data_dir;
 	my $host   = $self->host;
+	my $pgpath = $self->pgpath;
 
 	$params{allows_streaming} = 0 unless defined $params{allows_streaming};
 	$params{has_archiving}    = 0 unless defined $params{has_archiving};
@@ -405,7 +424,7 @@ sub init
 	mkdir $self->backup_dir;
 	mkdir $self->archive_dir;
 
-	TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N',
+	TestLib::system_or_bail($pgpath . 'initdb', '-D', $pgdata, '-A', 'trust', '-N',
 		@{ $params{extra} });
 	TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata);
 
@@ -499,9 +518,10 @@ sub backup
 	my $backup_path = $self->backup_dir . '/' . $backup_name;
 	my $port        = $self->port;
 	my $name        = $self->name;
+	my $pgpath      = $self->pgpath;
 
 	print "# Taking pg_basebackup $backup_name from node \"$name\"\n";
-	TestLib::system_or_bail('pg_basebackup', '-D', $backup_path, '-p', $port,
+	TestLib::system_or_bail($pgpath . 'pg_basebackup', '-D', $backup_path, '-p', $port,
 		'--no-sync');
 	print "# Backup finished\n";
 }
@@ -657,8 +677,9 @@ sub start
 	my $pgdata = $self->data_dir;
 	my $name   = $self->name;
 	BAIL_OUT("node \"$name\" is already running") if defined $self->{_pid};
+	my $pgpath = $self->pgpath;
 	print("### Starting node \"$name\"\n");
-	my $ret = TestLib::system_log('pg_ctl', '-D', $self->data_dir, '-l',
+	my $ret = TestLib::system_log($pgpath . 'pg_ctl', '-D', $self->data_dir, '-l',
 		$self->logfile, 'start');
 
 	if ($ret != 0)
@@ -689,10 +710,11 @@ sub stop
 	my $port   = $self->port;
 	my $pgdata = $self->data_dir;
 	my $name   = $self->name;
+	my $pgpath = $self->pgpath;
 	$mode = 'fast' unless defined $mode;
 	return unless defined $self->{_pid};
 	print "### Stopping node \"$name\" using mode $mode\n";
-	TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-m', $mode, 'stop');
+	TestLib::system_or_bail($pgpath . 'pg_ctl', '-D', $pgdata, '-m', $mode, 'stop');
 	$self->_update_pid(0);
 }
 
@@ -710,8 +732,10 @@ sub reload
 	my $port   = $self->port;
 	my $pgdata = $self->data_dir;
 	my $name   = $self->name;
+	my $pgpath = $self->pgpath;
 	print "### Reloading node \"$name\"\n";
-	TestLib::system_or_bail('pg_ctl', '-D', $pgdata, 'reload');
+	TestLib::system_or_bail($pgpath . 'pg_ctl', '-D', $pgdata, 'reload');
+
 }
 
 =pod
@@ -729,8 +753,9 @@ sub restart
 	my $pgdata  = $self->data_dir;
 	my $logfile = $self->logfile;
 	my $name    = $self->name;
+	my $pgpath  = $self->pgpath;
 	print "### Restarting node \"$name\"\n";
-	TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile,
+	TestLib::system_or_bail($pgpath . 'pg_ctl', '-D', $pgdata, '-l', $logfile,
 		'restart');
 	$self->_update_pid(1);
 }
@@ -750,8 +775,9 @@ sub promote
 	my $pgdata  = $self->data_dir;
 	my $logfile = $self->logfile;
 	my $name    = $self->name;
+	my $pgpath  = $self->pgpath;
 	print "### Promoting node \"$name\"\n";
-	TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile,
+	TestLib::system_or_bail($pgpath . 'pg_ctl', '-D', $pgdata, '-l', $logfile,
 		'promote');
 }
 
@@ -855,12 +881,15 @@ sub _update_pid
 
 =pod
 
-=item PostgresNode->get_new_node(node_name)
+=item PostgresNode->get_new_node(node_name, pgpath)
 
 Build a new object of class C<PostgresNode> (or of a subclass, if you have
 one), assigning a free port number.  Remembers the node, to prevent its port
 number from being reused for another node, and to ensure that it gets
-shut down when the test script exits.
+shut down when the test script exits. If the pgpath parameter is defined then
+the path is tested for containing a PostgreSQL installation with the correct
+permissions for execution.
+
 
 You should generally use this instead of C<PostgresNode::new(...)>.
 
@@ -872,8 +901,8 @@ which can only create objects of class C<PostgresNode>.
 sub get_new_node
 {
 	my $class = 'PostgresNode';
-	$class = shift if 1 < scalar @_;
-	my $name  = shift;
+	$class = shift if 2 < scalar @_;
+	my ($name, $pgpath) = @_;
 	my $found = 0;
 	my $port  = $last_port_assigned;
 
@@ -916,8 +945,19 @@ sub get_new_node
 
 	print "# Found free port $port\n";
 
+	# If a separate path to the binaries was specified then we do rudimentary
+	# checks for a sane installation. If an executable copy of initdb is there
+	# then let's go ahead.
+	if (defined $pgpath)
+	{
+		$pgpath =~ s!/*$!/!;
+		die "initdb missing in $pgpath" unless -x $pgpath . 'initdb';
+
+		print "# Found PostgreSQL installation in $pgpath\n";
+	}
+
 	# Lock port number found by creating a new node
-	my $node = $class->new($name, $test_pghost, $port);
+	my $node = $class->new($name, $test_pghost, $port, $pgpath);
 
 	# Add node to list of nodes
 	push(@all_nodes, $node);
@@ -1087,8 +1127,9 @@ sub psql
 	my $stderr            = $params{stderr};
 	my $timeout           = undef;
 	my $timeout_exception = 'psql timed out';
+	my $pgpath            = $self->pgpath;
 	my @psql_params =
-	  ('psql', '-XAtq', '-d', $self->connstr($dbname), '-f', '-');
+	  ($pgpath . 'psql', '-XAtq', '-d', $self->connstr($dbname), '-f', '-');
 
 	# If the caller wants an array and hasn't passed stdout/stderr
 	# references, allocate temporary ones to capture them so we
@@ -1230,12 +1271,12 @@ Returns 1 if successful, 0 if timed out.
 
 sub poll_query_until
 {
-	my ($self, $dbname, $query, $expected) = @_;
+	my ($self, $dbname, $query, $expected, $pgpath) = @_;
 
 	$expected = 't' unless defined($expected);	# default value
 
 	my $cmd =
-		[ 'psql', '-XAt', '-c', $query, '-d', $self->connstr($dbname) ];
+		[ $pgpath . 'psql', '-XAt', '-c', $query, '-d', $self->connstr($dbname) ];
 	my ($stdout, $stderr);
 	my $max_attempts = 180 * 10;
 	my $attempts     = 0;
@@ -1448,7 +1489,7 @@ sub wait_for_catchup
 	  . $self->name . "\n";
 	my $query =
 qq[SELECT '$target_lsn' <= ${mode}_lsn FROM pg_catalog.pg_stat_replication WHERE application_name = '$standby_name';];
-	$self->poll_query_until('postgres', $query)
+	$self->poll_query_until('postgres', $query, $self->pgpath)
 	  or die "timed out waiting for catchup, current location is "
 	  . ($self->safe_psql('postgres', $query) || '(unknown)');
 	print "done\n";
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 32df273929..f4daf46e44 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -59,7 +59,7 @@ chmod 0600, "ssl/client_tmp.key";
 #### Part 0. Set up the server.
 
 note "setting up data directory";
-my $node = get_new_node('master');
+my $node = get_new_node('master', $ENV{SSLTEST_SERVER_BIN});
 $node->init;
 
 # PGHOST is enforced here to set up the node, subsequent connections
-- 
2.13.0.rc0.45.ge2cb6ab.dirty

