Skip to content

Latest commit

 

History

History
275 lines (199 loc) · 5.82 KB

SNIPPETS.md

File metadata and controls

275 lines (199 loc) · 5.82 KB

Snippets

This document will describe common snippets of code that are frequently needed to perform some test checks.

Checking for router / test failures

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)

Checking FRR routers version

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.

Interacting with equipments

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 the mininet API functions directly to spawn commands.

Interacting with the Linux sandbox

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)

Interacting with VTYSH

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.

Invoking mininet CLI

Without Topogen

CLI(net)

With Topogen

tgen = get_topogen()
tgen.mininet_cli()

Reading files

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())

Comparing JSON output

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`.

Pausing execution

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)

ip route Linux command as JSON

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