Passed
Push — master ( dd71a3...270b5c )
by Italo Valcy
01:51 queued 12s
created

TestMain.test_circuit_with_invalid_id()   A

Complexity

Conditions 1

Size

Total Lines 13
Code Lines 11

Duplication

Lines 13
Ratio 100 %

Importance

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