
This is the beginning of the guidelines file. It will contain all necessary instructions to help people write topology tests.
9.6 KiB
Guidelines
This document describes how to use the topotests testing framework.
Executing Tests
To run the whole suite of tests the following commands must be executed at the top level directory of topotest:
$ # Change to the top level directory of topotests.
$ cd path/to/topotests
$ # Tests must be run as root, since Mininet requires it.
$ sudo pytest
In order to run a specific test, you can use the following command:
$ sudo pytest ospf-topo1/test_ospf_topo1.py
$ # or inside the test folder
$ cd ospf-topo1
$ sudo pytest # to run all tests inside the directory
$ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
The output of the tested daemons will be avaiable at the temporary folder of your machine:
$ ls /tmp
...
router1-zebra.err # zebra stderr output
router1-zebra.log # zebra log file
router1-zebra.out # zebra stdout output
...
You can also run memory leak tests to get reports:
$ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
...
$ ls /tmp/memleak_report_*
memleak_report_test_ospf_topo1.txt
Writing a New Test
This section will guide you in all recommended steps to produce a standard topology test.
This is the recommended test writing routine:
- Write a topology (Graphviz recommended)
- Obtain configuration files
- Write the test itself
- Create a Pull Request
Topotest File Hierarchy
Before starting to write any tests one must know the file hierarchy. The repository hierarchy looks like this:
$ cd path/to/topotest
$ find ./*
...
./README.md # repository read me
./GUIDELINES.md # this file
./conftest.py # test hooks - pytest related functions
./example-test # example test folder
./example-test/__init__.py # python package marker - must always exist.
./example-test/test_template.jpg # generated topology picture - see next section
./example-test/test_template.dot # Graphviz dot file
./example-test/test_template.py # the topology plus the test
...
./ospf-topo1 # the ospf topology test
./ospf-topo1/router1 # router 1 configuration files
./ospf-topo1/router1/zebra.conf # zebra configuration file
./ospf-topo1/router1/ospfd.conf # ospf configuration file
./ospf-topo1/router1/ospfroute.txt # 'show ip ospf' output reference file
# removed other for shortness sake
...
./lib # shared test/topology functions
./lib/topogen.py # topogen implementation
./lib/topotest.py # topotest implementation
Guidelines for creating/editing topotest:
- New topologies that don't fit the existing directories should create its own
- Always remember to add the init.py to new folders, this makes the life of developers easier, auto complete engines and pylint happy
- Router (Quagga/FRR) specific code should go on topotest.py
- Generic/repeated router actions should have an abstraction in topogen.TopoRouter.
- Generic/repeated non-router code should go to topotest.py
- pytest related code should go to conftest.py (e.g. specialized asserts)
Defining the Topology
The first step to write a new test is to define the topology. This step can be done in many ways, but the recommended is to use Graphviz to generate a drawing of the Topology. It allows us to see the topology graphically and to see the names of equipments, links and addresses.
Here is an example of Graphviz dot file that generates the template topology (the inlined code might get outdated, please see the linked file):
graph ospf_topo1 {
label="Template Topology";
# Make the Graph fit a A4 paper sheet
# 11inches x 8inches -> ~297mm x ~210mm
size="11,8!";
# Uncomment this one for vertical A4 paper sheet
#size="8,11!";
# Routers
router1 [
shape=octagon,
label="router1",
];
router2 [
shape=octagon
label="router2\nrtr-id 10.0.255.1",
];
# Switches
switch1 [shape=box];
switch2 [shape=box];
# Connections
router1 -- switch1 [label="router1-eth0\n192.168.0.1/24"];
router1 -- switch2 [label="router1-eth1\n192.168.1.100/24"];
router2 -- switch2 [label="router2-eth0\n192.168.1.1/24"];
}
Here is the produced graph:
Generating / Obtaining Configuration Files
In order to get the configuration files or command output for each router we need to run the topology and execute commands in vtysh. The quickest way to achieve that is writing the topology building code and running the topology.
To bootstrap your test topology, do the following steps:
- Copy the template test
$ mkdir new-topo/
$ touch new-topo/__init__.py
$ cp example-test/test_template.py new-topo/test_new_topo.py
- Modify the template according to your dot file
- Run the topology
Topogen allows us to run the topology without running any tests, you can do that using the following example commands:
$ # Running your bootstraped topology
$ sudo pytest -s --topology-only new-topo/test_new_topo.py
$ # Running the test_template.py topology
$ sudo pytest -s --topology-only example-test/test_template.py
$ # Running the ospf_topo1.py topology
$ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
Parameters explanation:
- -s: actives input/output capture. This is required by mininet in order to show the interactive shell.
- --topology-only: don't run anytest, just build the topology.
After executing the commands above you should get the following terminal output:
============================================================================================================ test session starts =============================================================================================================
platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
rootdir: /media/sf_src/topotests, inifile: pytest.ini
collected 3 items
ospf-topo1/test_ospf_topo1.py *** Starting controller
*** Starting 6 switches
switch1 switch2 switch3 switch4 switch5 switch6 ...
router2: frr zebra started
router2: frr ospfd started
router3: frr zebra started
router3: frr ospfd started
router1: frr zebra started
router1: frr ospfd started
router4: frr zebra started
router4: frr ospfd started
*** Starting CLI:
mininet>
The last line shows us that we are now using the Mininet CLI (Command Line Interface), from here you can call your router vtysh or even bash.
Here are some commands example:
mininet> router1 ping 10.0.3.1
PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data.
64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms
64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms
64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms
^C
--- 10.0.3.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms
mininet> router1 ping 10.0.3.3
PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data.
64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms
64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms
64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms
^C
--- 10.0.3.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms
mininet> router3 vtysh
Hello, this is FRRouting (version 3.1-devrzalamena-build).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
frr-1# show running-config
Building configuration...
Current configuration:
!
frr version 3.1-devrzalamena-build
frr defaults traditional
hostname router3
no service integrated-vtysh-config
!
log file /tmp/router3-zebra.log
!
log file /tmp/router3-ospfd.log
!
interface router3-eth0
ip address 10.0.3.1/24
!
interface router3-eth1
ip address 10.0.10.1/24
!
interface router3-eth2
ip address 172.16.0.2/24
!
router ospf
ospf router-id 10.0.255.3
redistribute kernel
redistribute connected
redistribute static
network 10.0.3.0/24 area 0
network 10.0.10.0/24 area 0
network 172.16.0.0/24 area 1
!
line vty
!
end
frr-1#
After you successfully configured your topology you can obtain the configuration files (per-daemon) using the following command:
mininet> router3 vtysh -d ospfd
Hello, this is FRRouting (version 3.1-devrzalamena-build).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
frr-1# show running-config
Building configuration...
Current configuration:
!
frr version 3.1-devrzalamena-build
frr defaults traditional
no service integrated-vtysh-config
!
log file /tmp/router3-ospfd.log
!
router ospf
ospf router-id 10.0.255.3
redistribute kernel
redistribute connected
redistribute static
network 10.0.3.0/24 area 0
network 10.0.10.0/24 area 0
network 172.16.0.0/24 area 1
!
line vty
!
end
frr-1#
Writing Tests
TODO
Debugging Execution
TODO
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PDB set_trace (IO-capturing turned off) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence()
-> for rnum in range(1, 5):
(Pdb) l
116
117 def test_ospf_convergence():
118 "Test OSPF daemon convergence"
119 import pdb
120 pdb.set_trace()
121 -> for rnum in range(1, 5):
122 router = 'router{}'.format(rnum)
123
124 # Load expected results from the command
125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
126 expected = open(reffile).read()
(Pdb) tgen = get_topogen()
(Pdb) pp tgen.gears['router1']
<lib.topogen.TopoRouter object at 0x7f2349c98c50>
(Pdb) pp str(tgen.gears['router1'])
'TopoGear<name="router1",links=["router1-eth0"<->"switch1-eth0","router1-eth1"<->"switch3-eth0"]> TopoRouter<>'