Total Complexity | 80 |
Total Lines | 1612 |
Duplicated Lines | 1.61 % |
Changes | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like build.tests.unit.models.test_evc_deploy often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | """Method to thest EVCDeploy class.""" |
||
2 | import sys |
||
3 | from unittest import TestCase |
||
4 | from unittest.mock import MagicMock, Mock, patch, call |
||
5 | |||
6 | from kytos.core.common import EntityStatus |
||
7 | from kytos.core.exceptions import KytosNoTagAvailableError |
||
8 | from kytos.core.interface import Interface |
||
9 | from kytos.core.switch import Switch |
||
10 | from kytos.lib.helpers import get_controller_mock |
||
11 | |||
12 | # pylint: disable=wrong-import-position |
||
13 | sys.path.insert(0, "/var/lib/kytos/napps/..") |
||
14 | # pylint: enable=wrong-import-position |
||
15 | |||
16 | from napps.kytos.mef_eline.models import EVC, EVCDeploy, Path # NOQA |
||
17 | from napps.kytos.mef_eline.settings import ( |
||
18 | MANAGER_URL, |
||
19 | SDN_TRACE_CP_URL, |
||
20 | EVPL_SB_PRIORITY, |
||
21 | EPL_SB_PRIORITY |
||
22 | ) # NOQA |
||
23 | from napps.kytos.mef_eline.exceptions import FlowModException # NOQA |
||
24 | from napps.kytos.mef_eline.tests.helpers import ( |
||
25 | get_link_mocked, |
||
26 | get_uni_mocked, |
||
27 | ) # NOQA |
||
28 | |||
29 | |||
30 | # pylint: disable=too-many-public-methods, too-many-lines |
||
31 | class TestEVC(TestCase): |
||
32 | """Tests to verify EVC class.""" |
||
33 | |||
34 | def setUp(self): |
||
35 | attributes = { |
||
36 | "controller": get_controller_mock(), |
||
37 | "name": "circuit_for_tests", |
||
38 | "uni_a": get_uni_mocked(is_valid=True), |
||
39 | "uni_z": get_uni_mocked(is_valid=True), |
||
40 | } |
||
41 | self.evc_deploy = EVCDeploy(**attributes) |
||
42 | |||
43 | def test_primary_links_zipped(self): |
||
44 | """Test primary links zipped method.""" |
||
45 | |||
46 | @staticmethod |
||
47 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
48 | def test_should_deploy_case1(log_mock): |
||
49 | """Test should deploy method without primary links.""" |
||
50 | log_mock.debug.return_value = True |
||
51 | attributes = { |
||
52 | "controller": get_controller_mock(), |
||
53 | "name": "custom_name", |
||
54 | "uni_a": get_uni_mocked(is_valid=True), |
||
55 | "uni_z": get_uni_mocked(is_valid=True), |
||
56 | } |
||
57 | |||
58 | evc = EVC(**attributes) |
||
59 | evc.should_deploy() |
||
60 | log_mock.debug.assert_called_with("Path is empty.") |
||
61 | |||
62 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
63 | def test_should_deploy_case2(self, log_mock): |
||
64 | """Test should deploy method with disable circuit.""" |
||
65 | log_mock.debug.return_value = True |
||
66 | attributes = { |
||
67 | "controller": get_controller_mock(), |
||
68 | "name": "custom_name", |
||
69 | "uni_a": get_uni_mocked(is_valid=True), |
||
70 | "uni_z": get_uni_mocked(is_valid=True), |
||
71 | "primary_links": [get_link_mocked(), get_link_mocked()], |
||
72 | } |
||
73 | evc = EVC(**attributes) |
||
74 | |||
75 | self.assertFalse(evc.should_deploy(attributes["primary_links"])) |
||
76 | log_mock.debug.assert_called_with(f"{evc} is disabled.") |
||
77 | |||
78 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
79 | def test_should_deploy_case3(self, log_mock): |
||
80 | """Test should deploy method with enabled and not active circuit.""" |
||
81 | log_mock.debug.return_value = True |
||
82 | attributes = { |
||
83 | "controller": get_controller_mock(), |
||
84 | "name": "custom_name", |
||
85 | "uni_a": get_uni_mocked(is_valid=True), |
||
86 | "uni_z": get_uni_mocked(is_valid=True), |
||
87 | "primary_links": [get_link_mocked(), get_link_mocked()], |
||
88 | "enabled": True, |
||
89 | } |
||
90 | evc = EVC(**attributes) |
||
91 | self.assertTrue(evc.should_deploy(attributes["primary_links"])) |
||
92 | log_mock.debug.assert_called_with(f"{evc} will be deployed.") |
||
93 | |||
94 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
95 | def test_should_deploy_case4(self, log_mock): |
||
96 | """Test should deploy method with enabled and active circuit.""" |
||
97 | log_mock.debug.return_value = True |
||
98 | attributes = { |
||
99 | "controller": get_controller_mock(), |
||
100 | "name": "custom_name", |
||
101 | "uni_a": get_uni_mocked(is_valid=True), |
||
102 | "uni_z": get_uni_mocked(is_valid=True), |
||
103 | "primary_links": [get_link_mocked(), get_link_mocked()], |
||
104 | "enabled": True, |
||
105 | "active": True, |
||
106 | } |
||
107 | evc = EVC(**attributes) |
||
108 | self.assertFalse(evc.should_deploy(attributes["primary_links"])) |
||
109 | |||
110 | @patch("napps.kytos.mef_eline.models.evc.requests") |
||
111 | def test_send_flow_mods_case1(self, requests_mock): |
||
112 | """Test if you are sending flow_mods.""" |
||
113 | flow_mods = {"id": 20} |
||
114 | switch = Mock(spec=Switch, id=1) |
||
115 | |||
116 | response = MagicMock() |
||
117 | response.status_code = 201 |
||
118 | requests_mock.post.return_value = response |
||
119 | |||
120 | # pylint: disable=protected-access |
||
121 | EVC._send_flow_mods(switch.id, flow_mods) |
||
122 | |||
123 | expected_endpoint = f"{MANAGER_URL}/flows/{switch.id}" |
||
124 | expected_data = {"flows": flow_mods, "force": False} |
||
125 | self.assertEqual(requests_mock.post.call_count, 1) |
||
126 | requests_mock.post.assert_called_once_with( |
||
127 | expected_endpoint, json=expected_data |
||
128 | ) |
||
129 | |||
130 | @patch("napps.kytos.mef_eline.models.evc.requests") |
||
131 | def test_send_flow_mods_case2(self, requests_mock): |
||
132 | """Test if you are sending flow_mods.""" |
||
133 | flow_mods = {"id": 20} |
||
134 | switch = Mock(spec=Switch, id=1) |
||
135 | response = MagicMock() |
||
136 | response.status_code = 201 |
||
137 | requests_mock.post.return_value = response |
||
138 | |||
139 | # pylint: disable=protected-access |
||
140 | EVC._send_flow_mods(switch.id, flow_mods, command='delete', force=True) |
||
141 | |||
142 | expected_endpoint = f"{MANAGER_URL}/delete/{switch.id}" |
||
143 | expected_data = {"flows": flow_mods, "force": True} |
||
144 | self.assertEqual(requests_mock.post.call_count, 1) |
||
145 | requests_mock.post.assert_called_once_with( |
||
146 | expected_endpoint, json=expected_data |
||
147 | ) |
||
148 | |||
149 | @patch("napps.kytos.mef_eline.models.evc.requests") |
||
150 | def test_send_flow_mods_error(self, requests_mock): |
||
151 | """Test flow_manager call fails.""" |
||
152 | flow_mods = {"id": 20} |
||
153 | switch = Mock(spec=Switch, id=1) |
||
154 | response = MagicMock() |
||
155 | response.status_code = 415 |
||
156 | requests_mock.post.return_value = response |
||
157 | |||
158 | # pylint: disable=protected-access |
||
159 | with self.assertRaises(FlowModException): |
||
160 | EVC._send_flow_mods( |
||
161 | switch.id, |
||
162 | flow_mods, |
||
163 | command='delete', |
||
164 | force=True |
||
165 | ) |
||
166 | |||
167 | def test_prepare_flow_mod(self): |
||
168 | """Test prepare flow_mod method.""" |
||
169 | interface_a = Interface("eth0", 1, Mock(spec=Switch)) |
||
170 | interface_z = Interface("eth1", 3, Mock(spec=Switch)) |
||
171 | attributes = { |
||
172 | "controller": get_controller_mock(), |
||
173 | "name": "custom_name", |
||
174 | "uni_a": get_uni_mocked(is_valid=True), |
||
175 | "uni_z": get_uni_mocked(is_valid=True), |
||
176 | "primary_links": [get_link_mocked(), get_link_mocked()], |
||
177 | "enabled": True, |
||
178 | "active": True, |
||
179 | } |
||
180 | evc = EVC(**attributes) |
||
181 | |||
182 | # pylint: disable=protected-access |
||
183 | flow_mod = evc._prepare_flow_mod(interface_a, interface_z) |
||
184 | expected_flow_mod = { |
||
185 | "match": {"in_port": interface_a.port_number}, |
||
186 | "cookie": evc.get_cookie(), |
||
187 | "actions": [ |
||
188 | {"action_type": "output", "port": interface_z.port_number} |
||
189 | ], |
||
190 | "priority": EVPL_SB_PRIORITY, |
||
191 | } |
||
192 | self.assertEqual(expected_flow_mod, flow_mod) |
||
193 | |||
194 | def test_prepare_pop_flow(self): |
||
195 | """Test prepare pop flow method.""" |
||
196 | attributes = { |
||
197 | "controller": get_controller_mock(), |
||
198 | "name": "custom_name", |
||
199 | "uni_a": get_uni_mocked(interface_port=1, is_valid=True), |
||
200 | "uni_z": get_uni_mocked(interface_port=2, is_valid=True), |
||
201 | } |
||
202 | evc = EVC(**attributes) |
||
203 | interface_a = evc.uni_a.interface |
||
204 | interface_z = evc.uni_z.interface |
||
205 | in_vlan = 10 |
||
206 | |||
207 | # pylint: disable=protected-access |
||
208 | flow_mod = evc._prepare_pop_flow( |
||
209 | interface_a, interface_z, in_vlan |
||
210 | ) |
||
211 | |||
212 | expected_flow_mod = { |
||
213 | "match": {"in_port": interface_a.port_number, "dl_vlan": in_vlan}, |
||
214 | "cookie": evc.get_cookie(), |
||
215 | "actions": [ |
||
216 | {"action_type": "pop_vlan"}, |
||
217 | {"action_type": "output", "port": interface_z.port_number}, |
||
218 | ], |
||
219 | "priority": EVPL_SB_PRIORITY, |
||
220 | } |
||
221 | self.assertEqual(expected_flow_mod, flow_mod) |
||
222 | |||
223 | def test_prepare_push_flow(self): |
||
224 | """Test prepare push flow method.""" |
||
225 | attributes = { |
||
226 | "controller": get_controller_mock(), |
||
227 | "name": "custom_name", |
||
228 | "uni_a": get_uni_mocked(interface_port=1, is_valid=True), |
||
229 | "uni_z": get_uni_mocked(interface_port=2, is_valid=True), |
||
230 | } |
||
231 | evc = EVC(**attributes) |
||
232 | interface_a = evc.uni_a.interface |
||
233 | interface_z = evc.uni_z.interface |
||
234 | out_vlan_a = 20 |
||
235 | |||
236 | for in_vlan_a in [100, "4096/4096", 0, None]: |
||
237 | for in_vlan_z in [50, "4096/4096", 0, None]: |
||
238 | with self.subTest(in_vlan_a=in_vlan_a, in_vlan_z=in_vlan_z): |
||
239 | # pylint: disable=protected-access |
||
240 | flow_mod = evc._prepare_push_flow(interface_a, interface_z, |
||
241 | in_vlan_a, out_vlan_a, |
||
242 | in_vlan_z) |
||
243 | expected_flow_mod = { |
||
244 | 'match': {'in_port': interface_a.port_number}, |
||
245 | 'cookie': evc.get_cookie(), |
||
246 | 'actions': [ |
||
247 | {'action_type': 'push_vlan', 'tag_type': 's'}, |
||
248 | {'action_type': 'set_vlan', 'vlan_id': out_vlan_a}, |
||
249 | { |
||
250 | 'action_type': 'output', |
||
251 | 'port': interface_z.port_number |
||
252 | } |
||
253 | ], |
||
254 | "priority": EVPL_SB_PRIORITY, |
||
255 | } |
||
256 | if in_vlan_a is not None: |
||
257 | expected_flow_mod['match']['dl_vlan'] = in_vlan_a |
||
258 | else: |
||
259 | expected_flow_mod['priority'] = EPL_SB_PRIORITY |
||
260 | |||
261 | if in_vlan_z not in {"4096/4096", 0, None}: |
||
262 | new_action = {"action_type": "set_vlan", |
||
263 | "vlan_id": in_vlan_z} |
||
264 | expected_flow_mod["actions"].insert(0, new_action) |
||
265 | |||
266 | View Code Duplication | if in_vlan_a not in {"4096/4096", 0, None}: |
|
|
|||
267 | if in_vlan_z == 0: |
||
268 | new_action = {"action_type": "pop_vlan"} |
||
269 | expected_flow_mod["actions"].insert(0, new_action) |
||
270 | elif in_vlan_a == "4096/4096": |
||
271 | if in_vlan_z == 0: |
||
272 | new_action = {"action_type": "pop_vlan"} |
||
273 | expected_flow_mod["actions"].insert(0, new_action) |
||
274 | elif not in_vlan_a: |
||
275 | if in_vlan_z not in {"4096/4096", 0, None}: |
||
276 | new_action = {"action_type": "push_vlan", |
||
277 | "tag_type": "c"} |
||
278 | expected_flow_mod["actions"].insert(0, new_action) |
||
279 | self.assertEqual(expected_flow_mod, flow_mod) |
||
280 | |||
281 | if in_vlan_z not in {"4096/4096", 0, None}: |
||
282 | new_action = {"action_type": "set_vlan", |
||
283 | "vlan_id": in_vlan_z} |
||
284 | expected_flow_mod["actions"].insert(0, new_action) |
||
285 | |||
286 | View Code Duplication | if in_vlan_a not in {"4096/4096", 0, None}: |
|
287 | if in_vlan_z == 0: |
||
288 | new_action = {"action_type": "pop_vlan"} |
||
289 | expected_flow_mod["actions"].insert(0, new_action) |
||
290 | elif in_vlan_a == "4096/4096": |
||
291 | if in_vlan_z == 0: |
||
292 | new_action = {"action_type": "pop_vlan"} |
||
293 | expected_flow_mod["actions"].insert(0, new_action) |
||
294 | elif not in_vlan_a: |
||
295 | if in_vlan_z not in {"4096/4096", 0, None}: |
||
296 | new_action = {"action_type": "push_vlan", |
||
297 | "tag_type": "c"} |
||
298 | expected_flow_mod["actions"].insert(0, new_action) |
||
299 | self.assertEqual(expected_flow_mod, flow_mod) |
||
300 | |||
301 | @staticmethod |
||
302 | @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods") |
||
303 | def test_install_uni_flows(send_flow_mods_mock): |
||
304 | """Test install uni flows method. |
||
305 | |||
306 | This test will verify the flows send to the send_flow_mods method. |
||
307 | """ |
||
308 | evc = TestEVC.create_evc_inter_switch() |
||
309 | |||
310 | # pylint: disable=protected-access |
||
311 | evc._install_uni_flows() |
||
312 | send_flow_mods_mock.assert_not_called() |
||
313 | |||
314 | # pylint: disable=protected-access |
||
315 | evc._install_uni_flows(evc.primary_links) |
||
316 | |||
317 | expected_flow_mod_a = [ |
||
318 | { |
||
319 | "match": { |
||
320 | "in_port": evc.uni_a.interface.port_number, |
||
321 | "dl_vlan": evc.uni_a.user_tag.value, |
||
322 | }, |
||
323 | "cookie": evc.get_cookie(), |
||
324 | "actions": [ |
||
325 | { |
||
326 | "action_type": "set_vlan", |
||
327 | "vlan_id": evc.uni_z.user_tag.value |
||
328 | }, |
||
329 | {"action_type": "push_vlan", "tag_type": "s"}, |
||
330 | { |
||
331 | "action_type": "set_vlan", |
||
332 | "vlan_id": evc.primary_links[0] |
||
333 | .get_metadata("s_vlan") |
||
334 | .value, |
||
335 | }, |
||
336 | { |
||
337 | "action_type": "output", |
||
338 | "port": evc.primary_links[0].endpoint_a.port_number, |
||
339 | }, |
||
340 | ], |
||
341 | "priority": EVPL_SB_PRIORITY, |
||
342 | }, |
||
343 | { |
||
344 | "match": { |
||
345 | "in_port": evc.primary_links[0].endpoint_a.port_number, |
||
346 | "dl_vlan": evc.primary_links[0] |
||
347 | .get_metadata("s_vlan") |
||
348 | .value, |
||
349 | }, |
||
350 | "cookie": evc.get_cookie(), |
||
351 | "actions": [ |
||
352 | {"action_type": "pop_vlan"}, |
||
353 | { |
||
354 | "action_type": "output", |
||
355 | "port": evc.uni_a.interface.port_number, |
||
356 | }, |
||
357 | ], |
||
358 | "priority": EVPL_SB_PRIORITY, |
||
359 | }, |
||
360 | ] |
||
361 | |||
362 | send_flow_mods_mock.assert_any_call( |
||
363 | evc.uni_a.interface.switch.id, expected_flow_mod_a |
||
364 | ) |
||
365 | |||
366 | expected_flow_mod_z = [ |
||
367 | { |
||
368 | "match": { |
||
369 | "in_port": evc.uni_z.interface.port_number, |
||
370 | "dl_vlan": evc.uni_z.user_tag.value, |
||
371 | }, |
||
372 | "cookie": evc.get_cookie(), |
||
373 | "actions": [ |
||
374 | { |
||
375 | "action_type": "set_vlan", |
||
376 | "vlan_id": evc.uni_a.user_tag.value |
||
377 | }, |
||
378 | {"action_type": "push_vlan", "tag_type": "s"}, |
||
379 | { |
||
380 | "action_type": "set_vlan", |
||
381 | "vlan_id": evc.primary_links[-1] |
||
382 | .get_metadata("s_vlan") |
||
383 | .value, |
||
384 | }, |
||
385 | { |
||
386 | "action_type": "output", |
||
387 | "port": evc.primary_links[-1].endpoint_b.port_number, |
||
388 | }, |
||
389 | ], |
||
390 | "priority": EVPL_SB_PRIORITY, |
||
391 | }, |
||
392 | { |
||
393 | "match": { |
||
394 | "in_port": evc.primary_links[-1].endpoint_b.port_number, |
||
395 | "dl_vlan": evc.primary_links[-1] |
||
396 | .get_metadata("s_vlan") |
||
397 | .value, |
||
398 | }, |
||
399 | "cookie": evc.get_cookie(), |
||
400 | "actions": [ |
||
401 | {"action_type": "pop_vlan"}, |
||
402 | { |
||
403 | "action_type": "output", |
||
404 | "port": evc.uni_z.interface.port_number, |
||
405 | }, |
||
406 | ], |
||
407 | "priority": EVPL_SB_PRIORITY, |
||
408 | }, |
||
409 | ] |
||
410 | |||
411 | send_flow_mods_mock.assert_any_call( |
||
412 | evc.uni_z.interface.switch.id, expected_flow_mod_z |
||
413 | ) |
||
414 | |||
415 | @staticmethod |
||
416 | def create_evc_inter_switch(): |
||
417 | """Create inter-switch EVC with two links in the path""" |
||
418 | uni_a = get_uni_mocked( |
||
419 | interface_port=2, |
||
420 | tag_value=82, |
||
421 | switch_id=1, |
||
422 | switch_dpid=1, |
||
423 | is_valid=True, |
||
424 | ) |
||
425 | uni_z = get_uni_mocked( |
||
426 | interface_port=3, |
||
427 | tag_value=83, |
||
428 | switch_id=3, |
||
429 | switch_dpid=3, |
||
430 | is_valid=True, |
||
431 | ) |
||
432 | |||
433 | attributes = { |
||
434 | "controller": get_controller_mock(), |
||
435 | "name": "custom_name", |
||
436 | "id": "1", |
||
437 | "uni_a": uni_a, |
||
438 | "uni_z": uni_z, |
||
439 | "primary_links": [ |
||
440 | get_link_mocked( |
||
441 | switch_a=Switch(1), |
||
442 | switch_b=Switch(2), |
||
443 | endpoint_a_port=9, |
||
444 | endpoint_b_port=10, |
||
445 | metadata={"s_vlan": 5}, |
||
446 | ), |
||
447 | get_link_mocked( |
||
448 | switch_a=Switch(2), |
||
449 | switch_b=Switch(3), |
||
450 | endpoint_a_port=11, |
||
451 | endpoint_b_port=12, |
||
452 | metadata={"s_vlan": 6}, |
||
453 | ), |
||
454 | ], |
||
455 | } |
||
456 | return EVC(**attributes) |
||
457 | |||
458 | @staticmethod |
||
459 | @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods") |
||
460 | def test_install_nni_flows(send_flow_mods_mock): |
||
461 | """Test install nni flows method. |
||
462 | |||
463 | This test will verify the flows send to the send_flow_mods method. |
||
464 | """ |
||
465 | evc = TestEVC.create_evc_inter_switch() |
||
466 | |||
467 | # pylint: disable=protected-access |
||
468 | evc._install_nni_flows(evc.primary_links) |
||
469 | |||
470 | in_vlan = evc.primary_links[0].get_metadata("s_vlan").value |
||
471 | out_vlan = evc.primary_links[-1].get_metadata("s_vlan").value |
||
472 | |||
473 | in_port = evc.primary_links[0].endpoint_b.port_number |
||
474 | out_port = evc.primary_links[-1].endpoint_a.port_number |
||
475 | |||
476 | expected_flow_mods = [ |
||
477 | { |
||
478 | "match": {"in_port": in_port, "dl_vlan": in_vlan}, |
||
479 | "cookie": evc.get_cookie(), |
||
480 | "actions": [ |
||
481 | {"action_type": "set_vlan", "vlan_id": out_vlan}, |
||
482 | {"action_type": "output", "port": out_port}, |
||
483 | ], |
||
484 | "priority": EVPL_SB_PRIORITY |
||
485 | }, |
||
486 | { |
||
487 | "match": {"in_port": out_port, "dl_vlan": out_vlan}, |
||
488 | "cookie": evc.get_cookie(), |
||
489 | "actions": [ |
||
490 | {"action_type": "set_vlan", "vlan_id": in_vlan}, |
||
491 | {"action_type": "output", "port": in_port}, |
||
492 | ], |
||
493 | "priority": EVPL_SB_PRIORITY, |
||
494 | }, |
||
495 | ] |
||
496 | |||
497 | dpid = evc.primary_links[0].endpoint_b.switch.id |
||
498 | send_flow_mods_mock.assert_called_once_with(dpid, expected_flow_mods) |
||
499 | |||
500 | @patch("requests.post") |
||
501 | @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc") |
||
502 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
503 | @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans") |
||
504 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows") |
||
505 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows") |
||
506 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_direct_uni_flows") |
||
507 | @patch("napps.kytos.mef_eline.models.evc.EVC.activate") |
||
508 | @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy") |
||
509 | def test_deploy_successfully(self, *args): |
||
510 | """Test if all methods to deploy are called.""" |
||
511 | # pylint: disable=too-many-locals |
||
512 | ( |
||
513 | should_deploy_mock, |
||
514 | activate_mock, |
||
515 | install_direct_uni_flows_mock, |
||
516 | install_uni_flows_mock, |
||
517 | install_nni_flows, |
||
518 | chose_vlans_mock, |
||
519 | log_mock, |
||
520 | _, |
||
521 | requests_mock, |
||
522 | ) = args |
||
523 | |||
524 | response = MagicMock() |
||
525 | response.status_code = 201 |
||
526 | requests_mock.return_value = response |
||
527 | |||
528 | should_deploy_mock.return_value = True |
||
529 | evc = self.create_evc_inter_switch() |
||
530 | deployed = evc.deploy_to_path(evc.primary_links) |
||
531 | |||
532 | self.assertEqual(should_deploy_mock.call_count, 1) |
||
533 | self.assertEqual(activate_mock.call_count, 1) |
||
534 | self.assertEqual(install_uni_flows_mock.call_count, 1) |
||
535 | self.assertEqual(install_nni_flows.call_count, 1) |
||
536 | self.assertEqual(chose_vlans_mock.call_count, 1) |
||
537 | log_mock.info.assert_called_with(f"{evc} was deployed.") |
||
538 | self.assertTrue(deployed) |
||
539 | |||
540 | # intra switch EVC |
||
541 | evc = self.create_evc_intra_switch() |
||
542 | self.assertTrue(evc.deploy_to_path(evc.primary_links)) |
||
543 | self.assertEqual(install_direct_uni_flows_mock.call_count, 1) |
||
544 | self.assertEqual(activate_mock.call_count, 2) |
||
545 | self.assertEqual(log_mock.info.call_count, 2) |
||
546 | log_mock.info.assert_called_with(f"{evc} was deployed.") |
||
547 | |||
548 | @patch("requests.post") |
||
549 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
550 | @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths") |
||
551 | @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans") |
||
552 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows") |
||
553 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows") |
||
554 | @patch("napps.kytos.mef_eline.models.evc.EVC.activate") |
||
555 | @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy") |
||
556 | @patch("napps.kytos.mef_eline.models.EVC.sync") |
||
557 | def test_deploy_fail(self, *args): |
||
558 | """Test if all methods is ignored when the should_deploy is false.""" |
||
559 | # pylint: disable=too-many-locals |
||
560 | ( |
||
561 | sync_mock, |
||
562 | should_deploy_mock, |
||
563 | activate_mock, |
||
564 | install_uni_flows_mock, |
||
565 | install_nni_flows, |
||
566 | choose_vlans_mock, |
||
567 | discover_new_paths_mock, |
||
568 | log_mock, |
||
569 | requests_mock, |
||
570 | ) = args |
||
571 | |||
572 | response = MagicMock() |
||
573 | response.status_code = 201 |
||
574 | requests_mock.return_value = response |
||
575 | |||
576 | evc = self.create_evc_inter_switch() |
||
577 | should_deploy_mock.return_value = False |
||
578 | discover_new_paths_mock.return_value = [] |
||
579 | deployed = evc.deploy_to_path() |
||
580 | |||
581 | self.assertEqual(discover_new_paths_mock.call_count, 1) |
||
582 | self.assertEqual(should_deploy_mock.call_count, 1) |
||
583 | self.assertEqual(activate_mock.call_count, 0) |
||
584 | self.assertEqual(install_uni_flows_mock.call_count, 0) |
||
585 | self.assertEqual(install_nni_flows.call_count, 0) |
||
586 | self.assertEqual(choose_vlans_mock.call_count, 0) |
||
587 | self.assertEqual(log_mock.info.call_count, 0) |
||
588 | self.assertEqual(sync_mock.call_count, 1) |
||
589 | self.assertFalse(deployed) |
||
590 | |||
591 | # NoTagAvailable on static path |
||
592 | should_deploy_mock.return_value = True |
||
593 | choose_vlans_mock.side_effect = KytosNoTagAvailableError("error") |
||
594 | self.assertFalse(evc.deploy_to_path(evc.primary_links)) |
||
595 | |||
596 | # NoTagAvailable on dynamic path |
||
597 | should_deploy_mock.return_value = False |
||
598 | discover_new_paths_mock.return_value = [Path(['a', 'b'])] |
||
599 | choose_vlans_mock.side_effect = KytosNoTagAvailableError("error") |
||
600 | self.assertFalse(evc.deploy_to_path(evc.primary_links)) |
||
601 | |||
602 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
603 | @patch( |
||
604 | "napps.kytos.mef_eline.models.evc.EVC.discover_new_paths", |
||
605 | return_value=[], |
||
606 | ) |
||
607 | @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans") |
||
608 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows") |
||
609 | @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy") |
||
610 | @patch("napps.kytos.mef_eline.models.evc.EVC.remove_current_flows") |
||
611 | @patch("napps.kytos.mef_eline.models.evc.EVC.sync") |
||
612 | def test_deploy_error(self, *args): |
||
613 | """Test if all methods is ignored when the should_deploy is false.""" |
||
614 | # pylint: disable=too-many-locals |
||
615 | ( |
||
616 | sync_mock, |
||
617 | remove_current_flows, |
||
618 | should_deploy_mock, |
||
619 | install_nni_flows, |
||
620 | choose_vlans_mock, |
||
621 | discover_new_paths, |
||
622 | log_mock, |
||
623 | ) = args |
||
624 | |||
625 | install_nni_flows.side_effect = FlowModException |
||
626 | should_deploy_mock.return_value = True |
||
627 | uni_a = get_uni_mocked( |
||
628 | interface_port=2, |
||
629 | tag_value=82, |
||
630 | switch_id="switch_uni_a", |
||
631 | is_valid=True, |
||
632 | ) |
||
633 | uni_z = get_uni_mocked( |
||
634 | interface_port=3, |
||
635 | tag_value=83, |
||
636 | switch_id="switch_uni_z", |
||
637 | is_valid=True, |
||
638 | ) |
||
639 | |||
640 | primary_links = [ |
||
641 | get_link_mocked( |
||
642 | endpoint_a_port=9, endpoint_b_port=10, metadata={"s_vlan": 5} |
||
643 | ), |
||
644 | get_link_mocked( |
||
645 | endpoint_a_port=11, endpoint_b_port=12, metadata={"s_vlan": 6} |
||
646 | ), |
||
647 | ] |
||
648 | |||
649 | attributes = { |
||
650 | "controller": get_controller_mock(), |
||
651 | "name": "custom_name", |
||
652 | "uni_a": uni_a, |
||
653 | "uni_z": uni_z, |
||
654 | "primary_links": primary_links, |
||
655 | "queue_id": 5, |
||
656 | } |
||
657 | # Setup path to deploy |
||
658 | path = Path() |
||
659 | path.append(primary_links[0]) |
||
660 | path.append(primary_links[1]) |
||
661 | |||
662 | evc = EVC(**attributes) |
||
663 | |||
664 | deployed = evc.deploy_to_path(path) |
||
665 | |||
666 | self.assertEqual(discover_new_paths.call_count, 0) |
||
667 | self.assertEqual(should_deploy_mock.call_count, 1) |
||
668 | self.assertEqual(install_nni_flows.call_count, 1) |
||
669 | self.assertEqual(choose_vlans_mock.call_count, 1) |
||
670 | self.assertEqual(log_mock.error.call_count, 1) |
||
671 | self.assertEqual(sync_mock.call_count, 0) |
||
672 | self.assertEqual(remove_current_flows.call_count, 2) |
||
673 | self.assertFalse(deployed) |
||
674 | |||
675 | @patch("napps.kytos.mef_eline.models.evc.notify_link_available_tags") |
||
676 | @patch("napps.kytos.mef_eline.models.evc.EVC.get_failover_path_candidates") |
||
677 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows") |
||
678 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows") |
||
679 | @patch("napps.kytos.mef_eline.models.evc.EVC.remove_path_flows") |
||
680 | @patch("napps.kytos.mef_eline.models.EVC.sync") |
||
681 | def test_setup_failover_path(self, *args): |
||
682 | """Test setup_failover_path method.""" |
||
683 | ( |
||
684 | sync_mock, |
||
685 | remove_path_flows_mock, |
||
686 | install_uni_flows_mock, |
||
687 | install_nni_flows_mock, |
||
688 | get_failover_path_candidates_mock, |
||
689 | notify_mock, |
||
690 | ) = args |
||
691 | |||
692 | # case1: early return intra switch |
||
693 | evc1 = self.create_evc_intra_switch() |
||
694 | |||
695 | self.assertFalse(evc1.setup_failover_path()) |
||
696 | self.assertEqual(sync_mock.call_count, 0) |
||
697 | |||
698 | # case2: early return not eligible for path failover |
||
699 | evc2 = self.create_evc_inter_switch() |
||
700 | evc2.is_eligible_for_failover_path = MagicMock(return_value=False) |
||
701 | |||
702 | self.assertFalse(evc2.setup_failover_path()) |
||
703 | self.assertEqual(sync_mock.call_count, 0) |
||
704 | |||
705 | # case3: success failover_path setup |
||
706 | evc2.is_eligible_for_failover_path = MagicMock(return_value=True) |
||
707 | evc2.failover_path = ["link1", "link2"] |
||
708 | path_mock = MagicMock() |
||
709 | path_mock.__iter__.return_value = ["link3"] |
||
710 | get_failover_path_candidates_mock.return_value = [None, path_mock] |
||
711 | |||
712 | self.assertTrue(evc2.setup_failover_path()) |
||
713 | remove_path_flows_mock.assert_called_with(["link1", "link2"]) |
||
714 | path_mock.choose_vlans.assert_called() |
||
715 | notify_mock.assert_called() |
||
716 | install_nni_flows_mock.assert_called_with(path_mock) |
||
717 | install_uni_flows_mock.assert_called_with(path_mock, skip_in=True) |
||
718 | self.assertEqual(evc2.failover_path, path_mock) |
||
719 | self.assertEqual(sync_mock.call_count, 1) |
||
720 | |||
721 | # case 4: failed to setup failover_path - No Tag available |
||
722 | evc2.failover_path = [] |
||
723 | path_mock.choose_vlans.side_effect = KytosNoTagAvailableError("error") |
||
724 | sync_mock.call_count = 0 |
||
725 | |||
726 | self.assertFalse(evc2.setup_failover_path()) |
||
727 | self.assertEqual(list(evc2.failover_path), []) |
||
728 | self.assertEqual(sync_mock.call_count, 1) |
||
729 | |||
730 | # case 5: failed to setup failover_path - FlowMod exception |
||
731 | evc2.failover_path = [] |
||
732 | path_mock.choose_vlans.side_effect = None |
||
733 | install_nni_flows_mock.side_effect = FlowModException("error") |
||
734 | sync_mock.call_count = 0 |
||
735 | |||
736 | self.assertFalse(evc2.setup_failover_path()) |
||
737 | self.assertEqual(list(evc2.failover_path), []) |
||
738 | self.assertEqual(sync_mock.call_count, 1) |
||
739 | remove_path_flows_mock.assert_called_with(path_mock) |
||
740 | |||
741 | @patch("napps.kytos.mef_eline.models.evc.EVC.deploy_to_path") |
||
742 | @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths") |
||
743 | def test_deploy_to_backup_path1( |
||
744 | self, discover_new_paths_mocked, deploy_to_path_mocked |
||
745 | ): |
||
746 | """Test deployment when dynamic_backup_path is False in same switch""" |
||
747 | uni_a = get_uni_mocked(interface_port=2, tag_value=82, is_valid=True) |
||
748 | uni_z = get_uni_mocked(interface_port=3, tag_value=83, is_valid=True) |
||
749 | |||
750 | switch = Mock(spec=Switch) |
||
751 | uni_a.interface.switch = switch |
||
752 | uni_z.interface.switch = switch |
||
753 | |||
754 | attributes = { |
||
755 | "controller": get_controller_mock(), |
||
756 | "name": "custom_name", |
||
757 | "uni_a": uni_a, |
||
758 | "uni_z": uni_z, |
||
759 | "enabled": True, |
||
760 | "dynamic_backup_path": False, |
||
761 | } |
||
762 | |||
763 | evc = EVC(**attributes) |
||
764 | discover_new_paths_mocked.return_value = [] |
||
765 | deploy_to_path_mocked.return_value = True |
||
766 | |||
767 | deployed = evc.deploy_to_backup_path() |
||
768 | |||
769 | deploy_to_path_mocked.assert_called_once_with() |
||
770 | self.assertEqual(deployed, True) |
||
771 | |||
772 | @patch("requests.post") |
||
773 | @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc") |
||
774 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
775 | @patch("napps.kytos.mef_eline.models.path.Path.choose_vlans") |
||
776 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_nni_flows") |
||
777 | @patch("napps.kytos.mef_eline.models.evc.EVC._install_uni_flows") |
||
778 | @patch("napps.kytos.mef_eline.models.evc.EVC.activate") |
||
779 | @patch("napps.kytos.mef_eline.models.evc.EVC.should_deploy") |
||
780 | @patch("napps.kytos.mef_eline.models.evc.EVC.discover_new_paths") |
||
781 | def test_deploy_without_path_case1(self, *args): |
||
782 | """Test if not path is found a dynamic path is used.""" |
||
783 | # pylint: disable=too-many-locals |
||
784 | ( |
||
785 | discover_new_paths_mocked, |
||
786 | should_deploy_mock, |
||
787 | activate_mock, |
||
788 | install_uni_flows_mock, |
||
789 | install_nni_flows, |
||
790 | chose_vlans_mock, |
||
791 | log_mock, |
||
792 | _, |
||
793 | requests_mock, |
||
794 | ) = args |
||
795 | |||
796 | response = MagicMock() |
||
797 | response.status_code = 201 |
||
798 | requests_mock.return_value = response |
||
799 | |||
800 | should_deploy_mock.return_value = False |
||
801 | uni_a = get_uni_mocked( |
||
802 | interface_port=2, |
||
803 | tag_value=82, |
||
804 | switch_id="switch_uni_a", |
||
805 | is_valid=True, |
||
806 | ) |
||
807 | uni_z = get_uni_mocked( |
||
808 | interface_port=3, |
||
809 | tag_value=83, |
||
810 | switch_id="switch_uni_z", |
||
811 | is_valid=True, |
||
812 | ) |
||
813 | |||
814 | attributes = { |
||
815 | "controller": get_controller_mock(), |
||
816 | "name": "custom_name", |
||
817 | "uni_a": uni_a, |
||
818 | "uni_z": uni_z, |
||
819 | "enabled": True, |
||
820 | "dynamic_backup_path": False, |
||
821 | } |
||
822 | |||
823 | dynamic_backup_path = Path( |
||
824 | [ |
||
825 | get_link_mocked( |
||
826 | endpoint_a_port=9, |
||
827 | endpoint_b_port=10, |
||
828 | metadata={"s_vlan": 5}, |
||
829 | ), |
||
830 | get_link_mocked( |
||
831 | endpoint_a_port=11, |
||
832 | endpoint_b_port=12, |
||
833 | metadata={"s_vlan": 6}, |
||
834 | ), |
||
835 | ] |
||
836 | ) |
||
837 | |||
838 | evc = EVC(**attributes) |
||
839 | discover_new_paths_mocked.return_value = [dynamic_backup_path] |
||
840 | |||
841 | deployed = evc.deploy_to_path() |
||
842 | |||
843 | self.assertEqual(should_deploy_mock.call_count, 1) |
||
844 | self.assertEqual(discover_new_paths_mocked.call_count, 1) |
||
845 | self.assertEqual(activate_mock.call_count, 1) |
||
846 | self.assertEqual(install_uni_flows_mock.call_count, 1) |
||
847 | self.assertEqual(install_nni_flows.call_count, 1) |
||
848 | self.assertEqual(chose_vlans_mock.call_count, 1) |
||
849 | log_mock.info.assert_called_with(f"{evc} was deployed.") |
||
850 | self.assertTrue(deployed) |
||
851 | |||
852 | @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.deploy_to_primary_path") |
||
853 | @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.deploy_to_backup_path") |
||
854 | @patch("napps.kytos.mef_eline.models.evc.emit_event") |
||
855 | def test_deploy(self, *args): |
||
856 | """Test method deploy""" |
||
857 | (emit_event_mock, deploy_primary_mock, deploy_backup_mock) = args |
||
858 | |||
859 | # case 1: deploy to primary |
||
860 | self.evc_deploy.archived = False |
||
861 | deploy_primary_mock.return_value = True |
||
862 | self.assertTrue(self.evc_deploy.deploy()) |
||
863 | self.assertEqual(emit_event_mock.call_count, 1) |
||
864 | |||
865 | # case 2: deploy to backup |
||
866 | deploy_primary_mock.return_value = False |
||
867 | deploy_backup_mock.return_value = True |
||
868 | self.assertTrue(self.evc_deploy.deploy()) |
||
869 | self.assertEqual(emit_event_mock.call_count, 2) |
||
870 | |||
871 | # case 3: fail to deploy to primary and backup |
||
872 | deploy_backup_mock.return_value = False |
||
873 | self.assertFalse(self.evc_deploy.deploy()) |
||
874 | self.assertEqual(emit_event_mock.call_count, 2) |
||
875 | |||
876 | # case 4: archived |
||
877 | self.evc_deploy.archived = True |
||
878 | self.assertFalse(self.evc_deploy.deploy()) |
||
879 | self.assertEqual(emit_event_mock.call_count, 2) |
||
880 | |||
881 | @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.remove_current_flows") |
||
882 | @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.sync") |
||
883 | @patch("napps.kytos.mef_eline.models.evc.emit_event") |
||
884 | def test_remove(self, *args): |
||
885 | """Test method remove""" |
||
886 | (emit_event_mock, sync_mock, remove_flows_mock) = args |
||
887 | self.evc_deploy.remove() |
||
888 | remove_flows_mock.assert_called() |
||
889 | sync_mock.assert_called() |
||
890 | emit_event_mock.assert_called() |
||
891 | self.assertFalse(self.evc_deploy.is_enabled()) |
||
892 | |||
893 | @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc") |
||
894 | @patch("napps.kytos.mef_eline.models.evc.notify_link_available_tags") |
||
895 | @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods") |
||
896 | @patch("napps.kytos.mef_eline.models.evc.log.error") |
||
897 | def test_remove_current_flows(self, *args): |
||
898 | """Test remove current flows.""" |
||
899 | # pylint: disable=too-many-locals |
||
900 | (log_error_mock, send_flow_mods_mocked, notify_mock, _) = args |
||
901 | uni_a = get_uni_mocked( |
||
902 | interface_port=2, |
||
903 | tag_value=82, |
||
904 | switch_id="switch_uni_a", |
||
905 | is_valid=True, |
||
906 | ) |
||
907 | uni_z = get_uni_mocked( |
||
908 | interface_port=3, |
||
909 | tag_value=83, |
||
910 | switch_id="switch_uni_z", |
||
911 | is_valid=True, |
||
912 | ) |
||
913 | |||
914 | switch_a = Switch("00:00:00:00:00:01") |
||
915 | switch_b = Switch("00:00:00:00:00:02") |
||
916 | switch_c = Switch("00:00:00:00:00:03") |
||
917 | |||
918 | attributes = { |
||
919 | "controller": get_controller_mock(), |
||
920 | "name": "custom_name", |
||
921 | "uni_a": uni_a, |
||
922 | "uni_z": uni_z, |
||
923 | "active": True, |
||
924 | "enabled": True, |
||
925 | "primary_links": [ |
||
926 | get_link_mocked( |
||
927 | switch_a=switch_a, |
||
928 | switch_b=switch_b, |
||
929 | endpoint_a_port=9, |
||
930 | endpoint_b_port=10, |
||
931 | metadata={"s_vlan": 5}, |
||
932 | ), |
||
933 | get_link_mocked( |
||
934 | switch_a=switch_b, |
||
935 | switch_b=switch_c, |
||
936 | endpoint_a_port=11, |
||
937 | endpoint_b_port=12, |
||
938 | metadata={"s_vlan": 6}, |
||
939 | ), |
||
940 | ], |
||
941 | } |
||
942 | |||
943 | evc = EVC(**attributes) |
||
944 | |||
945 | evc.current_path = evc.primary_links |
||
946 | evc.remove_current_flows() |
||
947 | notify_mock.assert_called() |
||
948 | |||
949 | self.assertEqual(send_flow_mods_mocked.call_count, 5) |
||
950 | self.assertFalse(evc.is_active()) |
||
951 | flows = [ |
||
952 | {"cookie": evc.get_cookie(), "cookie_mask": 18446744073709551615} |
||
953 | ] |
||
954 | switch_1 = evc.primary_links[0].endpoint_a.switch |
||
955 | switch_2 = evc.primary_links[0].endpoint_b.switch |
||
956 | send_flow_mods_mocked.assert_any_call(switch_1.id, flows, 'delete', |
||
957 | force=True) |
||
958 | send_flow_mods_mocked.assert_any_call(switch_2.id, flows, 'delete', |
||
959 | force=True) |
||
960 | |||
961 | send_flow_mods_mocked.side_effect = FlowModException("error") |
||
962 | evc.remove_current_flows() |
||
963 | log_error_mock.assert_called() |
||
964 | |||
965 | @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc") |
||
966 | @patch("napps.kytos.mef_eline.models.evc.notify_link_available_tags") |
||
967 | @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods") |
||
968 | @patch("napps.kytos.mef_eline.models.evc.log.error") |
||
969 | def test_remove_failover_flows_exclude_uni_switches(self, *args): |
||
970 | """Test remove failover flows excluding UNI switches.""" |
||
971 | # pylint: disable=too-many-locals |
||
972 | (log_error_mock, send_flow_mods_mocked, |
||
973 | notify_mock, mock_upsert) = args |
||
974 | uni_a = get_uni_mocked( |
||
975 | interface_port=2, |
||
976 | tag_value=82, |
||
977 | switch_id="00:00:00:00:00:00:00:01", |
||
978 | is_valid=True, |
||
979 | ) |
||
980 | uni_z = get_uni_mocked( |
||
981 | interface_port=3, |
||
982 | tag_value=83, |
||
983 | switch_id="00:00:00:00:00:00:00:03", |
||
984 | is_valid=True, |
||
985 | ) |
||
986 | |||
987 | switch_a = Switch("00:00:00:00:00:00:00:01") |
||
988 | switch_b = Switch("00:00:00:00:00:00:00:02") |
||
989 | switch_c = Switch("00:00:00:00:00:00:00:03") |
||
990 | |||
991 | attributes = { |
||
992 | "controller": get_controller_mock(), |
||
993 | "name": "custom_name", |
||
994 | "uni_a": uni_a, |
||
995 | "uni_z": uni_z, |
||
996 | "active": True, |
||
997 | "enabled": True, |
||
998 | "failover_path": [ |
||
999 | get_link_mocked( |
||
1000 | switch_a=switch_a, |
||
1001 | switch_b=switch_b, |
||
1002 | endpoint_a_port=9, |
||
1003 | endpoint_b_port=10, |
||
1004 | metadata={"s_vlan": 5}, |
||
1005 | ), |
||
1006 | get_link_mocked( |
||
1007 | switch_a=switch_b, |
||
1008 | switch_b=switch_c, |
||
1009 | endpoint_a_port=11, |
||
1010 | endpoint_b_port=12, |
||
1011 | metadata={"s_vlan": 6}, |
||
1012 | ), |
||
1013 | ], |
||
1014 | } |
||
1015 | |||
1016 | evc = EVC(**attributes) |
||
1017 | evc.remove_failover_flows(exclude_uni_switches=True, sync=True) |
||
1018 | notify_mock.assert_called() |
||
1019 | |||
1020 | assert send_flow_mods_mocked.call_count == 1 |
||
1021 | flows = [ |
||
1022 | {"cookie": evc.get_cookie(), |
||
1023 | "cookie_mask": int(0xffffffffffffffff)} |
||
1024 | ] |
||
1025 | send_flow_mods_mocked.assert_any_call(switch_b.id, flows, 'delete', |
||
1026 | force=True) |
||
1027 | assert mock_upsert.call_count == 1 |
||
1028 | |||
1029 | send_flow_mods_mocked.side_effect = FlowModException("error") |
||
1030 | evc.remove_current_flows() |
||
1031 | log_error_mock.assert_called() |
||
1032 | |||
1033 | @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc") |
||
1034 | @patch("napps.kytos.mef_eline.models.evc.notify_link_available_tags") |
||
1035 | @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods") |
||
1036 | def test_remove_failover_flows_include_all(self, *args): |
||
1037 | """Test remove failover flows including UNI switches.""" |
||
1038 | # pylint: disable=too-many-locals |
||
1039 | (send_flow_mods_mocked, |
||
1040 | notify_mock, mock_upsert) = args |
||
1041 | uni_a = get_uni_mocked( |
||
1042 | interface_port=2, |
||
1043 | tag_value=82, |
||
1044 | switch_id="00:00:00:00:00:00:00:01", |
||
1045 | is_valid=True, |
||
1046 | ) |
||
1047 | uni_z = get_uni_mocked( |
||
1048 | interface_port=3, |
||
1049 | tag_value=83, |
||
1050 | switch_id="00:00:00:00:00:00:00:03", |
||
1051 | is_valid=True, |
||
1052 | ) |
||
1053 | |||
1054 | switch_a = Switch("00:00:00:00:00:00:00:01") |
||
1055 | switch_b = Switch("00:00:00:00:00:00:00:02") |
||
1056 | switch_c = Switch("00:00:00:00:00:00:00:03") |
||
1057 | |||
1058 | attributes = { |
||
1059 | "controller": get_controller_mock(), |
||
1060 | "name": "custom_name", |
||
1061 | "uni_a": uni_a, |
||
1062 | "uni_z": uni_z, |
||
1063 | "active": True, |
||
1064 | "enabled": True, |
||
1065 | "failover_path": [ |
||
1066 | get_link_mocked( |
||
1067 | switch_a=switch_a, |
||
1068 | switch_b=switch_b, |
||
1069 | endpoint_a_port=9, |
||
1070 | endpoint_b_port=10, |
||
1071 | metadata={"s_vlan": 5}, |
||
1072 | ), |
||
1073 | get_link_mocked( |
||
1074 | switch_a=switch_b, |
||
1075 | switch_b=switch_c, |
||
1076 | endpoint_a_port=11, |
||
1077 | endpoint_b_port=12, |
||
1078 | metadata={"s_vlan": 6}, |
||
1079 | ), |
||
1080 | ], |
||
1081 | } |
||
1082 | |||
1083 | evc = EVC(**attributes) |
||
1084 | evc.remove_failover_flows(exclude_uni_switches=False, sync=True) |
||
1085 | notify_mock.assert_called() |
||
1086 | |||
1087 | assert send_flow_mods_mocked.call_count == 3 |
||
1088 | flows = [ |
||
1089 | {"cookie": evc.get_cookie(), |
||
1090 | "cookie_mask": int(0xffffffffffffffff)} |
||
1091 | ] |
||
1092 | send_flow_mods_mocked.assert_any_call(switch_a.id, flows, 'delete', |
||
1093 | force=True) |
||
1094 | send_flow_mods_mocked.assert_any_call(switch_b.id, flows, 'delete', |
||
1095 | force=True) |
||
1096 | send_flow_mods_mocked.assert_any_call(switch_c.id, flows, 'delete', |
||
1097 | force=True) |
||
1098 | assert mock_upsert.call_count == 1 |
||
1099 | |||
1100 | @staticmethod |
||
1101 | def create_evc_intra_switch(): |
||
1102 | """Create intra-switch EVC.""" |
||
1103 | switch = Mock(spec=Switch) |
||
1104 | switch.dpid = 2 |
||
1105 | switch.id = switch.dpid |
||
1106 | interface_a = Interface("eth0", 1, switch) |
||
1107 | interface_z = Interface("eth1", 3, switch) |
||
1108 | uni_a = get_uni_mocked( |
||
1109 | tag_value=82, |
||
1110 | is_valid=True, |
||
1111 | ) |
||
1112 | uni_z = get_uni_mocked( |
||
1113 | tag_value=84, |
||
1114 | is_valid=True, |
||
1115 | ) |
||
1116 | uni_a.interface = interface_a |
||
1117 | uni_z.interface = interface_z |
||
1118 | attributes = { |
||
1119 | "controller": get_controller_mock(), |
||
1120 | "name": "custom_name", |
||
1121 | "id": "1", |
||
1122 | "uni_a": uni_a, |
||
1123 | "uni_z": uni_z, |
||
1124 | "enabled": True, |
||
1125 | } |
||
1126 | return EVC(**attributes) |
||
1127 | |||
1128 | # pylint: disable=too-many-branches |
||
1129 | @staticmethod |
||
1130 | @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods") |
||
1131 | def test_deploy_direct_uni_flows(send_flow_mods_mock): |
||
1132 | """Test _install_direct_uni_flows""" |
||
1133 | evc = TestEVC.create_evc_intra_switch() |
||
1134 | expected_dpid = evc.uni_a.interface.switch.id |
||
1135 | |||
1136 | for uni_a in [100, "4096/4096", 0, None]: |
||
1137 | for uni_z in [100, "4096/4096", 0, None]: |
||
1138 | expected_flows = [ |
||
1139 | { |
||
1140 | "match": {"in_port": 1}, |
||
1141 | "cookie": evc.get_cookie(), |
||
1142 | "actions": [ |
||
1143 | {"action_type": "output", "port": 3}, |
||
1144 | ], |
||
1145 | "priority": EPL_SB_PRIORITY |
||
1146 | }, |
||
1147 | { |
||
1148 | "match": {"in_port": 3}, |
||
1149 | "cookie": evc.get_cookie(), |
||
1150 | "actions": [ |
||
1151 | {"action_type": "output", "port": 1}, |
||
1152 | ], |
||
1153 | "priority": EPL_SB_PRIORITY |
||
1154 | } |
||
1155 | ] |
||
1156 | evc.uni_a = get_uni_mocked(tag_value=uni_a, is_valid=True) |
||
1157 | evc.uni_a.interface.port_number = 1 |
||
1158 | evc.uni_z = get_uni_mocked(tag_value=uni_z, is_valid=True) |
||
1159 | evc.uni_z.interface.port_number = 3 |
||
1160 | expected_dpid = evc.uni_a.interface.switch.id |
||
1161 | evc._install_direct_uni_flows() |
||
1162 | if uni_a is not None: |
||
1163 | expected_flows[0]["match"]["dl_vlan"] = uni_a |
||
1164 | expected_flows[0]["priority"] = EVPL_SB_PRIORITY |
||
1165 | if uni_z is not None: |
||
1166 | expected_flows[1]["match"]["dl_vlan"] = uni_z |
||
1167 | expected_flows[1]["priority"] = EVPL_SB_PRIORITY |
||
1168 | |||
1169 | if uni_z not in {None, "4096/4096", 0}: |
||
1170 | expected_flows[0]["actions"].insert( |
||
1171 | 0, {"action_type": "set_vlan", "vlan_id": uni_z} |
||
1172 | ) |
||
1173 | if uni_a not in {None, "4096/4096", 0}: |
||
1174 | expected_flows[1]["actions"].insert( |
||
1175 | 0, {"action_type": "set_vlan", "vlan_id": uni_a} |
||
1176 | ) |
||
1177 | if not uni_z: |
||
1178 | expected_flows[1]["actions"].insert( |
||
1179 | 0, {"action_type": "push_vlan", "tag_type": "c"} |
||
1180 | ) |
||
1181 | if uni_z == 0: |
||
1182 | new_action = {"action_type": "pop_vlan"} |
||
1183 | expected_flows[0]["actions"].insert(0, new_action) |
||
1184 | elif uni_a == "4096/4096": |
||
1185 | if uni_z == 0: |
||
1186 | new_action = {"action_type": "pop_vlan"} |
||
1187 | expected_flows[0]["actions"].insert(0, new_action) |
||
1188 | elif uni_a == 0: |
||
1189 | if uni_z not in {None, "4096/4096", 0}: |
||
1190 | expected_flows[0]["actions"].insert( |
||
1191 | 0, {"action_type": "push_vlan", "tag_type": "c"} |
||
1192 | ) |
||
1193 | if uni_z: |
||
1194 | new_action = {"action_type": "pop_vlan"} |
||
1195 | expected_flows[1]["actions"].insert(0, new_action) |
||
1196 | elif uni_a is None: |
||
1197 | if uni_z not in {None, "4096/4096", 0}: |
||
1198 | expected_flows[0]["actions"].insert( |
||
1199 | 0, {"action_type": "push_vlan", "tag_type": "c"} |
||
1200 | ) |
||
1201 | send_flow_mods_mock.assert_called_with( |
||
1202 | expected_dpid, expected_flows |
||
1203 | ) |
||
1204 | |||
1205 | @staticmethod |
||
1206 | @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods") |
||
1207 | def test_deploy_direct_uni_flows_untagged_any(send_flow_mods_mock): |
||
1208 | """Test _install_direct_uni_flows with untagged and any.""" |
||
1209 | evc = TestEVC.create_evc_intra_switch() |
||
1210 | |||
1211 | evc.uni_a = get_uni_mocked(tag_value="untagged", is_valid=True) |
||
1212 | evc.uni_z = get_uni_mocked(tag_value="untagged", is_valid=True) |
||
1213 | expected_dpid = evc.uni_a.interface.switch.id |
||
1214 | expected_flows = [ |
||
1215 | { |
||
1216 | "match": {"in_port": 1, "dl_vlan": 0}, |
||
1217 | "cookie": evc.get_cookie(), |
||
1218 | "actions": [ |
||
1219 | {"action_type": "output", "port": 1}, |
||
1220 | ], |
||
1221 | "priority": EVPL_SB_PRIORITY |
||
1222 | }, |
||
1223 | { |
||
1224 | "match": {"in_port": 1, "dl_vlan": 0}, |
||
1225 | "cookie": evc.get_cookie(), |
||
1226 | "actions": [ |
||
1227 | {"action_type": "output", "port": 1}, |
||
1228 | ], |
||
1229 | "priority": EVPL_SB_PRIORITY |
||
1230 | } |
||
1231 | ] |
||
1232 | evc._install_direct_uni_flows() |
||
1233 | send_flow_mods_mock.assert_called_with( |
||
1234 | expected_dpid, expected_flows |
||
1235 | ) |
||
1236 | |||
1237 | evc.uni_a = get_uni_mocked(tag_value="any", is_valid=True) |
||
1238 | evc.uni_z = get_uni_mocked(tag_value="any", is_valid=True) |
||
1239 | expected_dpid = evc.uni_a.interface.switch.id |
||
1240 | expected_flows = [ |
||
1241 | { |
||
1242 | "match": {"in_port": 1, "dl_vlan": "4096/4096"}, |
||
1243 | "cookie": evc.get_cookie(), |
||
1244 | "actions": [ |
||
1245 | {"action_type": "output", "port": 1}, |
||
1246 | ], |
||
1247 | "priority": EVPL_SB_PRIORITY |
||
1248 | }, |
||
1249 | { |
||
1250 | "match": {"in_port": 1, "dl_vlan": "4096/4096"}, |
||
1251 | "cookie": evc.get_cookie(), |
||
1252 | "actions": [ |
||
1253 | {"action_type": "output", "port": 1}, |
||
1254 | ], |
||
1255 | "priority": EVPL_SB_PRIORITY |
||
1256 | } |
||
1257 | ] |
||
1258 | evc._install_direct_uni_flows() |
||
1259 | send_flow_mods_mock.assert_called_with( |
||
1260 | expected_dpid, expected_flows |
||
1261 | ) |
||
1262 | |||
1263 | evc.uni_a = get_uni_mocked(tag_value="any", is_valid=True) |
||
1264 | evc.uni_z = get_uni_mocked(tag_value=100, is_valid=True) |
||
1265 | expected_dpid = evc.uni_a.interface.switch.id |
||
1266 | expected_flows = [ |
||
1267 | { |
||
1268 | "match": {"in_port": 1, "dl_vlan": "4096/4096"}, |
||
1269 | "cookie": evc.get_cookie(), |
||
1270 | "actions": [ |
||
1271 | {"action_type": "set_vlan", "vlan_id": 100}, |
||
1272 | {"action_type": "output", "port": 1}, |
||
1273 | ], |
||
1274 | "priority": EVPL_SB_PRIORITY |
||
1275 | }, |
||
1276 | { |
||
1277 | "match": {"in_port": 1, "dl_vlan": 100}, |
||
1278 | "cookie": evc.get_cookie(), |
||
1279 | "actions": [ |
||
1280 | {"action_type": "output", "port": 1}, |
||
1281 | ], |
||
1282 | "priority": EVPL_SB_PRIORITY |
||
1283 | } |
||
1284 | ] |
||
1285 | evc._install_direct_uni_flows() |
||
1286 | send_flow_mods_mock.assert_called_with( |
||
1287 | expected_dpid, expected_flows |
||
1288 | ) |
||
1289 | |||
1290 | def test_is_affected_by_link(self): |
||
1291 | """Test is_affected_by_link method""" |
||
1292 | self.evc_deploy.current_path = Path(['a', 'b', 'c']) |
||
1293 | self.assertTrue(self.evc_deploy.is_affected_by_link('b')) |
||
1294 | |||
1295 | def test_is_backup_path_affected_by_link(self): |
||
1296 | """Test is_backup_path_affected_by_link method""" |
||
1297 | self.evc_deploy.backup_path = Path(['a', 'b', 'c']) |
||
1298 | self.assertFalse(self.evc_deploy.is_backup_path_affected_by_link('d')) |
||
1299 | |||
1300 | def test_is_primary_path_affected_by_link(self): |
||
1301 | """Test is_primary_path_affected_by_link method""" |
||
1302 | self.evc_deploy.primary_path = Path(['a', 'b', 'c']) |
||
1303 | self.assertTrue(self.evc_deploy.is_primary_path_affected_by_link('c')) |
||
1304 | |||
1305 | def test_is_using_primary_path(self): |
||
1306 | """Test is_using_primary_path method""" |
||
1307 | self.evc_deploy.primary_path = Path(['a', 'b', 'c']) |
||
1308 | self.evc_deploy.current_path = Path(['e', 'f', 'g']) |
||
1309 | self.assertFalse(self.evc_deploy.is_using_primary_path()) |
||
1310 | |||
1311 | def test_is_using_backup_path(self): |
||
1312 | """Test is_using_backup_path method""" |
||
1313 | self.evc_deploy.backup_path = Path(['a', 'b', 'c']) |
||
1314 | self.evc_deploy.current_path = Path(['e', 'f', 'g']) |
||
1315 | self.assertFalse(self.evc_deploy.is_using_backup_path()) |
||
1316 | |||
1317 | @patch('napps.kytos.mef_eline.models.path.Path.status') |
||
1318 | def test_is_using_dynamic_path(self, mock_status): |
||
1319 | """Test is_using_dynamic_path method""" |
||
1320 | mock_status.return_value = False |
||
1321 | self.evc_deploy.backup_path = Path([]) |
||
1322 | self.evc_deploy.primary_path = Path([]) |
||
1323 | self.assertFalse(self.evc_deploy.is_using_dynamic_path()) |
||
1324 | |||
1325 | def test_get_path_status(self): |
||
1326 | """Test get_path_status method""" |
||
1327 | path = Path([]) |
||
1328 | self.assertEqual( |
||
1329 | self.evc_deploy.get_path_status(path), |
||
1330 | EntityStatus.DISABLED |
||
1331 | ) |
||
1332 | path = Path([ |
||
1333 | get_link_mocked(status=EntityStatus.UP), |
||
1334 | get_link_mocked(status=EntityStatus.DOWN) |
||
1335 | ]) |
||
1336 | self.assertEqual( |
||
1337 | self.evc_deploy.get_path_status(path), |
||
1338 | EntityStatus.DOWN |
||
1339 | ) |
||
1340 | path = Path([ |
||
1341 | get_link_mocked(status=EntityStatus.UP), |
||
1342 | get_link_mocked(status=EntityStatus.UP) |
||
1343 | ]) |
||
1344 | self.assertEqual( |
||
1345 | self.evc_deploy.get_path_status(path), |
||
1346 | EntityStatus.UP |
||
1347 | ) |
||
1348 | |||
1349 | @patch("napps.kytos.mef_eline.models.evc.EVC._prepare_uni_flows") |
||
1350 | def test_get_failover_flows(self, prepare_uni_flows_mock): |
||
1351 | """Test get_failover_flows method.""" |
||
1352 | evc = self.create_evc_inter_switch() |
||
1353 | evc.failover_path = Path([]) |
||
1354 | self.assertEqual(evc.get_failover_flows(), {}) |
||
1355 | |||
1356 | path = MagicMock() |
||
1357 | evc.failover_path = path |
||
1358 | evc.get_failover_flows() |
||
1359 | prepare_uni_flows_mock.assert_called_with(path, skip_out=True) |
||
1360 | |||
1361 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
1362 | @patch("napps.kytos.mef_eline.models.evc.EVC._send_flow_mods") |
||
1363 | @patch("napps.kytos.mef_eline.models.path.Path.make_vlans_available") |
||
1364 | def test_remove_path_flows(self, *args): |
||
1365 | """Test remove path flows.""" |
||
1366 | ( |
||
1367 | make_vlans_available_mock, |
||
1368 | send_flow_mods_mock, |
||
1369 | log_mock, |
||
1370 | ) = args |
||
1371 | |||
1372 | evc = self.create_evc_inter_switch() |
||
1373 | |||
1374 | evc.remove_path_flows() |
||
1375 | make_vlans_available_mock.assert_not_called() |
||
1376 | |||
1377 | expected_flows_1 = [ |
||
1378 | { |
||
1379 | 'cookie': 12249790986447749121, |
||
1380 | 'cookie_mask': 18446744073709551615, |
||
1381 | 'match': {'in_port': 9, 'dl_vlan': 5} |
||
1382 | }, |
||
1383 | ] |
||
1384 | expected_flows_2 = [ |
||
1385 | { |
||
1386 | 'cookie': 12249790986447749121, |
||
1387 | 'cookie_mask': 18446744073709551615, |
||
1388 | 'match': {'in_port': 10, 'dl_vlan': 5} |
||
1389 | }, |
||
1390 | { |
||
1391 | 'cookie': 12249790986447749121, |
||
1392 | 'cookie_mask': 18446744073709551615, |
||
1393 | 'match': {'in_port': 11, 'dl_vlan': 6} |
||
1394 | }, |
||
1395 | ] |
||
1396 | expected_flows_3 = [ |
||
1397 | { |
||
1398 | 'cookie': 12249790986447749121, |
||
1399 | 'cookie_mask': 18446744073709551615, |
||
1400 | 'match': {'in_port': 12, 'dl_vlan': 6} |
||
1401 | }, |
||
1402 | ] |
||
1403 | |||
1404 | evc.remove_path_flows(evc.primary_links) |
||
1405 | send_flow_mods_mock.assert_has_calls([ |
||
1406 | call(1, expected_flows_1, 'delete', force=True), |
||
1407 | call(2, expected_flows_2, 'delete', force=True), |
||
1408 | call(3, expected_flows_3, 'delete', force=True), |
||
1409 | ], any_order=True) |
||
1410 | |||
1411 | send_flow_mods_mock.side_effect = FlowModException("err") |
||
1412 | evc.remove_path_flows(evc.primary_links) |
||
1413 | log_mock.error.assert_called() |
||
1414 | |||
1415 | @patch("requests.put") |
||
1416 | def test_run_sdntrace(self, put_mock): |
||
1417 | """Test run_sdntrace method.""" |
||
1418 | evc = self.create_evc_inter_switch() |
||
1419 | response = MagicMock() |
||
1420 | response.status_code = 200 |
||
1421 | response.json.return_value = {"result": "ok"} |
||
1422 | put_mock.return_value = response |
||
1423 | |||
1424 | expected_endpoint = f"{SDN_TRACE_CP_URL}/trace" |
||
1425 | expected_payload = { |
||
1426 | 'trace': { |
||
1427 | 'switch': {'dpid': 1, 'in_port': 2}, |
||
1428 | 'eth': {'dl_type': 0x8100, 'dl_vlan': 82} |
||
1429 | } |
||
1430 | } |
||
1431 | |||
1432 | result = evc.run_sdntrace(evc.uni_a) |
||
1433 | put_mock.assert_called_with(expected_endpoint, json=expected_payload) |
||
1434 | self.assertEqual(result, "ok") |
||
1435 | |||
1436 | response.status_code = 400 |
||
1437 | result = evc.run_sdntrace(evc.uni_a) |
||
1438 | self.assertEqual(result, []) |
||
1439 | |||
1440 | @patch("requests.put") |
||
1441 | def test_run_bulk_sdntraces(self, put_mock): |
||
1442 | """Test run_bulk_sdntraces method for bulh request.""" |
||
1443 | evc = self.create_evc_inter_switch() |
||
1444 | response = MagicMock() |
||
1445 | response.status_code = 200 |
||
1446 | response.json.return_value = {"result": "ok"} |
||
1447 | put_mock.return_value = response |
||
1448 | |||
1449 | expected_endpoint = f"{SDN_TRACE_CP_URL}/traces" |
||
1450 | expected_payload = [ |
||
1451 | { |
||
1452 | 'trace': { |
||
1453 | 'switch': {'dpid': 1, 'in_port': 2}, |
||
1454 | 'eth': {'dl_type': 0x8100, 'dl_vlan': 82} |
||
1455 | } |
||
1456 | } |
||
1457 | ] |
||
1458 | result = EVCDeploy.run_bulk_sdntraces([evc.uni_a]) |
||
1459 | put_mock.assert_called_with( |
||
1460 | expected_endpoint, |
||
1461 | json=expected_payload, |
||
1462 | timeout=30 |
||
1463 | ) |
||
1464 | self.assertEqual(result['result'], "ok") |
||
1465 | |||
1466 | response.status_code = 400 |
||
1467 | result = EVCDeploy.run_bulk_sdntraces([evc.uni_a]) |
||
1468 | self.assertEqual(result, {"result": []}) |
||
1469 | |||
1470 | @patch("napps.kytos.mef_eline.models.evc.log") |
||
1471 | @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.run_bulk_sdntraces") |
||
1472 | def test_check_list_traces(self, run_bulk_sdntraces_mock, _): |
||
1473 | """Test check_list_traces method.""" |
||
1474 | evc = self.create_evc_inter_switch() |
||
1475 | |||
1476 | for link in evc.primary_links: |
||
1477 | link.metadata['s_vlan'] = MagicMock(value=link.metadata['s_vlan']) |
||
1478 | evc.current_path = evc.primary_links |
||
1479 | |||
1480 | trace_a = [ |
||
1481 | {"dpid": 1, "port": 2, "time": "t1", "type": "start", "vlan": 82}, |
||
1482 | {"dpid": 2, "port": 10, "time": "t2", "type": "trace", "vlan": 5}, |
||
1483 | {"dpid": 3, "port": 12, "time": "t3", "type": "trace", "vlan": 6}, |
||
1484 | ] |
||
1485 | trace_z = [ |
||
1486 | {"dpid": 3, "port": 3, "time": "t1", "type": "start", "vlan": 83}, |
||
1487 | {"dpid": 2, "port": 11, "time": "t2", "type": "trace", "vlan": 6}, |
||
1488 | {"dpid": 1, "port": 9, "time": "t3", "type": "trace", "vlan": 5}, |
||
1489 | ] |
||
1490 | |||
1491 | run_bulk_sdntraces_mock.return_value = { |
||
1492 | "result": [trace_a, trace_z] |
||
1493 | } |
||
1494 | result = EVCDeploy.check_list_traces([evc]) |
||
1495 | self.assertTrue(result[evc.id]) |
||
1496 | |||
1497 | # case2: fail incomplete trace from uni_a |
||
1498 | run_bulk_sdntraces_mock.return_value = { |
||
1499 | "result": [ |
||
1500 | trace_a[:2], |
||
1501 | trace_z |
||
1502 | ] |
||
1503 | } |
||
1504 | result = EVCDeploy.check_list_traces([evc]) |
||
1505 | self.assertFalse(result[evc.id]) |
||
1506 | |||
1507 | # case3: fail incomplete trace from uni_z |
||
1508 | run_bulk_sdntraces_mock.return_value = { |
||
1509 | "result": [ |
||
1510 | trace_a, |
||
1511 | trace_z[:2] |
||
1512 | ] |
||
1513 | } |
||
1514 | result = EVCDeploy.check_list_traces([evc]) |
||
1515 | self.assertFalse(result[evc.id]) |
||
1516 | |||
1517 | # case4: fail wrong vlan id in trace from uni_a |
||
1518 | trace_a[1]["vlan"] = 5 |
||
1519 | trace_z[1]["vlan"] = 99 |
||
1520 | run_bulk_sdntraces_mock.return_value = { |
||
1521 | "result": [trace_a, trace_z] |
||
1522 | } |
||
1523 | result = EVCDeploy.check_list_traces([evc]) |
||
1524 | self.assertFalse(result[evc.id]) |
||
1525 | |||
1526 | # case5: fail wrong vlan id in trace from uni_z |
||
1527 | trace_a[1]["vlan"] = 99 |
||
1528 | run_bulk_sdntraces_mock.return_value = { |
||
1529 | "result": [trace_a, trace_z] |
||
1530 | } |
||
1531 | result = EVCDeploy.check_list_traces([evc]) |
||
1532 | self.assertFalse(result[evc.id]) |
||
1533 | |||
1534 | # case6: success when no output in traces |
||
1535 | trace_a[1]["vlan"] = 5 |
||
1536 | trace_z[1]["vlan"] = 6 |
||
1537 | result = EVCDeploy.check_list_traces([evc]) |
||
1538 | self.assertTrue(result[evc.id]) |
||
1539 | |||
1540 | # case7: fail when output is None in trace_a or trace_b |
||
1541 | trace_a[-1]["out"] = None |
||
1542 | result = EVCDeploy.check_list_traces([evc]) |
||
1543 | self.assertFalse(result[evc.id]) |
||
1544 | trace_a[-1].pop("out", None) |
||
1545 | trace_z[-1]["out"] = None |
||
1546 | result = EVCDeploy.check_list_traces([evc]) |
||
1547 | self.assertFalse(result[evc.id]) |
||
1548 | |||
1549 | # case8: success when the output is correct on both uni |
||
1550 | trace_a[-1]["out"] = {"port": 3, "vlan": 83} |
||
1551 | trace_z[-1]["out"] = {"port": 2, "vlan": 82} |
||
1552 | result = EVCDeploy.check_list_traces([evc]) |
||
1553 | self.assertTrue(result[evc.id]) |
||
1554 | |||
1555 | # case9: fail if any output is incorrect |
||
1556 | trace_a[-1]["out"] = {"port": 3, "vlan": 99} |
||
1557 | trace_z[-1]["out"] = {"port": 2, "vlan": 82} |
||
1558 | result = EVCDeploy.check_list_traces([evc]) |
||
1559 | self.assertFalse(result[evc.id]) |
||
1560 | trace_a[-1]["out"] = {"port": 3, "vlan": 83} |
||
1561 | trace_z[-1]["out"] = {"port": 2, "vlan": 99} |
||
1562 | result = EVCDeploy.check_list_traces([evc]) |
||
1563 | self.assertFalse(result[evc.id]) |
||
1564 | |||
1565 | @patch( |
||
1566 | "napps.kytos.mef_eline.models.path.DynamicPathManager" |
||
1567 | ".get_disjoint_paths" |
||
1568 | ) |
||
1569 | def test_get_failover_path_vandidates(self, get_disjoint_paths_mock): |
||
1570 | """Test get_failover_path_candidates method""" |
||
1571 | self.evc_deploy.get_failover_path_candidates() |
||
1572 | get_disjoint_paths_mock.assert_called_once() |
||
1573 | |||
1574 | def test_is_failover_path_affected_by_link(self): |
||
1575 | """Test is_failover_path_affected_by_link method""" |
||
1576 | link1 = get_link_mocked(endpoint_a_port=1, endpoint_b_port=2) |
||
1577 | link2 = get_link_mocked(endpoint_a_port=3, endpoint_b_port=4) |
||
1578 | link3 = get_link_mocked(endpoint_a_port=5, endpoint_b_port=6) |
||
1579 | self.evc_deploy.failover_path = Path([link1, link2]) |
||
1580 | self.assertTrue( |
||
1581 | self.evc_deploy.is_failover_path_affected_by_link(link1) |
||
1582 | ) |
||
1583 | self.assertFalse( |
||
1584 | self.evc_deploy.is_failover_path_affected_by_link(link3) |
||
1585 | ) |
||
1586 | |||
1587 | def test_is_eligible_for_failover_path(self): |
||
1588 | """Test is_eligible_for_failover_path method""" |
||
1589 | self.assertFalse(self.evc_deploy.is_eligible_for_failover_path()) |
||
1590 | self.evc_deploy.dynamic_backup_path = True |
||
1591 | self.evc_deploy.primary_path = Path([]) |
||
1592 | self.evc_deploy.backup_path = Path([]) |
||
1593 | self.assertTrue(self.evc_deploy.is_eligible_for_failover_path()) |
||
1594 | |||
1595 | def test_get_value_from_uni_tag(self): |
||
1596 | """Test _get_value_from_uni_tag""" |
||
1597 | uni = get_uni_mocked(tag_value=None) |
||
1598 | value = EVC._get_value_from_uni_tag(uni) |
||
1599 | self.assertEqual(value, None) |
||
1600 | |||
1601 | uni = get_uni_mocked(tag_value="any") |
||
1602 | value = EVC._get_value_from_uni_tag(uni) |
||
1603 | self.assertEqual(value, "4096/4096") |
||
1604 | |||
1605 | uni = get_uni_mocked(tag_value="untagged") |
||
1606 | value = EVC._get_value_from_uni_tag(uni) |
||
1607 | self.assertEqual(value, 0) |
||
1608 | |||
1609 | uni = get_uni_mocked(tag_value=100) |
||
1610 | value = EVC._get_value_from_uni_tag(uni) |
||
1611 | self.assertEqual(value, 100) |
||
1612 |