Passed
Pull Request — master (#330)
by
unknown
07:02
created

TestDynamicPathManager.test_get_disjoint_paths()   B

Complexity

Conditions 1

Size

Total Lines 300
Code Lines 226

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 226
nop 2
dl 0
loc 300
ccs 43
cts 43
cp 1
crap 1
rs 7
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
"""Module to test the Path class."""
2 1
import sys
3 1
from unittest import TestCase
4 1
from unittest.mock import call, patch, Mock, MagicMock
5
6 1
from kytos.core.common import EntityStatus
7 1
from kytos.core.link import Link
8 1
from kytos.core.switch import Switch
9
10
# pylint: disable=wrong-import-position
11
12 1
sys.path.insert(0, "/var/lib/kytos/napps/..")
13
# pylint: enable=wrong-import-position
14 1
from napps.kytos.mef_eline.exceptions import DisabledSwitch, InvalidPath  # NOQA pycodestyle
15 1
from napps.kytos.mef_eline.models import Path, DynamicPathManager  # NOQA pycodestyle
16 1
from napps.kytos.mef_eline.tests.helpers import (
17
    MockResponse,
18
    id_to_interface_mock,
19
    get_link_mocked,
20
    get_mocked_requests,
21
)  # NOQA pycodestyle
22
23
24 1
class TestPath(TestCase):
25
    """Class to test path methods."""
26
27 1
    def test_is_affected_by_link_1(self):
28
        """Test method is affected by link."""
29 1
        path = Path()
30 1
        self.assertIs(path.is_affected_by_link(), False)
31
32 1
    def test_link_affected_by_interface_1(self):
33
        """Test method to get the link using an interface."""
34 1
        link1 = Mock()
35 1
        link1.endpoint_a = "a"
36 1
        link1.endpoint_b = "b"
37 1
        link2 = Mock()
38 1
        link2.endpoint_a = "c"
39 1
        link2.endpoint_b = "d"
40 1
        path = Path([link1, link2])
41 1
        self.assertIsNone(path.link_affected_by_interface())
42
43 1
    def test_link_affected_by_interface_2(self):
44
        """Test method to get the link using an interface."""
45 1
        link1 = Mock()
46 1
        link1.endpoint_a = "a"
47 1
        link1.endpoint_b = "b"
48 1
        link2 = Mock()
49 1
        link2.endpoint_a = "c"
50 1
        link2.endpoint_b = "d"
51 1
        path = Path([link1, link2])
52 1
        self.assertEqual(path.link_affected_by_interface("a"), link1)
53
54 1
    def test_status_case_1(self):
55
        """Test if empty link is DISABLED."""
56 1
        current_path = Path()
57 1
        self.assertEqual(current_path.status, EntityStatus.DISABLED)
58
59 1
    @patch("requests.get", side_effect=get_mocked_requests)
60 1
    def test_status_case_2(self, requests_mocked):
61
        # pylint: disable=unused-argument
62
        """Test if link status is DOWN."""
63 1
        link1 = get_link_mocked()
64 1
        link2 = get_link_mocked()
65 1
        link1.id = "def"
66 1
        link2.id = "abc"
67 1
        links = [link1, link2]
68 1
        current_path = Path(links)
69 1
        self.assertEqual(current_path.status, EntityStatus.DOWN)
70
71 1
    def test_status_case_3(self):
72
        """Test if link status is DISABLED."""
73 1
        links = []
74 1
        current_path = Path(links)
75 1
        self.assertEqual(current_path.status, EntityStatus.DISABLED)
76
77
    # This method will be used by the mock to replace requests.get
78 1
    def _mocked_requests_get_status_case_4(self):
79 1
        return MockResponse(
80
            {
81
                "links": {
82
                    "abc": {"active": True, "enabled": True},
83
                    "def": {"active": True, "enabled": True},
84
                }
85
            },
86
            200,
87
        )
88
89 1
    @patch("requests.get", side_effect=_mocked_requests_get_status_case_4)
90 1
    def test_status_case_4(self, requests_mocked):
91
        # pylint: disable=unused-argument
92
        """Test if link status is UP."""
93 1
        link1 = get_link_mocked()
94 1
        link2 = get_link_mocked()
95 1
        link1.id = "def"
96 1
        link2.id = "abc"
97 1
        links = [link1, link2]
98 1
        current_path = Path(links)
99 1
        self.assertEqual(current_path.status, EntityStatus.UP)
100
101
    # This method will be used by the mock to replace requests.get
102 1
    def _mocked_requests_get_status_case_5(self):
103 1
        return MockResponse(
104
            {
105
                "links": {
106
                    "abc": {"active": True, "enabled": True},
107
                    "def": {"active": False, "enabled": False},
108
                }
109
            },
110
            200,
111
        )
112
113 1
    @patch("requests.get", side_effect=_mocked_requests_get_status_case_5)
114 1
    def test_status_case_5(self, requests_mocked):
115
        # pylint: disable=unused-argument
116
        """Test if link status is UP."""
117 1
        link1 = get_link_mocked()
118 1
        link2 = get_link_mocked()
119 1
        link1.id = "def"
120 1
        link2.id = "abc"
121 1
        links = [link1, link2]
122 1
        current_path = Path(links)
123 1
        self.assertEqual(current_path.status, EntityStatus.DISABLED)
124
125
    # This method will be used by the mock to replace requests.get
126 1
    def _mocked_requests_get_status_case_6(self):
127 1
        return MockResponse(
128
            {
129
                "links": {
130
                    "abc": {"active": False, "enabled": False},
131
                    "def": {"active": False, "enabled": True},
132
                }
133
            },
134
            200,
135
        )
136
137 1
    @patch("requests.get", side_effect=_mocked_requests_get_status_case_6)
138 1
    def test_status_case_6(self, requests_mocked):
139
        # pylint: disable=unused-argument
140
        """Test if link status is UP."""
141 1
        link1 = get_link_mocked()
142 1
        link2 = get_link_mocked()
143 1
        link1.id = "def"
144 1
        link2.id = "abc"
145 1
        links = [link1, link2]
146 1
        current_path = Path(links)
147 1
        self.assertEqual(current_path.status, EntityStatus.DISABLED)
148
149 1
    def test_compare_same_paths(self):
150
        """Test compare paths with same links."""
151 1
        links = [
152
            get_link_mocked(
153
                endpoint_a_port=9, endpoint_b_port=10, metadata={"s_vlan": 5}
154
            ),
155
            get_link_mocked(
156
                endpoint_a_port=11, endpoint_b_port=12, metadata={"s_vlan": 6}
157
            ),
158
        ]
159
160 1
        path_1 = Path(links)
161 1
        path_2 = Path(links)
162 1
        self.assertEqual(path_1, path_2)
163
164 1
    def test_compare_different_paths(self):
165
        """Test compare paths with different links."""
166 1
        links_1 = [
167
            get_link_mocked(
168
                endpoint_a_port=9, endpoint_b_port=10, metadata={"s_vlan": 5}
169
            ),
170
            get_link_mocked(
171
                endpoint_a_port=11, endpoint_b_port=12, metadata={"s_vlan": 6}
172
            ),
173
        ]
174 1
        links_2 = [
175
            get_link_mocked(
176
                endpoint_a_port=12, endpoint_b_port=11, metadata={"s_vlan": 5}
177
            ),
178
            get_link_mocked(
179
                endpoint_a_port=14, endpoint_b_port=16, metadata={"s_vlan": 11}
180
            ),
181
        ]
182
183 1
        path_1 = Path(links_1)
184 1
        path_2 = Path(links_2)
185 1
        self.assertNotEqual(path_1, path_2)
186
187 1
    def test_as_dict(self):
188
        """Test path as dict."""
189 1
        links = [
190
            get_link_mocked(link_dict={"id": 3}),
191
            get_link_mocked(link_dict={"id": 2}),
192
        ]
193
194 1
        current_path = Path(links)
195 1
        expected_dict = [{"id": 3}, {"id": 2}]
196 1
        self.assertEqual(expected_dict, current_path.as_dict())
197
198 1
    def test_empty_is_valid(self) -> None:
199
        """Test empty path is valid."""
200 1
        path = Path([])
201 1
        self.assertEqual(path.is_valid(MagicMock(), MagicMock(), False), True)
202
203 1
    def test_is_valid(self):
204
        """Test is_valid method."""
205 1
        switch1 = Switch("00:00:00:00:00:00:00:01")
206 1
        switch2 = Switch("00:00:00:00:00:00:00:02")
207 1
        switch3 = Switch("00:00:00:00:00:00:00:03")
208 1
        switch4 = Switch("00:00:00:00:00:00:00:04")
209 1
        switch5 = Switch("00:00:00:00:00:00:00:05")
210 1
        switch6 = Switch("00:00:00:00:00:00:00:06")
211 1
        switch1.enable()
212 1
        switch2.enable()
213 1
        switch3.enable()
214 1
        switch4.enable()
215 1
        switch5.enable()
216 1
        switch6.enable()
217
218 1
        links1 = [
219
            get_link_mocked(switch_a=switch1, switch_b=switch2),
220
            get_link_mocked(switch_a=switch2, switch_b=switch3),
221
            get_link_mocked(switch_a=switch3, switch_b=switch4),
222
            get_link_mocked(switch_a=switch4, switch_b=switch5),
223
            get_link_mocked(switch_a=switch5, switch_b=switch6),
224
        ]
225
226 1
        links2 = [
227
            get_link_mocked(switch_a=switch1, switch_b=switch2),
228
            get_link_mocked(switch_a=switch3, switch_b=switch2),
229
            get_link_mocked(switch_a=switch3, switch_b=switch4),
230
        ]
231
232 1
        for links, switch_a, switch_z, expected in (
233
            (links1, switch1, switch6, True),
234
            (links2, switch1, switch4, False),
235
            (links1, switch2, switch6, False),
236
        ):
237 1
            with self.subTest(
238
                links=links,
239
                switch_a=switch_a,
240
                switch_z=switch_z,
241
                expected=expected,
242
            ):
243 1
                path = Path(links)
244 1
                if expected:
245 1
                    self.assertEqual(
246
                        path.is_valid(switch_a, switch_z), expected
247
                    )
248
                else:
249 1
                    with self.assertRaises(InvalidPath):
250 1
                        path.is_valid(switch_a, switch_z)
251
252 1
    def test_is_valid_disabled_switch(self):
253
        """Test is_valid method with DisabledSwitch."""
254 1
        switch1 = Switch("00:00:00:00:00:00:00:01")
255 1
        switch2 = Switch("00:00:00:00:00:00:00:02")
256 1
        switch1.enable()
257
258 1
        links1 = [
259
            get_link_mocked(switch_a=switch1, switch_b=switch2),
260
        ]
261
262 1
        path = Path(links1)
263 1
        with self.assertRaises(DisabledSwitch):
264 1
            path.is_valid(switch1, switch2)
265
266
267 1
class TestDynamicPathManager(TestCase):
268
    """Tests for the DynamicPathManager class"""
269
270 1
    def test_clear_path(self):
271
        """Test _clear_path method"""
272 1
        path = [
273
            '00:00:00:00:00:00:00:01:1',
274
            '00:00:00:00:00:00:00:02:3',
275
            '00:00:00:00:00:00:00:02',
276
            '00:00:00:00:00:00:00:02:4',
277
            '00:00:00:00:00:00:00:03:2',
278
            '00:00:00:00:00:00:00:03',
279
            '00:00:00:00:00:00:00:03:1',
280
            '00:00:00:00:00:00:00:04:1'
281
        ]
282 1
        expected_path = [
283
            '00:00:00:00:00:00:00:01:1',
284
            '00:00:00:00:00:00:00:02:3',
285
            '00:00:00:00:00:00:00:02:4',
286
            '00:00:00:00:00:00:00:03:2',
287
            '00:00:00:00:00:00:00:03:1',
288
            '00:00:00:00:00:00:00:04:1'
289
        ]
290
        # pylint: disable=protected-access
291 1
        self.assertEqual(DynamicPathManager._clear_path(path), expected_path)
292
293 1
    def test_create_path_invalid(self):
294
        """Test create_path method"""
295 1
        path = [
296
            '00:00:00:00:00:00:00:01:1',
297
            '00:00:00:00:00:00:00:02:3',
298
            '00:00:00:00:00:00:00:02',
299
            '00:00:00:00:00:00:00:02:4',
300
            '00:00:00:00:00:00:00:03:2',
301
            '00:00:00:00:00:00:00:03',
302
            '00:00:00:00:00:00:00:03:1',
303
        ]
304 1
        self.assertIsNone(DynamicPathManager.create_path(path))
305
306 1
    @patch("requests.post")
307 1
    def test_get_best_path(self, mock_requests_post):
308
        """Test get_best_path method."""
309 1
        controller = MagicMock()
310 1
        controller.get_interface_by_id.side_effect = id_to_interface_mock
311 1
        DynamicPathManager.set_controller(controller)
312
313 1
        paths1 = {
314
            "paths": [
315
                {
316
                    "cost": 5,
317
                    "hops": [
318
                        "00:00:00:00:00:00:00:01:1",
319
                        "00:00:00:00:00:00:00:01",
320
                        "00:00:00:00:00:00:00:01:2",
321
                        "00:00:00:00:00:00:00:02:2",
322
                        "00:00:00:00:00:00:00:02",
323
                        "00:00:00:00:00:00:00:02:1"
324
                        ]
325
                },
326
            ]
327
        }
328
329 1
        expected_path = [
330
            Link(
331
                id_to_interface_mock("00:00:00:00:00:00:00:01:2"),
332
                id_to_interface_mock("00:00:00:00:00:00:00:02:2")
333
            ),
334
        ]
335
336
        # test success case
337 1
        mock_response = MagicMock()
338 1
        mock_response.status_code = 200
339 1
        mock_response.json.return_value = paths1
340 1
        mock_requests_post.return_value = mock_response
341
342 1
        res_paths = list(DynamicPathManager.get_best_path(MagicMock()))
343 1
        self.assertEqual(
344
            [link.id for link in res_paths],
345
            [link.id for link in expected_path]
346
        )
347
348
        # test failure when controller dont find the interface on create_path
349 1
        controller.get_interface_by_id.side_effect = [
350
            id_to_interface_mock("00:00:00:00:00:00:00:01:2"),
351
            None
352
        ]
353 1
        self.assertIsNone(DynamicPathManager.get_best_path(MagicMock()))
354
355 1
        mock_response.status_code = 400
356 1
        mock_response.json.return_value = {}
357 1
        mock_requests_post.return_value = mock_response
358
359 1
        res_paths = DynamicPathManager.get_best_path(MagicMock())
360 1
        self.assertIsNone(res_paths)
361
362 1
    @patch("requests.post")
363 1
    def test_get_best_paths(self, mock_requests_post):
364
        """Test get_best_paths method."""
365 1
        controller = MagicMock()
366 1
        controller.get_interface_by_id.side_effect = id_to_interface_mock
367 1
        DynamicPathManager.set_controller(controller)
368
369 1
        paths1 = {
370
            "paths": [
371
                {
372
                    "cost": 5,
373
                    "hops": [
374
                        "00:00:00:00:00:00:00:01:1",
375
                        "00:00:00:00:00:00:00:01",
376
                        "00:00:00:00:00:00:00:01:2",
377
                        "00:00:00:00:00:00:00:02:2",
378
                        "00:00:00:00:00:00:00:02",
379
                        "00:00:00:00:00:00:00:02:1"
380
                        ]
381
                },
382
                {
383
                    "cost": 11,
384
                    "hops": [
385
                        "00:00:00:00:00:00:00:01:1",
386
                        "00:00:00:00:00:00:00:01",
387
                        "00:00:00:00:00:00:00:01:2",
388
                        "00:00:00:00:00:00:00:02:2",
389
                        "00:00:00:00:00:00:00:02",
390
                        "00:00:00:00:00:00:00:02:3",
391
                        "00:00:00:00:00:00:00:03:3",
392
                        "00:00:00:00:00:00:00:03",
393
                        "00:00:00:00:00:00:00:03:4",
394
                        "00:00:00:00:00:00:00:04:4",
395
                        "00:00:00:00:00:00:00:04",
396
                        "00:00:00:00:00:00:00:04:1"
397
                        ]
398
                },
399
            ]
400
        }
401
402 1
        expected_paths_0 = [
403
            Link(
404
                id_to_interface_mock("00:00:00:00:00:00:00:01:2"),
405
                id_to_interface_mock("00:00:00:00:00:00:00:02:2")
406
            ),
407
        ]
408
409 1
        expected_paths_1 = [
410
            Link(
411
                id_to_interface_mock("00:00:00:00:00:00:00:01:2"),
412
                id_to_interface_mock("00:00:00:00:00:00:00:02:2")
413
            ),
414
            Link(
415
                id_to_interface_mock("00:00:00:00:00:00:00:02:3"),
416
                id_to_interface_mock("00:00:00:00:00:00:00:03:3")
417
            ),
418
            Link(
419
                id_to_interface_mock("00:00:00:00:00:00:00:03:4"),
420
                id_to_interface_mock("00:00:00:00:00:00:00:04:4")
421
            ),
422
        ]
423
424 1
        mock_response = MagicMock()
425 1
        mock_response.status_code = 200
426 1
        mock_response.json.return_value = paths1
427 1
        mock_requests_post.return_value = mock_response
428 1
        kwargs = {
429
            "spf_max_path_cost": 8,
430
            "mandatory_metrics": {
431
                "ownership": "red"
432
            }
433
        }
434 1
        circuit = MagicMock()
435 1
        circuit.uni_a.interface.id = "1"
436 1
        circuit.uni_z.interface.id = "2"
437 1
        max_paths = 2
438 1
        res_paths = list(DynamicPathManager.get_best_paths(circuit,
439
                         max_paths=max_paths, **kwargs))
440 1
        self.assertEqual(
441
            [link.id for link in res_paths[0]],
442
            [link.id for link in expected_paths_0]
443
        )
444 1
        self.assertEqual(
445
            [link.id for link in res_paths[1]],
446
            [link.id for link in expected_paths_1]
447
        )
448 1
        expected_call = call(
449
            "http://localhost:8181/api/kytos/pathfinder/v3/",
450
            json={
451
                **{
452
                    "source": circuit.uni_a.interface.id,
453
                    "destination": circuit.uni_z.interface.id,
454
                    "spf_max_paths": max_paths,
455
                },
456
                **kwargs
457
            },
458
        )
459 1
        mock_requests_post.assert_has_calls([expected_call])
460
461 1
    @patch("requests.post")
462 1
    def test_get_disjoint_paths(self, mock_requests_post):
463
        """Test get_disjoint_paths method."""
464
465 1
        controller = MagicMock()
466 1
        controller.get_interface_by_id.side_effect = id_to_interface_mock
467 1
        DynamicPathManager.set_controller(controller)
468
469 1
        evc = MagicMock()
470 1
        evc.secondary_constraints = {
471
            "spf_max_path_cost": 20,
472
            "mandatory_metrics": {
473
                "ownership": "red"
474
            }
475
        }
476 1
        evc.uni_a.interface.id = "1"
477 1
        evc.uni_z.interface.id = "2"
478
479
        # Topo0
480 1
        paths1 = {
481
            "paths": [
482
                {
483
                    "cost": 11,
484
                    "hops": [
485
                        "00:00:00:00:00:00:00:01:1",
486
                        "00:00:00:00:00:00:00:01",
487
                        "00:00:00:00:00:00:00:01:2",
488
                        "00:00:00:00:00:00:00:02:2",
489
                        "00:00:00:00:00:00:00:02",
490
                        "00:00:00:00:00:00:00:02:3",
491
                        "00:00:00:00:00:00:00:04:2",
492
                        "00:00:00:00:00:00:00:04",
493
                        "00:00:00:00:00:00:00:04:3",
494
                        "00:00:00:00:00:00:00:05:2",
495
                        "00:00:00:00:00:00:00:05",
496
                        "00:00:00:00:00:00:00:05:1"
497
                        ]
498
                },
499
                {
500
                    "cost": 11,
501
                    "hops": [
502
                        "00:00:00:00:00:00:00:01:1",
503
                        "00:00:00:00:00:00:00:01",
504
                        "00:00:00:00:00:00:00:01:3",
505
                        "00:00:00:00:00:00:00:03:2",
506
                        "00:00:00:00:00:00:00:03",
507
                        "00:00:00:00:00:00:00:03:3",
508
                        "00:00:00:00:00:00:00:04:4",
509
                        "00:00:00:00:00:00:00:04",
510
                        "00:00:00:00:00:00:00:04:3",
511
                        "00:00:00:00:00:00:00:05:2",
512
                        "00:00:00:00:00:00:00:05",
513
                        "00:00:00:00:00:00:00:05:1"
514
                        ]
515
                },
516
                {
517
                    "cost": 14,
518
                    "hops": [
519
                        "00:00:00:00:00:00:00:01:1",
520
                        "00:00:00:00:00:00:00:01",
521
                        "00:00:00:00:00:00:00:01:2",
522
                        "00:00:00:00:00:00:00:02:2",
523
                        "00:00:00:00:00:00:00:02",
524
                        "00:00:00:00:00:00:00:02:3",
525
                        "00:00:00:00:00:00:00:04:2",
526
                        "00:00:00:00:00:00:00:04",
527
                        "00:00:00:00:00:00:00:04:5",
528
                        "00:00:00:00:00:00:00:06:2",
529
                        "00:00:00:00:00:00:00:06",
530
                        "00:00:00:00:00:00:00:06:3",
531
                        "00:00:00:00:00:00:00:05:3",
532
                        "00:00:00:00:00:00:00:05",
533
                        "00:00:00:00:00:00:00:05:1"
534
                    ]
535
                },
536
                {
537
                    "cost": 14,
538
                    "hops": [
539
                        "00:00:00:00:00:00:00:01:1",
540
                        "00:00:00:00:00:00:00:01",
541
                        "00:00:00:00:00:00:00:01:3",
542
                        "00:00:00:00:00:00:00:03:2",
543
                        "00:00:00:00:00:00:00:03",
544
                        "00:00:00:00:00:00:00:03:3",
545
                        "00:00:00:00:00:00:00:04:4",
546
                        "00:00:00:00:00:00:00:04",
547
                        "00:00:00:00:00:00:00:04:5",
548
                        "00:00:00:00:00:00:00:06:2",
549
                        "00:00:00:00:00:00:00:06",
550
                        "00:00:00:00:00:00:00:06:3",
551
                        "00:00:00:00:00:00:00:05:3",
552
                        "00:00:00:00:00:00:00:05",
553
                        "00:00:00:00:00:00:00:05:1"
554
                    ]
555
                },
556
                {
557
                    "cost": 17,
558
                    "hops": [
559
                        "00:00:00:00:00:00:00:01:1",
560
                        "00:00:00:00:00:00:00:01",
561
                        "00:00:00:00:00:00:00:01:3",
562
                        "00:00:00:00:00:00:00:03:2",
563
                        "00:00:00:00:00:00:00:03",
564
                        "00:00:00:00:00:00:00:03:3",
565
                        "00:00:00:00:00:00:00:04:4",
566
                        "00:00:00:00:00:00:00:04",
567
                        "00:00:00:00:00:00:00:04:5",
568
                        "00:00:00:00:00:00:00:06:2",
569
                        "00:00:00:00:00:00:00:06",
570
                        "00:00:00:00:00:00:00:06:4",
571
                        "00:00:00:00:00:00:00:07:2",
572
                        "00:00:00:00:00:00:00:07",
573
                        "00:00:00:00:00:00:00:07:3",
574
                        "00:00:00:00:00:00:00:05:4",
575
                        "00:00:00:00:00:00:00:05",
576
                        "00:00:00:00:00:00:00:05:1"
577
                    ]
578
                },
579
            ]
580
        }
581
582 1
        mock_response = MagicMock()
583 1
        mock_response.status_code = 200
584 1
        mock_response.json.return_value = paths1
585
586
        # when we dont have the current_path
587 1
        mock_requests_post.return_value = mock_response
588 1
        disjoint_paths = list(DynamicPathManager.get_disjoint_paths(evc, []))
589 1
        self.assertEqual(disjoint_paths, [])
590
591 1
        current_path = [
592
            Link(
593
                id_to_interface_mock("00:00:00:00:00:00:00:01:2"),
594
                id_to_interface_mock("00:00:00:00:00:00:00:02:2")
595
            ),
596
            Link(
597
                id_to_interface_mock("00:00:00:00:00:00:00:02:3"),
598
                id_to_interface_mock("00:00:00:00:00:00:00:04:2")
599
            ),
600
            Link(
601
                id_to_interface_mock("00:00:00:00:00:00:00:04:3"),
602
                id_to_interface_mock("00:00:00:00:00:00:00:05:2")
603
            ),
604
        ]
605
606
        # only one path available from pathfinder (precesilly the
607
        # current_path), so the maximum disjoint path will be empty
608 1
        mock_response.json.return_value = {"paths": paths1["paths"][0:1]}
609 1
        mock_requests_post.return_value = mock_response
610 1
        paths = list(DynamicPathManager.get_disjoint_paths(evc, current_path))
611 1
        self.assertEqual(len(paths), 0)
612
613 1
        expected_disjoint_path = [
614
            Link(
615
                id_to_interface_mock("00:00:00:00:00:00:00:01:3"),
616
                id_to_interface_mock("00:00:00:00:00:00:00:03:2")
617
            ),
618
            Link(
619
                id_to_interface_mock("00:00:00:00:00:00:00:03:3"),
620
                id_to_interface_mock("00:00:00:00:00:00:00:04:4")
621
            ),
622
            Link(
623
                id_to_interface_mock("00:00:00:00:00:00:00:04:5"),
624
                id_to_interface_mock("00:00:00:00:00:00:00:06:2")
625
            ),
626
            Link(
627
                id_to_interface_mock("00:00:00:00:00:00:00:06:3"),
628
                id_to_interface_mock("00:00:00:00:00:00:00:05:3")
629
            ),
630
        ]
631
632
        # there are one alternative path
633 1
        mock_response.json.return_value = paths1
634 1
        mock_requests_post.return_value = mock_response
635 1
        paths = list(DynamicPathManager.get_disjoint_paths(evc, current_path))
636 1
        self.assertEqual(len(paths), 4)
637
        # for more information on the paths please refer to EP029
638 1
        self.assertEqual(len(paths[0]), 4)  # path S-Z-W-I-D
639 1
        self.assertEqual(len(paths[1]), 5)  # path S-Z-W-I-J-D
640 1
        self.assertEqual(len(paths[2]), 3)  # path S-Z-W-D
641 1
        self.assertEqual(len(paths[3]), 4)  # path S-X-W-I-D
642 1
        self.assertEqual(
643
            [link.id for link in paths[0]],
644
            [link.id for link in expected_disjoint_path]
645
        )
646
647 1
        max_paths = 10
648 1
        expected_call = call(
649
            "http://localhost:8181/api/kytos/pathfinder/v3/",
650
            json={
651
                **{
652
                    "source": evc.uni_a.interface.id,
653
                    "destination": evc.uni_z.interface.id,
654
                    "spf_max_paths": max_paths,
655
                },
656
                **evc.secondary_constraints
657
            },
658
        )
659 1
        assert mock_requests_post.call_count >= 1
660
        # If secondary_constraints are set they are expected to be parametrized
661 1
        mock_requests_post.assert_has_calls([expected_call])
662
663
        # EP029 Topo2
664 1
        paths2 = {
665
            "paths": [
666
                {
667
                    "cost": 14,
668
                    "hops": [
669
                        "00:00:00:00:00:00:00:01:1",
670
                        "00:00:00:00:00:00:00:01",
671
                        "00:00:00:00:00:00:00:01:2",
672
                        "00:00:00:00:00:00:00:02:1",
673
                        "00:00:00:00:00:00:00:02",
674
                        "00:00:00:00:00:00:00:02:2",
675
                        "00:00:00:00:00:00:00:03:1",
676
                        "00:00:00:00:00:00:00:03",
677
                        "00:00:00:00:00:00:00:03:2",
678
                        "00:00:00:00:00:00:00:04:1",
679
                        "00:00:00:00:00:00:00:04",
680
                        "00:00:00:00:00:00:00:04:2",
681
                        "00:00:00:00:00:00:00:07:2",
682
                        "00:00:00:00:00:00:00:07",
683
                        "00:00:00:00:00:00:00:07:1"
684
                    ]
685
                },
686
                {
687
                    "cost": 17,
688
                    "hops": [
689
                        "00:00:00:00:00:00:00:01:1",
690
                        "00:00:00:00:00:00:00:01",
691
                        "00:00:00:00:00:00:00:01:2",
692
                        "00:00:00:00:00:00:00:02:1",
693
                        "00:00:00:00:00:00:00:02",
694
                        "00:00:00:00:00:00:00:02:3",
695
                        "00:00:00:00:00:00:00:05:1",
696
                        "00:00:00:00:00:00:00:05",
697
                        "00:00:00:00:00:00:00:05:2",
698
                        "00:00:00:00:00:00:00:06:1",
699
                        "00:00:00:00:00:00:00:06",
700
                        "00:00:00:00:00:00:00:06:2",
701
                        "00:00:00:00:00:00:00:04:3",
702
                        "00:00:00:00:00:00:00:04",
703
                        "00:00:00:00:00:00:00:04:2",
704
                        "00:00:00:00:00:00:00:07:2",
705
                        "00:00:00:00:00:00:00:07",
706
                        "00:00:00:00:00:00:00:07:1"
707
                    ]
708
                }
709
            ]
710
        }
711
712 1
        current_path = [
713
            Link(
714
                id_to_interface_mock("00:00:00:00:00:00:00:01:2"),
715
                id_to_interface_mock("00:00:00:00:00:00:00:02:1")
716
            ),
717
            Link(
718
                id_to_interface_mock("00:00:00:00:00:00:00:02:2"),
719
                id_to_interface_mock("00:00:00:00:00:00:00:03:1")
720
            ),
721
            Link(
722
                id_to_interface_mock("00:00:00:00:00:00:00:03:2"),
723
                id_to_interface_mock("00:00:00:00:00:00:00:04:1")
724
            ),
725
            Link(
726
                id_to_interface_mock("00:00:00:00:00:00:00:04:2"),
727
                id_to_interface_mock("00:00:00:00:00:00:00:07:2")
728
            ),
729
        ]
730
731 1
        expected_disjoint_path = [
732
            Link(
733
                id_to_interface_mock("00:00:00:00:00:00:00:01:2"),
734
                id_to_interface_mock("00:00:00:00:00:00:00:02:1")
735
            ),
736
            Link(
737
                id_to_interface_mock("00:00:00:00:00:00:00:02:3"),
738
                id_to_interface_mock("00:00:00:00:00:00:00:05:1")
739
            ),
740
            Link(
741
                id_to_interface_mock("00:00:00:00:00:00:00:05:2"),
742
                id_to_interface_mock("00:00:00:00:00:00:00:06:1")
743
            ),
744
            Link(
745
                id_to_interface_mock("00:00:00:00:00:00:00:06:2"),
746
                id_to_interface_mock("00:00:00:00:00:00:00:04:3")
747
            ),
748
            Link(
749
                id_to_interface_mock("00:00:00:00:00:00:00:04:2"),
750
                id_to_interface_mock("00:00:00:00:00:00:00:07:2")
751
            ),
752
        ]
753
754 1
        mock_response.json.return_value = {"paths": paths2["paths"]}
755 1
        mock_requests_post.return_value = mock_response
756 1
        paths = list(DynamicPathManager.get_disjoint_paths(evc, current_path))
757 1
        self.assertEqual(len(paths), 1)
758 1
        self.assertEqual(
759
            [link.id for link in paths[0]],
760
            [link.id for link in expected_disjoint_path]
761
        )
762