Add support for "and" and "or" to the critical/warnings options, with tests.
authorDavid E. Wheeler <[email protected]>
Mon, 24 Jan 2011 17:34:37 +0000 (12:34 -0500)
committerGreg Sabino Mullane <[email protected]>
Mon, 24 Jan 2011 17:34:37 +0000 (12:34 -0500)
check_postgres.pl
t/01_validate_range.t [new file with mode: 0644]
t/02_bloat.t
t/02_disk_space.t

index a61a6eede8321ba1fbf94305340f59252633d554..79a8507de917fc8868d12e5814434510fb296fa8 100755 (executable)
@@ -754,7 +754,7 @@ for my $mv (keys %tempopt) {
 
 our $VERBOSE = $opt{verbose} || 0;
 
-our $OUTPUT = lc $opt{output} || '';
+our $OUTPUT = lc($opt{output} || '');
 
 ## Allow the optimization of the get_methods list by an argument
 if ($opt{get_method}) {
@@ -2342,7 +2342,7 @@ sub validate_range {
     }
     elsif ($type =~ /integer/) {
         $warning =~ s/_//g;
-        if (length $warning and $warning !~ /^\d+$/) {
+        if (length $warning and $warning !~ /^[-+]?\d+$/) {
             ndie $type =~ /positive/ ? msg('range-int-pos', 'warning') : msg('range-int', 'warning');
         }
         elsif (length $warning && $type =~ /positive/ && $warning <= 0) {
@@ -2350,7 +2350,7 @@ sub validate_range {
         }
 
         $critical =~ s/_//g;
-        if (length $critical and $critical !~ /^\d+$/) {
+        if (length $critical and $critical !~ /^[-+]?\d+$/) {
             ndie $type =~ /positive/ ? msg('range-int-pos', 'critical') : msg('range-int', 'critical');
         }
         elsif (length $critical && $type =~ /positive/ && $critical <= 0) {
@@ -2367,6 +2367,8 @@ sub validate_range {
             ) {
             ndie msg('range-warnbig');
         }
+        $warning = int $warning if length $warning;
+        $critical = int $critical if length $warning;
     }
     elsif ('restringex' eq $type) {
         if (! length $critical and ! length $warning) {
@@ -2390,6 +2392,8 @@ sub validate_range {
                 ndie msg('range-badpercent', 'warning');
             }
         }
+        $warning = int $warning if length $warning;
+        $critical = int $critical if length $warning;
     }
     elsif ('size or percent' eq $type) {
         if (length $critical) {
@@ -2488,6 +2492,53 @@ sub validate_range {
 } ## end of validate_range
 
 
+sub validate_size_or_percent_with_oper {
+
+    my $arg = shift || {};
+    ndie qq{validate_range must be called with a hashref\n}
+        unless ref $arg eq 'HASH';
+
+    my $warning  = exists $opt{warning}  ? $opt{warning} :
+        exists $opt{critical} ? '' : $arg->{default_warning} || '';
+    my $critical = exists $opt{critical} ? $opt{critical} :
+        exists $opt{warning} ? '' : $arg->{default_critical} || '';
+
+    ndie msg('range-noopt-size') unless length $critical || length $warning;
+    my @subs;
+    for my $val ($warning, $critical) {
+        if ($val =~ /^([^&|]+)\s([&|]{2}|and|or)\s([^&|]+)$/i) {
+            my ($l, $op, $r) = ($1, $2, $3);
+            local $opt{warning} = $l;
+            local $opt{critical} = 0;
+            ($l) = validate_range({ type => 'size or percent' });
+            $opt{warning} = $r;
+            ($r) = validate_range({ type => 'size or percent' });
+            if ($l =~ s/%$//) {
+                ($l, $r) = ($r, $l);
+            } else {
+                $r =~ s/%$//;
+            }
+            push @subs, $op eq '&&' || lc $op eq 'and' ? sub {
+                $_[0] >= $l && $_[1] >= $r;
+            } : sub {
+                $_[0] >= $l || $_[1] >= $r;
+            };
+        }
+        else {
+            local $opt{warning} = $val;
+            local $opt{critical} = 0;
+            my ($v) = validate_range({ type => 'size or percent' });
+            push @subs, !length $v ? sub { 0 }
+                    : $v =~ s/%$// ? sub { $_[1] >= $v }
+                                   : sub { $_[0] >= $v };
+        }
+    }
+
+    return @subs;
+
+} ## end of validate_size_or_percent_with_oper
+
+
 sub check_autovac_freeze {
 
     ## Check how close all databases are to autovacuum_freeze_max_age
@@ -2770,9 +2821,8 @@ sub check_bloat {
         $LIMIT = $opt{perflimit};
     }
 
-    my ($warning, $critical) = validate_range
+    my ($warning, $critical) = validate_size_or_percent_with_oper
         ({
-          type               => 'size or percent',
           default_warning    => '1 GB',
           default_critical   => '5 GB',
           });
@@ -2893,32 +2943,14 @@ FROM (
                     $stats{table}{"DB=$dbname TABLE=$schema.$table"} = [$wb, $bloat];
                     next;
                 }
-                if (length $critical) {
-                    if (index($critical,'%')>=0) {
-                        (my $critical2 = $critical) =~ s/\%//;
-                        if ($perbloat >= $critical2) {
-                            add_critical $msg;
-                            $ok = 0;
-                        }
-                    }
-                    elsif ($wb >= $critical) {
-                        add_critical $msg;
-                        $ok = 0;
-                    }
+                if ($critical->($wb, $perbloat)) {
+                    add_critical $msg;
+                    $ok = 0;
                 }
 
-                if (length $warning and $ok) {
-                    if (index($warning,'%')>=0) {
-                        (my $warning2 = $warning) =~ s/\%//;
-                        if ($perbloat >= $warning2) {
-                            add_warning $msg;
-                            $ok = 0;
-                        }
-                    }
-                    elsif ($wb >= $warning) {
-                        add_warning $msg;
-                        $ok = 0;
-                    }
+                if ($ok && $warning->($wb, $perbloat)) {
+                    add_warning $msg;
+                    $ok = 0;
                 }
                 ($max = $wb, $maxmsg = $msg) if $wb > $max and $ok;
             }
@@ -2934,34 +2966,15 @@ FROM (
                     $stats{index}{"DB=$dbname INDEX=$index"} = [$iwb, $ibloat];
                     next;
                 }
-                if (length $critical) {
-                    if (index($critical,'%')>=0) {
-                        (my $critical2 = $critical) =~ s/\%//;
-                        if ($iperbloat >= $critical2) {
-                            add_critical $msg;
-                            $ok = 0;
-                        }
-                    }
-                    elsif ($iwb >= $critical) {
-                        add_critical $msg;
-                        $ok = 0;
-                    }
+                if ($critical->($iwb, $iperbloat)) {
+                    add_critical $msg;
+                    $ok = 0;
                 }
 
-                if (length $warning and $ok) {
-                    if (index($warning,'%')>=0) {
-                        (my $warning2 = $warning) =~ s/\%//;
-                        if ($iperbloat >= $warning2) {
-                            add_warning $msg;
-                            $ok = 0;
-                        }
-                    }
-                    elsif ($iwb >= $warning) {
-                        add_warning $msg;
-                        $ok = 0;
-                    }
+                if ($ok && $warning->($iwb, $iperbloat)) {
+                    add_warning $msg;
+                    $ok = 0;
                 }
-
                 ($max = $iwb, $maxmsg = $msg) if $iwb > $max and $ok;
             }
         }
@@ -3440,9 +3453,8 @@ sub check_disk_space {
     ## NOTE: Needs to run on the same system (for now)
     ## XXX Allow custom ssh commands for remote df and the like
 
-    my ($warning, $critical) = validate_range
+    my ($warning, $critical) = validate_size_or_percent_with_oper
         ({
-          type             => 'size or percent',
           default_warning  => '90%',
           default_critical => '95%',
           });
@@ -3549,32 +3561,16 @@ WHERE spclocation <> ''
             $db->{perf} = "$fs=$used";
 
             my $ok = 1;
-            if (length $critical) {
-                if (index($critical,'%')>=0) {
-                    (my $critical2 = $critical) =~ s/\%//;
-                    if ($percent >= $critical2) {
-                        add_critical $msg;
-                        $ok = 0;
-                    }
-                }
-                elsif ($used >= $critical) {
-                    add_critical $msg;
-                    $ok = 0;
-                }
+            if ($critical->($used, $percent)) {
+                add_critical $msg;
+                $ok = 0;
             }
-            if (length $warning and $ok) {
-                if (index($warning,'%')>=0) {
-                    (my $warning2 = $warning) =~ s/\%//;
-                    if ($percent >= $warning2) {
-                        add_warning $msg;
-                        $ok = 0;
-                    }
-                }
-                elsif ($used >= $warning) {
-                    add_warning $msg;
-                    $ok = 0;
-                }
+
+            if ($ok && $warning->($used, $percent)) {
+                add_warning $msg;
+                $ok = 0;
             }
+
             if ($ok) {
                 add_ok $msg;
             }
@@ -7724,7 +7720,7 @@ enabled on the target databases, and requires that ANALYZE is run frequently.
 The I<--include> and I<--exclude> options can be used to filter out which tables 
 to look at. See the L</"BASIC FILTERING"> section for more details.
 
-The I<--warning> and I<--critical> options can be specified as sizes or percents.
+The I<--warning> and I<--critical> options can be specified as sizes, percents, or both.
 Valid size units are bytes, kilobytes, megabytes, gigabytes, terabytes, exabytes, 
 petabytes, and zettabytes. You can abbreviate all of those with the first letter. Items 
 without units are assumed to be 'bytes'. The default values are '1 GB' and '5 GB'. The value 
@@ -7751,7 +7747,7 @@ should give a rough idea of how bloated things are.
 
 Example 1: Warn if any table on port 5432 is over 100 MB bloated, and critical if over 200 MB
 
-  check_postgres_bloat --port=5432 --warning='100 M', --critical='200 M'
+  check_postgres_bloat --port=5432 --warning='100 M' --critical='200 M'
 
 Example 2: Give a critical if table 'orders' on host 'sami' has more than 10 megs of bloat
 
@@ -7761,6 +7757,16 @@ Example 3: Give a critical if table 'q4' on database 'sales' is over 50% bloated
 
   check_postgres_bloat --db=sales --include=q4 --critical='50%'
 
+Example 4: Give a critical any table is over 20% bloated I<and> has over 150
+MB of bloat:
+
+  check_postgres_bloat --port=5432 --critical='20% and 150 M'
+
+Example 5: Give a critical any table is over 40% bloated I<or> has over 500 MB
+of bloat:
+
+  check_postgres_bloat --port=5432 --warning='500 M or 40%'
+
 For MRTG output, the first line gives the highest number of wasted bytes for the tables, and the 
 second line gives the highest number of wasted bytes for the indexes. The fourth line gives the database 
 name, table name, and index name information. If you want to output the bloat ratio instead (how many 
@@ -7998,7 +8004,7 @@ For MRTG output, returns the number of disabled triggers on the first line.
 that you have the executable "/bin/df" available to report on disk sizes, and it 
 also needs to be run as a superuser, so it can examine the B<data_directory> 
 setting inside of Postgres. The I<--warning> and I<--critical> options are 
-given in either sizes or percentages. If using sizes, the standard unit types 
+given in either sizes or percentages or both. If using sizes, the standard unit types 
 are allowed: bytes, kilobytes, gigabytes, megabytes, gigabytes, terabytes, or 
 exabytes. Each may be abbreviated to the first letter only; no units at all 
 indicates 'bytes'. The default values are '90%' and '95%'.
@@ -8027,6 +8033,15 @@ Example 2: Check that all file systems starting with /dev/sda are smaller than 1
 
   check_postgres_disk_space --port=5432 --warning='10 GB' --critical='11 GB' --include="~^/dev/sda"
 
+Example 4: Make sure that no file system is both over 50% I<and> has over 15 GB
+
+  check_postgres_disk_space --critical='50% and 15 GB'
+
+Example 5: Issue a warning if any file system is either over 70% full I<or> has
+more than 1T
+
+  check_postgres_disk_space --warning='1T or 75'
+
 For MRTG output, returns the size in bytes of the file system on the first line, 
 and the name of the file system on the fourth line.
 
diff --git a/t/01_validate_range.t b/t/01_validate_range.t
new file mode 100644 (file)
index 0000000..2507c67
--- /dev/null
@@ -0,0 +1,421 @@
+#!perl
+
+## Test the "validate_range" function
+
+use 5.006;
+use strict;
+use warnings;
+use Test::More tests => 139;
+
+eval {
+    local @ARGV = qw(--action nonexistent);
+    require 'check_postgres.pl'; ## no critic (RequireBarewordIncludes)
+};
+like($@, qr{\-\-help}, 'check_postgres.pl compiles')
+    or BAIL_OUT "Script did not compile, cancelling rest of tests.\n";
+
+SECONDS: {
+    local %check_postgres::opt = (
+        warning  => '1s',
+        critical => '42 seconds'
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'seconds' });
+    is $w,  1, 'Should have warning == 1 seconds';
+    is $c, 42, 'Should have critical == 42 seconds';
+}
+
+TIME: {
+    local %check_postgres::opt = (
+        warning  => '1s',
+        critical => '42 seconds'
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'time' });
+    is $w, 1, 'Should have warning == 1 second';
+    is $c, 42, 'Should have critical == 42 seconds';
+
+    %check_postgres::opt = (
+        warning  => '1m',
+        critical => '42 minutes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'time' });
+    is $w, 60, 'Should have warning == 1 minute';
+    is $c, 2520, 'Should have critical == 42 minutes';
+
+    %check_postgres::opt = (
+        warning  => '1h',
+        critical => '42 hours'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'time' });
+    is $w, 3600, 'Should have warning == 1 hour';
+    is $c, 151200, 'Should have critical == 42 hours';
+
+    %check_postgres::opt = (
+        warning  => '1d',
+        critical => '42 days'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'time' });
+    is $w, 86400, 'Should have warning == 1 day';
+    is $c, 3628800, 'Should have critical == 42 days';
+
+    %check_postgres::opt = (
+        warning  => '1w',
+        critical => '4 weeks'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'time' });
+    is $w, 604800, 'Should have warning == 1 week';
+    is $c, 2419200, 'Should have critical == 4 weeks';
+
+    %check_postgres::opt = (
+        warning  => '1y',
+        critical => '4 years'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'time' });
+    is $w, 31536000, 'Should have warning == 1 year';
+    is $c, 126144000, 'Should have critical == 4 years';
+
+    %check_postgres::opt = (
+        warning  => '1',
+        critical => '42'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'time' });
+    is $w, 1, 'Should have warning == 1';
+    is $c, 42, 'Should have critical == 42';
+}
+
+VERSION: {
+    local %check_postgres::opt = (
+        warning  => '8.4.2',
+        critical => '9.0beta1'
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'version' });
+    is $w, '8.4.2', 'Should have warning == 8.4.2';
+    is $c, '9.0beta1', 'Should have critical == 9.0beta1';
+}
+
+SIZE: {
+    local %check_postgres::opt = (
+        warning  => '1',
+        critical => '42 bytes'
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'size' });
+    is $w, 1, 'Should have warning == 1 byte';
+    is $c, 42, 'Should have critical == 42 bytes';
+
+    %check_postgres::opt = (
+        warning  => '1k',
+        critical => '42 kilobytes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size' });
+    is $w, 1024, 'Should have warning == 1 kilobytes';
+    is $c, 43008, 'Should have critical == 42 kilobytes';
+
+    %check_postgres::opt = (
+        warning  => '1m',
+        critical => '42 megabytes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size' });
+    is $w, 1048576, 'Should have warning == 1 megabytes';
+    is $c, 44040192, 'Should have critical == 42 megabytes';
+
+    %check_postgres::opt = (
+        warning  => '1g',
+        critical => '42 gigabytes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size' });
+    is $w, 1073741824, 'Should have warning == 1 gigabytes';
+    is $c, 45097156608, 'Should have critical == 42 gigabytes';
+
+    %check_postgres::opt = (
+        warning  => '1t',
+        critical => '42 terabytes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size' });
+    is $w, 1099511627776, 'Should have warning == 1 terabytes';
+    is $c, 46179488366592, 'Should have critical == 42 terabytes';
+
+    %check_postgres::opt = (
+        warning  => '1p',
+        critical => '42 petabytes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size' });
+    is $w, 1125899906842624, 'Should have warning == 1 petabytes';
+    is $c, 47287796087390208, 'Should have critical == 42 petaytes';
+
+    %check_postgres::opt = (
+        warning  => '1e',
+        critical => '42 exobytes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size' });
+    is $w, 1.15292150460685e+18, 'Should have warning == 1 exobytes';
+    is $c, 4.84227031934876e+19, 'Should have critical == 42 exobytes';
+
+    %check_postgres::opt = (
+        warning  => '1z',
+        critical => '42 zettabytes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size' });
+    is $w, 1.18059162071741e+21, 'Should have warning == 1 zettabytes';
+    is $c, 4.95848480701313e+22, 'Should have critical == 42 zettaytes';
+}
+
+INTEGER: {
+    local %check_postgres::opt = (
+        warning  => '1',
+        critical => '42'
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'integer' });
+    is $w, 1, 'Should have warning == 1';
+    is $c, 42, 'Should have critical == 42';
+
+    %check_postgres::opt = (
+        warning  => '1_0',
+        critical => '42_1'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'integer' });
+    is $w, 10, 'Should have warning == 10';
+    is $c, 421, 'Should have critical == 421';
+
+    %check_postgres::opt = (
+        warning  => -1,
+        critical => '+42'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'integer' });
+    is $w, -1, 'Should have warning == -1';
+    is $c, +42, 'Should have critical == +42';
+
+    %check_postgres::opt = (
+        warning  => '+1',
+        critical => '+42'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'positive_integer' });
+    is $w, +1, 'Should have warning == +1';
+    is $c, +42, 'Should have critical == +42';
+}
+
+RESTRINGEX: {
+    local %check_postgres::opt = (
+        warning => '~bucardo',
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'restringex' });
+    is $w, '~bucardo', 'Should have warning == "~bucardo"';
+    is $c, '', 'Should have critical == ""';
+
+    %check_postgres::opt = (
+        critical => 'whatever',
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'restringex' });
+    is $w, '', 'Should have warning == ""';
+    is $c, 'whatever', 'Should have critical == "whatever"';
+}
+
+PERCENT: {
+    local %check_postgres::opt = (
+        critical => '90%',
+        warning  => '5%',
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'percent' });
+    is $w, '5%', 'Should have warning == 5%';
+    is $c, '90%', 'Should have critical == 90%';
+}
+
+SIZEORPERCENT: {
+    local %check_postgres::opt = (
+        critical => '95%',
+        warning  => '7%',
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'size or percent' });
+    is $w, '7%', 'Should have warning == 7%';
+    is $c, '95%', 'Should have critical == 95%';
+
+    %check_postgres::opt = (
+        critical => '1024k',
+        warning  => '10%',
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size or percent' });
+    is $w, '10%', 'Should have warning == 10%';
+    is $c, '1048576', 'Should have critical == 1024K';
+
+    %check_postgres::opt = (
+        warning  => '1m',
+        critical => '42 megabytes'
+    );
+    ($w, $c) = check_postgres::validate_range({ type => 'size or percent' });
+    is $w, 1048576, 'Should have warning == 1 megabytes';
+    is $c, 44040192, 'Should have critical == 42 megabytes';
+}
+
+CHECKSUM: {
+    local %check_postgres::opt = (
+        critical => '3d9442fc242f11e09b7e001e52fffe51',
+        warning  => '7367ff2379b947d9b637f69494b2f3fc',
+    );
+    my ($w, $c) = check_postgres::validate_range({ type => 'checksum' });
+    is $w, '7367ff2379b947d9b637f69494b2f3fc',
+        'Should have warning == 7367ff2379b947d9b637f69494b2f3fc';
+    is $c, '3d9442fc242f11e09b7e001e52fffe51',
+        'Should have critical == 3d9442fc242f11e09b7e001e52fffe51';
+}
+
+CACTI: {
+    local %check_postgres::opt;
+    my ($w, $c) = check_postgres::validate_range({ type => 'cacti' });
+    is $w, '', 'Should have warning == ""';
+    is $c, '', 'Should have critical == ""';
+}
+
+RANGEOP: {
+    # Try size.
+    local %check_postgres::opt = (
+        warning  => '1k',
+        critical => '42 kilobytes'
+    );
+    my ($w, $c) = check_postgres::validate_size_or_percent_with_oper();
+    isa_ok $w, 'CODE', 'warning';
+    isa_ok $c, 'CODE', 'critical';
+
+    ok !$c->(43), '43b is less than 43kb';
+    ok $c->(43008), '43008b is 43kb';
+    ok $c->(90210), '90210b is greater than 43kb';
+
+    ok !$w->(10), '10b is less than 1kb';
+    ok $w->(1024), '1024b is 1kb';
+    ok $w->(2048), '2048 is greater than 1kb';
+
+    # Try percentages.
+    %check_postgres::opt = (
+        critical => '95%',
+        warning  => '7%',
+    );
+    ($w, $c) = check_postgres::validate_size_or_percent_with_oper();
+    isa_ok $w, 'CODE', 'warning';
+    isa_ok $c, 'CODE', 'critical';
+
+    ok !$c->(undef, 20), '20 is less than 95';
+    ok $c->(undef, 95), '95 is 95';
+    ok $c->(undef, 98), '98 is greater than 95';
+
+    ok !$w->(undef, 5), '5 is less than 7';
+    ok $w->(undef, 7), '7 is 7';
+    ok $w->(undef, 10), '10 is greater than 7';
+
+    # Try both.
+    %check_postgres::opt = (
+        warning  => '1k && 20%',
+        critical => '42 kilobytes and 30%'
+    );
+    ($w, $c) = check_postgres::validate_size_or_percent_with_oper();
+    isa_ok $w, 'CODE', 'warning';
+    isa_ok $c, 'CODE', 'critical';
+
+    ok !$c->(42, 20), 'Should get false for critical 42, 20';
+    ok !$c->(44000, 20), 'Should get false for critical 44000, 20';
+    ok  $c->(44000, 30), 'Should get true for critical 44000, 30';
+
+    ok !$w->(42, 10), 'Should get false for warning 42, 10';
+    ok !$w->(1024, 10), 'Should get false for warning 1024, 10';
+    ok  $w->(44000, 20), 'Should get true for warning 1024, 20';
+
+    # Reverse them.
+    %check_postgres::opt = (
+        warning  => '20% AND 1k',
+        critical => '30% && 42 kilobytes'
+    );
+    ($w, $c) = check_postgres::validate_size_or_percent_with_oper();
+    isa_ok $w, 'CODE', 'reversed warning';
+    isa_ok $c, 'CODE', 'reversed critical';
+
+    ok !$c->(42, 20), 'Should get false for critical 42, 20';
+    ok !$c->(44000, 20), 'Should get false for critical 44000, 20';
+    ok  $c->(44000, 30), 'Should get true for critical 44000, 30';
+
+    ok !$w->(42, 10), 'Should get false for warning 42, 10';
+    ok !$w->(1024, 10), 'Should get false for warning 1024, 10';
+    ok  $w->(44000, 20), 'Should get true for warning 1024, 20';
+
+    # Try either.
+    %check_postgres::opt = (
+        warning  => '1k || 20%',
+        critical => '42 kilobytes or 30%'
+    );
+    ($w, $c) = check_postgres::validate_size_or_percent_with_oper();
+    isa_ok $w, 'CODE', 'or warning';
+    isa_ok $c, 'CODE', 'or critical';
+
+    ok !$c->(42, 20), 'Should get false for critical 42, 20';
+    ok $c->(44000, 20), 'Should get true for critical 44000, 20';
+    ok $c->(42, 30), 'Should get true for critical 42, 30';
+    ok  $c->(44000, 30), 'Should get true for critical 44000, 30';
+
+    ok !$w->(42, 10), 'Should get false for warning 42, 10';
+    ok $w->(1024, 10), 'Should get true for warning 1024, 10';
+    ok $w->(42, 20), 'Should get true for warning 42, 20';
+    ok  $w->(1024, 20), 'Should get true for warning 1024, 20';
+
+    # Reverse them.
+    %check_postgres::opt = (
+        warning  => '20% OR 1k',
+        critical => '30% || 42 kilobytes'
+    );
+    ($w, $c) = check_postgres::validate_size_or_percent_with_oper();
+    isa_ok $w, 'CODE', 'reversed or warning';
+    isa_ok $c, 'CODE', 'reversed or critical';
+
+    ok !$c->(42, 20), 'Should get false for critical 42, 20';
+    ok $c->(44000, 20), 'Should get true for critical 44000, 20';
+    ok $c->(42, 30), 'Should get true for critical 42, 30';
+    ok  $c->(44000, 30), 'Should get true for critical 44000, 30';
+
+    ok !$w->(42, 10), 'Should get false for warning 42, 10';
+    ok $w->(1024, 10), 'Should get true for warning 1024, 10';
+    ok $w->(42, 20), 'Should get true for warning 42, 20';
+    ok  $w->(1024, 20), 'Should get true for warning 1024, 20';
+
+    # Try with defaults.
+    %check_postgres::opt = ();
+    ($w, $c) = check_postgres::validate_size_or_percent_with_oper({
+        default_warning  => '20% or 1k',
+        default_critical => '30% || 42 kilobytes'
+    });
+    isa_ok $w, 'CODE', 'default warning';
+    isa_ok $c, 'CODE', 'default critical';
+
+    ok !$c->(42, 20), 'Should get false for critical 42, 20';
+    ok $c->(44000, 20), 'Should get true for critical 44000, 20';
+    ok $c->(42, 30), 'Should get true for critical 42, 30';
+    ok  $c->(44000, 30), 'Should get true for critical 44000, 30';
+
+    ok !$w->(42, 10), 'Should get false for warning 42, 10';
+    ok $w->(1024, 10), 'Should get true for warning 1024, 10';
+    ok $w->(42, 20), 'Should get true for warning 42, 20';
+    ok  $w->(1024, 20), 'Should get true for warning 1024, 20';
+
+    # Try with just critical.
+    %check_postgres::opt = ( critical  => '20% or 1k');
+    ($w, $c) = check_postgres::validate_size_or_percent_with_oper();
+    isa_ok $w, 'CODE', 'missing warning';
+    isa_ok $c, 'CODE', 'critical';
+
+    ok !$c->(42, 10), 'Should get false for critical 42, 10';
+    ok $c->(1024, 10), 'Should get true for critical 1024, 10';
+    ok $c->(42, 20), 'Should get true for critical 42, 20';
+    ok  $c->(1024, 20), 'Should get true for critical 1024, 20';
+
+    ok !$w->(0), 'Warning should return false';
+    ok !$w->(undef), 'Warning should always return false';
+    ok !$w->('whatever'), 'Warning should really always return false';
+
+    # Try with just warning.
+    %check_postgres::opt = ( warning  => '20% or 1k');
+    ($w, $c) = check_postgres::validate_size_or_percent_with_oper();
+    isa_ok $w, 'CODE', 'warning';
+    isa_ok $c, 'CODE', 'missing critical';
+
+    ok !$c->(0), 'Critical should return false';
+    ok !$c->(undef), 'Critical should always return false';
+    ok !$c->('whatever'), 'Critical should really always return false';
+
+    ok !$w->(42, 10), 'Should get false for warning 42, 10';
+    ok $w->(1024, 10), 'Should get true for warning 1024, 10';
+    ok $w->(42, 20), 'Should get true for warning 42, 20';
+    ok  $w->(1024, 20), 'Should get true for warning 1024, 20';
+}
index 566540402d5c2277655b8658706c8e6163250d9c..82014509aca01970ab5bec72f7139c38129ff50d 100644 (file)
@@ -6,7 +6,7 @@ use 5.006;
 use strict;
 use warnings;
 use Data::Dumper;
