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