mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-11-03 04:28:24 +00:00
topotest: added two new sections to guidelines
And fixed some smaller details in the previous sections.
This commit is contained in:
parent
5f8f05be6e
commit
cef6ca99f9
@ -63,6 +63,7 @@ This is the recommended test writing routine:
|
||||
* Write the test itself
|
||||
* Create a Pull Request
|
||||
|
||||
|
||||
### Topotest File Hierarchy
|
||||
|
||||
Before starting to write any tests one must know the file hierarchy. The
|
||||
@ -211,9 +212,9 @@ $ 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
|
||||
* `-s`: actives input/output capture. This is required by mininet in order to show
|
||||
the interactive shell.
|
||||
* --topology-only: don't run any tests, just build the topology.
|
||||
* `--topology-only`: don't run any tests, just build the topology.
|
||||
|
||||
After executing the commands above, you should get the following terminal
|
||||
output:
|
||||
@ -351,22 +352,129 @@ frr-1#
|
||||
|
||||
### Writing Tests
|
||||
|
||||
**TODO**
|
||||
Test topologies should always be bootstrapped from the
|
||||
[example-test/test_template.py](example-test/test_template.py),
|
||||
because it contains important boilerplate code that can't be avoided, like:
|
||||
|
||||
* imports: os, sys, pytest, topotest/topogen and mininet topology class
|
||||
* The global variable CWD (Current Working directory): which is most likely
|
||||
going to be used to reference the routers configuration file location
|
||||
|
||||
Example:
|
||||
|
||||
```py
|
||||
# For all registered routers, load the zebra configuration file
|
||||
for rname, router in router_list.iteritems():
|
||||
router.load_config(
|
||||
TopoRouter.RD_ZEBRA,
|
||||
os.path.join(CWD, '{}/zebra.conf'.format(rname))
|
||||
)
|
||||
# os.path.join() joins the CWD string with arguments adding the necessary
|
||||
# slashes ('/'). Arguments must not begin with '/'.
|
||||
```
|
||||
|
||||
* The topology class that inherits from Mininet Topo class
|
||||
|
||||
```py
|
||||
class TemplateTopo(Topo):
|
||||
def build(self, *_args, **_opts):
|
||||
tgen = get_topogen(self)
|
||||
# topology build code
|
||||
```
|
||||
|
||||
* pytest `setup_module()` and `teardown_module()` to start the topology
|
||||
|
||||
```py
|
||||
def setup_module(_m):
|
||||
tgen = Topogen(TemplateTopo)
|
||||
tgen.start_topology('debug')
|
||||
|
||||
def teardown_module(_m):
|
||||
tgen = get_topogen()
|
||||
tgen.stop_topology()
|
||||
```
|
||||
|
||||
* `__main__` initialization code (to support running the script directly)
|
||||
|
||||
```py
|
||||
if __name__ == '__main__':
|
||||
sys.exit(pytest.main(["-s"]))
|
||||
```
|
||||
|
||||
Requirements:
|
||||
|
||||
* Test code should always be declared inside functions that begin with the
|
||||
`test_` prefix. Functions beginning with different prefixes will not be run by
|
||||
pytest.
|
||||
* Configuration files and long output commands should go into separated files
|
||||
inside folders named after the equipment.
|
||||
* Tests must be able to run without any interaction. To make sure your test
|
||||
conforms with this, run it without the `-s` parameter.
|
||||
|
||||
|
||||
### Debugging Execution
|
||||
|
||||
**TODO**
|
||||
The most effective ways to inspect topology tests are:
|
||||
|
||||
* Run pytest with `--pdb` option. This option will cause a pdb shell to appear
|
||||
when an assertion fails
|
||||
|
||||
Example: `pytest -s --pdb ospf-topo1/test_ospf_topo1.py`
|
||||
|
||||
* Set a breakpoint in the test code with `pdb`
|
||||
|
||||
Example:
|
||||
|
||||
```py
|
||||
# Add the pdb import at the beginning of the file
|
||||
import pdb
|
||||
# ...
|
||||
|
||||
# Add a breakpoint where you think the problem is
|
||||
def test_bla():
|
||||
# ...
|
||||
pdb.set_trace()
|
||||
# ...
|
||||
```
|
||||
|
||||
The [Python Debugger](https://docs.python.org/2.7/library/pdb.html) (pdb) shell
|
||||
allows us to run many useful operations like:
|
||||
|
||||
* Setting breaking point on file/function/conditions (e.g. `break`, `condition`)
|
||||
* Inspecting variables (e.g. `p` (print), `pp` (pretty print))
|
||||
* Running python code
|
||||
|
||||
TIP: The TopoGear (equipment abstraction class) implements the `__str__` method
|
||||
that allows the user to inspect equipment information.
|
||||
|
||||
Example of pdb usage:
|
||||
|
||||
```shell
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 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
|
||||
(Pdb) help
|
||||
Documented commands (type help <topic>):
|
||||
========================================
|
||||
EOF bt cont enable jump pp run unt
|
||||
a c continue exit l q s until
|
||||
alias cl d h list quit step up
|
||||
args clear debug help n r tbreak w
|
||||
b commands disable ignore next restart u whatis
|
||||
break condition down j p return unalias where
|
||||
|
||||
Miscellaneous help topics:
|
||||
==========================
|
||||
exec pdb
|
||||
|
||||
Undocumented commands:
|
||||
======================
|
||||
retval rv
|
||||
|
||||
(Pdb) list
|
||||
116 title2="Expected output")
|
||||
117
|
||||
118 def test_ospf_convergence():
|
||||
119 "Test OSPF daemon convergence"
|
||||
120 pdb.set_trace()
|
||||
121 -> for rnum in range(1, 5):
|
||||
122 router = 'r{}'.format(rnum)
|
||||
@ -374,9 +482,37 @@ frr-1#
|
||||
124 # Load expected results from the command
|
||||
125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
|
||||
126 expected = open(reffile).read()
|
||||
(Pdb) step
|
||||
> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence()
|
||||
-> router = 'r{}'.format(rnum)
|
||||
(Pdb) step
|
||||
> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence()
|
||||
-> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
|
||||
(Pdb) print rnum
|
||||
1
|
||||
(Pdb) print router
|
||||
r1
|
||||
(Pdb) tgen = get_topogen()
|
||||
(Pdb) pp tgen.gears['r1']
|
||||
<lib.topogen.TopoRouter object at 0x7f2349c98c50>
|
||||
(Pdb) pp str(tgen.gears['r1'])
|
||||
'TopoGear<name="r1",links=["r1-eth0"<->"switch1-eth0","r1-eth1"<->"switch3-eth0"]> TopoRouter<>'
|
||||
(Pdb) pp tgen.gears[router]
|
||||
<lib.topogen.TopoRouter object at 0x7f74e06c9850>
|
||||
(Pdb) pp str(tgen.gears[router])
|
||||
'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>'
|
||||
(Pdb) l 125
|
||||
120 pdb.set_trace()
|
||||
121 for rnum in range(1, 5):
|
||||
122 router = 'r{}'.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()
|
||||
127
|
||||
128 # Run test function until we get an result. Wait at most 60 seconds.
|
||||
129 test_func = partial(compare_show_ip_ospf, router, expected)
|
||||
130 result, diff = topotest.run_and_expect(test_func, '',
|
||||
(Pdb) router1 = tgen.gears[router]
|
||||
(Pdb) router1.vtysh_cmd('show ip ospf route')
|
||||
'============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n'
|
||||
(Pdb) tgen.mininet_cli()
|
||||
*** Starting CLI:
|
||||
mininet>
|
||||
```
|
||||
|
||||
Loading…
Reference in New Issue
Block a user