#67 Juniper EX4300 Missing/Wrong information

Modify Q-Bridge methods to work on both pre-Enhanced Layer 2 Software (ELS) such as EX4200 and newer Enhanced Layer 2 Software (ELS) based switches such as EX4300 and QFX series
This commit is contained in:
Eric A. Miller
2018-04-19 18:23:48 -04:00
parent 4919cb0f69
commit 2aca6d9300
3 changed files with 1000 additions and 132 deletions

View File

@@ -20,6 +20,7 @@ Version 3.55
[BUG FIXES] [BUG FIXES]
* #67 Juniper EX4300 Missing/Wrong information
* #61 ZyXEL (X)GS1900 family MIB - Fix loop in layers method * #61 ZyXEL (X)GS1900 family MIB - Fix loop in layers method
* Fix ISA in AMAP and EDP classes * Fix ISA in AMAP and EDP classes
* Add missing MIB in L2::Trapeze, L2::NWSS2300, and L3::Dell * Add missing MIB in L2::Trapeze, L2::NWSS2300, and L3::Dell

View File

@@ -52,37 +52,45 @@ $VERSION = '3.54';
'JUNIPER-L2ALD-MIB' => 'jnxL2aldVlanFdbId', 'JUNIPER-L2ALD-MIB' => 'jnxL2aldVlanFdbId',
); );
%GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, %GLOBALS = (
%SNMP::Info::Layer3::GLOBALS,
%SNMP::Info::LLDP::GLOBALS, %SNMP::Info::LLDP::GLOBALS,
'serial' => 'jnxBoxSerialNo.0', 'serial' => 'jnxBoxSerialNo',
'mac' => 'dot1dBaseBridgeAddress', 'mac' => 'dot1dBaseBridgeAddress',
'box_descr' => 'jnxBoxDescr', 'box_descr' => 'jnxBoxDescr',
'version' => 'jnxVirtualChassisMemberSWVersion.0', 'version' => 'jnxVirtualChassisMemberSWVersion',
'vc_model' => 'jnxVirtualChassisMemberModel.0', 'vc_model' => 'jnxVirtualChassisMemberModel',
); );
%FUNCS = ( %SNMP::Info::Layer3::FUNCS, %FUNCS = (
%SNMP::Info::Layer3::FUNCS,
%SNMP::Info::LLDP::FUNCS, %SNMP::Info::LLDP::FUNCS,
# JUNIPER-VLAN-MIB::jnxExVlanTable
'v_index' => 'jnxExVlanTag',
'v_type' => 'jnxExVlanType',
'vlan_name' => 'jnxExVlanName',
# JUNIPER-VLAN-MIB::jnxExVlanPortGroupTable # JUNIPER-VLAN-MIB::jnxExVlanPortGroupTable
'i_trunk' => 'jnxExVlanPortAccessMode', 'i_trunk' => 'jnxExVlanPortAccessMode',
# JUNPIER-MIB # JUNIPER-MIB
'e_contents_type' => 'jnxContentsType', 'e_contents_type' => 'jnxContentsType',
'e_containers_type' => 'jnxContainersType', 'e_containers_type' => 'jnxContainersType',
'e_hwver' => 'jnxContentsRevision', 'e_hwver' => 'jnxContentsRevision',
'v_fdb_id' => 'jnxL2aldVlanFdbId', # JUNIPER-VLAN-MIB::jnxExVlanTable
'v_vlan_tag' => 'jnxL2aldVlanTag', 'jnx_v_name' => 'jnxExVlanName',
'v_vlan_name' => 'jnxL2aldVlanName', 'jnx_v_index' => 'jnxExVlanTag',
'jnx_v_type' => 'jnxExVlanType',
# JUNIPER-L2ALD-MIB::jnxL2aldVlanTable
# Used in Enhanced Layer 2 Software (ELS)
# replaces JUNIPER-VLAN-MIB::jnxExVlanTable
# in newer switches
'jnx_els_v_name' => 'jnxL2aldVlanName',
'jnx_els_v_index' => 'jnxL2aldVlanTag',
'jnx_els_v_type' => 'jnxL2aldVlanType',
'jnx_els_v_fdb_id' => 'jnxL2aldVlanFdbId',
); );
%MUNGE = ( %SNMP::Info::Layer3::MUNGE, %MUNGE = (
%SNMP::Info::Layer3::MUNGE,
%SNMP::Info::LLDP::MUNGE, %SNMP::Info::LLDP::MUNGE,
'e_containers_type' => \&SNMP::Info::munge_e_type, 'e_containers_type' => \&SNMP::Info::munge_e_type,
'e_contents_type' => \&SNMP::Info::munge_e_type, 'e_contents_type' => \&SNMP::Info::munge_e_type,
@@ -174,43 +182,60 @@ sub i_trunk {
foreach (keys %$access) foreach (keys %$access)
{ {
my $old_key = $_; my $old_key = $_;
m/^\d+\.(\d+)$/o; my $new_key = $old_key;
my $new_key = $1; $new_key = $1 if m/^\d+\.(\d+)$/;
$i_trunk{$new_key} = $access->{$old_key}; $i_trunk{$new_key} = $access->{$old_key};
} }
return \%i_trunk; return \%i_trunk;
} }
# Note: For overridden VLAN methods where we have to distinguish between newer
# ELS and older models we try the newer methods first assuming they will be
# more common to save on network queries. Short circuit operation depends on
# leaf not present and snmp query returning undef
sub qb_fdb_index { sub qb_fdb_index {
my $juniper = shift; my $juniper = shift;
my $partial = shift; my $partial = shift;
return $juniper->jnxExVlanTag($partial); # Lots of indirection here
my $v_index = $juniper->jnx_els_v_index($partial);
if ( ref {} eq ref $v_index and scalar keys %$v_index ) {
my $fdb_index = $juniper->jnx_els_v_fdb_id($partial);
my $qb_fdb_index = {};
for my $key ( keys(%$v_index) ) {
my $vlan = $v_index->{$key};
next unless defined $vlan;
my $fdb = $fdb_index->{$key};
next unless defined $fdb;
$qb_fdb_index->{$fdb} = $vlan;
}
return $qb_fdb_index;
} }
# 'v_type' => 'jnxExVlanType', $juniper->jnx_v_index($partial);
}
sub v_type { sub v_type {
my $juniper = shift; my $juniper = shift;
my $partial = shift; my $partial = shift;
my $v_type = $juniper->jnxExVlanType($partial); return $juniper->jnx_els_v_type($partial)
|| $juniper->jnx_v_type($partial);
return $v_type;
} }
# 'v_index' => 'jnxExVlanTag',
sub v_index { sub v_index {
my ($juniper) = shift; my ($juniper) = shift;
my ($partial) = shift; my ($partial) = shift;
my ($v_index) = $juniper->jnxExVlanTag($partial); return $juniper->jnx_els_v_index($partial)
my ($v_vlan_index) = $juniper->v_vlan_tag($partial); || $juniper->jnx_v_index($partial);
return $v_index unless $v_vlan_index;
return $v_vlan_index;
} }
sub i_vlan { sub i_vlan {
my $juniper = shift; my $juniper = shift;
my $partial = shift; my $partial = shift;
@@ -223,13 +248,15 @@ sub i_vlan {
$partial = $r_index{$partial}; $partial = $r_index{$partial};
} }
my $v_index = $juniper->jnxExVlanTag(); my $v_index = $juniper->v_index();
my $i_pvid = $juniper->qb_i_vlan($partial) || {}; my $i_pvid = $juniper->qb_i_vlan($partial) || {};
my $i_vlan = {}; my $i_vlan = {};
foreach my $bport ( keys %$i_pvid ) { foreach my $bport ( keys %$i_pvid ) {
my $q_vlan = $i_pvid->{$bport}; my $q_vlan = $i_pvid->{$bport};
my $vlan = $v_index->{$q_vlan} || $q_vlan; my $vlan = $q_vlan;
# Use defined as check since VLAN can be zero
$vlan = $v_index->{$q_vlan} if defined $v_index->{$q_vlan};
my $ifindex = $index->{$bport}; my $ifindex = $index->{$bport};
unless ( defined $ifindex ) { unless ( defined $ifindex ) {
print " Port $bport has no bp_index mapping. Skipping.\n" print " Port $bport has no bp_index mapping. Skipping.\n"
@@ -240,11 +267,11 @@ sub i_vlan {
} }
return $i_vlan; return $i_vlan;
} }
sub v_name { sub v_name {
my $juniper = shift; my $juniper = shift;
my $name = $juniper->v_vlan_name();
return $juniper->vlan_name() unless $name; return $juniper->jnx_els_v_name() || $juniper->jnx_v_name();
return $name;
} }
# Index doesn't use VLAN ID, so override the HOA private method here to # Index doesn't use VLAN ID, so override the HOA private method here to
@@ -254,7 +281,7 @@ sub _vlan_hoa {
my ( $v_ports, $partial ) = @_; my ( $v_ports, $partial ) = @_;
my $index = $juniper->bp_index(); my $index = $juniper->bp_index();
my $v_index = $juniper->jnxExVlanTag($partial); my $v_index = $juniper->v_index($partial);
my $vlan_hoa = {}; my $vlan_hoa = {};
foreach my $idx ( keys %$v_ports ) { foreach my $idx ( keys %$v_ports ) {
@@ -282,36 +309,58 @@ sub _vlan_hoa {
return $vlan_hoa; return $vlan_hoa;
} }
# Older switches use RFC 4363 standard PortList definition, newer ELS switches
# return an ASCII-encoded, comma separated string of port indexes - wow
sub i_vlan_membership { sub i_vlan_membership {
my $juniper = shift; my $juniper = shift;
my $partial = shift; my $partial = shift;
# Use presence of JUNIPER-VLAN-MIB::jnxExVlanTag to indicate if we should
# treat as RFC 4363 standard PortList
my $old_index = $juniper->jnx_v_index();
if ( scalar keys %$old_index ) {
return $juniper->SUPER::i_vlan_membership($partial);
}
my $res; my $res;
my $dot1qVlanStaticEgressPorts = $juniper->dot1qVlanCurrentEgressPorts($partial) || $juniper->dot1qVlanStaticEgressPorts($partial); # This isn't a PortList so use _raw to prevent munge
my $v_ports = $juniper->qb_cv_egress_raw($partial)
|| $juniper->qb_v_egress_raw($partial);
my $bp_index = $juniper->bp_index(); my $bp_index = $juniper->bp_index();
foreach my $vlan (keys %$dot1qVlanStaticEgressPorts) {
my @bp_indexes = split /,/, $dot1qVlanStaticEgressPorts->{$vlan}; foreach my $vlan ( keys %$v_ports ) {
my @bp_indexes = split /,/, $v_ports->{$vlan};
push @{ $res->{ $bp_index->{$_} } }, $vlan for @bp_indexes; push @{ $res->{ $bp_index->{$_} } }, $vlan for @bp_indexes;
} }
return $res; return $res;
} }
sub qb_fw_vlan { sub i_vlan_membership_untagged {
my $juniper = shift; my $juniper = shift;
my $partial = shift;
my $qb_fw_vlan = $juniper->SUPER::qb_fw_vlan(); # Use presence of JUNIPER-VLAN-MIB::jnxExVlanTag to indicate if we should
my $v_fdb_id = $juniper->v_fdb_id(); # treat as RFC 4363 standard PortList
my $v_vlan_tag = $juniper->v_vlan_tag(); my $old_index = $juniper->jnx_v_index();
return $qb_fw_vlan unless $v_fdb_id && $v_vlan_tag;
my %fdb_id_to_tag = reverse %$v_fdb_id;
foreach my $key (keys %$qb_fw_vlan) { if ( scalar keys %$old_index ) {
my $v = $qb_fw_vlan->{$key}; return $juniper->SUPER::i_vlan_membership_untagged($partial);
$qb_fw_vlan->{$key} = $v_vlan_tag->{$fdb_id_to_tag{$v}};
} }
return $qb_fw_vlan; my $res;
# This isn't a PortList so use _raw to prevent munge
my $v_ports = $juniper->qb_cv_untagged_raw($partial)
|| $juniper->qb_v_untagged_raw($partial);
my $bp_index = $juniper->bp_index();
foreach my $vlan ( keys %$v_ports ) {
my @bp_indexes = split /,/, $v_ports->{$vlan};
push @{ $res->{ $bp_index->{$_} } }, $vlan for @bp_indexes;
}
return $res;
} }
# Pseudo ENTITY-MIB methods # Pseudo ENTITY-MIB methods
@@ -342,11 +391,14 @@ sub _e_virtual_index {
my %v_index; my %v_index;
foreach my $key ( keys %$containers ) { foreach my $key ( keys %$containers ) {
foreach my $member ( keys %$members ) { foreach my $member ( keys %$members ) {
# Virtual chassis members start at zero # Virtual chassis members start at zero
$member++; $member++;
# We will be duplicating and eliminating some keys, # We will be duplicating and eliminating some keys,
# but this is for the benefit of e_parent() # but this is for the benefit of e_parent()
my $index = sprintf ("%02d", $key) . sprintf ("%02d", $member) . "0000"; my $index = sprintf( "%02d", $key )
. sprintf( "%02d", $member ) . "0000";
my $iid = "$key\.$member\.0\.0"; my $iid = "$key\.$member\.0\.0";
$v_index{$iid} = $index; $v_index{$iid} = $index;
} }
@@ -554,7 +606,7 @@ sub e_vendor {
sub e_pos { sub e_pos {
my $juniper = shift; my $juniper = shift;
# We could look at index levels, but his will work as well # We could look at index levels, but this will work as well
return $juniper->e_index(); return $juniper->e_index();
} }
@@ -577,14 +629,19 @@ sub e_parent {
if ( !$is_virtual and ( $iid =~ /^(\d+)\.\d+/ ) ) { if ( !$is_virtual and ( $iid =~ /^(\d+)\.\d+/ ) ) {
$e_parent{$iid} = sprintf( "%02d", $1 ) . "000000"; $e_parent{$iid} = sprintf( "%02d", $1 ) . "000000";
} }
elsif ( $is_virtual and ($descr =~ /chassis/i) and ($iid =~ /^(\d+)\.(\d+)(\.0)+?/) ) { elsif ( $is_virtual
and ( $descr =~ /chassis/i )
and ( $iid =~ /^(\d+)\.(\d+)(\.0)+?/ ) )
{
$e_parent{$iid} = sprintf( "%02d", $1 ) . "000000"; $e_parent{$iid} = sprintf( "%02d", $1 ) . "000000";
} }
elsif ( $is_virtual and ( $iid =~ /^(\d+)\.(\d+)(\.0)+?/ ) ) { elsif ( $is_virtual and ( $iid =~ /^(\d+)\.(\d+)(\.0)+?/ ) ) {
$e_parent{$iid} = sprintf ("%02d", $within) . sprintf ("%02d", $2) . "0000"; $e_parent{$iid}
= sprintf( "%02d", $within ) . sprintf( "%02d", $2 ) . "0000";
} }
elsif ( $is_virtual and ( $iid =~ /^(\d+)\.(\d+)\.[1-9]+/ ) ) { elsif ( $is_virtual and ( $iid =~ /^(\d+)\.(\d+)\.[1-9]+/ ) ) {
$e_parent{$iid} = sprintf ("%02d", $1) . sprintf ("%02d", $2) . "0000"; $e_parent{$iid}
= sprintf( "%02d", $1 ) . sprintf( "%02d", $2 ) . "0000";
} }
elsif ( defined $within and $iid =~ /\d+/ ) { elsif ( defined $within and $iid =~ /\d+/ ) {
$e_parent{$iid} = sprintf( "%02d", $within ) . "000000"; $e_parent{$iid} = sprintf( "%02d", $within ) . "000000";
@@ -648,6 +705,8 @@ Subclass for Juniper Devices running JUNOS
=item F<JUNIPER-VIRTUALCHASSIS-MIB> =item F<JUNIPER-VIRTUALCHASSIS-MIB>
=item F<JUNIPER-L2ALD-MIB>
=back =back
=head2 Inherited Classes' MIBs =head2 Inherited Classes' MIBs
@@ -689,7 +748,7 @@ beginning.
Returns serial number Returns serial number
(C<jnxBoxSerialNo.0>) (C<jnxBoxSerialNo>)
=item $juniper->mac() =item $juniper->mac()
@@ -702,7 +761,15 @@ to in a unique fashion.
The name, model, or detailed description of the device. The name, model, or detailed description of the device.
(C<jnxBoxDescr.0>) (C<jnxBoxDescr>)
=item $juniper->version()
(C<jnxVirtualChassisMemberSWVersion>)
=item $juniper->vc_model()
(C<jnxVirtualChassisMemberModel>)
=back =back
@@ -723,23 +790,22 @@ to a hash.
=item $juniper->qb_fdb_index() =item $juniper->qb_fdb_index()
Returns reference to hash: key = VLAN ID, value = FDB ID. Returns reference to hash: key = FDB ID, value = VLAN ID.
=item $juniper->qb_fw_vlan()
Returns reference to hash of forwarding table entries VLAN ID
=item $juniper->v_index() =item $juniper->v_index()
(C<jnxExVlanTag>) Returns (C<jnxL2aldVlanTag>) or (C<jnxExVlanTag>) depending upon switch
software version
=item $juniper->v_name() =item $juniper->v_name()
(C<jnxExVlanName>) Returns (C<jnxL2aldVlanName>) or (C<jnxExVlanName>) depending upon switch
software version
=item $juniper->v_type() =item $juniper->v_type()
(C<jnxExVlanType>) Returns (C<jnxL2aldVlanType>) or (C<jnxExVlanType>) depending upon switch
software version
=item $juniper->i_trunk() =item $juniper->i_trunk()
@@ -754,6 +820,12 @@ Returns a mapping between C<ifIndex> and the PVID or default VLAN.
Returns reference to hash of arrays: key = C<ifIndex>, value = array of VLAN Returns reference to hash of arrays: key = C<ifIndex>, value = array of VLAN
IDs. These are the VLANs which are members of the egress list for the port. IDs. These are the VLANs which are members of the egress list for the port.
=item $juniper->i_vlan_membership_untagged()
Returns reference to hash of arrays: key = C<ifIndex>, value = array of VLAN
IDs. These are the VLANs which are members of the untagged egress list for
the port.
=back =back
=head2 Pseudo F<ENTITY-MIB> information =head2 Pseudo F<ENTITY-MIB> information

View File

@@ -33,14 +33,6 @@ use Test::Class::Most parent => 'My::Test::Class';
use SNMP::Info::Layer3::Juniper; use SNMP::Info::Layer3::Juniper;
# Remove this startup override once we have full method coverage
sub startup : Tests(startup => 1) {
my $test = shift;
$test->SUPER::startup();
$test->todo_methods(1);
}
sub setup : Tests(setup) { sub setup : Tests(setup) {
my $test = shift; my $test = shift;
$test->SUPER::setup; $test->SUPER::setup;
@@ -48,15 +40,818 @@ sub setup : Tests(setup) {
# Start with a common cache that will serve most tests # Start with a common cache that will serve most tests
my $d_string = 'Juniper Networks, Inc. ex4200-24t internet router, '; my $d_string = 'Juniper Networks, Inc. ex4200-24t internet router, ';
$d_string .= 'kernel JUNOS 10.4R6.5 '; $d_string .= 'kernel JUNOS 10.4R6.5 ';
my $cache_data = { my $cache_data = {
'_layers' => 6, '_layers' => 6,
'_description' => $d_string, '_description' => $d_string,
# JUNIPER-CHASSIS-DEFINES-MIB::jnxProductNameEX4200 # JUNIPER-CHASSIS-DEFINES-MIB::jnxProductNameEX4200
'_id' => '.1.3.6.1.4.1.2636.1.1.1.2.31', '_id' => '.1.3.6.1.4.1.2636.1.1.1.2.31',
'store' => {}, '_version' => '14.1X53-D40.8',
'_serial' => 'AB0123456789',
'_jnxExVlanPortAccessMode' => 1,
'_jnx_v_name' => 1,
'_jnx_v_index' => 1,
'_jnx_v_type' => 1,
# Newer table doesn't exist in EX4200, but in cache to simplify testing
# method code
'_jnx_els_v_name' => 1,
'_jnx_els_v_index' => 1,
'_jnx_els_v_type' => 1,
'_jnx_els_v_fdb_id' => 1,
'_bp_index' => 1,
'_qb_i_vlan' => 1,
'_qb_v_egress' => 1,
'_qb_v_untagged' => 1,
'_qb_fw_port' => 1,
# For pseudo entity testing
'_box_descr' => 'Juniper Virtual Chassis Ethernet Switch',
'_jnxVirtualChassisMemberRole' => 'master',
'_jnxContainersWithin' => 1,
'_jnxContentsDescr' => 1,
'_jnxContentsSerialNo' => 1,
'_jnxFruType' => 1,
'_jnxContainersDescr' => 1,
'_e_containers_type' => 1,
'_jnxContentsPartNo' => 1,
'_e_contents_type' => 1,
'_jnxContainersWithin' => 1,
'store' => {
'jnxExVlanPortAccessMode' => {'2.514' => 'access', '7.513' => 'trunk'},
'jnx_v_name' => {2 => 'default', 3 => 'management'},
'jnx_v_index' => {2 => 0, 3 => 120},
'jnx_v_type' => {2 => 'static', 3 => 'static'},
# Newer table doesn't exist in EX4200, but in cache to simplify testing
# method code
'jnx_els_v_name' =>
{6 => 'VLAN0114_VPN78087', 7 => 'VLAN2088_VPN78117', 8 => 'default'},
'jnx_els_v_index' => {6 => 114, 7 => 2088, 8 => 1},
'jnx_els_v_type' => {6 => 'static', 7 => 'static', 8 => 'static'},
'jnx_els_v_fdb_id' => {6 => 393216, 7 => 458752, 8 => 524288},
'bp_index' => {4 => 662, 491 => 509, 492 => 510},
'qb_i_vlan' => {4 => 0, 491 => 113, 492 => 2088},
'qb_v_egress' => {114 => '4', 2088 => '491,492'},
'qb_v_untagged' => {114 => '4', 2088 => '491,492'},
'qb_fw_port' =>
{'393216.0.19.149.30.221.37' => 4, '458752.0.9.245.16.59.121' => 492},
'jnxContainersWithin' => {1 => 0, 2 => 1, 4 => 1, 7 => 1, 8 => 7, 9 => 1},
'jnxContentsDescr' => {
'1.1.0.0' => '',
'2.1.1.0' => 'Power Supply: Power Supply 0 @ 0/0/*',
'2.1.2.0' => 'Power Supply: Power Supply 1 @ 0/1/*',
'2.2.1.0' => 'Power Supply: Power Supply 0 @ 1/0/*',
'2.2.2.0' => 'Power Supply: Power Supply 1 @ 1/1/*',
'4.1.1.1' => 'FAN 0 @ 0/0/0',
'4.1.2.1' => 'FAN 1 @ 0/1/0',
'4.2.1.1' => 'FAN 0 @ 1/0/0',
'4.2.2.1' => 'FAN 1 @ 1/1/0',
'7.1.0.0' => 'FPC: EX4300-48T @ 0/*/*',
'7.2.0.0' => 'FPC: EX4300-48T @ 1/*/*',
'8.1.1.0' => 'PIC: 48x 10/100/1000 Base-T @ 0/0/*',
'8.1.2.0' => 'PIC: 4x 40GE QSFP+ @ 0/1/*',
'8.1.3.0' => 'PIC: 4x 1G/10G SFP/SFP+ @ 0/2/*',
'8.2.1.0' => 'PIC: 48x 10/100/1000 Base-T @ 1/0/*',
'8.2.2.0' => 'PIC: 4x 40GE QSFP+ @ 1/1/*',
'8.2.3.0' => 'PIC: 4x 1G/10G SFP/SFP+ @ 1/2/*',
'9.1.0.0' => 'Routing Engine 0',
'9.2.0.0' => 'Routing Engine 1'
},
'jnxContentsSerialNo' => {
'2.1.1.0' => '1EDD1234567',
'2.1.2.0' => '1EDD2345678',
'2.2.1.0' => '1EDD3456789',
'2.2.2.0' => '1EDD4567890',
'7.1.0.0' => 'PE1234567890',
'7.2.0.0' => 'PE0123456789',
'8.1.1.0' => 'BUILTIN',
'8.1.2.0' => 'BUILTIN',
'8.1.3.0' => 'MY1234567890',
'8.2.1.0' => 'BUILTIN',
'8.2.2.0' => 'BUILTIN',
'8.2.3.0' => 'MY0123456789',
'9.1.0.0' => 'PE2345678901',
'9.2.0.0' => 'PE3456789012'
},
'jnxFruType' => {
'2.1.1.0' => 'powerEntryModule',
'2.1.2.0' => 'powerEntryModule',
'2.2.1.0' => 'powerEntryModule',
'2.2.2.0' => 'powerEntryModule',
'4.1.1.1' => 'fan',
'4.1.2.1' => 'fan',
'4.2.1.1' => 'fan',
'4.2.2.1' => 'fan',
'7.1.0.0' => 'flexiblePicConcentrator',
'7.2.0.0' => 'flexiblePicConcentrator',
'8.1.1.0' => 'portInterfaceCard',
'8.1.2.0' => 'portInterfaceCard',
'8.1.3.0' => 'portInterfaceCard',
'8.2.1.0' => 'portInterfaceCard',
'8.2.2.0' => 'portInterfaceCard',
'8.2.3.0' => 'portInterfaceCard',
'9.1.0.0' => 'routingEngine',
'9.2.0.0' => 'routingEngine'
},
'jnxContentsPartNo' => {
'2.1.1.0' => '740-046876',
'2.1.2.0' => '740-046876',
'2.2.1.0' => '740-046876',
'2.2.2.0' => '740-046876',
'7.1.0.0' => '650-044932',
'7.2.0.0' => '650-044932',
'8.1.1.0' => 'BUILTIN',
'8.1.2.0' => 'BUILTIN',
'8.1.3.0' => '611-063980',
'8.2.1.0' => 'BUILTIN',
'8.2.2.0' => 'BUILTIN',
'8.2.3.0' => '611-063980',
'9.1.0.0' => '650-044932',
'9.2.0.0' => '650-044932'
},
# These are cached raw
'e_contents_type' => {
'1.1.0.0' => '.1.3.6.1.4.1.2636.1.1.2.1.63.0',
'2.1.1.0' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.1.0',
'2.1.2.0' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.1.0',
'2.2.1.0' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.1.0',
'2.2.2.0' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.1.0',
'4.1.1.1' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.2.0',
'4.1.2.1' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.2.0',
'4.2.1.1' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.2.0',
'4.2.2.1' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.2.0',
'7.1.0.0' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.0',
'7.2.0.0' => '.1.3.6.1.4.1.2636.1.1.3.2.63.1.0',
'8.1.1.0' => '.1.3.6.1.4.1.2636.1.1.1.4.63.2.0',
'8.1.2.0' => '.1.3.6.1.4.1.2636.1.1.3.3.12.1.319.0',
'8.1.3.0' => '.1.3.6.1.4.1.2636.1.1.3.3.12.1.320.0',
'8.2.1.0' => '.1.3.6.1.4.1.2636.1.1.1.4.63.2.0',
'8.2.2.0' => '.1.3.6.1.4.1.2636.1.1.3.3.12.1.319.0',
'8.2.3.0' => '.1.3.6.1.4.1.2636.1.1.3.3.12.1.320.0',
'9.1.0.0' => '.1.3.6.1.4.1.2636.1.1.2.1.63.1.0',
'9.2.0.0' => '.1.3.6.1.4.1.2636.1.1.2.1.63.1.0'
},
'jnxContainersDescr' => {
1 => 'chassis frame',
2 => 'Power Supply slot',
4 => 'FAN slot',
7 => 'FPC slot',
8 => 'PIC slot',
9 => 'Routing Engine slot'
},
# These are cached raw
'e_containers_type' => {
1 => '.1.3.6.1.4.1.2636.1.1.2.1.63.0',
2 => '.1.3.6.1.4.1.2636.1.1.2.2.63.1.1.0',
4 => '.1.3.6.1.4.1.2636.1.1.2.2.63.1.2.0',
7 => '.1.3.6.1.4.1.2636.1.1.2.2.63.1.0',
8 => '.1.3.6.1.4.1.2636.1.1.2.3.63.1.0',
9 => '.1.3.6.1.4.1.2636.1.1.2.1.63.1.0'
},
'jnxContainersWithin' => {1 => 0, 2 => 1, 4 => 1, 7 => 1, 8 => 7, 9 => 1}
}
}; };
$test->{info}->cache($cache_data); $test->{info}->cache($cache_data);
} }
sub vendor : Tests(2) {
my $test = shift;
can_ok($test->{info}, 'vendor');
is($test->{info}->vendor(), 'juniper', q(Vendor returns 'juniper'));
}
sub os : Tests(2) {
my $test = shift;
can_ok($test->{info}, 'os');
is($test->{info}->os(), 'junos', q(OS returns 'junos'));
}
sub layers : Tests(5) {
my $test = shift;
can_ok($test->{info}, 'layers');
is($test->{info}->layers(), '00000110', q(Original layers unmodified));
# Set to layer 3 only and with presence of FDB 'qb_fw_port' will turn on
# layer 2
$test->{info}{_layers} = 4;
is($test->{info}->layers(),
'00000110', q(Layer2 added due to presence of FDB));
# Delete FDB cache flag, layers still = 4 binary (3 only)
delete $test->{info}{_qb_fw_port};
is($test->{info}->layers(), '00000100', q(No layer2 without FDB));
$test->{info}->clear_cache();
is($test->{info}->layers(), undef, q(No data returns undef layers));
}
sub os_ver : Tests(5) {
my $test = shift;
can_ok($test->{info}, 'os_ver');
is($test->{info}->os_ver(),
'14.1X53-D40.8',
q(OS version returned from 'jnxVirtualChassisMemberSWVersion'));
delete $test->{info}{_version};
is($test->{info}->os_ver(),
'10.4R6.5', q(OS version returned from 'sysDescr'));
delete $test->{info}{_description};
$test->{info}{_lldp_sysdesc}
= 'Juniper Networks, Inc. srx240h-poe , version 12.1R3.5 Build date: ';
is($test->{info}->os_ver(),
'12.1R3.5', q(OS version returned from 'lldpLocSysDesc'));
$test->{info}->clear_cache();
is($test->{info}->os_ver(), undef, q(No data returns undef OS version));
}
sub model : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'model');
is($test->{info}->model(), 'EX4200', q(Model translates id));
$test->{info}{_id} = '.100.3.6.1.4.1.6527.1.3.1';
is($test->{info}->model(), '.100.3.6.1.4.1.6527.1.3.1', q(Model uses id));
$test->{info}{_vc_model} = 'qfx5100-48s-6q';
is($test->{info}->model(),
'QFX5100-48S-6Q', q(Model uses 'jnxVirtualChassisMemberModel'));
}
sub serial : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'serial');
is($test->{info}->serial(),
'AB0123456789', q(Serial returns 'jnxBoxSerialNo'));
$test->{info}->clear_cache();
is($test->{info}->serial(), undef, q(No data returns undef serial));
}
sub i_trunk : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'i_trunk');
my $expected = {'514' => 'access', '513' => 'trunk'};
cmp_deeply($test->{info}->i_trunk(),
$expected, q(Interface trunk status returns expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->i_trunk(), {}, q(No data returns empty hash));
}
sub qb_fdb_index : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'qb_fdb_index');
my $expected = {393216 => 114, 458752 => 2088, 524288 => 1};
cmp_deeply($test->{info}->qb_fdb_index(),
$expected, q(ELS VLAN to FDB index returned expected values));
delete $test->{info}{'_jnx_els_v_index'};
$expected = {2 => 0, 3 => 120};
cmp_deeply($test->{info}->qb_fdb_index(),
$expected, q(Older VLAN to FDB index returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->qb_fdb_index(), undef, q(No data returns undef));
}
sub v_type : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'v_type');
my $expected = {6 => 'static', 7 => 'static', 8 => 'static'};
cmp_deeply($test->{info}->v_type(),
$expected, q(ELS VLAN types returned expected values));
delete $test->{info}{'_jnx_els_v_type'};
$expected = {2 => 'static', 3 => 'static'};
cmp_deeply($test->{info}->v_type(),
$expected, q(Older VLAN types returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->v_type(), undef, q(No data returns undef));
}
sub v_index : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'v_index');
my $expected = {6 => 114, 7 => 2088, 8 => 1};
cmp_deeply($test->{info}->v_index(),
$expected, q(ELS VLAN index returned expected values));
delete $test->{info}{'_jnx_els_v_index'};
$expected = {2 => 0, 3 => 120};
cmp_deeply($test->{info}->v_index(),
$expected, q(Older VLAN index returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->v_index(), undef, q(No data returns undef));
}
sub i_vlan : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'i_vlan');
my $expected = {662 => 0, 509 => 113, 510 => 2088};
cmp_deeply($test->{info}->i_vlan(),
$expected, q(ELS PVID returned expected values));
delete $test->{info}{'_jnx_els_v_index'};
$test->{info}{store}{bp_index} = {513 => 505, 514 => 507};
$test->{info}{store}{qb_i_vlan} = {513 => 3, 514 => 2};
$expected = {505 => 120, 507 => 0};
cmp_deeply($test->{info}->i_vlan(),
$expected, q(Older PVID returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->i_vlan(), {}, q(No data returns empty hash));
}
sub v_name : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'v_name');
my $expected
= {6 => 'VLAN0114_VPN78087', 7 => 'VLAN2088_VPN78117', 8 => 'default'};
cmp_deeply($test->{info}->v_name(),
$expected, q(ELS VLAN names returned expected values));
delete $test->{info}{'_jnx_els_v_name'};
$expected = {2 => 'default', 3 => 'management'};
cmp_deeply($test->{info}->v_name(),
$expected, q(Older VLAN names returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->v_name(), undef, q(No data returns undef));
}
sub i_vlan_membership : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'i_vlan_membership');
# Delete this so we can test new method first
delete $test->{info}{'_jnx_v_index'};
my $expected = {662 => [114], 509 => [2088], 510 => [2088]};
cmp_deeply($test->{info}->i_vlan_membership(),
$expected, q(ELS VLAN membership returned expected values));
# Restore so we can trigger test for older devices
$test->{info}{'_jnx_v_index'} = 1;
delete $test->{info}{'_jnx_els_v_index'};
my $padding = '00000000000000000000000000000000' x 4;
# This has bits 516 - 536 on
my $portlist2 = $padding . '1FFFFF';
# This has bits 512 - 515 on
my $portlist3 = $padding . 'E0';
# To simplify the expected value, we're only going to define the mapping
# for five ports
$test->{info}{store}{bp_index}
= {513 => 505, 514 => 507, 515 => 509, 516 => 511, 536 => 551};
$test->{info}{store}{qb_v_egress}
= {2 => pack("H*", $portlist2), 3 => pack("H*", $portlist3)};
$expected
= {505 => [120], 507 => [120], 509 => [120], 511 => [0], 551 => [0]};
cmp_deeply($test->{info}->i_vlan_membership(),
$expected, q(VLAN membership returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->i_vlan_membership(),
undef, q(No data returns undef));
}
# Same code as i_vlan_membership, untagged just uses different leaf
sub i_vlan_membership_untagged : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'i_vlan_membership_untagged');
# Delete this so we can test new method first
delete $test->{info}{'_jnx_v_index'};
my $expected = {662 => [114], 509 => [2088], 510 => [2088]};
cmp_deeply($test->{info}->i_vlan_membership_untagged(),
$expected, q(ELS VLAN membership untagged returned expected values));
# Restore so we can trigger test for older devices
$test->{info}{'_jnx_v_index'} = 1;
delete $test->{info}{'_jnx_els_v_index'};
my $padding = '00000000000000000000000000000000' x 4;
# This has bits 516 - 536 on
my $portlist2 = $padding . '1FFFFF';
# This has bits 512 - 515 on
my $portlist3 = $padding . 'E0';
# To simplify the expected value, we're only going to define the mapping
# for five ports
$test->{info}{store}{bp_index}
= {513 => 505, 514 => 507, 515 => 509, 516 => 511, 536 => 551};
$test->{info}{store}{qb_v_untagged}
= {2 => pack("H*", $portlist2), 3 => pack("H*", $portlist3)};
$expected
= {505 => [120], 507 => [120], 509 => [120], 511 => [0], 551 => [0]};
cmp_deeply($test->{info}->i_vlan_membership_untagged(),
$expected, q(VLAN membership untagged returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->i_vlan_membership_untagged(),
undef, q(No data returns undef));
}
# These is no longer defined in the class, but tested due to past issues with
# VLAN mapping due to changes with the introduction of ELS. See issue #67
# Juniper EX4300 Missing/Wrong information #67
sub qb_fw_vlan : Tests(4) {
my $test = shift;
can_ok($test->{info}, 'qb_fw_vlan');
my $expected
= {'393216.0.19.149.30.221.37' => 114, '458752.0.9.245.16.59.121' => 2088};
cmp_deeply($test->{info}->qb_fw_vlan(),
$expected,
q(ELS forwarding table entries to VLAN IDs returned expected values));
delete $test->{info}{'_jnx_els_v_index'};
$test->{info}{store}{qb_fw_port}
= {'2.0.19.149.30.221.37' => 513, '3.0.9.245.16.59.121' => 507};
$expected = {'2.0.19.149.30.221.37' => 0, '3.0.9.245.16.59.121' => 120};
cmp_deeply($test->{info}->qb_fw_vlan(),
$expected,
q(Older forwarding table entries to VLAN IDs returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->qb_fw_vlan(), {}, q(No data returns empty hash));
}
sub e_index : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_index');
my $expected = {
'1' => '01000000',
'1.1.0.0' => '01010000',
'2' => '02000000',
'2.1.1.0' => '02010100',
'2.1.2.0' => '02010200',
'2.2.1.0' => '02020100',
'2.2.2.0' => '02020200',
'4' => '04000000',
'4.1.1.1' => '04010101',
'4.1.2.1' => '04010201',
'4.2.1.1' => '04020101',
'4.2.2.1' => '04020201',
'7' => '07000000',
'7.1.0.0' => '07010000',
'7.2.0.0' => '07020000',
'8' => '08000000',
'8.1.1.0' => '08010100',
'8.1.2.0' => '08010200',
'8.1.3.0' => '08010300',
'8.2.1.0' => '08020100',
'8.2.2.0' => '08020200',
'8.2.3.0' => '08020300',
'9' => '09000000',
'9.1.0.0' => '09010000',
'9.2.0.0' => '09020000'
};
cmp_deeply($test->{info}->e_index(),
$expected, q(Entity index returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_index(), {}, q(No data returns empty hash));
}
sub e_class : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_class');
my $expected = {
'1' => 'chassis',
'1.1.0.0' => 'container',
'2' => 'container',
'2.1.1.0' => 'powerSupply',
'2.1.2.0' => 'powerSupply',
'2.2.1.0' => 'powerSupply',
'2.2.2.0' => 'powerSupply',
'4' => 'container',
'4.1.1.1' => 'fan',
'4.1.2.1' => 'fan',
'4.2.1.1' => 'fan',
'4.2.2.1' => 'fan',
'7' => 'container',
'7.1.0.0' => 'module',
'7.2.0.0' => 'module',
'8' => 'container',
'8.1.1.0' => 'module',
'8.1.2.0' => 'module',
'8.1.3.0' => 'module',
'8.2.1.0' => 'module',
'8.2.2.0' => 'module',
'8.2.3.0' => 'module',
'9' => 'container',
'9.1.0.0' => 'module',
'9.2.0.0' => 'module'
};
cmp_deeply($test->{info}->e_class(),
$expected, q(Entity classes returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_class(), {}, q(No data returns empty hash));
}
sub e_descr : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_descr');
my $expected = {
'1' => 'Juniper Virtual Chassis Ethernet Switch',
'1.1.0.0' => 'chassis frame',
'2' => 'Power Supply slot',
'2.1.1.0' => 'Power Supply: Power Supply 0 @ 0/0/*',
'2.1.2.0' => 'Power Supply: Power Supply 1 @ 0/1/*',
'2.2.1.0' => 'Power Supply: Power Supply 0 @ 1/0/*',
'2.2.2.0' => 'Power Supply: Power Supply 1 @ 1/1/*',
'4' => 'FAN slot',
'4.1.1.1' => 'FAN 0 @ 0/0/0',
'4.1.2.1' => 'FAN 1 @ 0/1/0',
'4.2.1.1' => 'FAN 0 @ 1/0/0',
'4.2.2.1' => 'FAN 1 @ 1/1/0',
'7' => 'FPC slot',
'7.1.0.0' => 'FPC: EX4300-48T @ 0/*/*',
'7.2.0.0' => 'FPC: EX4300-48T @ 1/*/*',
'8' => 'PIC slot',
'8.1.1.0' => 'PIC: 48x 10/100/1000 Base-T @ 0/0/*',
'8.1.2.0' => 'PIC: 4x 40GE QSFP+ @ 0/1/*',
'8.1.3.0' => 'PIC: 4x 1G/10G SFP/SFP+ @ 0/2/*',
'8.2.1.0' => 'PIC: 48x 10/100/1000 Base-T @ 1/0/*',
'8.2.2.0' => 'PIC: 4x 40GE QSFP+ @ 1/1/*',
'8.2.3.0' => 'PIC: 4x 1G/10G SFP/SFP+ @ 1/2/*',
'9' => 'Routing Engine slot',
'9.1.0.0' => 'Routing Engine 0',
'9.2.0.0' => 'Routing Engine 1'
};
cmp_deeply($test->{info}->e_descr(),
$expected, q(Entity descriptions returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_descr(), {}, q(No data returns empty hash));
}
sub e_serial : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_serial');
my $expected = {
'1' => 'AB0123456789',
'2.1.1.0' => '1EDD1234567',
'2.1.2.0' => '1EDD2345678',
'2.2.1.0' => '1EDD3456789',
'2.2.2.0' => '1EDD4567890',
'7.1.0.0' => 'PE1234567890',
'7.2.0.0' => 'PE0123456789',
'8.1.3.0' => 'MY1234567890',
'8.2.3.0' => 'MY0123456789',
'9.1.0.0' => 'PE2345678901',
'9.2.0.0' => 'PE3456789012'
};
cmp_deeply($test->{info}->e_serial(),
$expected, q(Entity serial numbers returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_serial(), {}, q(No data returns empty hash));
}
sub e_fru : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_fru');
my $expected = {
'1' => 'false',
'1.1.0.0' => 'false',
'2' => 'false',
'2.1.1.0' => 'true',
'2.1.2.0' => 'true',
'2.2.1.0' => 'true',
'2.2.2.0' => 'true',
'4' => 'false',
'4.1.1.1' => 'false',
'4.1.2.1' => 'false',
'4.2.1.1' => 'false',
'4.2.2.1' => 'false',
'7' => 'false',
'7.1.0.0' => 'true',
'7.2.0.0' => 'true',
'8' => 'false',
'8.1.1.0' => 'false',
'8.1.2.0' => 'false',
'8.1.3.0' => 'true',
'8.2.1.0' => 'false',
'8.2.2.0' => 'false',
'8.2.3.0' => 'true',
'9' => 'false',
'9.1.0.0' => 'true',
'9.2.0.0' => 'true'
};
cmp_deeply($test->{info}->e_fru(),
$expected, q(Entity FRUs returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_fru(), {}, q(No data returns empty hash));
}
sub e_type : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_type');
my $expected = {
'1' => 'jnxChassisEX4300',
'2' => 'jnxEX4300SlotPower',
'1.1.0.0' => 'jnxChassisEX4300',
'2.1.1.0' => 'jnxEX4300Power',
'2.1.2.0' => 'jnxEX4300Power',
'2.2.1.0' => 'jnxEX4300Power',
'2.2.2.0' => 'jnxEX4300Power',
'4' => 'jnxEX4300SlotFan',
'4.1.1.1' => 'jnxEX4300Fan',
'4.1.2.1' => 'jnxEX4300Fan',
'4.2.1.1' => 'jnxEX4300Fan',
'4.2.2.1' => 'jnxEX4300Fan',
'7' => 'jnxEX4300SlotFPC',
'7.1.0.0' => 'jnxEX4300FPC',
'7.2.0.0' => 'jnxEX4300FPC',
'8' => 'jnxEX4300MediaCardSpacePIC',
'8.1.1.0' => 'jnxProductEX4300port48T',
'8.1.2.0' => 'jnxPicEX4300QSFP4Port',
'8.1.3.0' => 'jnxPicEX4300UplinkSFPPlus4Port',
'8.2.1.0' => 'jnxProductEX4300port48T',
'8.2.2.0' => 'jnxPicEX4300QSFP4Port',
'8.2.3.0' => 'jnxPicEX4300UplinkSFPPlus4Port',
'9' => 'jnxEX4300RE0',
'9.1.0.0' => 'jnxEX4300RE0',
'9.2.0.0' => 'jnxEX4300RE0'
};
cmp_deeply($test->{info}->e_type(),
$expected, q(Entity types returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_type(), {}, q(No data returns empty hash));
}
sub e_vendor : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_vendor');
my $expected = {
'1' => 'juniper',
'2' => 'juniper',
'1.1.0.0' => 'juniper',
'2.1.1.0' => 'juniper',
'2.1.2.0' => 'juniper',
'2.2.1.0' => 'juniper',
'2.2.2.0' => 'juniper',
'4' => 'juniper',
'4.1.1.1' => 'juniper',
'4.1.2.1' => 'juniper',
'4.2.1.1' => 'juniper',
'4.2.2.1' => 'juniper',
'7' => 'juniper',
'7.1.0.0' => 'juniper',
'7.2.0.0' => 'juniper',
'8' => 'juniper',
'8.1.1.0' => 'juniper',
'8.1.2.0' => 'juniper',
'8.1.3.0' => 'juniper',
'8.2.1.0' => 'juniper',
'8.2.2.0' => 'juniper',
'8.2.3.0' => 'juniper',
'9' => 'juniper',
'9.1.0.0' => 'juniper',
'9.2.0.0' => 'juniper'
};
cmp_deeply($test->{info}->e_vendor(),
$expected, q(Entity vendor returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_vendor(), {}, q(No data returns empty hash));
}
sub e_pos : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_pos');
my $expected = {
'1' => '01000000',
'1.1.0.0' => '01010000',
'2' => '02000000',
'2.1.1.0' => '02010100',
'2.1.2.0' => '02010200',
'2.2.1.0' => '02020100',
'2.2.2.0' => '02020200',
'4' => '04000000',
'4.1.1.1' => '04010101',
'4.1.2.1' => '04010201',
'4.2.1.1' => '04020101',
'4.2.2.1' => '04020201',
'7' => '07000000',
'7.1.0.0' => '07010000',
'7.2.0.0' => '07020000',
'8' => '08000000',
'8.1.1.0' => '08010100',
'8.1.2.0' => '08010200',
'8.1.3.0' => '08010300',
'8.2.1.0' => '08020100',
'8.2.2.0' => '08020200',
'8.2.3.0' => '08020300',
'9' => '09000000',
'9.1.0.0' => '09010000',
'9.2.0.0' => '09020000'
};
cmp_deeply($test->{info}->e_pos(),
$expected, q(Entity position returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_pos(), {}, q(No data returns empty hash));
}
sub e_parent : Tests(3) {
my $test = shift;
can_ok($test->{info}, 'e_parent');
my $expected = {
'1' => '00000000',
'1.1.0.0' => '01000000',
'2' => '01000000',
'2.1.1.0' => '02000000',
'2.1.2.0' => '02000000',
'2.2.1.0' => '02000000',
'2.2.2.0' => '02000000',
'4' => '01000000',
'4.1.1.1' => '04000000',
'4.1.2.1' => '04000000',
'4.2.1.1' => '04000000',
'4.2.2.1' => '04000000',
'7' => '01000000',
'7.1.0.0' => '07000000',
'7.2.0.0' => '07000000',
'8' => '07000000',
'8.1.1.0' => '08000000',
'8.1.2.0' => '08000000',
'8.1.3.0' => '08000000',
'8.2.1.0' => '08000000',
'8.2.2.0' => '08000000',
'8.2.3.0' => '08000000',
'9' => '01000000',
'9.1.0.0' => '09000000',
'9.2.0.0' => '09000000'
};
cmp_deeply($test->{info}->e_parent(),
$expected, q(Entity parent returned expected values));
$test->{info}->clear_cache();
cmp_deeply($test->{info}->e_parent(), {}, q(No data returns empty hash));
}
1; 1;