File Coverage

blib/lib/Device/Cisco/NXAPI/Test.pm
Criterion Covered Total %
statement 68 68 100.0
branch 3 4 75.0
condition n/a
subroutine 16 16 100.0
pod 5 5 100.0
total 92 93 98.9


line stmt bran cond sub pod time code
1             package Device::Cisco::NXAPI::Test;
2              
3 6     6   87 use 5.020;
  6         13  
4 6     6   22 use strict;
  6         7  
  6         89  
5 6     6   15 use warnings;
  6         5  
  6         105  
6              
7 6     6   19 use Moose;
  6         6  
  6         41  
8 6     6   29267 use Modern::Perl;
  6         8  
  6         46  
9 6     6   807 use Data::Dumper;
  6         7  
  6         247  
10 6     6   23 use Carp;
  6         7  
  6         263  
11 6     6   25 use List::Util qw( any );
  6         6  
  6         296  
12 6     6   24 use List::MoreUtils qw( uniq );
  6         6  
  6         33  
13 6     6   4453 use Array::Utils qw{ array_minus };
  6         1899  
  6         313  
14 6     6   27 use Params::Validate qw( :all );
  6         8  
  6         4871  
15              
16             =head1 NAME
17              
18             Device::Cisco::NXAPI::Test - Run a suite of tests on switches that support NXAPI.
19              
20             =head1 VERSION
21              
22             Version 0.02
23              
24             =cut
25              
26             our $VERSION = '0.02';
27              
28              
29             =head1 SYNOPSIS
30              
31             This module contains a set of methods that run tests against an NXAPI compatible switch.
32             The functions take arguments and return 1 or 0 depending on the current runtime state of the switch.
33              
34             These methods should be used in conjunction with the B<ok()> function provided by B<Test::More>.
35              
36             use Device::Cisco::NXAPI;
37             use Test::More;
38              
39             # The Device::Cisco::NXAPI module provides a method that returns a Device::Cisco::NXAPI::Test object.
40             my $tests = Device::Cisco::NXAPI->new(uri => 'http://hostname', username => 'admin', password => 'admin')->tester();
41              
42             # Test whether interfaces are up
43             ok( $tests->interfaces_up(interfaces => ['Ethernet1/1', 'Ethernet1/2']), "Interfaces are up" );
44              
45             # Test for the presence of routes
46             ok( $tests->routes(routes => ['192.168.1.0/24', '10.0.0.0/8']), 'Routes in routing table' );
47            
48             =cut
49              
50             has 'switch' => ( is => 'ro', isa => 'Device::Cisco::NXAPI', default => sub { });
51              
52             =head1 SUBROUTINES
53              
54             =cut
55              
56             =head2 routes(%options)
57              
58             ok(
59             $tests->routes(
60             vrf => '',
61             af => 'ipv4' | 'ipv6',
62             routes => [],
63             )
64             );
65              
66             Returns 1 is all of the routes specified in the ARRAYREF are present in the routing table.
67             Returns 0 if any of the routes are not int the routing table.
68              
69             B<vrf =>> defaults to the global routing table if not specified, B<af =>> defaults to 'ipv4'.
70              
71             =cut
72              
73             sub routes {
74 12     12 1 4750 my $self = shift;
75 12         253 my %args = validate(@_,
76             {
77             vrf => { default => 'default', type => SCALAR | UNDEF },
78             af => { default => 'ipv4', type => SCALAR | UNDEF },
79             routes => { type => ARRAYREF },
80             }
81             );
82 12         43 my @returned_prefixes = ();
83              
84 12         12 my @test_routes = @{ delete $args{routes} };
  12         26  
85              
86             # Let the routes() method call validate the arguments
87 12         459 my @retrieved_routes = map { $_->{prefix} } $self->switch()->routes(%args);
  120         149  
88              
89 12         196 return !array_minus(@test_routes, @retrieved_routes);
90             }
91              
92             =head2 arp_entries(%options)
93              
94             ok(
95             $tests->arp_entries(
96             vrf => '',
97             ips => [ ]
98             )
99             );
100              
101             Returns 1 if all of the IPs specified by B<ips =>> have valid entries in the ARP table of the specified VRF, otherwise returns 0.
102             B<vrf =>> defaults to the global routing table if not specified.
103              
104             =cut
105              
106             sub arp_entries {
107 6     6 1 1708 my $self = shift;
108 6         116 my %args = validate(@_,
109             {
110             vrf => { default => 'default', type => SCALAR | UNDEF },
111             ips => { type => ARRAYREF },
112             }
113             );
114              
115 6         19 my @test_arp_entries = @{ delete $args{ips} };
  6         14  
116              
117 6         183 my @retrieved_arp = map { $_->{ip} } $self->switch()->arp();
  30         38  
118              
119 6         39 return scalar !array_minus(@test_arp_entries, @retrieved_arp);
120             }
121              
122              
123             =head2 interfaces_up(%options)
124              
125             ok(
126             $tests->interfaces_up(
127             interfaces => [ ]
128             )
129             );
130              
131             Returns 1 if all of the interfaces specified are in the 'up' operational state, otherwise returns 0.
132             Interfaces must be written exactly as they would appear in the CLI, and are case sensitive.
133             e.g. [ 'Ethernet1/4', 'mgmt0' ]
134              
135             =cut
136              
137             sub interfaces_up {
138 11     11 1 3047 my $self = shift;
139 11         192 my %args = validate(@_,
140             {
141             interfaces => { type => ARRAYREF },
142             }
143             );
144              
145 11         31 my @test_interfaces = @{ $args{interfaces} };
  11         27  
146              
147 11 100       378 my @retrieved_up_interfaces = map { $_->{name} if $_->{op_state} eq 'up' } $self->switch()->physical_interfaces();
  66         180  
148            
149 11         354 return scalar !array_minus(@test_interfaces, @retrieved_up_interfaces);
150             }
151              
152              
153             =head2 bgp_peers_up(%options)
154              
155             ok(
156             $tests->bgp_peers_up(
157             vrf => '',
158             af => 'ipv4 | ipv6',
159             peers => [ ]
160             )
161             );
162              
163             Returns 1 if all of the peers specified are in the 'up' operational state, otherwise returns 0.
164             BGP peers are specified by upon their IP address.
165              
166             B<vrf =>> defaults to the global routing table if not specified, B<af =>> defaults to 'ipv4'.
167              
168             =cut
169              
170             sub bgp_peers_up {
171 1     1 1 435 my $self = shift;
172 1         47 my %args = validate(@_,
173             {
174             vrf => { default => 'default', type => SCALAR | UNDEF },
175             af => { default => 'ipv4', type => SCALAR | UNDEF, regex => qr{(ipv4|ipv6)} },
176             peers => { type => ARRAYREF },
177             }
178             );
179              
180 1         6 my @test_peers = @{ delete $args{peers} };
  1         4  
181              
182 1 50       31 my @retrieved_up_peers = map{ $_->{neighbor} if $_->{up} eq 'true' } $self->switch()->bgp_peers(%args);
  1         6  
183              
184 1         10 return scalar !array_minus(@test_peers, @retrieved_up_peers);
185             }
186              
187             =head2 bgp_rib_prefixes(%options)
188              
189             ok(
190             $tests->bgp_rib_prefixes(
191             vrf => '',
192             af => 'ipv4 | ipv6',
193             prefixes => [ ]
194             )
195             );
196              
197             Searches for the prefixes within the BGP RIB. All of the prefixes must be present in the
198             RIB for the function to return 'true', otherwise the function returns false.
199              
200             B<vrf =>> defaults to the global routing table if not specified, B<af =>> defaults to 'ipv4'.
201              
202             =cut
203              
204             sub bgp_rib_prefixes {
205 4     4 1 1203 my $self = shift;
206 4         101 my %args = validate(@_,
207             {
208             vrf => { default => 'default', type => SCALAR | UNDEF },
209             af => { default => 'ipv4', type => SCALAR | UNDEF, regex => qr{(ipv4|ipv6)} },
210             prefixes => { type => ARRAYREF },
211             }
212             );
213              
214 4         20 my @test_prefixes = @{ delete $args{prefixes} };
  4         10  
215 4         121 my @retrieved_prefixes = map { $_->{prefix} } $self->switch()->bgp_rib(%args);
  8         15  
216              
217 4         27 return !array_minus(@test_prefixes, @retrieved_prefixes);
218             }
219              
220              
221             =head1 AUTHOR
222              
223             Greg Foletta, C<< <greg at foletta.org> >>
224              
225             =head1 BUGS
226              
227             Please report any bugs or feature requests to C<bug-switch-nxapi at rt.cpan.org>, or through
228             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Switch-NXAPI>. I will be notified, and then you'll
229             automatically be notified of progress on your bug as I make changes.
230              
231              
232              
233              
234             =head1 SUPPORT
235              
236             You can find documentation for this module with the perldoc command.
237              
238             perldoc Device::Cisco::NXAPI
239              
240              
241             You can also look for information at:
242              
243             =over 4
244              
245             =item * RT: CPAN's request tracker (report bugs here)
246              
247             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Switch-NXAPI>
248              
249             =item * AnnoCPAN: Annotated CPAN documentation
250              
251             L<http://annocpan.org/dist/Switch-NXAPI>
252              
253             =item * CPAN Ratings
254              
255             L<http://cpanratings.perl.org/d/Switch-NXAPI>
256              
257             =item * Search CPAN
258              
259             L<http://search.cpan.org/dist/Switch-NXAPI/>
260              
261             =back
262              
263              
264             =head1 ACKNOWLEDGEMENTS
265              
266              
267             =head1 LICENSE AND COPYRIGHT
268              
269             Copyright 2016 Greg Foletta.
270              
271             This program is free software; you can redistribute it and/or modify it
272             under the terms of the the Artistic License (2.0). You may obtain a
273             copy of the full license at:
274              
275             L<http://www.perlfoundation.org/artistic_license_2_0>
276              
277             Any use, modification, and distribution of the Standard or Modified
278             Versions is governed by this Artistic License. By using, modifying or
279             distributing the Package, you accept this license. Do not use, modify,
280             or distribute the Package, if you do not accept this license.
281              
282             If your Modified Version has been derived from a Modified Version made
283             by someone other than you, you are nevertheless required to ensure that
284             your Modified Version complies with the requirements of this license.
285              
286             This license does not grant you the right to use any trademark, service
287             mark, tradename, or logo of the Copyright Holder.
288              
289             This license includes the non-exclusive, worldwide, free-of-charge
290             patent license to make, have made, use, offer to sell, sell, import and
291             otherwise transfer the Package with respect to any patent claims
292             licensable by the Copyright Holder that are necessarily infringed by the
293             Package. If you institute patent litigation (including a cross-claim or
294             counterclaim) against any party alleging that the Package constitutes
295             direct or contributory patent infringement, then this Artistic License
296             to you shall terminate on the date that such litigation is filed.
297              
298             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
299             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
300             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
301             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
302             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
303             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
304             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
305             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
306              
307              
308             =cut
309              
310             1; # End of Device::Cisco::NXAPI
311