Passed
Pull Request — master (#129)
by Vinicius
02:57
created

TestMain.test_get_circuit_not_found()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
"""Module to test the main napp file."""
2
import json
3
from unittest import TestCase
4
from unittest.mock import MagicMock, PropertyMock, call, create_autospec, patch
5
6
from kytos.core.events import KytosEvent
7
from kytos.core.interface import UNI, Interface
8
from napps.kytos.mef_eline.exceptions import InvalidPath
9
from napps.kytos.mef_eline.models import EVC
10
from napps.kytos.mef_eline.tests.helpers import (
11
    get_controller_mock,
12
    get_uni_mocked,
13
)
14
15
16
# pylint: disable=too-many-public-methods, too-many-lines
17
class TestMain(TestCase):
18
    """Test the Main class."""
19
20
    def setUp(self):
21
        """Execute steps before each tests.
22
23
        Set the server_name_url_url from kytos/mef_eline
24
        """
25
        self.server_name_url = "http://localhost:8181/api/kytos/mef_eline"
26
27
        # The decorator run_on_thread is patched, so methods that listen
28
        # for events do not run on threads while tested.
29
        # Decorators have to be patched before the methods that are
30
        # decorated with them are imported.
31
        patch("kytos.core.helpers.run_on_thread", lambda x: x).start()
32
        # pylint: disable=import-outside-toplevel
33
        from napps.kytos.mef_eline.main import Main
34
35
        self.addCleanup(patch.stopall)
36
        self.napp = Main(get_controller_mock())
37
38
    def test_get_event_listeners(self):
39
        """Verify all event listeners registered."""
40
        expected_events = [
41
            "kytos/core.shutdown",
42
            "kytos/core.shutdown.kytos/mef_eline",
43
            "kytos/topology.link_up",
44
            "kytos/topology.link_down",
45
        ]
46
        actual_events = self.napp.listeners()
47
48
        for _event in expected_events:
49
            self.assertIn(_event, actual_events, _event)
50
51
    def test_verify_api_urls(self):
52
        """Verify all APIs registered."""
53
        expected_urls = [
54
            ({}, {"POST", "OPTIONS"}, "/api/kytos/mef_eline/v2/evc/"),
55
            ({}, {"OPTIONS", "HEAD", "GET"}, "/api/kytos/mef_eline/v2/evc/"),
56
            (
57
                {"circuit_id": "[circuit_id]"},
58
                {"OPTIONS", "DELETE"},
59
                "/api/kytos/mef_eline/v2/evc/<circuit_id>",
60
            ),
61
            (
62
                {"circuit_id": "[circuit_id]"},
63
                {"OPTIONS", "HEAD", "GET"},
64
                "/api/kytos/mef_eline/v2/evc/<circuit_id>",
65
            ),
66
            (
67
                {"circuit_id": "[circuit_id]"},
68
                {"OPTIONS", "PATCH"},
69
                "/api/kytos/mef_eline/v2/evc/<circuit_id>",
70
            ),
71
            (
72
                {"circuit_id": "[circuit_id]"},
73
                {"OPTIONS", "HEAD", "GET"},
74
                "/api/kytos/mef_eline/v2/evc/<circuit_id>/metadata",
75
            ),
76
            (
77
                {"circuit_id": "[circuit_id]"},
78
                {"OPTIONS", "POST"},
79
                "/api/kytos/mef_eline/v2/evc/<circuit_id>/metadata",
80
            ),
81
            (
82
                {"circuit_id": "[circuit_id]", "key": "[key]"},
83
                {"OPTIONS", "DELETE"},
84
                "/api/kytos/mef_eline/v2/evc/<circuit_id>/metadata/<key>",
85
            ),
86
            (
87
                {"circuit_id": "[circuit_id]"},
88
                {"OPTIONS", "PATCH"},
89
                "/api/kytos/mef_eline/v2/evc/<circuit_id>/redeploy",
90
            ),
91
            (
92
                {},
93
                {"OPTIONS", "GET", "HEAD"},
94
                "/api/kytos/mef_eline/v2/evc/schedule",
95
            ),
96
            ({}, {"POST", "OPTIONS"}, "/api/kytos/mef_eline/v2/evc/schedule/"),
97
            (
98
                {"schedule_id": "[schedule_id]"},
99
                {"OPTIONS", "DELETE"},
100
                "/api/kytos/mef_eline/v2/evc/schedule/<schedule_id>",
101
            ),
102
            (
103
                {"schedule_id": "[schedule_id]"},
104
                {"OPTIONS", "PATCH"},
105
                "/api/kytos/mef_eline/v2/evc/schedule/<schedule_id>",
106
            ),
107
        ]
108
        urls = self.get_napp_urls(self.napp)
109
        self.assertEqual(len(expected_urls), len(urls))
110
111
    @patch('napps.kytos.mef_eline.main.log')
112
    @patch('napps.kytos.mef_eline.main.Main.execute_consistency')
113
    def test_execute(self, mock_execute_consistency, mock_log):
114
        """Test execute."""
115
        self.napp.execute()
116
        mock_execute_consistency.assert_called()
117
        self.assertEqual(mock_log.debug.call_count, 2)
118
119
        # Test locked should return
120
        mock_execute_consistency.call_count = 0
121
        mock_log.info.call_count = 0
122
        # pylint: disable=protected-access
123
        self.napp._lock = MagicMock()
124
        self.napp._lock.locked.return_value = True
125
        # pylint: enable=protected-access
126
        self.napp.execute()
127
        mock_execute_consistency.assert_not_called()
128
        mock_log.info.assert_not_called()
129
130
    @patch('napps.kytos.mef_eline.main.settings')
131
    @patch('napps.kytos.mef_eline.main.Main._load_evc')
132
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
133
    def test_execute_consistency(self, *args):
134
        """Test execute_consistency."""
135
        (mock_get_data, mock_load_evc, mock_settings) = args
136
137
        stored_circuits = {'1': {'name': 'circuit_1'},
138
                           '2': {'name': 'circuit_2'},
139
                           '3': {'name': 'circuit_3'}}
140
        mock_get_data.return_value = stored_circuits
141
        mock_settings.WAIT_FOR_OLD_PATH = -1
142
        evc1 = MagicMock()
143
        evc1.is_enabled.return_value = True
144
        evc1.is_active.return_value = False
145
        evc1.lock.locked.return_value = False
146
        evc1.check_traces.return_value = True
147
        evc2 = MagicMock()
148
        evc2.is_enabled.return_value = True
149
        evc2.is_active.return_value = False
150
        evc2.lock.locked.return_value = False
151
        evc2.check_traces.return_value = False
152
        self.napp.circuits = {'1': evc1, '2': evc2}
153
154
        self.napp.execute_consistency()
155
        self.assertEqual(evc1.activate.call_count, 1)
156
        self.assertEqual(evc1.sync.call_count, 1)
157
        self.assertEqual(evc2.deploy.call_count, 1)
158
        mock_load_evc.assert_called_with(stored_circuits['3'])
159
160
    @patch('napps.kytos.mef_eline.main.settings')
161
    def test_execute_consistency_wait_for(self, mock_settings):
162
        """Test execute and wait for setting."""
163
        evc1 = MagicMock()
164
        evc1.is_enabled.return_value = True
165
        evc1.is_active.return_value = False
166
        evc1.lock.locked.return_value = False
167
        evc1.check_traces.return_value = False
168
        evc1.deploy.call_count = 0
169
        self.napp.circuits = {'1': evc1}
170
        self.napp.execution_rounds = 0
171
        mock_settings.WAIT_FOR_OLD_PATH = 1
172
173
        self.napp.execute_consistency()
174
        self.assertEqual(evc1.deploy.call_count, 0)
175
        self.napp.execute_consistency()
176
        self.assertEqual(evc1.deploy.call_count, 1)
177
178
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
179
    @patch('napps.kytos.mef_eline.models.evc.EVCBase._validate')
180
    def test_evc_from_dict(self, _validate_mock, uni_from_dict_mock):
181
        """
182
        Test the helper method that create an EVN from dict.
183
184
        Verify object creation with circuit data and schedule data.
185
        """
186
        _validate_mock.return_value = True
187
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
188
        payload = {
189
            "name": "my evc1",
190
            "uni_a": {
191
                "interface_id": "00:00:00:00:00:00:00:01:1",
192
                "tag": {"tag_type": 1, "value": 80},
193
            },
194
            "uni_z": {
195
                "interface_id": "00:00:00:00:00:00:00:02:2",
196
                "tag": {"tag_type": 1, "value": 1},
197
            },
198
            "circuit_scheduler": [
199
                {"frequency": "* * * * *", "action": "create"}
200
            ],
201
            "queue_id": 5,
202
        }
203
        # pylint: disable=protected-access
204
        evc_response = self.napp._evc_from_dict(payload)
205
        self.assertIsNotNone(evc_response)
206
        self.assertIsNotNone(evc_response.uni_a)
207
        self.assertIsNotNone(evc_response.uni_z)
208
        self.assertIsNotNone(evc_response.circuit_scheduler)
209
        self.assertIsNotNone(evc_response.name)
210
        self.assertIsNotNone(evc_response.queue_id)
211
212
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
213
    @patch("napps.kytos.mef_eline.models.evc.EVCBase._validate")
214
    @patch("kytos.core.Controller.get_interface_by_id")
215
    def test_evc_from_dict_paths(
216
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
217
    ):
218
        """
219
        Test the helper method that create an EVN from dict.
220
221
        Verify object creation with circuit data and schedule data.
222
        """
223
        _get_interface_by_id_mock.return_value = True
224
        _validate_mock.return_value = True
225
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
226
        payload = {
227
            "name": "my evc1",
228
            "uni_a": {
229
                "interface_id": "00:00:00:00:00:00:00:01:1",
230
                "tag": {"tag_type": 1, "value": 80},
231
            },
232
            "uni_z": {
233
                "interface_id": "00:00:00:00:00:00:00:02:2",
234
                "tag": {"tag_type": 1, "value": 1},
235
            },
236
            "current_path": [],
237
            "primary_path": [
238
                {
239
                    "endpoint_a": {
240
                        "interface_id": "00:00:00:00:00:00:00:01:1"
241
                    },
242
                    "endpoint_b": {
243
                        "interface_id": "00:00:00:00:00:00:00:02:2"
244
                    },
245
                }
246
            ],
247
            "backup_path": [],
248
        }
249
250
        # pylint: disable=protected-access
251
        evc_response = self.napp._evc_from_dict(payload)
252
        self.assertIsNotNone(evc_response)
253
        self.assertIsNotNone(evc_response.uni_a)
254
        self.assertIsNotNone(evc_response.uni_z)
255
        self.assertIsNotNone(evc_response.circuit_scheduler)
256
        self.assertIsNotNone(evc_response.name)
257
        self.assertEqual(len(evc_response.current_path), 0)
258
        self.assertEqual(len(evc_response.backup_path), 0)
259
        self.assertEqual(len(evc_response.primary_path), 1)
260
261
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
262
    @patch("napps.kytos.mef_eline.models.evc.EVCBase._validate")
263
    @patch("kytos.core.Controller.get_interface_by_id")
264
    def test_evc_from_dict_links(
265
        self, _get_interface_by_id_mock, _validate_mock, uni_from_dict_mock
266
    ):
267
        """
268
        Test the helper method that create an EVN from dict.
269
270
        Verify object creation with circuit data and schedule data.
271
        """
272
        _get_interface_by_id_mock.return_value = True
273
        _validate_mock.return_value = True
274
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
275
        payload = {
276
            "name": "my evc1",
277
            "uni_a": {
278
                "interface_id": "00:00:00:00:00:00:00:01:1",
279
                "tag": {"tag_type": 1, "value": 80},
280
            },
281
            "uni_z": {
282
                "interface_id": "00:00:00:00:00:00:00:02:2",
283
                "tag": {"tag_type": 1, "value": 1},
284
            },
285
            "primary_links": [
286
                {
287
                    "endpoint_a": {
288
                        "interface_id": "00:00:00:00:00:00:00:01:1"
289
                    },
290
                    "endpoint_b": {
291
                        "interface_id": "00:00:00:00:00:00:00:02:2"
292
                    },
293
                }
294
            ],
295
            "backup_links": [],
296
        }
297
298
        # pylint: disable=protected-access
299
        evc_response = self.napp._evc_from_dict(payload)
300
        self.assertIsNotNone(evc_response)
301
        self.assertIsNotNone(evc_response.uni_a)
302
        self.assertIsNotNone(evc_response.uni_z)
303
        self.assertIsNotNone(evc_response.circuit_scheduler)
304
        self.assertIsNotNone(evc_response.name)
305
        self.assertEqual(len(evc_response.current_links_cache), 0)
306
        self.assertEqual(len(evc_response.backup_links), 0)
307
        self.assertEqual(len(evc_response.primary_links), 1)
308
309
    def test_list_without_circuits(self):
310
        """Test if list circuits return 'no circuit stored.'."""
311
        api = self.get_app_test_client(self.napp)
312
        url = f"{self.server_name_url}/v2/evc/"
313
        response = api.get(url)
314
        self.assertEqual(response.status_code, 200, response.data)
315
        self.assertEqual(json.loads(response.data.decode()), {})
316
317
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
318
    def test_list_no_circuits_stored(self, storehouse_data_mock):
319
        """Test if list circuits return all circuits stored."""
320
        circuits = {}
321
        storehouse_data_mock.return_value = circuits
322
323
        api = self.get_app_test_client(self.napp)
324
        url = f"{self.server_name_url}/v2/evc/"
325
326
        response = api.get(url)
327
        expected_result = circuits
328
        self.assertEqual(json.loads(response.data), expected_result)
329
330
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
331
    def test_list_with_circuits_stored(self, storehouse_data_mock):
332
        """Test if list circuits return all circuits stored."""
333
        circuits = {"1": {"name": "circuit_1"}, "2": {"name": "circuit_2"}}
334
        storehouse_data_mock.return_value = circuits
335
336
        api = self.get_app_test_client(self.napp)
337
        url = f"{self.server_name_url}/v2/evc/"
338
339
        response = api.get(url)
340
        expected_result = circuits
341
        self.assertEqual(json.loads(response.data), expected_result)
342
343 View Code Duplication
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
344
    def test_list_with_archived_circuits_stored_1(self, storehouse_data_mock):
345
        """Test if list circuits return only circuits not archived."""
346
        circuits = {
347
            "1": {"name": "circuit_1"},
348
            "2": {"name": "circuit_2", "archived": True},
349
        }
350
        storehouse_data_mock.return_value = circuits
351
352
        api = self.get_app_test_client(self.napp)
353
        url = f"{self.server_name_url}/v2/evc/"
354
355
        response = api.get(url)
356
        expected_result = {"1": circuits["1"]}
357
        self.assertEqual(json.loads(response.data), expected_result)
358
359 View Code Duplication
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
360
    def test_list_with_archived_circuits_stored_2(self, storehouse_data_mock):
361
        """Test if list circuits return all circuits."""
362
        circuits = {
363
            "1": {"name": "circuit_1"},
364
            "2": {"name": "circuit_2", "archived": True},
365
        }
366
        storehouse_data_mock.return_value = circuits
367
368
        api = self.get_app_test_client(self.napp)
369
        url = f"{self.server_name_url}/v2/evc/?archived=True"
370
371
        response = api.get(url)
372
        expected_result = circuits
373
        self.assertEqual(json.loads(response.data), expected_result)
374
375 View Code Duplication
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
376
    def test_circuit_with_valid_id(self, storehouse_data_mock):
377
        """Test if get_circuit return the circuit attributes."""
378
        circuits = {"1": {"name": "circuit_1"}, "2": {"name": "circuit_2"}}
379
        storehouse_data_mock.return_value = circuits
380
381
        api = self.get_app_test_client(self.napp)
382
        url = f"{self.server_name_url}/v2/evc/1"
383
        response = api.get(url)
384
        expected_result = circuits["1"]
385
        self.assertEqual(json.loads(response.data), expected_result)
386
387 View Code Duplication
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
388
    def test_circuit_with_invalid_id(self, storehouse_data_mock):
389
        """Test if get_circuit return invalid circuit_id."""
390
        circuits = {"1": {"name": "circuit_1"}, "2": {"name": "circuit_2"}}
391
        storehouse_data_mock.return_value = circuits
392
393
        api = self.get_app_test_client(self.napp)
394
        url = f"{self.server_name_url}/v2/evc/3"
395
        response = api.get(url)
396
        expected_result = "circuit_id 3 not found"
397
        self.assertEqual(
398
            json.loads(response.data)["description"], expected_result
399
        )
400
401
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
402
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
403
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
404
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
405
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.save_evc")
406
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
407
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
408
    def test_create_a_circuit_case_1(self, *args):
409
        """Test create a new circuit."""
410
        # pylint: disable=too-many-locals
411
        (
412
            validate_mock,
413
            evc_as_dict_mock,
414
            save_evc_mock,
415
            uni_from_dict_mock,
416
            sched_add_mock,
417
            storehouse_data_mock,
418
            evc_deploy_mock,
419
        ) = args
420
421
        validate_mock.return_value = True
422
        save_evc_mock.return_value = True
423
        evc_deploy_mock.return_value = True
424
        uni1 = create_autospec(UNI)
425
        uni2 = create_autospec(UNI)
426
        uni1.interface = create_autospec(Interface)
427
        uni2.interface = create_autospec(Interface)
428
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
429
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
430
        uni_from_dict_mock.side_effect = [uni1, uni2]
431
        evc_as_dict_mock.return_value = {}
432
        sched_add_mock.return_value = True
433
        storehouse_data_mock.return_value = {}
434
435
        api = self.get_app_test_client(self.napp)
436
        url = f"{self.server_name_url}/v2/evc/"
437
        payload = {
438
            "name": "my evc1",
439
            "frequency": "* * * * *",
440
            "uni_a": {
441
                "interface_id": "00:00:00:00:00:00:00:01:1",
442
                "tag": {"tag_type": 1, "value": 80},
443
            },
444
            "uni_z": {
445
                "interface_id": "00:00:00:00:00:00:00:02:2",
446
                "tag": {"tag_type": 1, "value": 1},
447
            },
448
            "dynamic_backup_path": True,
449
        }
450
451
        response = api.post(
452
            url, data=json.dumps(payload), content_type="application/json"
453
        )
454
        current_data = json.loads(response.data)
455
456
        # verify expected result from request
457
        self.assertEqual(201, response.status_code, response.data)
458
        self.assertIn("circuit_id", current_data)
459
460
        # verify uni called
461
        uni_from_dict_mock.called_twice()
462
        uni_from_dict_mock.assert_any_call(payload["uni_z"])
463
        uni_from_dict_mock.assert_any_call(payload["uni_a"])
464
465
        # verify validation called
466
        validate_mock.assert_called_once()
467
        validate_mock.assert_called_with(
468
            frequency="* * * * *",
469
            name="my evc1",
470
            uni_a=uni1,
471
            uni_z=uni2,
472
            dynamic_backup_path=True,
473
        )
474
        # verify save method is called
475
        save_evc_mock.assert_called_once()
476
477
        # verify evc as dict is called to save in the box
478
        evc_as_dict_mock.assert_called_once()
479
        # verify add circuit in sched
480
        sched_add_mock.assert_called_once()
481
482
    @staticmethod
483
    def get_napp_urls(napp):
484
        """Return the kytos/mef_eline urls.
485
486
        The urls will be like:
487
488
        urls = [
489
            (options, methods, url)
490
        ]
491
492
        """
493
        controller = napp.controller
494
        controller.api_server.register_napp_endpoints(napp)
495
496
        urls = []
497
        for rule in controller.api_server.app.url_map.iter_rules():
498
            options = {}
499
            for arg in rule.arguments:
500
                options[arg] = f"[{0}]".format(arg)
501
502
            if f"{napp.username}/{napp.name}" in str(rule):
503
                urls.append((options, rule.methods, f"{str(rule)}"))
504
505
        return urls
506
507
    @staticmethod
508
    def get_app_test_client(napp):
509
        """Return a flask api test client."""
510
        napp.controller.api_server.register_napp_endpoints(napp)
511
        return napp.controller.api_server.app.test_client()
512
513
    def test_create_a_circuit_case_2(self):
514
        """Test create a new circuit trying to send request without a json."""
515
        api = self.get_app_test_client(self.napp)
516
        url = f"{self.server_name_url}/v2/evc/"
517
518
        response = api.post(url)
519
        current_data = json.loads(response.data)
520
        expected_message = "The request body mimetype is not application/json."
521
        expected_data = expected_message
522
        self.assertEqual(415, response.status_code, response.data)
523
        self.assertEqual(current_data["description"], expected_data)
524
525
    def test_create_a_circuit_case_3(self):
526
        """Test create a new circuit trying to send request with an
527
        invalid json."""
528
        api = self.get_app_test_client(self.napp)
529
        url = f"{self.server_name_url}/v2/evc/"
530
531
        response = api.post(
532
            url,
533
            data="This is an {Invalid:} JSON",
534
            content_type="application/json",
535
        )
536
        current_data = json.loads(response.data)
537
        expected_data = "The request body is not a well-formed JSON."
538
539
        self.assertEqual(400, response.status_code, response.data)
540
        self.assertEqual(current_data["description"], expected_data)
541
542
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
543
    def test_create_a_circuit_case_4(self, uni_from_dict_mock):
544
        """Test create a new circuit trying to send request with an
545
        invalid value."""
546
        # pylint: disable=too-many-locals
547
        uni_from_dict_mock.side_effect = ValueError("Could not instantiate")
548
        api = self.get_app_test_client(self.napp)
549
        url = f"{self.server_name_url}/v2/evc/"
550
551
        payload = {
552
            "name": "my evc1",
553
            "frequency": "* * * * *",
554
            "uni_a": {
555
                "interface_id": "00:00:00:00:00:00:00:01:76",
556
                "tag": {"tag_type": 1, "value": 80},
557
            },
558
            "uni_z": {
559
                "interface_id": "00:00:00:00:00:00:00:02:2",
560
                "tag": {"tag_type": 1, "value": 1},
561
            },
562
        }
563
564
        response = api.post(
565
            url, data=json.dumps(payload), content_type="application/json"
566
        )
567
        current_data = json.loads(response.data)
568
        expected_data = "Error creating UNI: Invalid value"
569
        self.assertEqual(400, response.status_code, response.data)
570
        self.assertEqual(current_data["description"], expected_data)
571
572
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
573
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
574
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
575
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.save_evc")
576
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
577
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
578
    def test_create_circuit_already_enabled(self, *args):
579
        """Test create an already created circuit."""
580
        # pylint: disable=too-many-locals
581
        (
582
            evc_as_dict_mock,
583
            validate_mock,
584
            save_evc_mock,
585
            uni_from_dict_mock,
586
            sched_add_mock,
587
            evc_deploy_mock,
588
        ) = args
589
590
        validate_mock.return_value = True
591
        save_evc_mock.return_value = True
592
        sched_add_mock.return_value = True
593
        evc_deploy_mock.return_value = True
594
        uni1 = create_autospec(UNI)
595
        uni2 = create_autospec(UNI)
596
        uni1.interface = create_autospec(Interface)
597
        uni2.interface = create_autospec(Interface)
598
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
599
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
600
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
601
602
        api = self.get_app_test_client(self.napp)
603
        payload = {
604
            "name": "my evc1",
605
            "uni_a": {
606
                "interface_id": "00:00:00:00:00:00:00:01:1",
607
                "tag": {"tag_type": 1, "value": 80},
608
            },
609
            "uni_z": {
610
                "interface_id": "00:00:00:00:00:00:00:02:2",
611
                "tag": {"tag_type": 1, "value": 1},
612
            },
613
            "dynamic_backup_path": True,
614
        }
615
616
        evc_as_dict_mock.return_value = payload
617
        response = api.post(
618
            f"{self.server_name_url}/v2/evc/",
619
            data=json.dumps(payload),
620
            content_type="application/json",
621
        )
622
        self.assertEqual(201, response.status_code)
623
624
        response = api.post(
625
            f"{self.server_name_url}/v2/evc/",
626
            data=json.dumps(payload),
627
            content_type="application/json",
628
        )
629
        current_data = json.loads(response.data)
630
        expected_data = "The EVC already exists."
631
        self.assertEqual(current_data["description"], expected_data)
632
        self.assertEqual(409, response.status_code)
633
634
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
635
    def test_create_circuit_case_5(self, uni_from_dict_mock):
636
        """Test when neither primary path nor dynamic_backup_path is set."""
637
        api = self.get_app_test_client(self.napp)
638
        url = f"{self.server_name_url}/v2/evc/"
639
        uni1 = create_autospec(UNI)
640
        uni2 = create_autospec(UNI)
641
        uni1.interface = create_autospec(Interface)
642
        uni2.interface = create_autospec(Interface)
643
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
644
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
645
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
646
647
        payload = {
648
            "name": "my evc1",
649
            "frequency": "* * * * *",
650
            "uni_a": {
651
                "interface_id": "00:00:00:00:00:00:00:01:1",
652
                "tag": {"tag_type": 1, "value": 80},
653
            },
654
            "uni_z": {
655
                "interface_id": "00:00:00:00:00:00:00:02:2",
656
                "tag": {"tag_type": 1, "value": 1},
657
            },
658
        }
659
660
        response = api.post(
661
            url, data=json.dumps(payload), content_type="application/json"
662
        )
663
        current_data = json.loads(response.data)
664
        expected_data = "The EVC must have a primary path "
665
        expected_data += "or allow dynamic paths."
666
        self.assertEqual(400, response.status_code, response.data)
667
        self.assertEqual(current_data["description"], expected_data)
668
669
    def test_redeploy_evc(self):
670
        """Test endpoint to redeploy an EVC."""
671
        evc1 = MagicMock()
672
        evc1.is_enabled.return_value = True
673
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
674
        api = self.get_app_test_client(self.napp)
675
        url = f"{self.server_name_url}/v2/evc/1/redeploy"
676
        response = api.patch(url)
677
        self.assertEqual(response.status_code, 202, response.data)
678
679
    def test_redeploy_evc_disabled(self):
680
        """Test endpoint to redeploy an EVC."""
681
        evc1 = MagicMock()
682
        evc1.is_enabled.return_value = False
683
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
684
        api = self.get_app_test_client(self.napp)
685
        url = f"{self.server_name_url}/v2/evc/1/redeploy"
686
        response = api.patch(url)
687
        self.assertEqual(response.status_code, 409, response.data)
688
689
    def test_redeploy_evc_deleted(self):
690
        """Test endpoint to redeploy an EVC."""
691
        evc1 = MagicMock()
692
        evc1.is_enabled.return_value = True
693
        self.napp.circuits = {"1": evc1, "2": MagicMock()}
694
        api = self.get_app_test_client(self.napp)
695
        url = f"{self.server_name_url}/v2/evc/3/redeploy"
696
        response = api.patch(url)
697
        self.assertEqual(response.status_code, 404, response.data)
698
699
    def test_list_schedules__no_data(self):
700
        """Test list of schedules."""
701
        api = self.get_app_test_client(self.napp)
702
        url = f"{self.server_name_url}/v2/evc/schedule"
703
        response = api.get(url)
704
        self.assertEqual(response.status_code, 200, response.data)
705
        self.assertEqual(json.loads(response.data.decode()), {})
706
707
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
708
    def test_list_schedules__no_data_stored(self, storehouse_data_mock):
709
        """Test if list circuits return all circuits stored."""
710
        circuits = {}
711
        storehouse_data_mock.return_value = circuits
712
713
        api = self.get_app_test_client(self.napp)
714
        url = f"{self.server_name_url}/v2/evc/schedule"
715
716
        response = api.get(url)
717
        expected_result = circuits
718
719
        self.assertEqual(response.status_code, 200, response.data)
720
        self.assertEqual(json.loads(response.data), expected_result)
721
722
    # pylint: disable=no-self-use
723
    def _add_storehouse_schedule_data(self, storehouse_data_mock):
724
        """Add schedule data to storehouse mock object."""
725
        circuits = {}
726
        payload_1 = {
727
            "id": "aa:aa:aa",
728
            "name": "my evc1",
729
            "uni_a": {
730
                "interface_id": "00:00:00:00:00:00:00:01:1",
731
                "tag": {"tag_type": 1, "value": 80},
732
            },
733
            "uni_z": {
734
                "interface_id": "00:00:00:00:00:00:00:02:2",
735
                "tag": {"tag_type": 1, "value": 1},
736
            },
737
            "circuit_scheduler": [
738
                {"id": "1", "frequency": "* * * * *", "action": "create"},
739
                {"id": "2", "frequency": "1 * * * *", "action": "remove"},
740
            ],
741
        }
742
        circuits.update({"aa:aa:aa": payload_1})
743
        payload_2 = {
744
            "id": "bb:bb:bb",
745
            "name": "my second evc2",
746
            "uni_a": {
747
                "interface_id": "00:00:00:00:00:00:00:01:2",
748
                "tag": {"tag_type": 1, "value": 90},
749
            },
750
            "uni_z": {
751
                "interface_id": "00:00:00:00:00:00:00:03:2",
752
                "tag": {"tag_type": 1, "value": 100},
753
            },
754
            "circuit_scheduler": [
755
                {"id": "3", "frequency": "1 * * * *", "action": "create"},
756
                {"id": "4", "frequency": "2 * * * *", "action": "remove"},
757
            ],
758
        }
759
        circuits.update({"bb:bb:bb": payload_2})
760
        payload_3 = {
761
            "id": "cc:cc:cc",
762
            "name": "my third evc3",
763
            "uni_a": {
764
                "interface_id": "00:00:00:00:00:00:00:03:1",
765
                "tag": {"tag_type": 1, "value": 90},
766
            },
767
            "uni_z": {
768
                "interface_id": "00:00:00:00:00:00:00:04:2",
769
                "tag": {"tag_type": 1, "value": 100},
770
            },
771
        }
772
        circuits.update({"cc:cc:cc": payload_3})
773
        # Add one circuit to the storehouse.
774
        storehouse_data_mock.return_value = circuits
775
776
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
777
    def test_list_schedules_from_storehouse(self, storehouse_data_mock):
778
        """Test if list circuits return specific circuits stored."""
779
        self._add_storehouse_schedule_data(storehouse_data_mock)
780
781
        api = self.get_app_test_client(self.napp)
782
        url = f"{self.server_name_url}/v2/evc/schedule"
783
784
        # Call URL
785
        response = api.get(url)
786
        # Expected JSON data from response
787
        expected = [
788
            {
789
                "circuit_id": "aa:aa:aa",
790
                "schedule": {
791
                    "action": "create",
792
                    "frequency": "* * * * *",
793
                    "id": "1",
794
                },
795
                "schedule_id": "1",
796
            },
797
            {
798
                "circuit_id": "aa:aa:aa",
799
                "schedule": {
800
                    "action": "remove",
801
                    "frequency": "1 * * * *",
802
                    "id": "2",
803
                },
804
                "schedule_id": "2",
805
            },
806
            {
807
                "circuit_id": "bb:bb:bb",
808
                "schedule": {
809
                    "action": "create",
810
                    "frequency": "1 * * * *",
811
                    "id": "3",
812
                },
813
                "schedule_id": "3",
814
            },
815
            {
816
                "circuit_id": "bb:bb:bb",
817
                "schedule": {
818
                    "action": "remove",
819
                    "frequency": "2 * * * *",
820
                    "id": "4",
821
                },
822
                "schedule_id": "4",
823
            },
824
        ]
825
826
        self.assertEqual(response.status_code, 200, response.data)
827
        self.assertEqual(expected, json.loads(response.data))
828
829
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
830
    def test_get_specific_schedule_from_storehouse(self, storehouse_data_mock):
831
        """Test get schedules from a circuit."""
832
        self._add_storehouse_schedule_data(storehouse_data_mock)
833
834
        requested_circuit_id = "bb:bb:bb"
835
        api = self.get_app_test_client(self.napp)
836
        url = f"{self.server_name_url}/v2/evc/{requested_circuit_id}"
837
838
        # Call URL
839
        response = api.get(url)
840
841
        # Expected JSON data from response
842
        expected = [
843
            {"action": "create", "frequency": "1 * * * *", "id": "3"},
844
            {"action": "remove", "frequency": "2 * * * *", "id": "4"},
845
        ]
846
847
        self.assertEqual(response.status_code, 200)
848
        self.assertEqual(
849
            expected, json.loads(response.data)["circuit_scheduler"]
850
        )
851
852
    def test_get_specific_schedules_from_storehouse_not_found(self):
853
        """Test get specific schedule ID that does not exist."""
854
        requested_id = "blah"
855
        api = self.get_app_test_client(self.napp)
856
        url = f"{self.server_name_url}/v2/evc/{requested_id}"
857
858
        # Call URL
859
        response = api.get(url)
860
861
        expected = "circuit_id blah not found"
862
        # Assert response not found
863
        self.assertEqual(response.status_code, 404, response.data)
864
        self.assertEqual(expected, json.loads(response.data)["description"])
865
866
    def _uni_from_dict_side_effect(self, uni_dict):
867
        interface_id = uni_dict.get("interface_id")
868
        tag_dict = uni_dict.get("tag")
869
        interface = Interface(interface_id, "0", "switch")
870
        return UNI(interface, tag_dict)
871
872
    @patch("apscheduler.schedulers.background.BackgroundScheduler.add_job")
873
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
874
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
875
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
876
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.save_evc")
877
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
878
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
879
    def test_create_schedule(self, *args):  # pylint: disable=too-many-locals
880
        """Test create a circuit schedule."""
881
        (
882
            validate_mock,
883
            evc_as_dict_mock,
884
            save_evc_mock,
885
            uni_from_dict_mock,
886
            sched_add_mock,
887
            storehouse_data_mock,
888
            scheduler_add_job_mock,
889
        ) = args
890
891
        validate_mock.return_value = True
892
        save_evc_mock.return_value = True
893
        uni_from_dict_mock.side_effect = self._uni_from_dict_side_effect
894
        evc_as_dict_mock.return_value = {}
895
        sched_add_mock.return_value = True
896
        storehouse_data_mock.return_value = {}
897
898
        self._add_storehouse_schedule_data(storehouse_data_mock)
899
900
        requested_id = "bb:bb:bb"
901
        api = self.get_app_test_client(self.napp)
902
        url = f"{self.server_name_url}/v2/evc/schedule/"
903
904
        payload = {
905
            "circuit_id": requested_id,
906
            "schedule": {"frequency": "1 * * * *", "action": "create"},
907
        }
908
909
        # Call URL
910
        response = api.post(
911
            url, data=json.dumps(payload), content_type="application/json"
912
        )
913
914
        response_json = json.loads(response.data)
915
916
        self.assertEqual(response.status_code, 201, response.data)
917
        scheduler_add_job_mock.assert_called_once()
918
        save_evc_mock.assert_called_once()
919
        self.assertEqual(
920
            payload["schedule"]["frequency"], response_json["frequency"]
921
        )
922
        self.assertEqual(
923
            payload["schedule"]["action"], response_json["action"]
924
        )
925
        self.assertIsNotNone(response_json["id"])
926
927
        # Case 2: there is no schedule
928
        payload = {
929
              "circuit_id": "cc:cc:cc",
930
              "schedule": {
931
                "frequency": "1 * * * *",
932
                "action": "create"
933
              }
934
            }
935
        response = api.post(url, data=json.dumps(payload),
936
                            content_type='application/json')
937
        self.assertEqual(response.status_code, 201)
938
939
    def test_create_schedule_invalid_request(self):
940
        """Test create schedule API with invalid request."""
941
        evc1 = MagicMock()
942
        self.napp.circuits = {'bb:bb:bb': evc1}
943
        api = self.get_app_test_client(self.napp)
944
        url = f'{self.server_name_url}/v2/evc/schedule/'
945
946
        # case 1: empty post
947
        response = api.post(url, data="")
948
        self.assertEqual(response.status_code, 415)
949
950
        # case 2: content-type not specified
951
        payload = {
952
            "circuit_id": "bb:bb:bb",
953
            "schedule": {
954
                "frequency": "1 * * * *",
955
                "action": "create"
956
            }
957
        }
958
        response = api.post(url, data=json.dumps(payload))
959
        self.assertEqual(response.status_code, 415)
960
961
        # case 3: not a dictionary
962
        payload = []
963
        response = api.post(url, data=json.dumps(payload),
964
                            content_type='application/json')
965
        self.assertEqual(response.status_code, 400)
966
967
        # case 4: missing circuit id
968
        payload = {
969
            "schedule": {
970
                "frequency": "1 * * * *",
971
                "action": "create"
972
            }
973
        }
974
        response = api.post(url, data=json.dumps(payload),
975
                            content_type='application/json')
976
        self.assertEqual(response.status_code, 400)
977
978
        # case 5: missing schedule
979
        payload = {
980
            "circuit_id": "bb:bb:bb"
981
        }
982
        response = api.post(url, data=json.dumps(payload),
983
                            content_type='application/json')
984
        self.assertEqual(response.status_code, 400)
985
986
        # case 6: invalid circuit
987
        payload = {
988
            "circuit_id": "xx:xx:xx",
989
            "schedule": {
990
                "frequency": "1 * * * *",
991
                "action": "create"
992
            }
993
        }
994
        response = api.post(url, data=json.dumps(payload),
995
                            content_type='application/json')
996
        self.assertEqual(response.status_code, 404)
997
998
        # case 7: archived or deleted evc
999
        evc1.archived.return_value = True
1000
        payload = {
1001
            "circuit_id": "bb:bb:bb",
1002
            "schedule": {
1003
                "frequency": "1 * * * *",
1004
                "action": "create"
1005
            }
1006
        }
1007
        response = api.post(url, data=json.dumps(payload),
1008
                            content_type='application/json')
1009
        self.assertEqual(response.status_code, 403)
1010
1011
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
1012
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
1013
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1014
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1015
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
1016
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1017
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1018
    def test_update_schedule(self, *args):  # pylint: disable=too-many-locals
1019
        """Test create a circuit schedule."""
1020
        (
1021
            validate_mock,
1022
            evc_as_dict_mock,
1023
            save_evc_mock,
1024
            uni_from_dict_mock,
1025
            sched_add_mock,
1026
            storehouse_data_mock,
1027
            scheduler_remove_job_mock,
1028
        ) = args
1029
1030
        storehouse_payload_1 = {
1031
            "aa:aa:aa": {
1032
                "id": "aa:aa:aa",
1033
                "name": "my evc1",
1034
                "uni_a": {
1035
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1036
                    "tag": {"tag_type": 1, "value": 80},
1037
                },
1038
                "uni_z": {
1039
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1040
                    "tag": {"tag_type": 1, "value": 1},
1041
                },
1042
                "circuit_scheduler": [
1043
                    {"id": "1", "frequency": "* * * * *", "action": "create"}
1044
                ],
1045
            }
1046
        }
1047
1048
        validate_mock.return_value = True
1049
        save_evc_mock.return_value = True
1050
        sched_add_mock.return_value = True
1051
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1052
        evc_as_dict_mock.return_value = {}
1053
        storehouse_data_mock.return_value = storehouse_payload_1
1054
        scheduler_remove_job_mock.return_value = True
1055
1056
        requested_schedule_id = "1"
1057
        api = self.get_app_test_client(self.napp)
1058
        url = f"{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}"
1059
1060
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1061
1062
        # Call URL
1063
        response = api.patch(
1064
            url, data=json.dumps(payload), content_type="application/json"
1065
        )
1066
1067
        response_json = json.loads(response.data)
1068
1069
        self.assertEqual(response.status_code, 200, response.data)
1070
        scheduler_remove_job_mock.assert_called_once()
1071
        save_evc_mock.assert_called_once()
1072
        self.assertEqual(payload["frequency"], response_json["frequency"])
1073
        self.assertEqual(payload["action"], response_json["action"])
1074
        self.assertIsNotNone(response_json["id"])
1075
1076
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
1077
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1078
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1079
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1080
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1081
    def test_update_schedule_archived(self, *args):
1082
        """Test create a circuit schedule."""
1083
        # pylint: disable=too-many-locals
1084
        (
1085
            validate_mock,
1086
            evc_as_dict_mock,
1087
            uni_from_dict_mock,
1088
            sched_add_mock,
1089
            storehouse_data_mock,
1090
        ) = args
1091
1092
        storehouse_payload_1 = {
1093
            "aa:aa:aa": {
1094
                "id": "aa:aa:aa",
1095
                "name": "my evc1",
1096
                "archived": True,
1097
                "circuit_scheduler": [
1098
                    {"id": "1", "frequency": "* * * * *", "action": "create"}
1099
                ],
1100
            }
1101
        }
1102
1103
        validate_mock.return_value = True
1104
        sched_add_mock.return_value = True
1105
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1106
        evc_as_dict_mock.return_value = {}
1107
        storehouse_data_mock.return_value = storehouse_payload_1
1108
1109
        requested_schedule_id = "1"
1110
        api = self.get_app_test_client(self.napp)
1111
        url = f"{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}"
1112
1113
        payload = {"frequency": "*/1 * * * *", "action": "create"}
1114
1115
        # Call URL
1116
        response = api.patch(
1117
            url, data=json.dumps(payload), content_type="application/json"
1118
        )
1119
1120
        self.assertEqual(response.status_code, 403, response.data)
1121
1122
    @patch("apscheduler.schedulers.background.BackgroundScheduler.remove_job")
1123
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
1124
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1125
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.save_evc")
1126
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1127
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1128
    def test_delete_schedule(self, *args):
1129
        """Test create a circuit schedule."""
1130
        (
1131
            validate_mock,
1132
            evc_as_dict_mock,
1133
            save_evc_mock,
1134
            uni_from_dict_mock,
1135
            storehouse_data_mock,
1136
            scheduler_remove_job_mock,
1137
        ) = args
1138
1139
        storehouse_payload_1 = {
1140
            "2": {
1141
                "id": "2",
1142
                "name": "my evc1",
1143
                "uni_a": {
1144
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1145
                    "tag": {"tag_type": 1, "value": 80},
1146
                },
1147
                "uni_z": {
1148
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1149
                    "tag": {"tag_type": 1, "value": 1},
1150
                },
1151
                "circuit_scheduler": [
1152
                    {"id": "1", "frequency": "* * * * *", "action": "create"}
1153
                ],
1154
            }
1155
        }
1156
        validate_mock.return_value = True
1157
        save_evc_mock.return_value = True
1158
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1159
        evc_as_dict_mock.return_value = {}
1160
        storehouse_data_mock.return_value = storehouse_payload_1
1161
        scheduler_remove_job_mock.return_value = True
1162
1163
        requested_schedule_id = "1"
1164
        api = self.get_app_test_client(self.napp)
1165
        url = f"{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}"
1166
1167
        # Call URL
1168
        response = api.delete(url)
1169
1170
        self.assertEqual(response.status_code, 200, response.data)
1171
        scheduler_remove_job_mock.assert_called_once()
1172
        save_evc_mock.assert_called_once()
1173
        self.assertIn("Schedule removed", f"{response.data}")
1174
1175
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.get_data")
1176
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1177
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1178
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1179
    def test_delete_schedule_archived(self, *args):
1180
        """Test create a circuit schedule."""
1181
        (
1182
            validate_mock,
1183
            evc_as_dict_mock,
1184
            uni_from_dict_mock,
1185
            storehouse_data_mock,
1186
        ) = args
1187
1188
        storehouse_payload_1 = {
1189
            "2": {
1190
                "id": "2",
1191
                "name": "my evc1",
1192
                "archived": True,
1193
                "circuit_scheduler": [
1194
                    {"id": "1", "frequency": "* * * * *", "action": "create"}
1195
                ],
1196
            }
1197
        }
1198
1199
        validate_mock.return_value = True
1200
        uni_from_dict_mock.side_effect = ["uni_a", "uni_z"]
1201
        evc_as_dict_mock.return_value = {}
1202
        storehouse_data_mock.return_value = storehouse_payload_1
1203
1204
        requested_schedule_id = "1"
1205
        api = self.get_app_test_client(self.napp)
1206
        url = f"{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}"
1207
1208
        # Call URL
1209
        response = api.delete(url)
1210
1211
        self.assertEqual(response.status_code, 403, response.data)
1212
1213
    @patch('napps.kytos.mef_eline.main.Main._find_evc_by_schedule_id')
1214
    def test_delete_schedule_not_found(self, mock_find_evc_by_sched):
1215
        """Test delete a circuit schedule - unexisting."""
1216
        mock_find_evc_by_sched.return_value = (None, False)
1217
        api = self.get_app_test_client(self.napp)
1218
        url = f'{self.server_name_url}/v2/evc/schedule/1'
1219
        response = api.delete(url)
1220
        self.assertEqual(response.status_code, 404)
1221
1222
    def test_get_circuit_not_found(self):
1223
        """Test /v2/evc/<circuit_id> 404."""
1224
        api = self.get_app_test_client(self.napp)
1225
        url = f'{self.server_name_url}/v2/evc/1234'
1226
        response = api.get(url)
1227
        self.assertEqual(response.status_code, 404)
1228
1229
    @patch('requests.post')
1230
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
1231
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
1232
    @patch('napps.kytos.mef_eline.models.evc.EVC._validate')
1233
    @patch('kytos.core.Controller.get_interface_by_id')
1234
    @patch('napps.kytos.mef_eline.models.path.Path.is_valid')
1235
    @patch('napps.kytos.mef_eline.models.evc.EVCDeploy.deploy')
1236
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1237
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1238
    def test_update_circuit(self, *args):
1239
        """Test update a circuit circuit."""
1240
        # pylint: disable=too-many-locals,duplicate-code
1241
        (
1242
            evc_as_dict_mock,
1243
            uni_from_dict_mock,
1244
            evc_deploy,
1245
            *mocks,
1246
            requests_mock,
1247
        ) = args
1248
1249
        for mock in mocks:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable mocks does not seem to be defined.
Loading history...
1250
            mock.return_value = True
1251
        unis = [
1252
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:01"),
1253
            get_uni_mocked(switch_dpid="00:00:00:00:00:00:00:02"),
1254
        ]
1255
        uni_from_dict_mock.side_effect = 2 * unis
1256
1257
        response = MagicMock()
1258
        response.status_code = 201
1259
        requests_mock.return_value = response
1260
1261
        api = self.get_app_test_client(self.napp)
1262
        payloads = [
1263
            {
1264
                "name": "my evc1",
1265
                "uni_a": {
1266
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1267
                    "tag": {"tag_type": 1, "value": 80},
1268
                },
1269
                "uni_z": {
1270
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1271
                    "tag": {"tag_type": 1, "value": 1},
1272
                },
1273
                "dynamic_backup_path": True,
1274
            },
1275
            {
1276
                "primary_path": [
1277
                    {
1278
                        "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1279
                        "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1280
                    }
1281
                ]
1282
            },
1283
            {
1284
                "priority": 3
1285
            },
1286
            {
1287
                # It works only with 'enable' and not with 'enabled'
1288
                "enable": True
1289
            },
1290
            {
1291
                "name": "my evc1",
1292
                "active": True,
1293
                "enable": True,
1294
                "uni_a": {
1295
                    "interface_id": "00:00:00:00:00:00:00:01:1",
1296
                    "tag": {
1297
                        "tag_type": 1,
1298
                        "value": 80
1299
                    }
1300
                },
1301
                "uni_z": {
1302
                    "interface_id": "00:00:00:00:00:00:00:02:2",
1303
                    "tag": {
1304
                        "tag_type": 1,
1305
                        "value": 1
1306
                    }
1307
                },
1308
                "priority": 3,
1309
                "bandwidth": 1000,
1310
                "dynamic_backup_path": True
1311
            }
1312
        ]
1313
1314
        evc_as_dict_mock.return_value = payloads[0]
1315
        response = api.post(
1316
            f"{self.server_name_url}/v2/evc/",
1317
            data=json.dumps(payloads[0]),
1318
            content_type="application/json",
1319
        )
1320
        self.assertEqual(201, response.status_code)
1321
1322
        evc_deploy.reset_mock()
1323
        evc_as_dict_mock.return_value = payloads[1]
1324
        current_data = json.loads(response.data)
1325
        circuit_id = current_data["circuit_id"]
1326
        response = api.patch(
1327
            f"{self.server_name_url}/v2/evc/{circuit_id}",
1328
            data=json.dumps(payloads[1]),
1329
            content_type="application/json",
1330
        )
1331
        # evc_deploy.assert_called_once()
1332
        self.assertEqual(200, response.status_code)
1333
1334
        evc_deploy.reset_mock()
1335
        evc_as_dict_mock.return_value = payloads[2]
1336
        response = api.patch(
1337
            f"{self.server_name_url}/v2/evc/{circuit_id}",
1338
            data=json.dumps(payloads[2]),
1339
            content_type="application/json",
1340
        )
1341
        evc_deploy.assert_not_called()
1342
        self.assertEqual(200, response.status_code)
1343
1344
        evc_deploy.reset_mock()
1345
        evc_as_dict_mock.return_value = payloads[3]
1346
        response = api.patch(f'{self.server_name_url}/v2/evc/{circuit_id}',
1347
                             data=json.dumps(payloads[3]),
1348
                             content_type='application/json')
1349
        evc_deploy.assert_called_once()
1350
        self.assertEqual(200, response.status_code)
1351
1352
        evc_deploy.reset_mock()
1353
        response = api.patch(f'{self.server_name_url}/v2/evc/{circuit_id}',
1354
                             data='{"priority":5,}',
1355
                             content_type='application/json')
1356
        evc_deploy.assert_not_called()
1357
        self.assertEqual(400, response.status_code)
1358
1359
        evc_deploy.reset_mock()
1360
        response = api.patch(
1361
            f"{self.server_name_url}/v2/evc/{circuit_id}",
1362
            data=json.dumps(payloads[3]),
1363
            content_type="application/json",
1364
        )
1365
        evc_deploy.assert_called_once()
1366
        self.assertEqual(200, response.status_code)
1367
1368
        response = api.patch(
1369
            f"{self.server_name_url}/v2/evc/1234",
1370
            data=json.dumps(payloads[1]),
1371
            content_type="application/json",
1372
        )
1373
        current_data = json.loads(response.data)
1374
        expected_data = "circuit_id 1234 not found"
1375
        self.assertEqual(current_data["description"], expected_data)
1376
        self.assertEqual(404, response.status_code)
1377
1378
        api.delete(f"{self.server_name_url}/v2/evc/{circuit_id}")
1379
        evc_deploy.reset_mock()
1380
        response = api.patch(
1381
            f"{self.server_name_url}/v2/evc/{circuit_id}",
1382
            data=json.dumps(payloads[1]),
1383
            content_type="application/json",
1384
        )
1385
        evc_deploy.assert_not_called()
1386
        self.assertEqual(405, response.status_code)
1387
1388 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1389
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1390
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1391
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.save_evc")
1392
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1393
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1394
    def test_update_circuit_invalid_json(self, *args):
1395
        """Test update a circuit circuit."""
1396
        # pylint: disable=too-many-locals
1397
        (
1398
            evc_as_dict_mock,
1399
            validate_mock,
1400
            save_evc_mock,
1401
            uni_from_dict_mock,
1402
            sched_add_mock,
1403
            evc_deploy_mock,
1404
        ) = args
1405
1406
        validate_mock.return_value = True
1407
        save_evc_mock.return_value = True
1408
        sched_add_mock.return_value = True
1409
        evc_deploy_mock.return_value = True
1410
        uni1 = create_autospec(UNI)
1411
        uni2 = create_autospec(UNI)
1412
        uni1.interface = create_autospec(Interface)
1413
        uni2.interface = create_autospec(Interface)
1414
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1415
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1416
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1417
1418
        api = self.get_app_test_client(self.napp)
1419
        payload1 = {
1420
            "name": "my evc1",
1421
            "uni_a": {
1422
                "interface_id": "00:00:00:00:00:00:00:01:1",
1423
                "tag": {"tag_type": 1, "value": 80},
1424
            },
1425
            "uni_z": {
1426
                "interface_id": "00:00:00:00:00:00:00:02:2",
1427
                "tag": {"tag_type": 1, "value": 1},
1428
            },
1429
            "dynamic_backup_path": True,
1430
        }
1431
1432
        payload2 = {
1433
            "dynamic_backup_path": False,
1434
        }
1435
1436
        evc_as_dict_mock.return_value = payload1
1437
        response = api.post(
1438
            f"{self.server_name_url}/v2/evc/",
1439
            data=json.dumps(payload1),
1440
            content_type="application/json",
1441
        )
1442
        self.assertEqual(201, response.status_code)
1443
1444
        evc_as_dict_mock.return_value = payload2
1445
        current_data = json.loads(response.data)
1446
        circuit_id = current_data["circuit_id"]
1447
        response = api.patch(
1448
            f"{self.server_name_url}/v2/evc/{circuit_id}",
1449
            data=payload2,
1450
            content_type="application/json",
1451
        )
1452
        current_data = json.loads(response.data)
1453
        expected_data = "The request body is not a well-formed JSON."
1454
        self.assertEqual(current_data["description"], expected_data)
1455
        self.assertEqual(400, response.status_code)
1456
1457
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
1458
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1459
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1460
    @patch("napps.kytos.mef_eline.main.Main._link_from_dict")
1461
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.save_evc")
1462
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1463
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1464
    @patch("napps.kytos.mef_eline.models.path.Path.is_valid")
1465
    def test_update_circuit_invalid_path(self, *args):
1466
        """Test update a circuit circuit."""
1467
        # pylint: disable=too-many-locals
1468
        (
1469
            is_valid_mock,
1470
            evc_as_dict_mock,
1471
            validate_mock,
1472
            save_evc_mock,
1473
            link_from_dict_mock,
1474
            uni_from_dict_mock,
1475
            sched_add_mock,
1476
            evc_deploy_mock,
1477
        ) = args
1478
1479
        is_valid_mock.side_effect = InvalidPath("error")
1480
        validate_mock.return_value = True
1481
        save_evc_mock.return_value = True
1482
        sched_add_mock.return_value = True
1483
        evc_deploy_mock.return_value = True
1484
        link_from_dict_mock.return_value = 1
1485
        uni1 = create_autospec(UNI)
1486
        uni2 = create_autospec(UNI)
1487
        uni1.interface = create_autospec(Interface)
1488
        uni2.interface = create_autospec(Interface)
1489
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1490
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1491
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1492
1493
        api = self.get_app_test_client(self.napp)
1494
        payload1 = {
1495
            "name": "my evc1",
1496
            "uni_a": {
1497
                "interface_id": "00:00:00:00:00:00:00:01:1",
1498
                "tag": {"tag_type": 1, "value": 80},
1499
            },
1500
            "uni_z": {
1501
                "interface_id": "00:00:00:00:00:00:00:02:2",
1502
                "tag": {"tag_type": 1, "value": 1},
1503
            },
1504
            "dynamic_backup_path": True,
1505
        }
1506
1507
        payload2 = {
1508
            "primary_path": [
1509
                {
1510
                    "endpoint_a": {"id": "00:00:00:00:00:00:00:01:1"},
1511
                    "endpoint_b": {"id": "00:00:00:00:00:00:00:02:2"},
1512
                }
1513
            ]
1514
        }
1515
1516
        evc_as_dict_mock.return_value = payload1
1517
        response = api.post(
1518
            f"{self.server_name_url}/v2/evc/",
1519
            data=json.dumps(payload1),
1520
            content_type="application/json",
1521
        )
1522
        self.assertEqual(201, response.status_code)
1523
1524
        evc_as_dict_mock.return_value = payload2
1525
        current_data = json.loads(response.data)
1526
        circuit_id = current_data["circuit_id"]
1527
        response = api.patch(
1528
            f"{self.server_name_url}/v2/evc/{circuit_id}",
1529
            data=json.dumps(payload2),
1530
            content_type="application/json",
1531
        )
1532
        current_data = json.loads(response.data)
1533
        expected_data = "primary_path is not a valid path: error"
1534
        self.assertEqual(400, response.status_code)
1535
        self.assertEqual(current_data["description"], expected_data)
1536
1537 View Code Duplication
    @patch("napps.kytos.mef_eline.models.evc.EVC.deploy")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1538
    @patch("napps.kytos.mef_eline.scheduler.Scheduler.add")
1539
    @patch("napps.kytos.mef_eline.main.Main._uni_from_dict")
1540
    @patch("napps.kytos.mef_eline.storehouse.StoreHouse.save_evc")
1541
    @patch("napps.kytos.mef_eline.models.evc.EVC._validate")
1542
    @patch("napps.kytos.mef_eline.main.EVC.as_dict")
1543
    def test_update_evc_no_json_mime(self, *args):
1544
        """Test update a circuit with wrong mimetype."""
1545
        # pylint: disable=too-many-locals
1546
        (
1547
            evc_as_dict_mock,
1548
            validate_mock,
1549
            save_evc_mock,
1550
            uni_from_dict_mock,
1551
            sched_add_mock,
1552
            evc_deploy_mock,
1553
        ) = args
1554
1555
        validate_mock.return_value = True
1556
        save_evc_mock.return_value = True
1557
        sched_add_mock.return_value = True
1558
        evc_deploy_mock.return_value = True
1559
        uni1 = create_autospec(UNI)
1560
        uni2 = create_autospec(UNI)
1561
        uni1.interface = create_autospec(Interface)
1562
        uni2.interface = create_autospec(Interface)
1563
        uni1.interface.switch = "00:00:00:00:00:00:00:01"
1564
        uni2.interface.switch = "00:00:00:00:00:00:00:02"
1565
        uni_from_dict_mock.side_effect = [uni1, uni2, uni1, uni2]
1566
1567
        api = self.get_app_test_client(self.napp)
1568
        payload1 = {
1569
            "name": "my evc1",
1570
            "uni_a": {
1571
                "interface_id": "00:00:00:00:00:00:00:01:1",
1572
                "tag": {"tag_type": 1, "value": 80},
1573
            },
1574
            "uni_z": {
1575
                "interface_id": "00:00:00:00:00:00:00:02:2",
1576
                "tag": {"tag_type": 1, "value": 1},
1577
            },
1578
            "dynamic_backup_path": True,
1579
        }
1580
1581
        payload2 = {"dynamic_backup_path": False}
1582
1583
        evc_as_dict_mock.return_value = payload1
1584
        response = api.post(
1585
            f"{self.server_name_url}/v2/evc/",
1586
            data=json.dumps(payload1),
1587
            content_type="application/json",
1588
        )
1589
        self.assertEqual(201, response.status_code)
1590
1591
        evc_as_dict_mock.return_value = payload2
1592
        current_data = json.loads(response.data)
1593
        circuit_id = current_data["circuit_id"]
1594
        response = api.patch(
1595
            f"{self.server_name_url}/v2/evc/{circuit_id}", data=payload2
1596
        )
1597
        current_data = json.loads(response.data)
1598
        expected_data = "The request body mimetype is not application/json."
1599
        self.assertEqual(current_data["description"], expected_data)
1600
        self.assertEqual(415, response.status_code)
1601
1602
    def test_delete_no_evc(self):
1603
        """Test delete when EVC does not exist."""
1604
        api = self.get_app_test_client(self.napp)
1605
        response = api.delete(f"{self.server_name_url}/v2/evc/123")
1606
        current_data = json.loads(response.data)
1607
        expected_data = "circuit_id 123 not found"
1608
        self.assertEqual(current_data["description"], expected_data)
1609
        self.assertEqual(404, response.status_code)
1610
1611
    def test_handle_link_up(self):
1612
        """Test handle_link_up method."""
1613
        evc_mock = create_autospec(EVC)
1614
        evc_mock.is_enabled = MagicMock(side_effect=[True, False, True])
1615
        evc_mock.lock = MagicMock()
1616
        type(evc_mock).archived = PropertyMock(
1617
            side_effect=[True, False, False]
1618
        )
1619
        evcs = [evc_mock, evc_mock, evc_mock]
1620
        event = KytosEvent(name="test", content={"link": "abc"})
1621
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1622
        self.napp.handle_link_up(event)
1623
        evc_mock.handle_link_up.assert_called_once_with("abc")
1624
1625
    def test_handle_link_down(self):
1626
        """Test handle_link_down method."""
1627
        evc_mock = create_autospec(EVC)
1628
        evc_mock.is_affected_by_link = MagicMock(
1629
            side_effect=[True, False, True]
1630
        )
1631
        evc_mock.lock = MagicMock()
1632
        evc_mock.handle_link_down = MagicMock(side_effect=[True, True])
1633
        evcs = [evc_mock, evc_mock, evc_mock]
1634
        event = KytosEvent(name="test", content={"link": "abc"})
1635
        self.napp.circuits = dict(zip(["1", "2", "3"], evcs))
1636
        self.napp.handle_link_down(event)
1637
        evc_mock.handle_link_down.assert_has_calls([call(), call()])
1638
1639
    def test_add_metadata(self):
1640
        """Test method to add metadata"""
1641
        evc_mock = create_autospec(EVC)
1642
        evc_mock.metadata = {}
1643
        evc_mock.id = 1234
1644
        self.napp.circuits = {"1234": evc_mock}
1645
1646
        api = self.get_app_test_client(self.napp)
1647
        payload = {"metadata1": 1, "metadata2": 2}
1648
        response = api.post(
1649
            f"{self.server_name_url}/v2/evc/1234/metadata",
1650
            data=json.dumps(payload),
1651
            content_type="application/json",
1652
        )
1653
1654
        self.assertEqual(response.status_code, 201)
1655
        evc_mock.extend_metadata.assert_called_with(payload)
1656