]>
Commit | Line | Data |
---|---|---|
62f79ac1 | 1 | #!/usr/bin/env python |
acddc0ed | 2 | # SPDX-License-Identifier: ISC |
62f79ac1 OD |
3 | |
4 | # | |
5 | # test_cspf_topo1.py | |
6 | # Part of NetDEF Topology Tests | |
7 | # | |
8 | # Copyright (c) 2022 by Orange | |
9 | # Author: Olivier Dugeon <olivier.dugeon@orange.com> | |
10 | # | |
62f79ac1 OD |
11 | |
12 | """ | |
13 | test_cspf_topo1.py: Test the FRR Constraint Shortest Path First algorithm. | |
14 | ||
15 | +------------+ | |
16 | | | | |
17 | | R1 | | |
18 | | 10.0.225.1 | | |
19 | | | | |
20 | +------------+ | |
21 | r1-eth0| |r1-eth1 | |
22 | | | | |
23 | 10.0.0.0/24| |10.0.1.0/24 | |
24 | | |2001:db8:1:/64 | |
25 | | | | |
26 | r2-eth0| |r2-eth1 | |
27 | +------------+ +------------+ | |
28 | | | | | | |
29 | | R2 |r2-eth2 r3-eth0| R3 | | |
30 | | 10.0.255.2 +------------------+ 10.0.255.3 | | |
31 | | | 10.0.3.0/24 | | | |
32 | +------------+ 2001:db8:3:/64 +------+-----+ | |
33 | r2-eth3| r3-eth1| | |
34 | | | | |
35 | 10.0.4.0/24| | | |
36 | | | | |
37 | | | | |
38 | r4-eth0| 2001:db8:5:/64| | |
39 | +------------+ | | |
40 | | | | | |
41 | | R4 |r4-eth1 | | |
42 | | 10.0.255.4 +-------------------------+ | |
43 | | | | |
44 | +------------+ | |
45 | ||
46 | """ | |
47 | ||
48 | import os | |
49 | import sys | |
50 | import json | |
51 | from functools import partial | |
52 | ||
53 | # Save the Current Working Directory to find configuration files. | |
54 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
55 | sys.path.append(os.path.join(CWD, "../")) | |
56 | ||
57 | # pylint: disable=C0413 | |
58 | ||
59 | # Import topogen and topotest helpers | |
60 | from lib import topotest | |
61 | from lib.topogen import Topogen, TopoRouter, get_topogen | |
62 | from lib.topolog import logger | |
63 | ||
64 | # and Finally pytest | |
65 | import pytest | |
66 | ||
67 | pytestmark = [pytest.mark.isisd] | |
68 | ||
69 | ||
70 | def build_topo(tgen): | |
71 | "Build function" | |
72 | ||
73 | # Create 4 routers | |
74 | for routern in range(1, 5): | |
75 | tgen.add_router("r{}".format(routern)) | |
76 | ||
77 | # Interconect router 1 and 2 with 2 links | |
78 | switch = tgen.add_switch("s1") | |
79 | switch.add_link(tgen.gears["r1"]) | |
80 | switch.add_link(tgen.gears["r2"]) | |
81 | switch = tgen.add_switch("s2") | |
82 | switch.add_link(tgen.gears["r1"]) | |
83 | switch.add_link(tgen.gears["r2"]) | |
84 | ||
85 | # Interconect router 3 and 2 | |
86 | switch = tgen.add_switch("s3") | |
87 | switch.add_link(tgen.gears["r3"]) | |
88 | switch.add_link(tgen.gears["r2"]) | |
89 | ||
90 | # Interconect router 4 and 2 | |
91 | switch = tgen.add_switch("s4") | |
92 | switch.add_link(tgen.gears["r4"]) | |
93 | switch.add_link(tgen.gears["r2"]) | |
94 | ||
95 | # Interconnect router 3 and 4 | |
96 | switch = tgen.add_switch("s5") | |
97 | switch.add_link(tgen.gears["r3"]) | |
98 | switch.add_link(tgen.gears["r4"]) | |
99 | ||
100 | ||
101 | def setup_module(mod): | |
102 | "Sets up the pytest environment" | |
103 | ||
104 | logger.info("\n\n---- Starting CSPF tests ----\n") | |
105 | ||
106 | tgen = Topogen(build_topo, mod.__name__) | |
107 | tgen.start_topology() | |
108 | ||
109 | router_list = tgen.routers() | |
110 | ||
111 | for rname, router in router_list.items(): | |
112 | router.load_config( | |
113 | TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) | |
114 | ) | |
115 | router.load_config( | |
116 | TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) | |
117 | ) | |
118 | if rname == "r1": | |
119 | router.load_config( | |
120 | TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format("r1")) | |
121 | ) | |
122 | ||
123 | # Initialize all routers. | |
124 | tgen.start_router() | |
125 | ||
126 | ||
127 | def teardown_module(): | |
128 | "Teardown the pytest environment" | |
129 | ||
130 | tgen = get_topogen() | |
131 | tgen.stop_topology() | |
132 | ||
133 | logger.info("\n\n---- CSPF tests End ----\n") | |
134 | ||
135 | ||
136 | def compare_ted_json_output(tgen, rname, fileref): | |
137 | "Compare TED JSON output" | |
138 | ||
139 | logger.info('Comparing router "%s" TED output', rname) | |
140 | ||
141 | filename = "{}/reference/{}".format(CWD, fileref) | |
142 | expected = json.loads(open(filename).read()) | |
143 | command = "show sharp ted json" | |
144 | ||
145 | # Run test function until we get an result. Wait at most 60 seconds. | |
146 | test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) | |
147 | _, diff = topotest.run_and_expect(test_func, None, count=60, wait=2) | |
148 | assertmsg = '"{}" TED JSON output mismatches the expected result'.format(rname) | |
149 | assert diff is None, assertmsg | |
150 | ||
151 | ||
152 | def compare_cspf_output(tgen, rname, fileref, src, dst, cost, bw=""): | |
153 | "Compare CSPF output" | |
154 | ||
155 | logger.info('Comparing router "%s" CSPF output', rname) | |
156 | ||
157 | filename = "{}/reference/{}".format(CWD, fileref) | |
158 | expected = open(filename).read() | |
4b8daf6b LS |
159 | command = "show sharp cspf source {} destination {} {} {}".format( |
160 | src, dst, cost, bw | |
161 | ) | |
62f79ac1 OD |
162 | |
163 | # Run test function until we get an result. Wait at most 60 seconds. | |
4b8daf6b LS |
164 | test_func = partial( |
165 | topotest.router_output_cmp, tgen.gears[rname], command, expected | |
166 | ) | |
c6653ab2 | 167 | result, diff = topotest.run_and_expect(test_func, "", count=5, wait=2) |
4b8daf6b LS |
168 | assert result, "CSPF output mismatches the expected result on {}:\n{}".format( |
169 | rname, diff | |
170 | ) | |
171 | ||
62f79ac1 OD |
172 | |
173 | def setup_testcase(msg): | |
174 | "Setup test case" | |
175 | ||
176 | logger.info(msg) | |
177 | tgen = get_topogen() | |
178 | ||
179 | # Skip if previous fatal error condition is raised | |
180 | if tgen.routers_have_failure(): | |
181 | pytest.skip(tgen.errors) | |
182 | ||
183 | return tgen | |
184 | ||
185 | ||
186 | # Note that all routers must discover the same Network Topology, so the same TED. | |
187 | ||
188 | ||
189 | def test_step1(): | |
190 | "Step1: Check initial topology" | |
191 | ||
192 | tgen = setup_testcase("Step1: test initial IS-IS TE Data Base import") | |
193 | tgen.net["r1"].cmd('vtysh -c "sharp import-te"') | |
194 | ||
195 | compare_ted_json_output(tgen, "r1", "sharp-ted.json") | |
196 | ||
197 | ||
198 | def test_step2(): | |
199 | "Step2: Test CSPF from r1 to r4 for IPv4 with various metric" | |
200 | ||
201 | tgen = setup_testcase("Step2: CSPF(r1, r4, IPv4)") | |
202 | ||
4b8daf6b LS |
203 | compare_cspf_output( |
204 | tgen, "r1", "cspf-ipv4-metric.txt", "10.0.0.1", "10.0.255.4", "metric 50" | |
205 | ) | |
206 | compare_cspf_output( | |
207 | tgen, "r1", "cspf-ipv4-te-metric.txt", "10.0.255.1", "10.0.4.4", "te-metric 50" | |
208 | ) | |
209 | compare_cspf_output( | |
210 | tgen, "r1", "cspf-ipv4-delay.txt", "10.0.255.1", "10.0.255.4", "delay 50000" | |
211 | ) | |
212 | compare_cspf_output( | |
213 | tgen, | |
214 | "r1", | |
215 | "cspf-ipv4-delay.txt", | |
216 | "10.0.255.1", | |
217 | "10.0.255.4", | |
218 | "delay 50000", | |
219 | "rsv 7 1000000", | |
220 | ) | |
62f79ac1 OD |
221 | |
222 | ||
223 | def test_step3(): | |
224 | "Step3: Test CSPF from r1 to r4 for IPv6 with various metric" | |
225 | ||
226 | tgen = setup_testcase("Step2: CSPF(r1, r4, IPv6)") | |
227 | ||
4b8daf6b LS |
228 | compare_cspf_output( |
229 | tgen, | |
230 | "r1", | |
231 | "cspf-ipv6-metric.txt", | |
232 | "2001:db8:1::1:1", | |
233 | "2001:db8::4", | |
234 | "metric 50", | |
235 | ) | |
236 | compare_cspf_output( | |
237 | tgen, | |
238 | "r1", | |
239 | "cspf-ipv6-te-metric.txt", | |
240 | "2001:db8::1", | |
241 | "2001:db8:5::3:4", | |
242 | "te-metric 80", | |
243 | ) | |
244 | compare_cspf_output( | |
245 | tgen, "r1", "cspf-ipv6-delay.txt", "2001:db8::1", "2001:db8::4", "delay 80000" | |
246 | ) | |
247 | compare_cspf_output( | |
248 | tgen, | |
249 | "r1", | |
250 | "cspf-ipv6-delay.txt", | |
251 | "2001:db8::1", | |
252 | "2001:db8::4", | |
253 | "delay 80000", | |
254 | "rsv 7 1000000", | |
255 | ) | |
62f79ac1 OD |
256 | |
257 | ||
258 | def test_step4(): | |
259 | "Step4: Test CSPF from r1 to r4 with no possible path" | |
260 | ||
261 | tgen = setup_testcase("Step2: CSPF(r1, r4, failure)") | |
262 | ||
4b8daf6b LS |
263 | compare_cspf_output( |
264 | tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "metric 10" | |
265 | ) | |
266 | compare_cspf_output( | |
267 | tgen, "r1", "cspf-failed.txt", "2001:db8::1", "2001:db8::4", "te-metric 50" | |
268 | ) | |
269 | compare_cspf_output( | |
270 | tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "delay 5000" | |
271 | ) | |
272 | compare_cspf_output( | |
273 | tgen, | |
274 | "r1", | |
275 | "cspf-failed.txt", | |
276 | "2001:db8::1", | |
277 | "2001:db8::4", | |
278 | "delay 80000", | |
279 | "rsv 7 10000000", | |
280 | ) | |
281 | compare_cspf_output( | |
282 | tgen, "r1", "cspf-failed-src.txt", "10.0.0.3", "10.0.255.4", "metric 10" | |
283 | ) | |
284 | compare_cspf_output( | |
285 | tgen, "r1", "cspf-failed-dst.txt", "10.0.0.1", "10.0.4.40", "metric 10" | |
286 | ) | |
287 | compare_cspf_output( | |
288 | tgen, "r1", "cspf-failed-same.txt", "10.0.0.1", "10.0.0.1", "metric 10" | |
289 | ) | |
62f79ac1 OD |
290 | |
291 | ||
292 | def test_memory_leak(): | |
293 | "Run the memory leak test and report results." | |
294 | ||
295 | tgen = get_topogen() | |
296 | if not tgen.is_memleak_enabled(): | |
297 | pytest.skip("Memory leak test/report is disabled") | |
298 | ||
299 | tgen.report_memory_leaks() | |
300 | ||
301 | ||
302 | if __name__ == "__main__": | |
303 | args = ["-s"] + sys.argv[1:] | |
304 | sys.exit(pytest.main(args)) |