-use Test::More tests => 26;
+use Test::More tests => 30;
 use lib 't','.';
 use CP_Testing;
 
@@ -68,6 +68,18 @@ like ($cp->run('-c 100000'), qr{^$label CRITICAL:.+$tname}, $t);
 $t=qq{$S returns warning for bloated table using percentages};
 like ($cp->run('-w 10%'), qr{^$label WARNING:.+$tname}, $t);
 
+$t=qq{$S returns warning for bloated table using size or percent};
+like ($cp->run('-w "100000 || 10%"'), qr{^$label WARNING:.+$tname}, $t);
+
+$t=qq{$S returns warning for bloated table using big size or percent};
+like ($cp->run('-w "1000000000 || 10%"'), qr{^$label WARNING:.+$tname}, $t);
+
+$t=qq{$S returns warning for bloated table using size and percent};
+like ($cp->run('-w "10000 && 10%"'), qr{^$label WARNING:.+$tname}, $t);
+
+$t=qq{$S returns no warning for bloated table using big size and percent};
+like ($cp->run('-w "1000000000 && 10%"'), qr{^$label OK: DB "postgres".+$tname}, $t);
+
 $dbh->do("DROP TABLE $tname");
 
 exit;
index 3cae08fb99192b161af56f7a57170b6246d7a40c..0dee62a9bf0b192890d9366763882c01efece037 100644 (file)
@@ -6,7 +6,7 @@ use 5.006;
 use strict;
 use warnings;
 use Data::Dumper;
-use Test::More tests => 7;
+use Test::More tests => 8;
 use lib 't','.';
 use CP_Testing;
 
@@ -41,6 +41,9 @@ like ($result, qr{$label OK}, $t);
 $t = qq{$S flags insufficient space};
 like ($cp->run('-w 1b'), qr{$label WARNING:}, $t);
 
+$t = qq{$S flags insufficient space};
+like ($cp->run('-w "999z or 1%"'), qr{$label WARNING:}, $t);
+
 $t = qq{$S reports MRTG output};
 like ($cp->run('--output=mrtg'), qr{\A\d+\n0\n\n/.*\n}, $t);