Build.PL100644001750001750 45513361514502 14447 0ustar00tjctjc000000000000Test-PostgreSQL-1.27# ========================================================================= # THIS FILE IS AUTOMATICALLY GENERATED BY MINILLA. # DO NOT EDIT DIRECTLY. # ========================================================================= use 5.008_001; use strict; use Module::Build::Tiny 0.035; Build_PL(); Changes100644001750001750 706113361514502 14466 0ustar00tjctjc000000000000Test-PostgreSQL-1.27Revision history for Perl extension Test::PostgreSQL. 1.27 2018-10-17T02:06:08Z - Use pg_version attribute to better handle -b and -f psql switches depending on installed PostgreSQL version - Updated docs to reflect the changes - Tests are passing with PostgreSQL 9.3+ - pg_version attribute holds PostgreSQL version detected at startup - Improved test diagnostics 1.26 - Fix postgresql.conf test on PostgreSQL prior to 9.2 1.25 - Don't continue to wait if Postgres PID has gone - Database seeding after startup - Allow writing custom postgresql.conf instead of always emptying it - Suppress "pg_ctl: could not start server" messages on stderr - More config options 1.24 - Adds support for UNIX socket connections to PostgreSQL - Adds psql method to retrieve appropriate CLI parameters - Recognize devel PostgreSQL versions 1.23 - Fix missing META files RT:121425 1.22 - Add parentheses to all method keywords to deal with change in upstream F::P 1.21 - If run as root in a Docker container, attempts to setuid before calling pg_ctl 1.20 - Major refactor, including converting to Moo and improving error handling and reporting. - changes to help when stop is called during DESTROY RT#111181 - Fix RT#110972 by not rel2abs-ing File::Temp objects - add backwards-compatibility code for deprecated global %Defaults 1.10 - localise $? in DESTROY closes rt#107957 - Increase portability in general and for Windows especially 1.05 Tue Sep 16 12:23:27 2014 - Refactor how binaries are located on the path - Fix connection error when connecting too fast - fix POD 1.04 Fri Aug 15 15:27:53 2014 - Support POSTGRES_HOME environment variable - Tweak author, copyright; upgrade license to Artistic 2.0 1.03 Thu Aug 14 16:02:52 2014 - deadlock.t - Skip plan if we can't initialize postgresql - Add extra paths to postgresql, for BSDs 1.02 Wed Aug 6 13:49:25 2014 - Back out lower-case Test::postgresql as it caused too many problems with CPAN indexer 1.01 Mon Aug 4 12:28:13 2014 - Include lower-case Test::postgresql module as shim for users of that module to the new one 1.00 Wed Jul 09 11:30:00 2014 - Use pure default Postgresql config as some package managers mess around with postgresql.conf too much. - open log file in append mode to avoid different processes overwriting - Add URI accessor to return postgresql::// connection string - POD fixes 0.10 Fri Jun 22 15:30:00 2012 - Name change to Test::PostgreSQL - Avoid deadlocks during Postgres shutdown. 0.09 Fri Oct 23 16:50:00 2009 - change cwd and directory permissions, modes for better testing 0.08 Fri Oct 16 13:25:00 2009 - do not destroy postmaster when child process exits 0.07 Thu Oct 15 14:14:00 2009 - fix degradation in 0.04 (tests failed when running as root) 0.06 Thu Oct 15 09:40:00 2009 - dsn() defaults to an empty "test" database for better interoperability with Test::mysqld 0.05 Thu Oct 15 08:10:00 2009 - add macport installation target dir to default search paths - adjust pod synopsis to follow the changes in 0.04 0.04 Thu Oct 15 08:00:00 2009 - add dsn generator - use "postmaster_args" on pastmaster start (thanks to HSW) - create temporary files within base_dir (ubuntu / debian compatibility) - add .deb package installation target dir to default search paths 0.03 Thu Aug 20 21:00:00 2009 - preserve port number on restart 0.02 Wed Aug 19 19:30:00 2009 - use given port number if given 0.01 Mon Aug 17 21:15:00 2009 - initial release LICENSE100644001750001750 2130613361514502 14216 0ustar00tjctjc000000000000Test-PostgreSQL-1.27 The Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. META.json100644001750001750 561213361514502 14614 0ustar00tjctjc000000000000Test-PostgreSQL-1.27{ "abstract" : "PostgreSQL runner for tests", "author" : [ "Toby Corkindale, Kazuho Oku, Peter Mottram, Alex Tokarev, plus various contributors." ], "dynamic_config" : 0, "generated_by" : "Minilla/v3.1.2", "license" : [ "artistic_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Test-PostgreSQL", "no_index" : { "directory" : [ "t", "xt", "inc", "share", "eg", "examples", "author", "builder" ] }, "prereqs" : { "configure" : { "requires" : { "Module::Build::Tiny" : "0.035" } }, "develop" : { "requires" : { "Software::License" : "0", "Test::CPAN::Meta" : "0", "Test::MinimumVersion::Fast" : "0.04", "Test::PAUSE::Permissions" : "0.04", "Test::Pod" : "1.41", "Test::Spellunker" : "v0.2.7" } }, "runtime" : { "requires" : { "DBD::Pg" : "0", "DBI" : "0", "File::Spec" : "0", "File::Which" : "0", "Function::Parameters" : "0", "Moo" : "0", "POSIX" : "0", "Tie::Hash::Method" : "0", "Try::Tiny" : "0", "Types::Standard" : "0", "User::pwent" : "0", "perl" : "5.014" } }, "test" : { "requires" : { "DBD::Pg" : "0", "Test::SharedFork" : "0.06" } } }, "provides" : { "Test::PostgreSQL" : { "file" : "lib/Test/PostgreSQL.pm", "version" : "1.27" } }, "release_status" : "stable", "resources" : { "homepage" : "https://github.com/TJC/Test-postgresql", "repository" : { "url" : "git://github.com/TJC/Test-postgresql.git", "web" : "https://github.com/TJC/Test-postgresql" } }, "version" : "1.27", "x_contributors" : [ "Alex Tokarev ", "Alex Tokarev ", "Dagfinn Ilmari Mannsåker ", "Dan Book ", "David Steinbrunner ", "Don Armstrong ", "Eric Radman ", "Matthew Somerville ", "Michal Sedlák ", "Paul Williams ", "Peter Mottram ", "Russell Jenkins ", "Russell Jenkins ", "Toby ", "Toby Corkindale ", "root " ], "x_serialization_backend" : "JSON::PP version 2.27400_02", "x_static_install" : 1 } README.md100644001750001750 2057313361514502 14475 0ustar00tjctjc000000000000Test-PostgreSQL-1.27[![Build Status](https://circleci.com/gh/TJC/Test-postgresql.svg)](https://circleci.com/gh/TJC/Test-postgresql) # NAME Test::PostgreSQL - PostgreSQL runner for tests # SYNOPSIS use DBI; use Test::PostgreSQL; use Test::More; # optionally # (if not already set at shell): # # $ENV{POSTGRES_HOME} = '/path/to/my/pgsql/installation'; my $pgsql = eval { Test::PostgreSQL->new() } or plan skip_all => $@; plan tests => XXX; my $dbh = DBI->connect($pgsql->dsn); # DESCRIPTION `Test::PostgreSQL` automatically setups a PostgreSQL instance in a temporary directory, and destroys it when the perl script exits. This module is a fork of Test::postgresql, which was abandoned by its author several years ago. # ATTRIBUTES `Test::PostgreSQL` object has the following attributes, overridable by passing corresponding argument to constructor: ## dbname Database name to use in this `Test::PostgreSQL` instance. Default is `test`. ## dbowner Database owner user name. Default is `postgres`. ## host Host name or IP address to use for PostgreSQL instance connections. Default is `127.0.0.1`. ## base\_dir Base directory under which the PostgreSQL instance is being created. The property can be passed as a parameter to the constructor, in which case the directory will not be removed at exit. ## base\_port Connection port number to start with. If the port is already used we will increment the value and try again. Default: `15432`. ## unix\_socket Whether to only connect via UNIX sockets; if false (the default), connections can occur via localhost. \[This changes the ["dsn"](#dsn) returned to only give the UNIX socket directory, and avoids any issues with conflicting TCP ports on localhost.\] ## socket\_dir Unix socket directory to use if ["unix\_socket"](#unix_socket) is true. Default is `$basedir/tmp`. ## pg\_ctl Path to `pg_ctl` program which is part of the PostgreSQL distribution. Starting with PostgreSQL version 9.0 `pg_ctl` can be used to start/stop postgres without having to use fork/pipe and will be chosen automatically if ["pg\_ctl"](#pg_ctl) is not set but the program is found and the version is recent enough. **NOTE:** do NOT use this with PostgreSQL versions prior to version 9.0. By default we will try to find `pg_ctl` in PostgresSQL directory. ## initdb Path to `initdb` program which is part of the PostreSQL distribution. Default is to try and find it in PostgreSQL directory. ## initdb\_args Arguments to pass to `initdb` program when creating a new PostgreSQL database cluster for Test::PostgreSQL session. Defaults to `-U postgres -A trust`. See ["db\_owner"](#db_owner). ## extra\_initdb\_args Extra args to be appended to ["initdb\_args"](#initdb_args). Default is empty. ## pg\_config Configuration to place in `$basedir/data/postgresql.conf`. Use this to override PostgreSQL configuration defaults, e.g. to speed up PostgreSQL database init and seeding one might use something like this: my $pgsql = Test::PostgreSQL->new( pg_config => q| # foo baroo mymse throbbozongo fsync = off synchronous_commit = off full_page_writes = off bgwriter_lru_maxpages = 0 shared_buffers = 512MB effective_cache_size = 512MB work_mem = 100MB |); ## postmaster Path to `postmaster` which is part of the PostgreSQL distribution. If not set, the programs are automatically searched by looking up $PATH and other prefixed directories. Since `postmaster` is deprecated in newer PostgreSQL versions `postgres` is used in preference to `postmaster`. ## postmaster\_args Defaults to `-h 127.0.0.1 -F`. ## extra\_postmaster\_args Extra args to be appended to ["postmaster\_args"](#postmaster_args). Default is empty. ## psql Path to `psql` client which is part of the PostgreSQL distribution. `psql` can be used to run SQL scripts against the temporary database created by ["new"](#new): my $pgsql = Test::PostgreSQL->new(); my $psql = $pgsql->psql; my $out = `$psql -f /path/to/script.sql 2>&1`; die "Error executing script.sql: $out" unless $? == 0; ## psql\_args Command line arguments necessary for `psql` to connect to the correct PostgreSQL instance. Defaults to `-U postgres -d test -h 127.0.0.1 -p $self->port`. See also ["db\_owner"](#db_owner), ["dbname"](#dbname), ["host"](#host), ["base\_port"](#base_port). ## extra\_psql\_args Extra args to be appended to ["psql\_args"](#psql_args). ## run\_psql\_args Arguments specific for ["run\_psql"](#run_psql) invocation, used mostly to set up and seed database schema after PostgreSQL instance is launched and configured. Default is `-1Xqb -v ON_ERROR_STOP=1`. This means: - 1: Run all SQL statements in passed scripts as single transaction - X: Skip `.psqlrc` files - q: Run quietly, print only notices and errors on stderr (if any) - b: Echo SQL statements that cause PostgreSQL exceptions (version 9.5+) - -v ON\_ERROR\_STOP=1: Stop processing SQL statements after the first error ## seed\_scripts Arrayref with the list of SQL scripts to run after the database was instanced and set up. Default is `[]`. **NOTE** that `psql` older than 9.6 does not support multiple `-c` and `-f` switches in arguments so `seed_scripts` will be executed one by one. This implies multiple transactions instead of just one; if you need all seed statements to apply within a single transaction, combine them into one seed script. ## auto\_start Integer value that controls whether PostgreSQL server is started and setup after creating `Test::PostgreSQL` instance. Possible values: - `0` Do not start PostgreSQL. - `1` Start PostgreSQL but do not run ["setup"](#setup). - `2` Start PostgreSQL and run ["setup"](#setup). Default is `2`. # METHODS ## new Create and run a PostgreSQL instance. The instance is terminated when the returned object is being DESTROYed. If required programs (initdb and postmaster) were not found, the function returns undef and sets appropriate message to $Test::PostgreSQL::errstr. ## dsn Builds and returns dsn by using given parameters (if any). Default username is `postgres`, and dbname is `test` (an empty database). ## uri Builds and returns a connection URI using the given parameters (if any). See [URI::db](https://metacpan.org/pod/URI::db) for details about the format. Default username is `postgres`, and dbname is `test` (an empty database). ## pid Returns process id of PostgreSQL (or undef if not running). ## port Returns TCP port number on which postmaster is accepting connections (or undef if not running). ## start Starts postmaster. ## stop Stops postmaster. ## setup Setups the PostgreSQL instance. Note that this method should be invoked _before_ ["start"](#start). ## run\_psql Execute `psql` program with the given list of arguments. Usually this would be something like: $pgsql->run_psql('-c', q|'INSERT INTO foo (bar) VALUES (42)'|); Or: $pgsql->run_psql('-f', '/path/to/script.sql'); Note that when using literal SQL statements with `-c` parameter you will need to escape them manually like shown above. `run_psql` will not quote them for you. The actual command line to execute `psql` will be concatenated from ["psql\_args"](#psql_args), ["extra\_psql\_args"](#extra_psql_args), and ["run\_psql\_args"](#run_psql_args). **NOTE** that `psql` older than 9.6 does not support multiple `-c` and/or `-f` switches in arguments. ## run\_psql\_scripts Given a list of script file paths, invoke ["run\_psql"](#run_psql) once with `-f 'script'` for every path in PostgreSQL 9.6+, or once per `-f 'script'` for older PostgreSQL versions. # ENVIRONMENT ## POSTGRES\_HOME If your postgres installation is not located in a well known path, or you have many versions installed and want to run your tests against particular one, set this environment variable to the desired path. For example: export POSTGRES_HOME='/usr/local/pgsql94beta' This is the same idea and variable name which is used by the installer of [DBD::Pg](https://metacpan.org/pod/DBD::Pg). # AUTHOR Toby Corkindale, Kazuho Oku, Peter Mottram, Alex Tokarev, plus various contributors. # COPYRIGHT Current version copyright © 2012-2015 Toby Corkindale. Previous versions copyright (C) 2009 Cybozu Labs, Inc. # LICENSE This module is free software, released under the Perl Artistic License 2.0. See [http://www.perlfoundation.org/artistic\_license\_2\_0](http://www.perlfoundation.org/artistic_license_2_0) for more information. cpanfile100644001750001750 60213361514502 14651 0ustar00tjctjc000000000000Test-PostgreSQL-1.27requires 'perl' => '5.014'; requires 'File::Spec'; requires 'File::Which'; requires 'DBI'; requires 'DBD::Pg'; requires 'Try::Tiny'; requires 'Function::Parameters'; requires 'Types::Standard'; requires 'Moo'; requires 'POSIX'; requires 'User::pwent'; requires 'Tie::Hash::Method'; test_requires 'DBD::Pg'; test_requires 'Test::SharedFork' => 0.06; author_requires 'Software::License'; PostgreSQL.pm100644001750001750 6377513361514502 17257 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/lib/Testpackage Test::PostgreSQL; use 5.014; use strict; use warnings; use Moo; use Types::Standard -all; use Function::Parameters qw(:strict); use Try::Tiny; use DBI; use File::Spec; use File::Temp; use File::Which; use POSIX qw(SIGQUIT SIGKILL WNOHANG getuid setuid); use User::pwent; our $VERSION = '1.27'; our $errstr; # Deprecate use of %Defaults as we want to remove this package global use Tie::Hash::Method; tie our %Defaults, 'Tie::Hash::Method', FETCH => sub { my $msg = "\nWARNING: using \$Test::PostgreSQL::Defaults is DEPRECATED."; if ( $_[1] =~ /^(initdb|postmaster)_args$/ ) { $msg .= " Use Test::PostgreSQL->new( extra_$_[1] => ... ) instead."; } warn $msg; return $_[0]->base_hash->{ $_[1] }; }; %Defaults = ( auto_start => 2, initdb_args => '-U postgres -A trust', postmaster_args => '-h 127.0.0.1 -F', ); has dbname => ( is => 'ro', isa => Str, default => 'test', ); has dbowner => ( is => 'ro', isa => Str, default => 'postgres', ); has host => ( is => 'ro', isa => Str, default => '127.0.0.1', ); # Various paths that Postgres gets installed under, sometimes with a version on the end, # in which case take the highest version. We append /bin/ and so forth to the path later. # *Note that these are used only if the program isn't already in the path!* has search_paths => ( is => "ro", isa => ArrayRef, builder => "_search_paths", ); method _search_paths() { my @base_paths = ( # popular installation dir? qw(/usr/local/pgsql), # ubuntu (maybe debian as well, find the newest version) (sort { $b cmp $a } grep { -d $_ } glob "/usr/lib/postgresql/*"), # macport (sort { $b cmp $a } grep { -d $_ } glob "/opt/local/lib/postgresql*"), # Postgresapp.com (sort { $b cmp $a } grep { -d $_ } glob "/Applications/Postgres.app/Contents/Versions/*"), # BSDs end up with it in /usr/local/bin which doesn't appear to be in the path sometimes: "/usr/local", ); # This environment variable is used to override the default, so it gets # prefixed to the start of the search paths. if (defined $ENV{POSTGRES_HOME}) { return [$ENV{POSTGRES_HOME}, @base_paths]; } return \@base_paths; } # We attempt to use this port first, and will increment from there. # The final port ends up in the ->port attribute. has base_port => ( is => "ro", isa => Int, default => 15432, ); has auto_start => ( is => "ro", default => 2, ); has base_dir => ( is => "rw", default => sub { File::Temp->newdir( 'pgtest.XXXXX', CLEANUP => $ENV{TEST_POSTGRESQL_PRESERVE} ? undef : 1, EXLOCK => 0, TMPDIR => 1 ); }, coerce => fun ($newval) { # Ensure base_dir is absolute; usually only the case if the user set it. # Avoid munging objects such as File::Temp ref $newval ? $newval : File::Spec->rel2abs($newval); }, ); has socket_dir => ( is => "ro", isa => Str, lazy => 1, default => method () { File::Spec->catdir( $self->base_dir, 'tmp' ) }, ); has initdb => ( is => "ro", isa => Str, lazy => 1, default => method () { $self->_find_program('initdb') || die $errstr }, ); has initdb_args => ( is => "lazy", isa => Str, ); method _build_initdb_args() { return '-U '. $self->dbowner . ' -A trust ' . $self->extra_initdb_args; } has extra_initdb_args => ( is => "ro", isa => Str, default => "", ); has unix_socket => ( is => "ro", isa => Bool, default => 0, ); has pg_version => ( is => 'ro', isa => Str, lazy => 1, predicate => 1, builder => "_pg_version_builder", ); method _pg_version_builder() { my $ver_cmd = join ' ', ( $self->postmaster, '--version' ); my ($ver) = qx{$ver_cmd} =~ /(\d+(?:\.\d+)?)/; return $ver; } has pg_ctl => ( is => "ro", isa => Maybe[Str], lazy => 1, builder => "_pg_ctl_builder", ); method _pg_ctl_builder() { my $prog = $self->_find_program('pg_ctl'); if ( $prog ) { # we only use pg_ctl if Pg version is >= 9 my $ret = qx/"$prog" --version/; if ( $ret =~ /(\d+)(?:\.|devel)/ && $1 >= 9 ) { return $prog; } warn "pg_ctl version earlier than 9"; return; } return; } has pg_config => ( is => 'ro', isa => Str, ); has psql => ( is => 'ro', isa => Str, lazy => 1, default => method () { $self->_find_program('psql') || die $errstr }, ); has psql_args => ( is => 'lazy', isa => Str, ); method _build_psql_args() { return '-U ' . $self->dbowner . ' -d ' . $self->dbname . ' -h '. ($self->unix_socket ? $self->socket_dir : '127.0.0.1') . ' -p ' . $self->port . $self->extra_psql_args; } has extra_psql_args => ( is => 'ro', isa => Str, default => '', ); has run_psql_args => ( is => 'ro', isa => Str, lazy => 1, builder => "_build_run_psql_args", ); method _build_run_psql_args() { my @args = ( '-1', # Single transaction '-X', # Ignore .psqlrc '-q', # Quiet '-v ON_ERROR_STOP=1', # Stop on first error ); # Echo errors, available in psql 9.5+ push @args, '-b' if $self->pg_version >= 9.5; return join ' ', @args; } has seed_scripts => ( is => 'ro', isa => ArrayRef[Str], default => sub { [] }, ); has pid => ( is => "rw", isa => Maybe[Int], ); has port => ( is => "rw", isa => Maybe[Int], ); has uid => ( is => "rw", isa => Maybe[Int], ); # Are we running as root? (Typical when run inside Docker containers) has is_root => ( is => "ro", isa => Bool, default => sub { getuid == 0 } ); has postmaster => ( is => "rw", isa => Str, lazy => 1, default => method () { $self->_find_program("postgres") || $self->_find_program("postmaster") || die $errstr }, ); has postmaster_args => ( is => "lazy", isa => Str, ); method _build_postmaster_args() { return "-h ". ($self->unix_socket ? "''" : "127.0.0.1") . " -F " . $self->extra_postmaster_args; } has extra_postmaster_args => ( is => "ro", isa => Str, default => "", ); has _owner_pid => ( is => "ro", isa => Int, default => sub { $$ }, ); method BUILD($) { # Ensure we have one or the other ways of starting Postgres: try { $self->pg_ctl or $self->postmaster } catch { die $_ }; if (defined $self->uid and $self->uid == 0) { die "uid() must be set to a non-root user id."; } if (not defined($self->uid) and $self->is_root) { my $ent = getpwnam("nobody"); unless (defined $ent) { die "user nobody does not exist, use uid() to specify a non-root user."; } unless ($ent->uid > 0) { die "user nobody has uid 0; confused and exiting. use uid() to specify a non-root user."; } $self->uid($ent->uid); } # Ensure base dir is writable by our target uid, if we were running as root chown $self->uid, -1, $self->base_dir if defined $self->uid; if ($self->auto_start) { $self->setup if $self->auto_start >= 2; $self->start; } } method DEMOLISH($in_global_destruction) { local $?; if (defined $self->pid && $self->_owner_pid == $$) { $self->stop } return; } sub dsn { my %args = shift->_default_args(@_); return 'DBI:Pg:' . join(';', map { "$_=$args{$_}" } sort keys %args); } sub _default_args { my ($self, %args) = @_; # If we're doing socket-only (i.e., not listening on localhost), # then provide the path to the socket if ($self->{unix_socket}) { $args{host} //= $self->socket_dir; } else { $args{host} ||= $self->host; } $args{port} ||= $self->port; $args{user} ||= $self->dbowner; $args{dbname} ||= $self->dbname; return %args; } sub uri { my $self = shift; my %args = $self->_default_args(@_); return sprintf('postgresql://%s@%s:%d/%s', @args{qw/user host port dbname/}); } method start() { if (defined $self->pid) { warn "Apparently already started on " . $self->pid . "; not restarting."; return; } # If the user specified a port, try only that port: if ($self->port) { $self->_try_start($self->port); } else { $self->_find_port_and_launch; } # create "test" database $self->_create_test_database($self->dbname); } # This whole method was mostly cargo-culted from the earlier test-postgresql; # It could probably be made more sane. method _find_port_and_launch() { my $tries = 10; my $port = $self->base_port; # try by incrementing port number while (1) { my $good = try { $self->_try_start($port); 1; } catch { # warn "Postgres failed to start on port $port\n"; unless ($tries--) { die "Failed to start postgres on port $port: $_"; } undef; }; return if $good; $port++; } } method _try_start($port) { my $logfile = File::Spec->catfile($self->base_dir, 'postgres.log'); if ( $self->pg_ctl ) { my @cmd = ( $self->pg_ctl, 'start', '-w', '-s', '-D', File::Spec->catdir( $self->base_dir, 'data' ), '-l', $logfile, '-o', join( ' ', $self->postmaster_args, '-p', $port, '-k', $self->socket_dir) ); $self->setuid_cmd(\@cmd, 1); my $pid_path = File::Spec->catfile( $self->base_dir, 'data', 'postmaster.pid' ); open( my $pidfh, '<', $pid_path ) or die "Failed to open $pid_path: $!"; # Note that the file contains several lines; we only want the PID from the first. my $pid = <$pidfh>; chomp $pid; $self->pid($pid); close $pidfh; $self->port($port); } else { # old style - open log and fork open my $logfh, '>>', $logfile or die "failed to create log file: $logfile: $!"; my $pid = fork; die "fork(2) failed:$!" unless defined $pid; if ($pid == 0) { open STDOUT, '>>&', $logfh or die "dup(2) failed:$!"; open STDERR, '>>&', $logfh or die "dup(2) failed:$!"; chdir $self->base_dir or die "failed to chdir to:" . $self->base_dir . ":$!"; if (defined $self->uid) { setuid($self->uid) or die "setuid failed: $!"; } my $cmd = join( ' ', $self->postmaster, $self->postmaster_args, '-p', $port, '-D', File::Spec->catdir($self->base_dir, 'data'), '-k', $self->socket_dir, ); exec($cmd); die "failed to launch postmaster:$?"; } close $logfh; # wait until server becomes ready (or dies) for (my $i = 0; $i < 100; $i++) { open $logfh, '<', $logfile or die "failed to create log file: $logfile: $!"; my $lines = do { join '', <$logfh> }; close $logfh; last if $lines =~ /is ready to accept connections/; if (waitpid($pid, WNOHANG) > 0) { # failed die "Failed to start Postgres: $lines\n"; } sleep 1; } # PostgreSQL is ready $self->pid($pid); $self->port($port); } return; } method stop($sig = SIGQUIT) { if ( $self->pg_ctl && defined $self->base_dir ) { my @cmd = ( $self->pg_ctl, 'stop', '-s', '-D', File::Spec->catdir( $self->base_dir, 'data' ), '-m', 'fast' ); $self->setuid_cmd(\@cmd); } else { # old style or $self->base_dir File::Temp obj already DESTROYed return unless defined $self->pid; kill $sig, $self->pid; my $timeout = 10; while ($timeout > 0 and waitpid($self->pid, WNOHANG) == 0) { $timeout -= sleep(1); } if ($timeout <= 0) { warn "Pg refused to die gracefully; killing it violently.\n"; kill SIGKILL, $self->pid; $timeout = 5; while ($timeout > 0 and waitpid($self->pid, WNOHANG) == 0) { $timeout -= sleep(1); } if ($timeout <= 0) { warn "Pg really didn't die.. WTF?\n"; } } } $self->pid(undef); return; } method _create_test_database($dbname) { my $tries = 5; my $dbh; while ($tries) { $tries -= 1; $dbh = DBI->connect($self->dsn(dbname => 'template1'), '', '', { PrintError => 0, RaiseError => 0 }); last if $dbh; # waiting for database to start up if ($DBI::errstr =~ /the database system is starting up/ || $DBI::errstr =~ /Connection refused/) { sleep(1); next; } die $DBI::errstr; } die "Connection to the database failed even after 5 tries" unless ($dbh); if ($dbh->selectrow_arrayref(qq{SELECT COUNT(*) FROM pg_database WHERE datname='$dbname'})->[0] == 0) { $dbh->do("CREATE DATABASE $dbname") or die $dbh->errstr; } my $seed_scripts = $self->seed_scripts || []; $self->run_psql_scripts(@$seed_scripts) if @$seed_scripts; return; } method setup() { # (re)create directory structure mkdir $self->base_dir; chmod 0755, $self->base_dir or die "failed to chmod 0755 dir:" . $self->base_dir . ":$!"; if ($ENV{USER} && $ENV{USER} eq 'root') { chown $self->uid, -1, $self->base_dir or die "failed to chown dir:" . $self->base_dir . ":$!"; } my $tmpdir = $self->socket_dir; if (mkdir $tmpdir) { if ($self->uid) { chown $self->uid, -1, $tmpdir or die "failed to chown dir:$tmpdir:$!"; } } # initdb if (! -d File::Spec->catdir($self->base_dir, 'data')) { if ( $self->pg_ctl ) { my @cmd = ( $self->pg_ctl, 'init', '-s', '-D', File::Spec->catdir($self->base_dir, 'data'), '-o', $self->initdb_args, ); $self->setuid_cmd(\@cmd); } else { # old style pipe my $rfh, my $wfh or die "failed to create pipe:$!"; my $pid = fork; die "fork failed:$!" unless defined $pid; if ($pid == 0) { close $rfh; open STDOUT, '>&', $wfh or die "dup(2) failed:$!"; open STDERR, '>&', $wfh or die "dup(2) failed:$!"; chdir $self->base_dir or die "failed to chdir to:" . $self->base_dir . ":$!"; if (defined $self->uid) { setuid($self->uid) or die "setuid failed:$!"; } my $cmd = join( ' ', $self->initdb, $self->initdb_args, '-D', File::Spec->catdir($self->base_dir, 'data'), ); exec($cmd); die "failed to exec:$cmd:$!"; } close $wfh; my $output = ''; while (my $l = <$rfh>) { $output .= $l; } close $rfh; while (waitpid($pid, 0) <= 0) { } die "*** initdb failed ***\n$output\n" if $? != 0; } my $conf_file = File::Spec->catfile($self->base_dir, 'data', 'postgresql.conf'); if (my $pg_config = $self->pg_config) { open my $fh, '>', $conf_file or die "Can't open $conf_file: $!"; print $fh $pg_config; close $fh; } else { # use postgres hard-coded configuration as some packagers mess # around with postgresql.conf.sample too much: truncate $conf_file, 0; } } } method _find_program($prog) { undef $errstr; my $path = which $prog; return $path if $path; for my $sp (@{$self->search_paths}) { return "$sp/bin/$prog" if -x "$sp/bin/$prog"; return "$sp/$prog" if -x "$sp/$prog"; } $errstr = "could not find $prog, please set appropriate PATH or POSTGRES_HOME"; return; } method setuid_cmd($cmd, $suppress_errors = !1) { my $pid = fork; if ($pid == 0) { chdir $self->base_dir; if (defined $self->uid) { setuid($self->uid) or die "setuid failed: $!"; } close STDERR if $suppress_errors; exec(@$cmd) or die "Failed to exec pg_ctl: $!"; } else { waitpid($pid, 0); } } method run_psql(@psql_args) { my $cmd = join ' ', ( $self->psql, # Default connection settings $self->psql_args, # Extra connection settings or something else $self->extra_psql_args, # run_psql specific arguments $self->run_psql_args, @psql_args, ); # Usually anything less than WARNING is not really helpful # in batch mode. Does it make sense to make this configurable? local $ENV{PGOPTIONS} = '--client-min-messages=warning'; my $psql_out = qx{$cmd 2>&1}; die "Error executing psql: $psql_out" unless $? == 0; } method run_psql_scripts(@script_paths) { my @psql_commands; # psql 9.6+ supports multiple -c and -f commands invoked at once, # older psql does not. Executing psql multiple times breaks single # transaction semantics but is unlikely to cause problems in real world. if ( $self->pg_version > 9.6 ) { push @psql_commands, join ' ', map {; "-f $_" } @script_paths; } else { @psql_commands = map {; "-f $_" } @script_paths; } $self->run_psql($_) for @psql_commands; } 1; __END__ =pod =encoding utf8 =head1 NAME Test::PostgreSQL - PostgreSQL runner for tests =head1 SYNOPSIS use DBI; use Test::PostgreSQL; use Test::More; # optionally # (if not already set at shell): # # $ENV{POSTGRES_HOME} = '/path/to/my/pgsql/installation'; my $pgsql = eval { Test::PostgreSQL->new() } or plan skip_all => $@; plan tests => XXX; my $dbh = DBI->connect($pgsql->dsn); =head1 DESCRIPTION C automatically setups a PostgreSQL instance in a temporary directory, and destroys it when the perl script exits. This module is a fork of Test::postgresql, which was abandoned by its author several years ago. =head1 ATTRIBUTES C object has the following attributes, overridable by passing corresponding argument to constructor: =head2 dbname Database name to use in this C instance. Default is C. =head2 dbowner Database owner user name. Default is C. =head2 host Host name or IP address to use for PostgreSQL instance connections. Default is C<127.0.0.1>. =head2 base_dir Base directory under which the PostgreSQL instance is being created. The property can be passed as a parameter to the constructor, in which case the directory will not be removed at exit. =head2 base_port Connection port number to start with. If the port is already used we will increment the value and try again. Default: C<15432>. =head2 unix_socket Whether to only connect via UNIX sockets; if false (the default), connections can occur via localhost. [This changes the L returned to only give the UNIX socket directory, and avoids any issues with conflicting TCP ports on localhost.] =head2 socket_dir Unix socket directory to use if L is true. Default is C<$basedir/tmp>. =head2 pg_ctl Path to C program which is part of the PostgreSQL distribution. Starting with PostgreSQL version 9.0 C can be used to start/stop postgres without having to use fork/pipe and will be chosen automatically if L is not set but the program is found and the version is recent enough. B do NOT use this with PostgreSQL versions prior to version 9.0. By default we will try to find C in PostgresSQL directory. =head2 initdb Path to C program which is part of the PostreSQL distribution. Default is to try and find it in PostgreSQL directory. =head2 initdb_args Arguments to pass to C program when creating a new PostgreSQL database cluster for Test::PostgreSQL session. Defaults to C<-U postgres -A trust>. See L. =head2 extra_initdb_args Extra args to be appended to L. Default is empty. =head2 pg_config Configuration to place in C<$basedir/data/postgresql.conf>. Use this to override PostgreSQL configuration defaults, e.g. to speed up PostgreSQL database init and seeding one might use something like this: my $pgsql = Test::PostgreSQL->new( pg_config => q| # foo baroo mymse throbbozongo fsync = off synchronous_commit = off full_page_writes = off bgwriter_lru_maxpages = 0 shared_buffers = 512MB effective_cache_size = 512MB work_mem = 100MB |); =head2 postmaster Path to C which is part of the PostgreSQL distribution. If not set, the programs are automatically searched by looking up $PATH and other prefixed directories. Since C is deprecated in newer PostgreSQL versions C is used in preference to C. =head2 postmaster_args Defaults to C<-h 127.0.0.1 -F>. =head2 extra_postmaster_args Extra args to be appended to L. Default is empty. =head2 psql Path to C client which is part of the PostgreSQL distribution. C can be used to run SQL scripts against the temporary database created by L: my $pgsql = Test::PostgreSQL->new(); my $psql = $pgsql->psql; my $out = `$psql -f /path/to/script.sql 2>&1`; die "Error executing script.sql: $out" unless $? == 0; =head2 psql_args Command line arguments necessary for C to connect to the correct PostgreSQL instance. Defaults to C<-U postgres -d test -h 127.0.0.1 -p $self-Eport>. See also L, L, L, L. =head2 extra_psql_args Extra args to be appended to L. =head2 run_psql_args Arguments specific for L invocation, used mostly to set up and seed database schema after PostgreSQL instance is launched and configured. Default is C<-1Xqb -v ON_ERROR_STOP=1>. This means: =over 4 =item * 1: Run all SQL statements in passed scripts as single transaction =item * X: Skip C<.psqlrc> files =item * q: Run quietly, print only notices and errors on stderr (if any) =item * b: Echo SQL statements that cause PostgreSQL exceptions (version 9.5+) =item * -v ON_ERROR_STOP=1: Stop processing SQL statements after the first error =back =head2 seed_scripts Arrayref with the list of SQL scripts to run after the database was instanced and set up. Default is C<[]>. B that C older than 9.6 does not support multiple C<-c> and C<-f> switches in arguments so C will be executed one by one. This implies multiple transactions instead of just one; if you need all seed statements to apply within a single transaction, combine them into one seed script. =head2 auto_start Integer value that controls whether PostgreSQL server is started and setup after creating C instance. Possible values: =over 4 =item C<0> Do not start PostgreSQL. =item C<1> Start PostgreSQL but do not run L. =item C<2> Start PostgreSQL and run L. Default is C<2>. =back =head1 METHODS =head2 new Create and run a PostgreSQL instance. The instance is terminated when the returned object is being DESTROYed. If required programs (initdb and postmaster) were not found, the function returns undef and sets appropriate message to $Test::PostgreSQL::errstr. =head2 dsn Builds and returns dsn by using given parameters (if any). Default username is C, and dbname is C (an empty database). =head2 uri Builds and returns a connection URI using the given parameters (if any). See L for details about the format. Default username is C, and dbname is C (an empty database). =head2 pid Returns process id of PostgreSQL (or undef if not running). =head2 port Returns TCP port number on which postmaster is accepting connections (or undef if not running). =head2 start Starts postmaster. =head2 stop Stops postmaster. =head2 setup Setups the PostgreSQL instance. Note that this method should be invoked I L. =head2 run_psql Execute C program with the given list of arguments. Usually this would be something like: $pgsql->run_psql('-c', q|'INSERT INTO foo (bar) VALUES (42)'|); Or: $pgsql->run_psql('-f', '/path/to/script.sql'); Note that when using literal SQL statements with C<-c> parameter you will need to escape them manually like shown above. C will not quote them for you. The actual command line to execute C will be concatenated from L, L, and L. B that C older than 9.6 does not support multiple C<-c> and/or C<-f> switches in arguments. =head2 run_psql_scripts Given a list of script file paths, invoke L once with C<-f 'script'> for every path in PostgreSQL 9.6+, or once per C<-f 'script'> for older PostgreSQL versions. =head1 ENVIRONMENT =head2 POSTGRES_HOME If your postgres installation is not located in a well known path, or you have many versions installed and want to run your tests against particular one, set this environment variable to the desired path. For example: export POSTGRES_HOME='/usr/local/pgsql94beta' This is the same idea and variable name which is used by the installer of L. =head1 AUTHOR Toby Corkindale, Kazuho Oku, Peter Mottram, Alex Tokarev, plus various contributors. =head1 COPYRIGHT Current version copyright © 2012-2015 Toby Corkindale. Previous versions copyright (C) 2009 Cybozu Labs, Inc. =head1 LICENSE This module is free software, released under the Perl Artistic License 2.0. See L for more information. =cut minil.toml100644001750001750 21713361514502 15154 0ustar00tjctjc000000000000Test-PostgreSQL-1.27name="Test-PostgreSQL" module_maker="ModuleBuildTiny" tag_format="release-%v" license="artistic_2" no_github_issues=true badges = ['circleci'] 00-base.t100644001750001750 12313361514502 14722 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse strict; use warnings; use Test::More tests => 1; use_ok('Test::PostgreSQL'); 01-raii.t100644001750001750 175313361514502 14767 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse strict; use warnings; use DBI; use Test::More; use Test::PostgreSQL; use Try::Tiny; my $pgsql = try { Test::PostgreSQL->new } catch { plan skip_all => $_ }; plan tests => 5; my $version_cmd = join ' ', ( $pgsql->postmaster, '--version' ); my $version_str = qx{$version_cmd}; my ($want_version) = $version_str =~ /(\d+(?:\.\d+)?)/; my $have_version = $pgsql->pg_version; is $have_version, $want_version, "pg_version"; # diag() here is deliberate, to show Postgres version in smoker reports diag "PostgreSQL version: $want_version"; my $dsn = $pgsql->dsn; is( $dsn, "DBI:Pg:dbname=test;host=127.0.0.1;port=@{[$pgsql->port]};user=postgres", 'check dsn', ); my $dbh = DBI->connect($dsn); ok($dbh->ping, 'connected to PostgreSQL'); undef $dbh; my $uri = $pgsql->uri; like($uri, qr/^postgresql:\/\/postgres\@127.0.0.1/, "uri"); undef $pgsql; ok( ! DBI->connect($dsn, undef, undef, { PrintError => 0 }), "Removing variable causes shutdown of postgresql" ); 02-multi.t100644001750001750 43713361514502 15154 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse strict; use warnings; use DBI; use Test::More; use Test::PostgreSQL; use Try::Tiny; try { Test::PostgreSQL->new } catch { plan skip_all => $_ }; plan tests => 3; my @pgsql = map { my $pgsql = Test::PostgreSQL->new(); ok($pgsql); $pgsql; } 0..1; is(scalar @pgsql, 2); 04-multiprocess.t100644001750001750 121613361514502 16571 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse strict; use warnings; use DBI; use Test::More; use Test::PostgreSQL; use Test::SharedFork; use Try::Tiny; my $pgsql = try { Test::PostgreSQL->new } catch { plan skip_all => $_ }; plan tests => 3; my $dbh; ok($dbh = DBI->connect($pgsql->dsn), 'check if db is ready'); $dbh->disconnect; unless (my $pid = Test::SharedFork::fork) { die "fork failed:$!" unless defined $pid; # child process ok($dbh = DBI->connect($pgsql->dsn), 'connect from child process'); $dbh->disconnect; exit 0; } 1 while wait == -1; ok($dbh = DBI->connect($pgsql->dsn), 'connect after child exit'); $dbh->disconnect; undef $pgsql; 05-recycle-base-dir.t100644001750001750 152413361514502 17155 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse strict; use warnings; use DBI; use Test::More; use Test::PostgreSQL; use File::Temp qw(tempdir); use Try::Tiny; my $base_dir = tempdir(CLEANUP => 1); my $pgsql = try { Test::PostgreSQL->new( base_dir => $base_dir ) } catch { plan skip_all => $_ }; my $pid = $pgsql->pid; my $dsn = $pgsql->dsn; my $dbh = DBI->connect($dsn); ok($dbh->ping, 'Connected to the first instance'); undef $dbh; undef $pgsql; # kill ok( ! DBI->connect($dsn, undef, undef, { PrintError => 0 }), "Removing variable causes shutdown of the first instance" ); # This time expect the base dir to be set up $pgsql = Test::PostgreSQL->new( auto_start => 1, base_dir => $base_dir, ); $dsn = $pgsql->dsn; $dbh = DBI->connect($dsn); ok($dbh->ping, 'Connected to second instance using the same base_dir'); undef $dbh; undef $pgsql; # kill done_testing; 06-unix-socket.t100644001750001750 72713361514502 16301 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse strict; use warnings; use DBI; use Test::More; use Test::PostgreSQL; use Try::Tiny; # if we can't connect normally, unix_socket failure isn't an issue. my $pgsql = try { Test::PostgreSQL->new } catch { plan skip_all => $_ }; undef $pgsql; plan tests => 2; ok($pgsql = Test::PostgreSQL->new(unix_socket => 1), 'connected using unix socket'); my $dbh; ok($dbh = DBI->connect($pgsql->dsn), 'check if db is ready'); $dbh->disconnect; undef $pgsql; 07-configs.t100644001750001750 243313361514502 15475 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse Test::More; use strict; use warnings; use DBI; use Test::PostgreSQL; use Try::Tiny; my $pgsql = try { Test::PostgreSQL->new( dbname => 'foo', dbowner => 'foobaroo', host => 'localhost', ) } catch { plan skip_all => $_ }; plan tests => 7; ok defined $pgsql, "test instance with non-default configs"; my $have_dsn = $pgsql->dsn; my $default_dsn = q|DBI:Pg:dbname=test;host=127.0.0.1;port=| . $pgsql->port . q|;user=postgres|; my $want_dsn = q|DBI:Pg:dbname=foo;host=localhost;port=| . $pgsql->port . q|;user=foobaroo|; is $have_dsn, $want_dsn, "non-default configs DSN"; my $dbh = DBI->connect($want_dsn); my $ping = eval { $dbh->ping }; is $@, '', "dbh ping no exception: $@"; ok $ping, "non-default configs can connect to DSN"; undef $dbh; # Should not connect with default configs $dbh = DBI->connect($default_dsn, undef, undef, { PrintError => 0 }); ok !defined($dbh), "non-default configs can't connect to default DSN"; my $pid = $pgsql->pid; ok kill(0, $pid), "test Postgres instance is alive"; undef $pgsql; # Give it 5 seconds to shut down (usually overkill) my $watchdog = 50; while ( kill 0, $pid and $watchdog-- ) { select undef, undef, undef, 0.1; } ok !kill(0, $pid), "test Postgres instance stopped"; 08-postgresql_conf.t100644001750001750 441013361514502 17253 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse Test::More; use strict; use warnings; use DBI; use File::Spec; use Test::PostgreSQL; use Try::Tiny; use POSIX qw(getuid setuid); my $pg = try { Test::PostgreSQL->new() } catch { plan skip_all => $_ }; plan tests => 8; ok defined($pg), "test instance 1 created"; my $datadir = File::Spec->catfile($pg->base_dir, 'data'); my $conf_file = File::Spec->catfile($datadir, 'postgresql.conf'); # By default postgresql.conf is truncated is -s $conf_file, 0, "test 1 postgresql.conf size 0"; my $ver = $pg->pg_version; SKIP: { skip "No -C switch on PostgreSQL $ver (9.2 required)", 1 if $ver < 9.2; skip "Can't run postgres as root", 1 if (getuid == 0); my $cmd = join ' ', ( $pg->postmaster, '-D', $datadir, '-C', 'synchronous_commit' ); my $config_value = qx{$cmd}; # Default for synchronous_commit is on like $config_value, qr/^on/, "test 1 synchronous_commit = on"; } my @pids = ($pg->pid); undef $pg; $pg = Test::PostgreSQL->new( pg_config => q|# foo baroo mymse throbbozongo fsync = off synchronous_commit = off full_page_writes = off bgwriter_lru_maxpages = 0 shared_buffers = 512MB effective_cache_size = 512MB work_mem = 100MB |); ok defined($pg), "test instance 2 created"; my $dsn = $pg->dsn; my $dbh = DBI->connect($dsn, undef, undef, { PrintError => !1 }); # Means config was correct ok defined($dbh), "test instance 2 connected"; $datadir = File::Spec->catfile($pg->base_dir, 'data'); $conf_file = File::Spec->catfile($datadir, 'postgresql.conf'); SKIP: { skip "No -C switch on PostgreSQL $ver (9.2 required)", 1 if $ver < 9.2; skip "Can't run postgres as root", 1 if (getuid == 0); my $cmd = join ' ', ( $pg->postmaster, '-D', $datadir, '-C', 'synchronous_commit' ); my $config_value = qx{$cmd}; # Now it should be off (overridden above) like $config_value, qr/^off/, "test 2 synchronous_commit = off"; } open my $fh, '<', $conf_file; my $pg_conf = join '', <$fh>; close $fh; like $pg_conf, qr/foo baroo mymse throbbozongo/, "test instance 2 postgresql.conf match"; push @pids, $pg->pid; undef $pg; my $watchdog = 50; while ( kill 0, @pids and $watchdog-- ) { select undef, undef, undef, 0.1; } ok !kill(0, @pids), "test Postgres instances stopped"; 09-run_psql.t100644001750001750 145313361514502 15713 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse Test::More; use strict; use warnings; use DBI; use Test::PostgreSQL; use Try::Tiny; my $pg = try { Test::PostgreSQL->new() } catch { plan skip_all => $_ }; plan tests => 3; ok defined($pg), "new instance created"; my @psql_command; # psql 9.6+ supports multiple -c commands if ( $pg->pg_version >= 9.6 ) { @psql_command = ( '-c', q|'CREATE TABLE foo (bar int)'|, '-c', q|'INSERT INTO foo (bar) VALUES (42)'|, ); } else { @psql_command = ( '-c', q|'CREATE TABLE foo (bar int); INSERT INTO foo (bar) VALUES (42);'|, ); } eval { $pg->run_psql(@psql_command) }; is $@, '', "run_psql no exception" . ($@ ? ": $@" : ""); my $dbh = DBI->connect($pg->dsn); my @row = $dbh->selectrow_array('SELECT * FROM foo'); is_deeply \@row, [42], "seed values match"; 10-seed_scripts.t100644001750001750 101313361514502 16517 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/tuse Test::More; use strict; use warnings; use DBI; use Test::PostgreSQL; use Try::Tiny; my $pg = try { Test::PostgreSQL->new( seed_scripts => [ 't/seed/init.sql', 't/seed/seed.sql', ], ); } catch { plan skip_all => $_; }; plan tests => 3; is $@, '', "new no exception" . ($@ ? ": $@" : ""); ok defined($pg), "new instance created"; my $dbh = DBI->connect($pg->dsn); my @row = $dbh->selectrow_array('SELECT * FROM foo'); is_deeply \@row, [42], "seed values match"; deadlock.t100644001750001750 73113361514502 15346 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/t#!perl use strict; use warnings; use DBI; use Test::PostgreSQL; use Test::More; use Try::Tiny; my $pgsql = try { Test::PostgreSQL->new } catch { plan skip_all => $_ }; my $dbh = DBI->connect($pgsql->dsn); ok($dbh, "Connected to created database."); my $t1 = time(); $pgsql->stop; my $elapsed = time() - $t1; diag("elapsed: $elapsed"); ok(1, "Reached point after calling stop()"); ok($elapsed <= 12, "Shutdown took less than 12 seconds."); done_testing; init.sql100644001750001750 4213361514502 15772 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/t/seedCREATE TABLE foo ( bar int ); seed.sql100644001750001750 4313361514502 15750 0ustar00tjctjc000000000000Test-PostgreSQL-1.27/t/seedINSERT INTO foo (bar) VALUES (42); META.yml100644001750001750 350113361514502 14437 0ustar00tjctjc000000000000Test-PostgreSQL-1.27--- abstract: 'PostgreSQL runner for tests' author: - 'Toby Corkindale, Kazuho Oku, Peter Mottram, Alex Tokarev, plus various contributors.' build_requires: DBD::Pg: '0' Test::SharedFork: '0.06' configure_requires: Module::Build::Tiny: '0.035' dynamic_config: 0 generated_by: 'Minilla/v3.1.2, CPAN::Meta::Converter version 2.150010' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Test-PostgreSQL no_index: directory: - t - xt - inc - share - eg - examples - author - builder provides: Test::PostgreSQL: file: lib/Test/PostgreSQL.pm version: '1.27' requires: DBD::Pg: '0' DBI: '0' File::Spec: '0' File::Which: '0' Function::Parameters: '0' Moo: '0' POSIX: '0' Tie::Hash::Method: '0' Try::Tiny: '0' Types::Standard: '0' User::pwent: '0' perl: '5.014' resources: homepage: https://github.com/TJC/Test-postgresql repository: git://github.com/TJC/Test-postgresql.git version: '1.27' x_contributors: - 'Alex Tokarev ' - 'Alex Tokarev ' - 'Dagfinn Ilmari Mannsåker ' - 'Dan Book ' - 'David Steinbrunner ' - 'Don Armstrong ' - 'Eric Radman ' - 'Matthew Somerville ' - 'Michal Sedlák ' - 'Paul Williams ' - 'Peter Mottram ' - 'Russell Jenkins ' - 'Russell Jenkins ' - 'Toby ' - 'Toby Corkindale ' - 'root ' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' x_static_install: 1 MANIFEST100644001750001750 50413361514502 14277 0ustar00tjctjc000000000000Test-PostgreSQL-1.27Build.PL Changes LICENSE META.json README.md cpanfile lib/Test/PostgreSQL.pm minil.toml t/00-base.t t/01-raii.t t/02-multi.t t/04-multiprocess.t t/05-recycle-base-dir.t t/06-unix-socket.t t/07-configs.t t/08-postgresql_conf.t t/09-run_psql.t t/10-seed_scripts.t t/deadlock.t t/seed/init.sql t/seed/seed.sql META.yml MANIFEST