]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/eigrp-topo1/test_eigrp_topo1.py
tests: Run python formatter (black) for topotests
[mirror_frr.git] / tests / topotests / eigrp-topo1 / test_eigrp_topo1.py
CommitLineData
a4e471cf
DS
1#!/usr/bin/env python
2
3#
4# test_eigrp_topo1.py
5#
6# Copyright (c) 2017 by
7# Cumulus Networks, Inc.
8# Donald Sharp
9#
10# Permission to use, copy, modify, and/or distribute this software
11# for any purpose with or without fee is hereby granted, provided
12# that the above copyright notice and this permission notice appear
13# in all copies.
14#
15# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
16# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
18# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
19# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
21# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22# OF THIS SOFTWARE.
23#
24
25"""
26test_eigrp_topo1.py: Testing EIGRP
27
28"""
29
30import os
31import re
32import sys
a4e471cf 33import pytest
ee4523a2 34import json
a4e471cf 35
e5355a01
RZ
36# Save the Current Working Directory to find configuration files.
37CWD = os.path.dirname(os.path.realpath(__file__))
787e7624 38sys.path.append(os.path.join(CWD, "../"))
a4e471cf 39
e5355a01
RZ
40# pylint: disable=C0413
41# Import topogen and topotest helpers
a4e471cf 42from lib import topotest
e5355a01
RZ
43from lib.topogen import Topogen, TopoRouter, get_topogen
44from lib.topolog import logger
a4e471cf 45
e5355a01
RZ
46# Required to instantiate the topology builder class.
47from mininet.topo import Topo
a4e471cf
DS
48
49#####################################################
50##
51## Network Topology Definition
52##
53#####################################################
54
787e7624 55
a4e471cf
DS
56class NetworkTopo(Topo):
57 "EIGRP Topology 1"
58
59 def build(self, **_opts):
e5355a01
RZ
60 "Build function"
61
62 tgen = get_topogen(self)
63
64 for routern in range(1, 4):
787e7624 65 tgen.add_router("r{}".format(routern))
a4e471cf 66
a4e471cf
DS
67 # On main router
68 # First switch is for a dummy interface (for local network)
787e7624 69 switch = tgen.add_switch("sw1")
70 switch.add_link(tgen.gears["r1"])
e5355a01 71
a4e471cf
DS
72 # Switches for EIGRP
73 # switch 2 switch is for connection to EIGRP router
787e7624 74 switch = tgen.add_switch("sw2")
75 switch.add_link(tgen.gears["r1"])
76 switch.add_link(tgen.gears["r2"])
e5355a01 77
a4e471cf 78 # switch 4 is stub on remote EIGRP router
787e7624 79 switch = tgen.add_switch("sw4")
80 switch.add_link(tgen.gears["r3"])
a4e471cf 81
e5355a01 82 # switch 3 is between EIGRP routers
787e7624 83 switch = tgen.add_switch("sw3")
84 switch.add_link(tgen.gears["r2"])
85 switch.add_link(tgen.gears["r3"])
a4e471cf
DS
86
87
88#####################################################
89##
90## Tests starting
91##
92#####################################################
93
787e7624 94
a4e471cf 95def setup_module(module):
e5355a01
RZ
96 "Setup topology"
97 tgen = Topogen(NetworkTopo, module.__name__)
98 tgen.start_topology()
a4e471cf 99
e5355a01
RZ
100 # This is a sample of configuration loading.
101 router_list = tgen.routers()
102 for rname, router in router_list.iteritems():
103 router.load_config(
787e7624 104 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
e5355a01
RZ
105 )
106 router.load_config(
787e7624 107 TopoRouter.RD_EIGRP, os.path.join(CWD, "{}/eigrpd.conf".format(rname))
e5355a01 108 )
a4e471cf 109
e5355a01 110 tgen.start_router()
a4e471cf 111
a4e471cf 112
e5355a01
RZ
113def teardown_module(_mod):
114 "Teardown the pytest environment"
115 tgen = get_topogen()
a4e471cf 116
e5355a01
RZ
117 # This function tears down the whole topology.
118 tgen.stop_topology()
a4e471cf
DS
119
120
e5355a01
RZ
121def test_converge_protocols():
122 "Wait for protocol convergence"
a4e471cf 123
e5355a01
RZ
124 tgen = get_topogen()
125 # Don't run this test if we have any failure.
126 if tgen.routers_have_failure():
127 pytest.skip(tgen.errors)
a4e471cf 128
787e7624 129 topotest.sleep(5, "Waiting for EIGRP convergence")
a4e471cf 130
a4e471cf 131
e5355a01
RZ
132def test_eigrp_routes():
133 "Test EIGRP 'show ip eigrp'"
a4e471cf 134
e5355a01
RZ
135 tgen = get_topogen()
136 # Don't run this test if we have any failure.
137 if tgen.routers_have_failure():
138 pytest.skip(tgen.errors)
a4e471cf 139
e5355a01
RZ
140 # Verify EIGRP Status
141 logger.info("Verifying EIGRP routes")
a4e471cf 142
e5355a01
RZ
143 router_list = tgen.routers().values()
144 for router in router_list:
787e7624 145 refTableFile = "{}/{}/show_ip_eigrp.json".format(CWD, router.name)
a4e471cf 146
e5355a01 147 # Read expected result from file
7c1f9631 148 expected = json.loads(open(refTableFile).read())
a4e471cf 149
e5355a01 150 # Actual output from router
7c1f9631 151 actual = ip_eigrp_topo(router)
a4e471cf 152
7c1f9631
RZ
153 assertmsg = '"show ip eigrp topo" mismatches on {}'.format(router.name)
154 assert topotest.json_cmp(actual, expected) is None, assertmsg
a4e471cf 155
787e7624 156
e5355a01
RZ
157def test_zebra_ipv4_routingTable():
158 "Test 'show ip route'"
a4e471cf 159
e5355a01
RZ
160 tgen = get_topogen()
161 # Don't run this test if we have any failure.
162 if tgen.routers_have_failure():
163 pytest.skip(tgen.errors)
a4e471cf 164
a4e471cf 165 failures = 0
e5355a01
RZ
166 router_list = tgen.routers().values()
167 for router in router_list:
787e7624 168 output = router.vtysh_cmd("show ip route json", isjson=True)
169 refTableFile = "{}/{}/show_ip_route.json_ref".format(CWD, router.name)
ee4523a2 170 expected = json.loads(open(refTableFile).read())
a4e471cf 171
787e7624 172 assertmsg = "Zebra IPv4 Routing Table verification failed for router {}".format(
173 router.name
174 )
ee4523a2 175 assert topotest.json_cmp(output, expected) is None, assertmsg
a4e471cf 176
787e7624 177
84b5e534
DS
178def test_shut_interface_and_recover():
179 "Test shutdown of an interface and recovery of the interface"
180
181 tgen = get_topogen()
787e7624 182 router = tgen.gears["r1"]
183 router.run("ip link set r1-eth1 down")
184 topotest.sleep(5, "Waiting for EIGRP convergence")
185 router.run("ip link set r1-eth1 up")
84b5e534 186
a4e471cf
DS
187
188def test_shutdown_check_stderr():
787e7624 189 if os.environ.get("TOPOTESTS_CHECK_STDERR") is None:
190 pytest.skip("Skipping test for Stderr output and memory leaks")
a4e471cf 191
e5355a01
RZ
192 tgen = get_topogen()
193 # Don't run this test if we have any failure.
194 if tgen.routers_have_failure():
195 pytest.skip(tgen.errors)
a4e471cf 196
e5355a01 197 logger.info("Verifying unexpected STDERR output from daemons")
a4e471cf 198
e5355a01
RZ
199 router_list = tgen.routers().values()
200 for router in router_list:
201 router.stop()
a4e471cf 202
787e7624 203 log = tgen.net[router.name].getStdErr("eigrpd")
8e957dbb 204 if log:
787e7624 205 logger.error("EIGRPd StdErr Log:" + log)
206 log = tgen.net[router.name].getStdErr("zebra")
8e957dbb 207 if log:
787e7624 208 logger.error("Zebra StdErr Log:" + log)
a4e471cf
DS
209
210
787e7624 211if __name__ == "__main__":
e5355a01
RZ
212 args = ["-s"] + sys.argv[1:]
213 sys.exit(pytest.main(args))
7c1f9631
RZ
214
215#
216# Auxiliary Functions
217#
218def ip_eigrp_topo(node):
219 """
220 Parse 'show ip eigrp topo' from `node` and returns a dict with the
221 result.
222
223 Example:
224 {
225 'P': {
226 '192.168.1.0/24': {
227 'sucessors': 1,
228 'fd': 112233,
229 'serno': 0,
230 'via': 'Connected',
231 'interface': 'eth0',
232 },
233 '192.168.2.0/24': {
234 'sucessors': 1,
235 'fd': 112234,
236 'serno': 0,
237 'via': 'Connected',
238 'interface': 'eth1',
239 }
240 }
241 }
242 """
787e7624 243 output = topotest.normalize_text(node.vtysh_cmd("show ip eigrp topo")).splitlines()
7c1f9631
RZ
244 result = {}
245 for idx, line in enumerate(output):
787e7624 246 columns = line.split(" ", 1)
7c1f9631
RZ
247
248 # Parse the following format into python dicts
249 # code A.B.C.D/E, X successors, FD is Y, serno: Z
250 # via FOO, interface-name
251 code = columns[0]
787e7624 252 if code not in ["P", "A", "U", "Q", "R", "r", "s"]:
7c1f9631
RZ
253 continue
254
255 if not result.has_key(code):
256 result[code] = {}
257
258 # Split network from the rest
787e7624 259 columns = columns[1].split(",")
7c1f9631
RZ
260
261 # Parse first line data
262 network = columns[0]
263 result[code][network] = {}
264 for column in columns:
265 # Skip the network column
266 if column == columns[0]:
267 continue
268
787e7624 269 match = re.search(r"(\d+) successors", column)
7c1f9631 270 if match is not None:
787e7624 271 result[code][network]["successors"] = match.group(1)
7c1f9631
RZ
272 continue
273
787e7624 274 match = re.search(r"FD is (\d+)", column)
7c1f9631 275 if match is not None:
787e7624 276 result[code][network]["fd"] = match.group(1)
7c1f9631
RZ
277 continue
278
787e7624 279 match = re.search(r"serno: (\d+)", column)
7c1f9631 280 if match is not None:
787e7624 281 result[code][network]["serno"] = match.group(1)
7c1f9631
RZ
282 continue
283
284 # Parse second line data
285 nextline = output[idx + 1]
787e7624 286 columns = topotest.normalize_text(nextline).split(",")
7c1f9631 287 for column in columns:
787e7624 288 match = re.search(r"via (.+)", column)
7c1f9631 289 if match is not None:
787e7624 290 result[code][network]["via"] = match.group(1)
7c1f9631
RZ
291 continue
292
787e7624 293 match = re.search(r"(.+)", column)
7c1f9631 294 if match is not None:
787e7624 295 result[code][network]["interface"] = match.group(1)
7c1f9631
RZ
296 continue
297
298 return result