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