Test Failed
Push — master ( 4aff4f...dba1ae )
by Antonio
05:19 queued 12s
created

TestMain.test_redeploy_evc()   A

Complexity

Conditions 1

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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