diff options
Diffstat (limited to 'spec/unit')
-rw-r--r-- | spec/unit/provider/interface/cisco_spec.rb | 64 | ||||
-rw-r--r-- | spec/unit/type/interface_spec.rb | 93 | ||||
-rw-r--r-- | spec/unit/util/network_device/cisco/device_spec.rb | 501 | ||||
-rw-r--r-- | spec/unit/util/network_device/cisco/interface_spec.rb | 89 |
4 files changed, 747 insertions, 0 deletions
diff --git a/spec/unit/provider/interface/cisco_spec.rb b/spec/unit/provider/interface/cisco_spec.rb new file mode 100644 index 000000000..7904711f5 --- /dev/null +++ b/spec/unit/provider/interface/cisco_spec.rb @@ -0,0 +1,64 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/provider/interface/cisco' + +provider_class = Puppet::Type.type(:interface).provider(:cisco) + +describe provider_class do + before do + @resource = stub("resource", :name => "Fa0/1") + @provider = provider_class.new(@resource) + end + + it "should have a parent of Puppet::Provider::NetworkDevice" do + provider_class.should < Puppet::Provider::NetworkDevice + end + + it "should have an instances method" do + provider_class.should respond_to(:instances) + end + + describe "when looking up instances at prefetch" do + before do + @device = stub_everything 'device' + Puppet::Util::NetworkDevice::Cisco::Device.stubs(:new).returns(@device) + @device.stubs(:command).yields(@device) + end + + it "should initialize the network device with the given url" do + Puppet::Util::NetworkDevice::Cisco::Device.expects(:new).with(:url).returns(@device) + provider_class.lookup(:url, "Fa0/1") + end + + it "should delegate to the device interface fetcher" do + @device.expects(:interface) + provider_class.lookup("", "Fa0/1") + end + + it "should return the given interface data" do + @device.expects(:interface).returns({ :description => "thisone", :mode => :access}) + provider_class.lookup("", "Fa0").should == {:description => "thisone", :mode => :access } + end + + end + + describe "when an instance is being flushed" do + it "should call the device interface update method with current and past properties" do + @instance = provider_class.new(:ensure => :present, :name => "Fa0/1", :description => "myinterface") + @instance.description = "newdesc" + @instance.resource = @resource + @resource.stubs(:[]).with(:name).returns("Fa0/1") + device = stub_everything 'device' + @instance.stubs(:device).returns(device) + device.expects(:command).yields(device) + interface = stub 'interface' + device.expects(:new_interface).with("Fa0/1").returns(interface) + interface.expects(:update).with( {:ensure => :present, :name => "Fa0/1", :description => "myinterface"}, + {:ensure => :present, :name => "Fa0/1", :description => "newdesc"}) + + @instance.flush + end + end +end diff --git a/spec/unit/type/interface_spec.rb b/spec/unit/type/interface_spec.rb new file mode 100644 index 000000000..630e45aa9 --- /dev/null +++ b/spec/unit/type/interface_spec.rb @@ -0,0 +1,93 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Type.type(:interface) do + it "should have a 'name' parameter'" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1")[:name].should == "FastEthernet 0/1" + end + + it "should have a 'device_url' parameter'" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :device_url => :device)[:device_url].should == :device + end + + it "should have an ensure property" do + Puppet::Type.type(:interface).attrtype(:ensure).should == :property + end + + [:description, :speed, :duplex, :native_vlan, :encapsulation, :mode, :allowed_trunk_vlans, :etherchannel, :ipaddress].each do |p| + it "should have a #{p} property" do + Puppet::Type.type(:interface).attrtype(p).should == :property + end + end + + describe "when validating attribute values" do + before do + @provider = stub 'provider', :class => Puppet::Type.type(:interface).defaultprovider, :clear => nil + Puppet::Type.type(:interface).defaultprovider.stubs(:new).returns(@provider) + end + + it "should support :present as a value to :ensure" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ensure => :present) + end + + it "should support :shutdown as a value to :ensure" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ensure => :shutdown) + end + + it "should support :no_shutdown as a value to :ensure" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ensure => :no_shutdown) + end + + describe "especially speed" do + it "should allow a number" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :speed => "100") + end + + it "should allow :auto" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :speed => :auto) + end + end + + describe "especially duplex" do + it "should allow :half" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :duplex => :half) + end + + it "should allow :full" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :duplex => :full) + end + + it "should allow :auto" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :duplex => :auto) + end + end + + describe "especially ipaddress" do + it "should allow ipv4 addresses" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "192.168.0.1/24") + end + + it "should allow arrays of ipv4 addresses" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => ["192.168.0.1/24", "192.168.1.0/24"]) + end + + it "should allow ipv6 addresses" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "f0e9::/64") + end + + it "should allow ipv6 options" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "f0e9::/64 link-local") + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "f0e9::/64 eui-64") + end + + it "should allow a mix of ipv4 and ipv6" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => ["192.168.0.1/24", "f0e9::/64 link-local"]) + end + + it "should munge ip addresses to a computer format" do + Puppet::Type.type(:interface).new(:name => "FastEthernet 0/1", :ipaddress => "192.168.0.1/24")[:ipaddress].should == [[24, IPAddr.new('192.168.0.1'), nil]] + end + end + end +end diff --git a/spec/unit/util/network_device/cisco/device_spec.rb b/spec/unit/util/network_device/cisco/device_spec.rb new file mode 100644 index 000000000..9021bbd2c --- /dev/null +++ b/spec/unit/util/network_device/cisco/device_spec.rb @@ -0,0 +1,501 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../../spec_helper' + +require 'puppet/util/network_device/cisco/device' + +describe Puppet::Util::NetworkDevice::Cisco::Device do + before(:each) do + @transport = stub_everything 'transport', :is_a? => true, :command => "" + @cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/") + @cisco.transport = @transport + end + + describe "when creating the device" do + it "should find the enable password from the url" do + cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/?enable=enable_password") + cisco.enable_password.should == "enable_password" + end + + it "should find the enable password from the options" do + cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/?enable=enable_password", :enable_password => "mypass") + cisco.enable_password.should == "mypass" + end + end + + describe "when connecting to the physical device" do + it "should connect to the transport" do + @transport.expects(:connect) + @cisco.command + end + + it "should attempt to login" do + @cisco.expects(:login) + @cisco.command + end + + it "should tell the device to not page" do + @transport.expects(:command).with("terminal length 0") + @cisco.command + end + + it "should enter the enable password if returned prompt is not privileged" do + @transport.stubs(:command).yields("Switch>").returns("") + @cisco.expects(:enable) + @cisco.command + end + + it "should find device capabilities" do + @cisco.expects(:find_capabilities) + @cisco.command + end + + it "should execute given command" do + @transport.expects(:command).with("mycommand") + @cisco.command("mycommand") + end + + it "should yield to the command block if one is provided" do + @transport.expects(:command).with("mycommand") + @cisco.command do |c| + c.command("mycommand") + end + end + + it "should close the device transport" do + @transport.expects(:close) + @cisco.command + end + + describe "when login in" do + it "should not login if transport handles login" do + @transport.expects(:handles_login?).returns(true) + @transport.expects(:command).never + @transport.expects(:expect).never + @cisco.login + end + + it "should send username if one has been provided" do + @transport.expects(:command).with("user", :prompt => /^Password:/) + @cisco.login + end + + it "should send password after the username" do + @transport.expects(:command).with("user", :prompt => /^Password:/) + @transport.expects(:command).with("password") + @cisco.login + end + + it "should expect the Password: prompt if no user was sent" do + @cisco.url.user = '' + @transport.expects(:expect).with(/^Password:/) + @transport.expects(:command).with("password") + @cisco.login + end + end + + describe "when entering enable password" do + it "should raise an error if no enable password has been set" do + @cisco.enable_password = nil + lambda{ @cisco.enable }.should raise_error + end + + it "should send the enable command and expect an enable prompt" do + @cisco.enable_password = 'mypass' + @transport.expects(:command).with("enable", :prompt => /^Password:/) + @cisco.enable + end + + it "should send the enable password" do + @cisco.enable_password = 'mypass' + @transport.stubs(:command).with("enable", :prompt => /^Password:/) + @transport.expects(:command).with("mypass") + @cisco.enable + end + end + end + + describe "when finding network device capabilities" do + it "should try to execute sh vlan brief" do + @transport.expects(:command).with("sh vlan brief").returns("") + @cisco.find_capabilities + end + + it "should detect errors" do + @transport.stubs(:command).with("sh vlan brief").returns(<<eos) +Switch#sh vlan brief +% Ambiguous command: "sh vlan brief" +Switch# +eos + + @cisco.find_capabilities + @cisco.should_not be_support_vlan_brief + end + end + + + { + "Fa 0/1" => "FastEthernet0/1", + "Fa0/1" => "FastEthernet0/1", + "FastEth 0/1" => "FastEthernet0/1", + "Gi1" => "GigEthernet1", + "Di9" => "Dialer9", + "Ethernet 0/0/1" => "Ethernet0/0/1", + "E0" => "Ethernet0", + "ATM 0/1.1" => "ATM0/1.1", + "VLAN99" => "VLAN99" + }.each do |input,expected| + it "should canonicalize #{input} to #{expected}" do + @cisco.canonalize_ifname(input).should == expected + end + end + + + describe "when parsing interface" do + + it "should parse interface output" do + @cisco.expects(:parse_interface).returns({ :ensure => :present }) + + @cisco.interface("FastEthernet0/1").should == { :ensure => :present } + end + + it "should parse trunking and merge results" do + @cisco.stubs(:parse_interface).returns({ :ensure => :present }) + @cisco.expects(:parse_trunking).returns({ :native_vlan => "100" }) + + @cisco.interface("FastEthernet0/1").should == { :ensure => :present, :native_vlan => "100" } + end + + it "should return an absent interface if parse_interface returns nothing" do + @cisco.stubs(:parse_interface).returns({}) + + @cisco.interface("FastEthernet0/1").should == { :ensure => :absent } + end + + it "should parse ip address information and merge results" do + @cisco.stubs(:parse_interface).returns({ :ensure => :present }) + @cisco.expects(:parse_interface_config).returns({ :ipaddress => [24,IPAddr.new('192.168.0.24'), nil] }) + + @cisco.interface("FastEthernet0/1").should == { :ensure => :present, :ipaddress => [24,IPAddr.new('192.168.0.24'), nil] } + end + + it "should parse the sh interface command" do + @transport.stubs(:command).with("sh interface FastEthernet0/1").returns(<<eos) +Switch#sh interfaces FastEthernet 0/1 +FastEthernet0/1 is down, line protocol is down + Hardware is Fast Ethernet, address is 00d0.bbe2.19c1 (bia 00d0.bbe2.19c1) + MTU 1500 bytes, BW 100000 Kbit, DLY 100 usec, + reliability 255/255, txload 1/255, rxload 1/255 + Encapsulation ARPA, loopback not set + Keepalive not set + Auto-duplex , Auto Speed , 100BaseTX/FX + ARP type: ARPA, ARP Timeout 04:00:00 + Last input never, output 5d04h, output hang never + Last clearing of "show interface" counters never + Queueing strategy: fifo + Output queue 0/40, 0 drops; input queue 0/75, 0 drops + 5 minute input rate 0 bits/sec, 0 packets/sec + 5 minute output rate 0 bits/sec, 0 packets/sec + 580 packets input, 54861 bytes + Received 6 broadcasts, 0 runts, 0 giants, 0 throttles + 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored + 0 watchdog, 1 multicast + 0 input packets with dribble condition detected + 845 packets output, 80359 bytes, 0 underruns + 0 output errors, 0 collisions, 1 interface resets + 0 babbles, 0 late collision, 0 deferred + 0 lost carrier, 0 no carrier + 0 output buffer failures, 0 output buffers swapped out +Switch# +eos + + @cisco.parse_interface("FastEthernet0/1").should == { :ensure => :absent, :duplex => :auto, :speed => :auto } + end + + it "should be able to parse the sh vlan brief command output" do + @cisco.stubs(:support_vlan_brief?).returns(true) + @transport.stubs(:command).with("sh vlan brief").returns(<<eos) +Switch#sh vlan brief +VLAN Name Status Ports +---- -------------------------------- --------- ------------------------------- +1 default active Fa0/3, Fa0/4, Fa0/5, Fa0/6, + Fa0/7, Fa0/8, Fa0/9, Fa0/10, + Fa0/11, Fa0/12, Fa0/13, Fa0/14, + Fa0/15, Fa0/16, Fa0/17, Fa0/18, + Fa0/23, Fa0/24 +10 VLAN0010 active +100 management active Fa0/1, Fa0/2 +Switch# +eos + + @cisco.parse_vlans.should == {"100"=>{:status=>"active", :interfaces=>["FastEthernet0/1", "FastEthernet0/2"], :name=>"management", :id=>"100"}, "1"=>{:status=>"active", :interfaces=>["FastEthernet0/3", "FastEthernet0/4", "FastEthernet0/5", "FastEthernet0/6", "FastEthernet0/7", "FastEthernet0/8", "FastEthernet0/9", "FastEthernet0/10", "FastEthernet0/11", "FastEthernet0/12", "FastEthernet0/13", "FastEthernet0/14", "FastEthernet0/15", "FastEthernet0/16", "FastEthernet0/17", "FastEthernet0/18", "FastEthernet0/23", "FastEthernet0/24"], :name=>"default", :id=>"1"}, "10"=>{:status=>"active", :interfaces=>[], :name=>"VLAN0010", :id=>"10"}} + end + + it "should parse trunk switchport information" do + @transport.stubs(:command).with("sh interface FastEthernet0/21 switchport").returns(<<eos) +Switch#sh interfaces FastEthernet 0/21 switchport +Name: Fa0/21 +Switchport: Enabled +Administrative mode: trunk +Operational Mode: trunk +Administrative Trunking Encapsulation: dot1q +Operational Trunking Encapsulation: dot1q +Negotiation of Trunking: Disabled +Access Mode VLAN: 0 ((Inactive)) +Trunking Native Mode VLAN: 1 (default) +Trunking VLANs Enabled: ALL +Trunking VLANs Active: 1,10,100 +Pruning VLANs Enabled: 2-1001 + +Priority for untagged frames: 0 +Override vlan tag priority: FALSE +Voice VLAN: none +Appliance trust: none +Self Loopback: No +Switch# +eos + + @cisco.parse_trunking("FastEthernet0/21").should == { :mode => :trunk, :encapsulation => :dot1q, :allowed_trunk_vlans=>:all, } + end + + it "should parse trunk switchport information with allowed vlans" do + @transport.stubs(:command).with("sh interface GigabitEthernet 0/1 switchport").returns(<<eos) +c2960#sh interfaces GigabitEthernet 0/1 switchport +Name: Gi0/1 +Switchport: Enabled +Administrative Mode: trunk +Operational Mode: trunk +Administrative Trunking Encapsulation: dot1q +Operational Trunking Encapsulation: dot1q +Negotiation of Trunking: On +Access Mode VLAN: 1 (default) +Trunking Native Mode VLAN: 1 (default) +Administrative Native VLAN tagging: enabled +Voice VLAN: none +Administrative private-vlan host-association: none +Administrative private-vlan mapping: none +Administrative private-vlan trunk native VLAN: none +Administrative private-vlan trunk Native VLAN tagging: enabled +Administrative private-vlan trunk encapsulation: dot1q +Administrative private-vlan trunk normal VLANs: none +Administrative private-vlan trunk associations: none +Administrative private-vlan trunk mappings: none +Operational private-vlan: none +Trunking VLANs Enabled: 1,99 +Pruning VLANs Enabled: 2-1001 +Capture Mode Disabled +Capture VLANs Allowed: ALL + +Protected: false +Unknown unicast blocked: disabled +Unknown multicast blocked: disabled +Appliance trust: none +c2960# +eos + + @cisco.parse_trunking("GigabitEthernet 0/1").should == { :mode => :trunk, :encapsulation => :dot1q, :allowed_trunk_vlans=>"1,99", } + end + + it "should parse access switchport information" do + @transport.stubs(:command).with("sh interface FastEthernet0/1 switchport").returns(<<eos) +Switch#sh interfaces FastEthernet 0/1 switchport +Name: Fa0/1 +Switchport: Enabled +Administrative mode: static access +Operational Mode: static access +Administrative Trunking Encapsulation: isl +Operational Trunking Encapsulation: isl +Negotiation of Trunking: Disabled +Access Mode VLAN: 100 (SHDSL) +Trunking Native Mode VLAN: 1 (default) +Trunking VLANs Enabled: NONE +Pruning VLANs Enabled: NONE + +Priority for untagged frames: 0 +Override vlan tag priority: FALSE +Voice VLAN: none +Appliance trust: none +Self Loopback: No +Switch# +eos + + @cisco.parse_trunking("FastEthernet0/1").should == { :mode => :access, :native_vlan => "100" } + end + + it "should parse ip addresses" do + @transport.stubs(:command).with("sh running-config interface Vlan 1 | begin interface").returns(<<eos) +router#sh running-config interface Vlan 1 | begin interface +interface Vlan1 + description $ETH-SW-LAUNCH$$INTF-INFO-HWIC 4ESW$$FW_INSIDE$ + ip address 192.168.0.24 255.255.255.0 secondary + ip address 192.168.0.1 255.255.255.0 + ip access-group 100 in + no ip redirects + no ip proxy-arp + ip nbar protocol-discovery + ip dns view-group dow + ip nat inside + ip virtual-reassembly + ip route-cache flow + ipv6 address 2001:7A8:71C1::/64 eui-64 + ipv6 enable + ipv6 traffic-filter DENY-ACL6 out + ipv6 mtu 1280 + ipv6 nd prefix 2001:7A8:71C1::/64 + ipv6 nd ra interval 60 + ipv6 nd ra lifetime 180 + ipv6 verify unicast reverse-path + ipv6 inspect STD6 out +end + +router# +eos + @cisco.parse_interface_config("Vlan 1").should == {:ipaddress=>[[24, IPAddr.new('192.168.0.24'), 'secondary'], + [24, IPAddr.new('192.168.0.1'), nil], + [64, IPAddr.new('2001:07a8:71c1::'), "eui-64"]]} + end + + it "should parse etherchannel membership" do + @transport.stubs(:command).with("sh running-config interface Gi0/17 | begin interface").returns(<<eos) +c2960#sh running-config interface Gi0/17 | begin interface +interface GigabitEthernet0/17 + description member of Po1 + switchport mode access + channel-protocol lacp + channel-group 1 mode passive + spanning-tree portfast + spanning-tree bpduguard enable +end + +c2960# +eos + @cisco.parse_interface_config("Gi0/17").should == {:etherchannel=>"1"} + end + end +end + +# static access +# Switch#sh interfaces FastEthernet 0/1 switchport +# Name: Fa0/1 +# Switchport: Enabled +# Administrative mode: static access +# Operational Mode: static access +# Administrative Trunking Encapsulation: isl +# Operational Trunking Encapsulation: isl +# Negotiation of Trunking: Disabled +# Access Mode VLAN: 100 (SHDSL) +# Trunking Native Mode VLAN: 1 (default) +# Trunking VLANs Enabled: NONE +# Pruning VLANs Enabled: NONE +# +# Priority for untagged frames: 0 +# Override vlan tag priority: FALSE +# Voice VLAN: none +# Appliance trust: none +# Self Loopback: No +# Switch# + +# c2960#sh interfaces GigabitEthernet 0/1 switchport +# Name: Gi0/1 +# Switchport: Enabled +# Administrative Mode: trunk +# Operational Mode: trunk +# Administrative Trunking Encapsulation: dot1q +# Operational Trunking Encapsulation: dot1q +# Negotiation of Trunking: On +# Access Mode VLAN: 1 (default) +# Trunking Native Mode VLAN: 1 (default) +# Administrative Native VLAN tagging: enabled +# Voice VLAN: none +# Administrative private-vlan host-association: none +# Administrative private-vlan mapping: none +# Administrative private-vlan trunk native VLAN: none +# Administrative private-vlan trunk Native VLAN tagging: enabled +# Administrative private-vlan trunk encapsulation: dot1q +# Administrative private-vlan trunk normal VLANs: none +# Administrative private-vlan trunk associations: none +# Administrative private-vlan trunk mappings: none +# Operational private-vlan: none +# Trunking VLANs Enabled: 1,99 +# Pruning VLANs Enabled: 2-1001 +# Capture Mode Disabled +# Capture VLANs Allowed: ALL +# +# Protected: false +# Unknown unicast blocked: disabled +# Unknown multicast blocked: disabled +# Appliance trust: none +# c2960# + +# c2960#sh interfaces GigabitEthernet 0/2 switchport +# Name: Gi0/2 +# Switchport: Enabled +# Administrative Mode: static access +# Operational Mode: static access +# Administrative Trunking Encapsulation: dot1q +# Operational Trunking Encapsulation: native +# Negotiation of Trunking: Off +# Access Mode VLAN: 99 (MGMT) +# Trunking Native Mode VLAN: 1 (default) +# Administrative Native VLAN tagging: enabled +# Voice VLAN: none +# Administrative private-vlan host-association: none +# Administrative private-vlan mapping: none +# Administrative private-vlan trunk native VLAN: none +# Administrative private-vlan trunk Native VLAN tagging: enabled +# Administrative private-vlan trunk encapsulation: dot1q +# Administrative private-vlan trunk normal VLANs: none +# Administrative private-vlan trunk associations: none +# Administrative private-vlan trunk mappings: none +# Operational private-vlan: none +# Trunking VLANs Enabled: ALL +# Pruning VLANs Enabled: 2-1001 +# Capture Mode Disabled +# Capture VLANs Allowed: ALL +# +# Protected: false +# Unknown unicast blocked: disabled +# Unknown multicast blocked: disabled +# Appliance trust: none +# c2960# + +# c877#sh interfaces FastEthernet 1 switchport +# Name: Fa1 +# Switchport: Enabled +# Administrative Mode: trunk +# Operational Mode: trunk +# Administrative Trunking Encapsulation: dot1q +# Operational Trunking Encapsulation: dot1q +# Negotiation of Trunking: Disabled +# Access Mode VLAN: 0 ((Inactive)) +# Trunking Native Mode VLAN: 1 (default) +# Trunking VLANs Enabled: ALL +# Trunking VLANs Active: 1 +# Protected: false +# Priority for untagged frames: 0 +# Override vlan tag priority: FALSE +# Voice VLAN: none +# Appliance trust: none + + +# c2960#sh etherchannel summary +# Flags: D - down P - bundled in port-channel +# I - stand-alone s - suspended +# H - Hot-standby (LACP only) +# R - Layer3 S - Layer2 +# U - in use f - failed to allocate aggregator +# +# M - not in use, minimum links not met +# u - unsuitable for bundling +# w - waiting to be aggregated +# d - default port +# +# +# Number of channel-groups in use: 1 +# Number of aggregators: 1 +# +# Group Port-channel Protocol Ports +# ------+-------------+-----------+----------------------------------------------- +# 1 Po1(SU) LACP Gi0/17(P) Gi0/18(P) +# +# c2960# diff --git a/spec/unit/util/network_device/cisco/interface_spec.rb b/spec/unit/util/network_device/cisco/interface_spec.rb new file mode 100644 index 000000000..f6aa14747 --- /dev/null +++ b/spec/unit/util/network_device/cisco/interface_spec.rb @@ -0,0 +1,89 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../../spec_helper' + +require 'puppet/util/network_device' +require 'puppet/util/network_device/cisco/interface' + +describe Puppet::Util::NetworkDevice::Cisco::Interface do + before(:each) do + @transport = stub_everything 'transport' + @interface = Puppet::Util::NetworkDevice::Cisco::Interface.new("FastEthernet0/1",@transport) + end + + it "should include IPCalc" do + @interface.class.include?(Puppet::Util::NetworkDevice::IPCalc) + end + + describe "when updating the physical device" do + it "should enter global configuration mode" do + @transport.expects(:command).with("conf t") + @interface.update + end + + it "should enter interface configuration mode" do + @transport.expects(:command).with("interface FastEthernet0/1") + @interface.update + end + + it "should 'execute' all differing properties" do + @interface.expects(:execute).with(:description, "b") + @interface.expects(:execute).with(:mode, :access).never + @interface.update({ :description => "a", :mode => :access }, { :description => "b", :mode => :access }) + end + + it "should execute in cisco ios defined order" do + speed = states('speed').starts_as('notset') + @interface.expects(:execute).with(:speed, :auto).then(speed.is('set')) + @interface.expects(:execute).with(:duplex, :auto).when(speed.is('set')) + @interface.update({ :duplex => :half, :speed => "10" }, { :duplex => :auto, :speed => :auto }) + end + + it "should execute absent properties with a no prefix" do + @interface.expects(:execute).with(:description, "a", "no ") + @interface.update({ :description => "a"}, { }) + end + + it "should exit twice" do + @transport.expects(:command).with("exit").twice + @interface.update + end + end + + describe "when executing commands" do + it "should execute string commands directly" do + @transport.expects(:command).with("speed auto") + @interface.execute(:speed, :auto) + end + + it "should execute string commands with the given prefix" do + @transport.expects(:command).with("no speed auto") + @interface.execute(:speed, :auto, "no ") + end + + it "should stop at executing the first command that works for array" do + @transport.expects(:command).with("channel-group 1").yields("% Invalid command") + @transport.expects(:command).with("port group 1") + @interface.execute(:etherchannel, "1") + end + + it "should execute the block for block commands" do + @transport.expects(:command).with("ip address 192.168.0.1 255.255.255.0") + @interface.execute(:ipaddress, [[24, IPAddr.new('192.168.0.1'), nil]]) + end + + it "should execute the block for block commands" do + @transport.expects(:command).with("ipv6 address fe08::/76 link-local") + @interface.execute(:ipaddress, [[76, IPAddr.new('fe08::'), 'link-local']]) + end + + end + + describe "when sending commands to the device" do + it "should detect errors" do + Puppet.expects(:err) + @transport.stubs(:command).yields("% Invalid Command") + @interface.command("sh ver") + end + end +end
\ No newline at end of file |