Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8c361e4

Browse files
committed
TAP: Add easier, more flexible ways to invoke psql
The PostgresNode::psql method is limited - it offers no accessto the return code from psql, ignores SQL errors, and offersno access to psql's stderr.Provide a new psql_expert that addresses those limitations andcan be used more flexibly - see the embedded PerlDoc for details.Also add a new psql_check method that invokes psql and dies ifthe SQL fails with any error. Test scripts should use this sothey automatically die if SQL that should succeed fails instead;with the current psql method such failures would go undetected.
1 parent8fd42e6 commit8c361e4

File tree

1 file changed

+221
-12
lines changed

1 file changed

+221
-12
lines changed

‎src/test/perl/PostgresNode.pm

Lines changed: 221 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,20 @@ PostgresNode - class representing PostgreSQL server instance
2121
$node->restart('fast');
2222
2323
# run a query with psql
24-
# like: psql -qAXt postgres -c 'SELECT 1;'
25-
$psql_stdout = $node->psql('postgres', 'SELECT 1');
24+
# like:
25+
# echo 'SELECT 1' | psql -qAXt postgres -v ON_ERROR_STOP=1
26+
$psql_stdout = $node->psql_check('postgres', 'SELECT 1');
27+
28+
# Run psql with a timeout, capturing stdout and stderr
29+
# as well as the psql exit code. Pass some extra psql
30+
# options. If there's an error from psql raise an exception.
31+
my ($stdout, $stderr, $timed_out);
32+
my $cmdret = $psql_expert('postgres', 'SELECT pg_sleep(60)',
33+
stdout => \$stdout, stderr => \$stderr,
34+
timeout => 30, timed_out => \$timed_out,
35+
extra_params => ['--single-transaction'],
36+
on_error_die => 1)
37+
print "Sleep timed out" if $timed_out;
2638
2739
# run query every second until it returns 't'
2840
# or times out
@@ -69,6 +81,7 @@ use IPC::Run;
6981
use RecursiveCopy;
7082
use Test::More;
7183
use TestLib ();
84+
use Scalar::Utilqw(blessed);
7285

7386
our@EXPORT =qw(
7487
get_new_node
@@ -780,11 +793,16 @@ sub teardown_node
780793
781794
=item$node->psql(dbname, sql)
782795
783-
Run a query with psql and return stdout, or on error print stderr.
796+
Run a query with psql and return stdout if psql returns with no error.
784797
785-
Executes a query/script with psql and returns psql's standard output. psql is
786-
run in unaligned tuples-only quiet mode with psqlrc disabled so simple queries
787-
will just return the result row(s) with fields separated by commas.
798+
psql is run in unaligned tuples-only quiet mode with psqlrc disabled so simple
799+
queries will just return the result row(s) with fields separated by commas.
800+
801+
If any stderr output is generated it is printed and discarded.
802+
803+
Nonzero return codes from psql are ignored and discarded.
804+
805+
Use psql_expert for more control.
788806
789807
=cut
790808

@@ -793,24 +811,215 @@ sub psql
793811
my ($self,$dbname,$sql) =@_;
794812

795813
my ($stdout,$stderr);
814+
796815
my$name =$self->name;
797816
print("### Running SQL command on node\"$name\":$sql\n");
798817

799-
IPC::Run::run ['psql','-XAtq','-d',$self->connstr($dbname),'-f',
800-
'-' ],'<', \$sql,'>', \$stdout,'2>', \$stderr
801-
ordie;
818+
# Run the command, ignoring errors
819+
$self->psql_expert($dbname,$sql,stdout=> \$stdout,stderr=> \$stderr,
820+
on_error_die=> 0,on_error_stop=> 0);
821+
822+
if ($stderrne"")
823+
{
824+
print"#### Begin standard error\n";
825+
print$stderr;
826+
print"\n#### End standard error\n";
827+
}
828+
return$stdout;
829+
}
830+
831+
=pod $node->psql_check($dbname, $sql) => stdout
832+
833+
Invoke 'psql' to run 'sql' on 'dbname' and return its stdout on success.
834+
Die if the SQL produces an error. Runs with ON_ERROR_STOP set.
835+
836+
Takes optional extra params like timeout and timed_out parameters with the same
837+
options as psql_expert.
802838
839+
=cut
840+
841+
subpsql_check
842+
{
843+
my ($self,$dbname,$sql,%params) =@_;
844+
845+
my ($stdout,$stderr);
846+
847+
my$ret =$self->psql_expert($dbname,$sql,
848+
%params,
849+
stdout=> \$stdout,stderr=> \$stderr,
850+
on_error_die=> 1,on_error_stop=> 1);
851+
852+
# psql can emit stderr from NOTICEs etc
803853
if ($stderrne"")
804854
{
805855
print"#### Begin standard error\n";
806856
print$stderr;
807-
print"#### End standard error\n";
857+
print"\n#### End standard error\n";
808858
}
809-
chomp$stdout;
810-
$stdout =~s/\r//gif$Config{osname}eq'msys';
859+
811860
return$stdout;
812861
}
813862

