diff --git a/t/01-idle_xact.t b/t/01-idle_xact.t new file mode 100644 index 0000000..4b60969 --- /dev/null +++ b/t/01-idle_xact.t @@ -0,0 +1,194 @@ +#!/usr/bin/perl +# This program is open source, licensed under the PostgreSQL License. +# For license terms, see the LICENSE file. +# +# Copyright (C) 2012-2022: Open PostgreSQL Monitoring Development Group + +use strict; +use warnings; + +use lib 't/lib'; +use pgNode; +use pgSession; +use Test::More tests => 40; + +my $node = pgNode->get_new_node('prod'); +my $proc; + +$node->init; +$node->start; + +### Begin of tests ### + +# failing without thresholds +$node->command_checks_all( [ + './check_pgactivity', '--service' => 'oldest_idlexact', + '--username' => getlogin, + '--format' => 'human' + ], + 127, + [ qr/^$/ ], + [ qr/^FATAL: you must specify critical and warning thresholds.$/m ], + 'failing without thresholds' +); + +# Tests for PostreSQL 8.2 and before +SKIP: { + skip "testing incompatibility with PostgreSQL 8.2 and before", 3 + if $node->version >= 8.3; + + $node->command_checks_all( [ + './check_pgactivity', '--service' => 'oldest_idlexact', + '--username' => getlogin, + '--format' => 'human', + '--warning' => '30s', + '--critical' => '1h' + ], + 1, + [ qr/^$/ ], + [ qr/^Service oldest_idlexact is not compatible with host/ ], + 'non compatible PostgreSQL version' + ); +} + +SKIP: { + skip "incompatible tests with PostgreSQL < 8.3", 34 if $node->version < 8.3; + + # basic check + $node->command_checks_all( [ + './check_pgactivity', '--service' => 'oldest_idlexact', + '--username' => getlogin, + '--format' => 'human', + '--dbname' => 'template1', + '--warning' => '30s', + '--critical' => '1h' + ], + 0, + [ qr/^Service *: POSTGRES_OLDEST_IDLEXACT$/m, + qr/^Returns *: 0 \(OK\)$/m, + qr/^Message *: 0 idle transaction\(s\)$/m, + qr/^Perfdata *: template1 # idle xact=0$/m + ], + [ qr/^$/ ], + 'basic check' + ); + + # unit check + $node->command_checks_all( [ + './check_pgactivity', '--service' => 'oldest_idlexact', + '--username' => getlogin, + '--format' => 'human', + '--dbname' => 'template1', + '--warning' => '30m', + '--critical' => '1h' + ], + 0, + [ qr/^Service *: POSTGRES_OLDEST_IDLEXACT$/m, + qr/^Perfdata : template1 avg=NaNs warn=1800 crit=3600$/m, + ], + [ qr/^$/ ], + 'unit check' + ); + + $proc = pgSession->new( $node, 'postgres' ); + + $proc->query( 'BEGIN', 1 ); + $proc->query( 'SELECT txid_current()', 1 ); + + # OK check + $node->command_checks_all( [ + './check_pgactivity', '--service' => 'oldest_idlexact', + '--username' => getlogin, + '--format' => 'human', + '--dbname' => 'postgres', + '--warning' => '3s', + '--critical' => '1h' + ], + 0, + [ qr/^Service *: POSTGRES_OLDEST_IDLEXACT$/m, + qr/^Returns *: 0 \(OK\)$/m, + qr/^Message *: 1 idle transaction\(s\)$/m, + qr/^Perfdata *: postgres # idle xact=1$/m + ], + [ qr/^$/ ], + 'OK check' + ); + + # wait for transaction to be idle for more than 3 seconds + $node->poll_query_until( 'template1', q{ + SELECT current_timestamp - xact_start > interval '3s' + FROM pg_catalog.pg_stat_activity + WHERE datname = 'postgres' + AND xact_start IS NOT NULL + LIMIT 1 + }); + + # warning check + $node->command_checks_all( [ + './check_pgactivity', '--service' => 'oldest_idlexact', + '--username' => getlogin, + '--format' => 'human', + '--dbname' => 'postgres', + '--warning' => '2s', + '--critical' => '1h' + ], + 1, + [ qr/^Service *: POSTGRES_OLDEST_IDLEXACT$/m, + qr/^Returns *: 1 \(WARNING\)$/m, + qr/^Message *: 1 idle transaction\(s\)$/m, + qr/^Perfdata *: postgres # idle xact=1$/m + ], + [ qr/^$/ ], + 'warning check' + ); + + # critical check + $node->command_checks_all( [ + './check_pgactivity', '--service' => 'oldest_idlexact', + '--username' => getlogin, + '--format' => 'human', + '--dbname' => 'template1', + '--warning' => '1s', + '--critical' => '2s' + ], + 2, + [ qr/^Service *: POSTGRES_OLDEST_IDLEXACT$/m, + qr/^Returns *: 2 \(CRITICAL\)$/m, + qr/^Message *: 1 idle transaction\(s\)$/m, + qr/^Perfdata *: postgres # idle xact=1$/m + ], + [ qr/^$/ ], + 'critical check' + ); + + SKIP: { + skip "active xact are not detected before 9.2", 6 if $node->version < 9.2; + + # Emit one query and check that check_pga does not emit a warning or critical + $proc->query( 'SELECT count(*) FROM pg_class', 1 ); + + # active transaction check + $node->command_checks_all( [ + './check_pgactivity', '--service' => 'oldest_idlexact', + '--username' => getlogin, + '--format' => 'human', + '--dbname' => 'template1', + '--warning' => '2s', + '--critical' => '1h' + ], + 0, + [ qr/^Service *: POSTGRES_OLDEST_IDLEXACT$/m, + qr/^Returns *: 0 \(OK\)$/m, + qr/^Message *: 1 idle transaction\(s\)$/m, + qr/^Perfdata *: postgres # idle xact=1$/m + ], + [ qr/^$/ ], + 'active transaction check' + ); + } +} + +### End of tests ### + +# stop immediate to kill any remaining backends +$node->stop( 'immediate' ); diff --git a/t/lib/pgSession.pm b/t/lib/pgSession.pm index b7f06ff..c7348c4 100644 --- a/t/lib/pgSession.pm +++ b/t/lib/pgSession.pm @@ -20,10 +20,15 @@ sub new { $db = 'template1' unless defined $db; $self->{'timer'} = IPC::Run::timer(5); + $self->{'delim'} = 'CHECK_PGA_PROMPT_DELIM=>'; $self->{'in'} = ''; $self->{'out'} = ''; $self->{'proc'} = $node->interactive_psql( - $db, \$self->{'in'}, \$self->{'out'}, $self->{'timer'} + $db, \$self->{'in'}, \$self->{'out'}, $self->{'timer'}, + extra_params=>[ + '--pset=pager', + '--variable=PROMPT1='. $self->{'delim'} + ] ); return bless $self, $class; @@ -33,8 +38,20 @@ sub query { my ($self, $q, $t) = @_; $self->{'out'} = ''; - $self->{'in'} .= "$q;\n"; + $self->{'in'} = ''; + $self->{'timer'}->start($t); + + # wait for the prompt to appear + $self->{'proc'}->pump until $self->{'out'} =~ $self->{'delim'};; + + # reset the output to forget the banner + prompt + $self->{'out'} = ''; + + # write and run the query (this echoes the query in $out :/) + $self->{'in'} .= "$q;\n"; + + # push $in to the procs $self->{'proc'}->pump while length $self->{'in'}; }