]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/ripng-topo1/test_ripng_topo1.py
(all tests): Add extra check to make sure daemons are still running after each essent...
[mirror_frr.git] / tests / topotests / ripng-topo1 / test_ripng_topo1.py
CommitLineData
9f3e0f64
MW
1#!/usr/bin/env python
2
3#
4# test_ripng_topo1.py
5# Part of NetDEF Topology Tests
6#
7# Copyright (c) 2017 by
8# Network Device Education Foundation, Inc. ("NetDEF")
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_ripng_topo1.py: Test of RIPng Topology
27
28"""
29
30import os
31import re
32import sys
33import difflib
34import pytest
35import unicodedata
36from time import sleep
37
38from mininet.topo import Topo
39from mininet.net import Mininet
40from mininet.node import Node, OVSSwitch, Host
41from mininet.log import setLogLevel, info
42from mininet.cli import CLI
43from mininet.link import Intf
44
45from functools import partial
46
47sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
48from lib import topotest
49
50fatal_error = ""
51
52
53#####################################################
54##
55## Network Topology Definition
56##
57#####################################################
58
59class NetworkTopo(Topo):
60 "RIPng Topology 1"
61
62 def build(self, **_opts):
63
64 # Setup Routers
65 router = {}
66 #
67 # Setup Main Router
68 router[1] = topotest.addRouter(self, 'r1')
69 #
70 # Setup RIPng Routers
71 for i in range(2, 4):
72 router[i] = topotest.addRouter(self, 'r%s' % i)
73
74 # Setup Switches
75 switch = {}
76 #
77 # On main router
78 # First switch is for a dummy interface (for local network)
79 switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch)
80 self.addLink(switch[1], router[1], intfName2='r1-eth0')
81 #
82 # Switches for RIPng
83 # switch 2 switch is for connection to RIP router
84 switch[2] = self.addSwitch('sw2', cls=topotest.LegacySwitch)
85 self.addLink(switch[2], router[1], intfName2='r1-eth1')
86 self.addLink(switch[2], router[2], intfName2='r2-eth0')
87 # switch 3 is between RIP routers
88 switch[3] = self.addSwitch('sw3', cls=topotest.LegacySwitch)
89 self.addLink(switch[3], router[2], intfName2='r2-eth1')
90 self.addLink(switch[3], router[3], intfName2='r3-eth1')
91 # switch 4 is stub on remote RIP router
92 switch[4] = self.addSwitch('sw4', cls=topotest.LegacySwitch)
93 self.addLink(switch[4], router[3], intfName2='r3-eth0')
94
95
96
97#####################################################
98##
99## Tests starting
100##
101#####################################################
102
103def setup_module(module):
104 global topo, net
105
106 print("\n\n** %s: Setup Topology" % module.__name__)
107 print("******************************************\n")
108
109 print("Cleanup old Mininet runs")
110 os.system('sudo mn -c > /dev/null 2>&1')
111
112 thisDir = os.path.dirname(os.path.realpath(__file__))
113 topo = NetworkTopo()
114
115 net = Mininet(controller=None, topo=topo)
116 net.start()
117
118 # Starting Routers
119 #
120 for i in range(1, 4):
121 net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i))
122 net['r%s' % i].loadConf('ripngd', '%s/r%s/ripngd.conf' % (thisDir, i))
123 net['r%s' % i].startRouter()
124
125 # For debugging after starting Quagga/FRR daemons, uncomment the next line
126 # CLI(net)
127
128
129def teardown_module(module):
130 global net
131
132 print("\n\n** %s: Shutdown Topology" % module.__name__)
133 print("******************************************\n")
134
135 # End - Shutdown network
136 net.stop()
137
138
139def test_router_running():
140 global fatal_error
141 global net
142
143 # Skip if previous fatal error condition is raised
144 if (fatal_error != ""):
145 pytest.skip(fatal_error)
146
147 print("\n\n** Check if FRR/Quagga is running on each Router node")
148 print("******************************************\n")
149 sleep(5)
150
151 # Starting Routers
152 for i in range(1, 4):
153 fatal_error = net['r%s' % i].checkRouterRunning()
154 assert fatal_error == "", fatal_error
155
156 # For debugging after starting FRR/Quagga daemons, uncomment the next line
157 # CLI(net)
158
159
160def test_converge_protocols():
161 global fatal_error
162 global net
163
164 # Skip if previous fatal error condition is raised
165 if (fatal_error != ""):
166 pytest.skip(fatal_error)
167
168 thisDir = os.path.dirname(os.path.realpath(__file__))
169
170 print("\n\n** Waiting for protocols convergence")
171 print("******************************************\n")
172
173 # Not really implemented yet - just sleep 60 secs for now
174 sleep(60)
175
7e7fc73b
MW
176 # Make sure that all daemons are running
177 for i in range(1, 4):
178 fatal_error = net['r%s' % i].checkRouterRunning()
179 assert fatal_error == "", fatal_error
180
9f3e0f64
MW
181 # For debugging after starting FRR/Quagga daemons, uncomment the next line
182 #CLI(net)
183
184
185def test_ripng_status():
186 global fatal_error
187 global net
188
189 # Skip if previous fatal error condition is raised
190 if (fatal_error != ""):
191 pytest.skip(fatal_error)
192
193 thisDir = os.path.dirname(os.path.realpath(__file__))
194
195 # Verify RIP Status
b2764f90 196 print("\n\n** Verifying RIPng status")
9f3e0f64
MW
197 print("******************************************\n")
198 failures = 0
199 for i in range(1, 4):
200 refTableFile = '%s/r%s/ripng_status.ref' % (thisDir, i)
201 if os.path.isfile(refTableFile):
202 # Read expected result from file
203 expected = open(refTableFile).read().rstrip()
204 # Fix newlines (make them all the same)
205 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
206
207 # Actual output from router
208 actual = net['r%s' % i].cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null').rstrip()
209 # Mask out Link-Local mac address portion. They are random...
210 actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual)
211 # Drop time in next due
212 actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual)
213 # Drop time in last update
214 actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual)
215 # Fix newlines (make them all the same)
216 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
217
218 # Generate Diff
219 diff = ''.join(difflib.context_diff(actual, expected,
220 fromfile="actual IPv6 RIPng status",
221 tofile="expected IPv6 RIPng status"))
222
223 # Empty string if it matches, otherwise diff contains unified diff
224 if diff:
225 sys.stderr.write('r%s failed IPv6 RIPng status check:\n%s\n' % (i, diff))
226 failures += 1
227 else:
228 print("r%s ok" % i)
229
230 assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (i, diff)
231
7e7fc73b
MW
232 # Make sure that all daemons are running
233 for i in range(1, 4):
234 fatal_error = net['r%s' % i].checkRouterRunning()
235 assert fatal_error == "", fatal_error
236
9f3e0f64
MW
237 # For debugging after starting FRR/Quagga daemons, uncomment the next line
238 # CLI(net)
239
240
241def test_ripng_routes():
242 global fatal_error
243 global net
244
245 # Skip if previous fatal error condition is raised
246 if (fatal_error != ""):
247 pytest.skip(fatal_error)
248
249 thisDir = os.path.dirname(os.path.realpath(__file__))
250
251 # Verify RIPng Status
b2764f90 252 print("\n\n** Verifying RIPng routes")
9f3e0f64
MW
253 print("******************************************\n")
254 failures = 0
255 for i in range(1, 4):
256 refTableFile = '%s/r%s/show_ipv6_ripng.ref' % (thisDir, i)
257 if os.path.isfile(refTableFile):
258 # Read expected result from file
259 expected = open(refTableFile).read().rstrip()
260 # Fix newlines (make them all the same)
261 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
262
263 # Actual output from router
264 actual = net['r%s' % i].cmd('vtysh -c "show ipv6 ripng" 2> /dev/null').rstrip()
265 # Drop Time
266 actual = re.sub(r" [0-9][0-9]:[0-5][0-9]", " XX:XX", actual)
267 # Mask out Link-Local mac address portion. They are random...
268 actual = re.sub(r" fe80::[0-9a-f: ]+", " fe80::XXXX:XXXX:XXXX:XXXX ", actual)
269 # Remove trailing spaces on all lines
270 actual = '\n'.join([line.rstrip() for line in actual.splitlines()])
271
272 # Fix newlines (make them all the same)
273 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
274
275 # Generate Diff
276 diff = ''.join(difflib.context_diff(actual, expected,
277 fromfile="actual SHOW IPv6 RIPng",
278 tofile="expected SHOW IPv6 RIPng"))
279
280 # Empty string if it matches, otherwise diff contains unified diff
281 if diff:
282 sys.stderr.write('r%s failed SHOW IPv6 RIPng check:\n%s\n' % (i, diff))
283 failures += 1
284 else:
285 print("r%s ok" % i)
286
287 assert failures == 0, "SHOW IPv6 RIPng failed for router r%s:\n%s" % (i, diff)
288
7e7fc73b
MW
289 # Make sure that all daemons are running
290 for i in range(1, 4):
291 fatal_error = net['r%s' % i].checkRouterRunning()
292 assert fatal_error == "", fatal_error
293
9f3e0f64
MW
294 # For debugging after starting FRR/Quagga daemons, uncomment the next line
295 # CLI(net)
296
297
298def test_zebra_ipv6_routingTable():
299 global fatal_error
300 global net
301
302 # Skip if previous fatal error condition is raised
303 if (fatal_error != ""):
304 pytest.skip(fatal_error)
305
306 thisDir = os.path.dirname(os.path.realpath(__file__))
307
308 # Verify OSPFv3 Routing Table
b2764f90 309 print("\n\n** Verifying Zebra IPv6 Routing Table")
9f3e0f64
MW
310 print("******************************************\n")
311 failures = 0
312 for i in range(1, 4):
313 refTableFile = '%s/r%s/show_ipv6_route.ref' % (thisDir, i)
314 if os.path.isfile(refTableFile):
315 # Read expected result from file
316 expected = open(refTableFile).read().rstrip()
317 # Fix newlines (make them all the same)
318 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
319
320 # Actual output from router
321 actual = net['r%s' % i].cmd('vtysh -c "show ipv6 route" 2> /dev/null | grep "^R"').rstrip()
322 # Mask out Link-Local mac address portion. They are random...
323 actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual)
324 # Drop timers on end of line (older Quagga Versions)
325 actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual)
326 # Fix newlines (make them all the same)
327 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
328
329 # Generate Diff
330 diff = ''.join(difflib.context_diff(actual, expected,
331 fromfile="actual Zebra IPv6 routing table",
332 tofile="expected Zebra IPv6 routing table"))
333
334 # Empty string if it matches, otherwise diff contains unified diff
335 if diff:
336 sys.stderr.write('r%s failed Zebra IPv6 Routing Table Check:\n%s\n' % (i, diff))
337 failures += 1
338 else:
339 print("r%s ok" % i)
340
341 assert failures == 0, "Zebra IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff)
342
7e7fc73b
MW
343 # Make sure that all daemons are running
344 for i in range(1, 4):
345 fatal_error = net['r%s' % i].checkRouterRunning()
346 assert fatal_error == "", fatal_error
347
9f3e0f64
MW
348 # For debugging after starting FRR/Quagga daemons, uncomment the next line
349 # CLI(net)
350
351
352def test_shutdown_check_stderr():
353 global fatal_error
354 global net
355
356 # Skip if previous fatal error condition is raised
357 if (fatal_error != ""):
358 pytest.skip(fatal_error)
359
360 if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
50c40bde
MW
361 print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
362 pytest.skip('Skipping test for Stderr output')
9f3e0f64
MW
363
364 thisDir = os.path.dirname(os.path.realpath(__file__))
365
b2764f90 366 print("\n\n** Verifying unexpected STDERR output from daemons")
9f3e0f64
MW
367 print("******************************************\n")
368
369 net['r1'].stopRouter()
370
371 log = net['r1'].getStdErr('ripngd')
372 print("\nRIPngd StdErr Log:\n" + log)
373 log = net['r1'].getStdErr('zebra')
374 print("\nZebra StdErr Log:\n" + log)
375
376
50c40bde
MW
377def test_shutdown_check_memleak():
378 global fatal_error
379 global net
380
381 # Skip if previous fatal error condition is raised
382 if (fatal_error != ""):
383 pytest.skip(fatal_error)
384
385 if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None:
386 print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n")
387 pytest.skip('Skipping test for memory leaks')
388
389 thisDir = os.path.dirname(os.path.realpath(__file__))
390
391 net['r1'].stopRouter()
392 net['r1'].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__))
393
394
9f3e0f64
MW
395if __name__ == '__main__':
396
397 setLogLevel('info')
398 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
399 # retval = pytest.main(["-s", "--tb=no"])
400 retval = pytest.main(["-s"])
401 sys.exit(retval)