863+
=pod $node->psql_expert($dbname, $sql, %params) => psql_retval
864+
865+
Invoke 'psql' to run 'sql' on 'dbname' and return the return value from
866+
psql, which is run with on_error_stop by default so that it will stop running
867+
sql and return 3 if the passed SQL results in an error.
868+
869+
psql is invoked in tuples-only unaligned mode with reading of psqlrc disabled. That
870+
may be overridden by passing extra psql parameters.
871+
872+
stdout and stderr are transformed to unix line endings if on Windows and any
873+
trailing newline is removed.
874+
875+
Dies on failure to invoke psql but not if psql exits with a nonzero return code
876+
(unless on_error_die specified). Dies if psql exits with a signal.
877+
878+
=over
879+
880+
=itemstdout => \$stdout
881+
882+
If a scalar to write stdout to is passed as the keyword parameter 'stdout' it
883+
will be set to psql's stdout.
884+
885+
=itemstderr => \$stderr
886+
887+
Same as 'stdout' but gets stderr. If the same scalar is passed for both stdout
888+
and stderr the results may be interleaved unpredictably.
889+
890+
=itemon_error_stop => 1
891+
892+
By default psql_expert invokes psql with ON_ERROR_STOP=1 set so it will
893+
stop executing SQL at the first error and return exit code 2. If you want
894+
to ignore errors, pass 0 to on_error_stop.
895+
896+
=itemon_error_die => 0
897+
898+
By default psql_expert returns psql's result code. Pass on_error_die to instead
899+
die with an informative message.
900+
901+
=itemtimeout => 'interval'
902+
903+
Set a timeout for the psql call as an interval accepted by IPC::Run::timer.
904+
Integer seconds is fine. psql_expert dies with an exception on timeout unless
905+
the timed_out parameter is passed.
906+
907+
=itemtimed_out => \$timed_out
908+
909+
Keyword parameter. Pass a scalar reference and it'll be set to true if the psql
910+
call timed out instead of dying. Has no effect unless 'timeout' is set.
911+
912+
=itemextra_params => ['--single-transaction']
913+
914+
Pass additional parameters to psql. Must be an arrayref.
915+
916+
=back
917+
918+
e.g.
919+
920+
my ($stdout, $stderr, $timed_out);
921+
my $cmdret = $psql_expert('postgres', 'SELECT pg_sleep(60)',
922+
stdout => \$stdout, stderr => \$stderr,
923+
timeout => 30, timed_out => \$timed_out,
924+
extra_params => ['--single-transaction'])
925+
926+
will set $cmdret to undef and $timed_out to a true value.
927+
928+
$psql_expert('postgres', $sql, on_error_die => 1);
929+
930+
dies with an informative message if $sql fails.
931+
932+
=cut
933+
934+
subpsql_expert
935+
{
936+
my ($self,$dbname,$sql,%params) =@_;
937+
938+
my$stdout =$params{stdout};
939+
my$stderr =$params{stderr};
940+
my$timeout =undef;
941+
my$timeout_exception ='psql timed out';
942+
my@psql_params = ('psql','-XAtq','-d',$self->connstr($dbname),'-f','-');
943+
944+
$params{on_error_stop} = 1unlessdefined$params{on_error_stop};
945+
$params{on_error_die} = 0unlessdefined$params{on_error_die};
946+
947+
push@psql_params,'-v','ON_ERROR_STOP=1'if$params{on_error_stop};
948+
push@psql_params, @{$params{extra_params}}ifdefined$params{extra_params};
949+
950+
$timeout = IPC::Run::timeout($params{timeout},exception=>$timeout_exception)
951+
if (defined($params{timeout}));
952+
953+
# IPC::Run would otherwise append to existing contents:
954+
$$stdout =""ifref($stdout);
955+
$$stderr =""ifref($stderr);
956+
957+
my$ret;
958+
959+
# Perl's exception handling is ... interesting. Especially since we have to
960+
# support 5.8.8. So we hide that from the caller, returning true/false for
961+
# timeout instead. See
962+
# http://search.cpan.org/~ether/Try-Tiny-0.24/lib/Try/Tiny.pm for
963+
# background.
964+
my$error =do {
965+
local$@;
966+
eval {
967+
IPC::Run::run \@psql_params,'<', \$sql,'>',$stdout,'2>',$stderr,$timeout;
968+
$ret =$?;
969+
};
970+
my$exc_save =$@;
971+
if ($exc_save) {
972+
# IPC::Run::run threw an exception. re-throw unless it's a
973+
# timeout, which we'll handle by testing is_expired
974+
if (blessed($exc_save) ||$exc_savene$timeout_exception) {
975+
print"Exception from IPC::Run::run when invoking psql: '$exc_save'\n";
976+
die$exc_save;
977+
}else {
978+
$ret =undef;
979+
980+
die"Got timeout exception '$exc_save' but timer not expired?!"
981+
unless$timeout->is_expired;
982+
983+
if (defined($params{timed_out}))
984+
{
985+
${$params{timed_out}} = 1;
986+
}else {
987+
die"psql timed out while running '@psql_params', stderr '$$stderr'";
988+
}
989+
}
990+
}
991+
};
992+
993+
chomp$$stdout;
994+
$$stdout =~s/\r//gif$Config{osname}eq'msys';
995+
996+
chomp$$stderr;
997+
$$stderr =~s/\r//gif$Config{osname}eq'msys';
998+
999+
# See http://perldoc.perl.org/perlvar.html#%24CHILD_ERROR
1000+
# We don't use IPC::Run::Simple to limit dependencies.
1001+
#
1002+
# We always die on signal. If someone wants to capture signals
1003+
# to psql we can return it with another reference out parameter.
1004+
die"psql exited with signal" . ($ret & 127) .": '$$stderr' while running '@psql_params'"
1005+
if$ret & 127;
1006+
die"psql exited with core dump: '$$stderr' while running '@psql_params'"
1007+
if$ret & 128;
1008+
$ret =$ret >> 8;
1009+
1010+
if ($ret &&$params{on_error_die}) {
1011+
die"psql command line syntax error or internal error: '$$stderr' while running '@psql_params'"
1012+
if$ret == 1;
1013+
die"psql connection error: '$$stderr' while running '@psql_params'"
1014+
if$ret == 2;
1015+
die"error when running passed SQL: '$$stderr' while running '@psql_params'"
1016+
if$ret == 3;
1017+
die"unexpected error code$ret from psql: '$$stderr' while running '@psql_params'";
1018+
}
1019+
1020+
return$ret;
1021+
}
1022+
8141023
=pod
8151024
8161025
=item$node->poll_query_until(dbname, query)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp