This document will describe common snippets of code that are frequently needed to perform some test checks.
The following check uses the topogen API to check for software failure
(e.g. zebra died) and/or for errors manually set by Topogen.set_error()
.
# Get the topology reference
tgen = get_topogen()
# Check for errors in the topology
if tgen.routers_have_failure():
# Skip the test with the topology errors as reason
pytest.skip(tgen.errors)
This code snippet is usually run after the topology setup to make sure all routers instantiated in the topology have the correct software version.
# Get the topology reference
tgen = get_topogen()
# Get the router list
router_list = tgen.routers()
# Run the check for all routers
for router in router_list.values():
if router.has_version('<', '3'):
# Set topology error, so the next tests are skipped
tgen.set_error('unsupported version')
A sample of this snippet in a test can be found here.
You might want to interact with the topology equipments during the tests and there are different ways to do so.
Notes:
When using the Topogen API, all the equipments code derive from
Topogear
(lib/topogen.py). If you feel brave you can look by yourself how the abstractions that will be mentioned here works.
When not using the
Topogen
API there is only one way to interact with the equipments, which is by calling themininet
API functions directly to spawn commands.
Without Topogen
global net
output = net['r1'].cmd('echo "foobar"')
print 'output is: {}'.format(output)
With Topogen
tgen = get_topogen()
output = tgen.gears['r1'].run('echo "foobar"')
print 'output is: {}'.format(output)
Without Topogen
global net
output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null')
print 'output is: {}'.format(output)
With Topogen
tgen = get_topogen()
output = tgen.gears['r1'].vtysh_cmd("show ip route")
print 'output is: {}'.format(output)
Topogen
also supports sending multiple lines of command:
tgen = get_topogen()
output = tgen.gears['r1'].vtysh_cmd("""
configure terminal
router bgp 10
bgp router-id 10.0.255.1
neighbor 1.2.3.4 remote-as 10
!
router bgp 11
bgp router-id 10.0.255.2
!
""")
print 'output is: {}'.format(output)
You might also want to run multiple commands and get only the commands that failed:
tgen = get_topogen()
output = tgen.gears['r1'].vtysh_multicmd("""
configure terminal
router bgp 10
bgp router-id 10.0.255.1
neighbor 1.2.3.4 remote-as 10
!
router bgp 11
bgp router-id 10.0.255.2
!
""", pretty_output=false)
print 'output is: {}'.format(output)
Translating vtysh JSON output into Python structures:
tgen = get_topogen()
json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
output = json.dumps(json_output, indent=4)
print 'output is: {}'.format(output)
# You can also access the data structure as normal. For example:
# protocol = json_output['1.1.1.1/32']['protocol']
# assert protocol == "ospf", "wrong protocol"
NOTE: vtysh_(multi)cmd
is only available for router type of
equipments.
Without Topogen
CLI(net)
With Topogen
tgen = get_topogen()
tgen.mininet_cli()
Loading a normal text file content in the current directory:
# If you are using Topogen
# CURDIR = CWD
#
# Otherwise find the directory manually:
CURDIR = os.path.dirname(os.path.realpath(__file__))
file_name = '{}/r1/show_ip_route.txt'.format(CURDIR)
file_content = open(file_name).read()
Loading JSON from a file:
import json
file_name = '{}/r1/show_ip_route.json'.format(CURDIR)
file_content = json.loads(open(file_name).read())
After obtaining JSON output formated with Python data structures, you may use it to assert a minimalist schema:
tgen = get_topogen()
json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
expect = {
'1.1.1.1/32': {
'protocol': 'ospf'
}
}
assertmsg = "route 1.1.1.1/32 was not learned through OSPF"
assert json_cmp(json_output, expect) is None, assertmsg
json_cmp
function description (it might be outdated, you can find the
latest description in the source code at lib/topotest.py):
JSON compare function. Receives two parameters:
* `d1`: json value
* `d2`: json subset which we expect
Returns `None` when all keys that `d1` has matches `d2`,
otherwise a string containing what failed.
Note: key absence can be tested by adding a key with value `None`.
Preferably, choose the sleep
function that topotest
provides, as it
prints a notice during the test execution to help debug topology test
execution time.
# Using the topotest sleep
from lib import topotest
topotest.sleep(10, 'waiting 10 seconds for bla')
# or just tell it the time:
# topotest.sleep(10)
# It will print 'Sleeping for 10 seconds'.
# Or you can also use the Python sleep, but it won't show anything
from time import sleep
sleep(5)
topotest
has two helpers implemented that parses the output of
ip route
commands to JSON. It might simplify your comparison needs by
only needing to provide a Python dictionary.
from lib import topotest
tgen = get_topogen()
routes = topotest.ip4_route(tgen.gears['r1'])
expected = {
'10.0.1.0/24': {},
'10.0.2.0/24': {
'dev': 'r1-eth0'
}
}
assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24"
assert json_cmp(routes, expected) is None, assertmsg