use Test::More; # qw/no_plan/; use strict; use POE; use POE::Component::SNMP; use lib qw(t); use TestPCS; my $CONF = do "config.cache"; if ( $CONF->{skip_all_tests} ) { POE::Kernel->run(); plan skip_all => 'No SNMP data specified.'; } else { plan tests => 47; } POE::Session->create ( inline_states => { _start => \&snmp_run_tests, _stop => \&stop_session, snmp_get_cb => \&snmp_get_cb, }, ); $poe_kernel->run; ok 1; # clean exit exit 0; my $sysName = "1.3.6.1.2.1.1.5.0"; my $system_base = "1.3.6.1.2.1.1"; sub snmp_run_tests { my ($kernel, $heap) = @_[KERNEL, HEAP]; SKIP: { skip "parameter checks", 2; # if $ENV{POE_ASSERT_DEFAULT}; eval { # throws an error because no hostname: POE::Component::SNMP->create( alias => 'snmp_no_hostname', # hostname => $CONF->{'hostname'}, community => $CONF->{'community'}, debug => $CONF->{debug}, ); }; ok $@, '-hostname parameter required'; # this asserts that the alias does *not* exist ok ! $kernel->alias_resolve( 'snmp_no_hostname' ), "session not created with missing hostname"; } #### dupe sessions: # normal session POE::Component::SNMP->create( alias => 'snmp', hostname => $CONF->{'hostname'}, community => $CONF->{'community'}, timeout => 2, ); ok $kernel->alias_resolve('snmp'), "normal session create"; SKIP: { skip "dupe session check not safely trappable", 2 ; # if $POE::VERSION <= 0.37 and POE::Kernel::ASSERT_DEFAULT; # if exists $ENV{POE_ASSERT_DEFAULT}; # and $POE::VERSION <= 0.34; eval { POE::Component::SNMP->create( alias => 'snmp', hostname => $CONF->{'hostname'}, community => $CONF->{'community'}, timeout => 2, ); }; warn $@; ok $@ =~ /'snmp' already exists|'snmp' is in use by another session/, "duplicate alias is fatal"; ok $kernel->alias_resolve('snmp'), "existing session not affected"; } SKIP: { skip "need secondary hostname", 3 unless $CONF->{'hostname2'}; my $LOCALPORT = 43128; eval { POE::Component::SNMP->create( alias => 'snmp_localport', hostname => $CONF->{'hostname'}, community => $CONF->{'community'}, timeout => 2, localport => $LOCALPORT, ); }; ok $kernel->alias_resolve('snmp_localport'), "session created with localport $LOCALPORT"; eval { POE::Component::SNMP->create( alias => 'snmp_localport_conflict', hostname => $CONF->{'hostname2'}, community => $CONF->{'community2'}, timeout => 2, -localport => $LOCALPORT, ); }; ok $@ =~ /Address already in use/; my $localport_close = 0; $localport_close and $kernel->call(snmp_localport => 'finish'); # close the session SKIP: { skip "ASSERT_DEFAULT bug", 1 if $ENV{POE_ASSERT_DEFAULT} and $POE::VERSION <= 0.3401; ok !$kernel->alias_resolve('snmp_localport_conflict'), "session NOT created with duplicate localport"; $localport_close and ok !$kernel->alias_resolve('snmp_localport'), "session NOT created with duplicate localport"; } } $heap->{done} = 0; ### ### Throw some client-side errors: ### SKIP: { 0 and skip "client stuff", 3; # wants baseoid, NOT varbindlist # Invalid argument '-varbindlist' $heap->{planned}++; $kernel->post( snmp => walk => 'snmp_get_cb', -varbindlist => $sysName, ); get_sent($heap); # doesn't like empty baseoid parameter # Expected base OBJECT IDENTIFIER in dotted notation $heap->{planned}++; $kernel->post( snmp => walk => 'snmp_get_cb', -baseoid => '', ); get_sent($heap); # wants varbindlist, NOT baseoid # Invalid argument '-baseoid' $heap->{planned}++; $kernel->post( snmp => get => 'snmp_get_cb', -baseoid => $system_base, ); get_sent($heap); } SKIP: { ### ### Now throw some server-side errors: ### 0 and skip "server stuff", 5; ### ### THIS DOES *NOT* throw an error! ### ## ## This returns an empty, VALID result hash! ## NOT to be confused with an empty string. $heap->{planned}++; $kernel->post( snmp => get => 'snmp_get_cb', -varbindlist => undef, ); get_sent($heap); # doesn't like empty varbindlist # Expected array reference for variable-bindings $heap->{planned}++; $kernel->post( snmp => get => 'snmp_get_cb', -varbindlist => '', ); get_sent($heap); if (0) { # I expected this to complain, like the others, because # sysname isn't an array ref. It didn't. I'll figure it # out later. # doesn't like string varbindlist, wants an array ref: # Expected array reference for variable-bindings $heap->{planned}++; $kernel->post( snmp => get => 'snmp_get_cb', -varbindlist => $sysName, ); } # OID value out of range # An OBJECT IDENTIFIER must begin with either 0 (ccitt), 1 (iso), or 2 (joint-iso-ccitt) $heap->{planned}++; $kernel->post( snmp => get => 'snmp_get_cb', -varbindlist => [ '9.9.9.9.9.9.9' ], ); get_sent($heap); # no such variable in this MIB # Received noSuchName(2) error-status at error-index 1 $heap->{planned}++; $kernel->post( snmp => get => 'snmp_get_cb', -varbindlist => [ '1.9.9.9.9.9.9' ], ); get_sent($heap); } SKIP: { ### ### do some bad 'set' requests ### 0 and skip "write tests", 3; skip "no writeable SNMP device available", 3 + 6 if not length $CONF->{wcommunity}; # I picked this OID at random because I figured it would be readonly: # system.sysORTable.sysOREntry.sysORDescr.1 my $read_only_string_oid = ".1.3.6.1.2.1.1.9.1.3.1"; # invalid parms for 'set' # Expected [OBJECT IDENTIFIER, ASN.1 type, object value] combination $heap->{planned}++; $kernel->post( snmp => set => 'snmp_get_cb', -varbindlist => [ '1.9.9.9.9.9.9' ], ); get_sent($heap); # invalid parms for 'set' # Unknown ASN.1 type [STRING] $heap->{planned}++; $kernel->post( snmp => set => 'snmp_get_cb', -varbindlist => [ $read_only_string_oid, 'STRING', 'hi mom' ], ); get_sent($heap); # write to a readonly value # Received noSuchName(2) error-status at error-index 0 $heap->{planned}++; $kernel->post( snmp => set => 'snmp_get_cb', -varbindlist => [ $read_only_string_oid, 'OCTET_STRING', 'hi mom' ], ); get_sent($heap); } } # store results for future processing sub snmp_get_cb { my ($kernel, $heap, $request, $aref) = @_[KERNEL, HEAP, ARG0, ARG1]; ok get_seen($heap); ok ref $aref eq 'ARRAY'; my $href = $aref->[0]; if (ref $href) { # got server results ok ref $href eq 'HASH'; # no error # catch the results of $kernel->post( snmp => get => -varbindlist => undef ) # which should be: [ {}, '' ] if ($request->[2] eq 'get' and $request->[3] eq '-varbindlist' and not defined $request->[4]) { ok keys %$href == 0; # no extra args supplied, we didn't specify any callback_args ok @$aref == 1; ok ++$heap->{saw_empty}, "empty_request returned for undef -varbindlist"; } foreach my $k (keys %$href) { ok $heap->{results}{$k} = $href->{$k}, "got a result"; # got a result } } elsif (defined $href) { my $message = $href; ok $message, "received error: $message"; } if (check_done($heap)) { $kernel->post( snmp => 'finish' ); ok check_done($heap); # INTENTIONALLY double-dealloc. this should be completely harmless. $kernel->post( snmp => 'finish' ); } # $kernel->post( snmp => 'finish' ) if ++$heap->{done} == $heap->{planned}; # INTENTIONALLY double-dealloc # $kernel->post( snmp => 'finish' ) if ++$heap->{done} >= $heap->{planned}; } sub stop_session { my $r = $_[HEAP]->{results}; ok 1; # got here! ok $_[HEAP]->{saw_empty}; ok !(ref $r eq 'HASH'); # $r should be *empty*, this tests generates no value results. ok ! keys %$r; # # not exported by cygwin? # # ok exists($r->{'.1.3.6.1.2.1.1.7.0'}); # ok exists($r->{'.1.3.6.1.2.1.1.8.0'}); }