App-Netdisco
view release on metacpan or search on metacpan
xt/205-each-vrf-instance-context-probe.t view on Meta::CPAN
#!/usr/bin/env perl
use strict; use warnings;
BEGIN { $ENV{DANCER_ENVDIR} = '/dev/null'; }
use Test::More 0.88;
use Test::File::ShareDir::Dist { 'App-Netdisco' => 'share/' };
use App::Netdisco;
use App::Netdisco::DB;
use App::Netdisco::Util::VRF 'each_vrf_instance';
use App::Netdisco::Transport::SNMP ();
use Dancer qw/:script !pass/;
# A v2c community@vrf the device drops costs every attribute a VRF reader
# walks its own SNMP timeout; lab arpnip took 364 s of a 600 s job timeout for
# one dead context. each_vrf_instance asks the switched context for one
# scalar first, and only a timeout stops the read.
config->{'enable_incomplete_walk_protection'} = 1;
package FakeSession;
sub new { my ($class, $snmp) = @_; return bless { snmp => $snmp }, $class }
sub get {
my ($self, $oid) = @_;
my $snmp = $self->{snmp};
push @{ $snmp->{probes} }, [$snmp->{context}, $oid];
my $answer = $snmp->{answers}{ $snmp->{context} } || 'value';
if ($answer eq 'timeout') {
@$self{qw/ErrorStr ErrorNum/} = ('Timeout', -24);
return undef;
}
if (ref $answer) {
@$self{qw/ErrorStr ErrorNum/} = @$answer;
return undef;
}
@$self{qw/ErrorStr ErrorNum/} = ('', 0);
return ($answer eq 'nosuchobject' ? 'NOSUCHOBJECT' : 12345);
}
package FakeSNMP;
sub new {
my ($class, %vals) = @_;
my $self = bless { context => '', probes => [], walk_failures => [], %vals }, $class;
$self->{session} = FakeSession->new($self);
return $self;
}
sub snmp_ver { 2 }
sub snmp_comm { 'public' }
sub class { 'SNMP::Info::Layer3::Fake' }
sub session { $_[0]{session} }
sub walk_failures { $_[0]{walk_failures} }
sub error { my $self = shift; my $error = $self->{error}; $self->{error} = undef; return $error }
sub vrf_read_complete { 1 }
sub update {
my ($self, %args) = @_;
my $target = ($args{Community} =~ m/\@(.+)$/ ? $1 : '');
# SNMP::Info::update() keeps the old session and returns false on failure
if ($self->{fail_update_to}{$target}) {
$self->{error} = $self->{update_error} if exists $self->{update_error};
return;
}
$self->{context} = $target;
return $self->{session} || 1;
}
package main;
my $device = App::Netdisco::DB->resultset('Device')->new_result({ ip => '192.0.2.1' });
sub switched { my $name = shift;
return { name => $name, contexts => [{ kind => 'vrf', id => $name, v2c => "%s\@$name", v3 => $name }] } }
my %instances = (
default => { name => 'default', contexts => [{ kind => 'none' }] },
mgmt => { name => 'mgmt', contexts => [{ kind => 'none' }] },
blue => switched('blue'),
red => switched('red'),
);
sub run_each {
my $snmp = shift;
my @read;
my $reads = each_vrf_instance($device, $snmp, \%instances,
sub { my ($name) = @_; push @read, [$name, $snmp->{context}]; return "data of $name" });
return ($reads, \@read);
}
subtest 'each_vrf_instance__context_times_out__vrf_incomplete_reader_not_called' => sub {
my $snmp = FakeSNMP->new(answers => { red => 'timeout', blue => 'timeout' });
my ($reads, $read) = run_each($snmp);
is_deeply $reads->{red}, { complete => 0, data => undef }, 'red incomplete with no data';
ok !(grep { $_->[0] eq 'red' } @$read), 'red reader not called';
is_deeply [grep { $_->[0] eq 'red' } @{ $snmp->{probes} }],
[['red', '.1.3.6.1.2.1.1.3.0']], 'red asked for sysUpTime.0 once';
is $snmp->{context}, '', 'session back in the default context';
};
subtest 'each_vrf_instance__context_answers_nosuchobject__read_as_usual' => sub {
my $snmp = FakeSNMP->new(answers => { red => 'nosuchobject' });
my ($reads, $read) = run_each($snmp);
is_deeply $reads->{red}, { complete => 1, data => 'data of red' }, 'red read and complete';
is_deeply [grep { $_->[0] eq 'red' } @$read], [['red', 'red']], 'red read in its context';
};
subtest 'each_vrf_instance__one_dead_context__other_vrfs_still_read' => sub {
my $snmp = FakeSNMP->new(answers => { blue => 'timeout' });
my ($reads, $read) = run_each($snmp);
is_deeply $reads->{blue}, { complete => 0, data => undef }, 'blue incomplete';
is_deeply $reads->{red}, { complete => 1, data => 'data of red' }, 'red read after blue';
is_deeply $reads->{''}, { complete => 1, data => 'data of default' }, 'default read';
is_deeply $reads->{mgmt}, { complete => 1, data => 'data of mgmt' }, 'in-place mgmt read';
};
subtest 'each_vrf_instance__default_context__not_probed' => sub {
my $snmp = FakeSNMP->new;
( run in 0.744 second using v1.01-cache-2.11-cpan-145b269f2f3 )