Passed
Push — master ( 9ba056...d82f2c )
by Beraldo
04:53 queued 11s
created

TestMain.test_evc_from_dict_links()   A

Complexity

Conditions 1

Size

Total Lines 46
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 33
nop 4
dl 0
loc 46
rs 9.0879
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 patch
5
6
from kytos.core.interface import UNI, Interface
7
8
from napps.kytos.mef_eline.main import Main
9
from tests.helpers import get_controller_mock
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
        self.napp = Main(get_controller_mock())
23
24
    def test_get_event_listeners(self):
25
        """Verify all event listeners registered."""
26
        expected_events = ['kytos/core.shutdown',
27
                           'kytos/core.shutdown.kytos/mef_eline',
28
                           'kytos/topology.link_up',
29
                           'kytos/topology.link_down']
30
        actual_events = self.napp.listeners()
31
32
        for _event in expected_events:
33
            self.assertIn(_event, actual_events, '%s' % _event)
34
35
    def test_verify_api_urls(self):
36
        """Verify all APIs registered."""
37
        expected_urls = [
38
            ({}, {'POST', 'OPTIONS'},
39
             '/api/kytos/mef_eline/v2/evc/'),
40
41
            ({}, {'OPTIONS', 'HEAD', 'GET'},
42
             '/api/kytos/mef_eline/v2/evc/'),
43
44
            ({'circuit_id': '[circuit_id]'}, {'OPTIONS', 'DELETE'},
45
             '/api/kytos/mef_eline/v2/evc/<circuit_id>'),
46
47
            ({'circuit_id': '[circuit_id]'}, {'OPTIONS', 'HEAD', 'GET'},
48
             '/api/kytos/mef_eline/v2/evc/<circuit_id>'),
49
50
            ({'circuit_id': '[circuit_id]'}, {'OPTIONS', 'PATCH'},
51
             '/api/kytos/mef_eline/v2/evc/<circuit_id>'),
52
53
            ({}, {'OPTIONS', 'GET', 'HEAD'},
54
             '/api/kytos/mef_eline/v2/evc/schedule'),
55
56
            ({}, {'POST', 'OPTIONS'},
57
             '/api/kytos/mef_eline/v2/evc/schedule/'),
58
59
            ({'schedule_id': '[schedule_id]'},
60
             {'OPTIONS', 'DELETE'},
61
             '/api/kytos/mef_eline/v2/evc/schedule/<schedule_id>'),
62
63
            ({'schedule_id': '[schedule_id]'},
64
             {'OPTIONS', 'PATCH'},
65
             '/api/kytos/mef_eline/v2/evc/schedule/<schedule_id>')
66
            ]
67
68
        urls = self.get_napp_urls(self.napp)
69
        self.assertCountEqual(expected_urls, urls)
70
71
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
72
    @patch('napps.kytos.mef_eline.models.EVCBase._validate')
73
    def test_evc_from_dict(self, _validate_mock, uni_from_dict_mock):
74
        """
75
        Test the helper method that create an EVN from dict.
76
77
        Verify object creation with circuit data and schedule data.
78
        """
79
        _validate_mock.return_value = True
80
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
81
        payload = {
82
            "name": "my evc1",
83
            "uni_a": {
84
                "interface_id": "00:00:00:00:00:00:00:01:1",
85
                "tag": {
86
                    "tag_type": 1,
87
                    "value": 80
88
                }
89
            },
90
            "uni_z": {
91
                "interface_id": "00:00:00:00:00:00:00:02:2",
92
                "tag": {
93
                    "tag_type": 1,
94
                    "value": 1
95
                }
96
            },
97
            "circuit_scheduler": [{
98
                "frequency": "* * * * *",
99
                "action": "create"
100
            }]
101
        }
102
        # pylint: disable=protected-access
103
        evc_response = self.napp._evc_from_dict(payload)
104
        self.assertIsNotNone(evc_response)
105
        self.assertIsNotNone(evc_response.uni_a)
106
        self.assertIsNotNone(evc_response.uni_z)
107
        self.assertIsNotNone(evc_response.circuit_scheduler)
108
        self.assertIsNotNone(evc_response.name)
109
110
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
111
    @patch('napps.kytos.mef_eline.models.EVCBase._validate')
112
    @patch('kytos.core.Controller.get_interface_by_id')
113
    def test_evc_from_dict_paths(self, _get_interface_by_id_mock,
114
                                 _validate_mock, uni_from_dict_mock):
115
        """
116
        Test the helper method that create an EVN from dict.
117
118
        Verify object creation with circuit data and schedule data.
119
        """
120
        _get_interface_by_id_mock.return_value = True
121
        _validate_mock.return_value = True
122
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
123
        payload = {
124
            "name": "my evc1",
125
            "uni_a": {
126
                "interface_id": "00:00:00:00:00:00:00:01:1",
127
                "tag": {
128
                    "tag_type": 1,
129
                    "value": 80
130
                }
131
            },
132
            "uni_z": {
133
                "interface_id": "00:00:00:00:00:00:00:02:2",
134
                "tag": {
135
                    "tag_type": 1,
136
                    "value": 1
137
                }
138
            },
139
            "current_path": [],
140
            "primary_path": [
141
                {"endpoint_a": {"interface_id": "00:00:00:00:00:00:00:01:1"},
142
                 "endpoint_b": {"interface_id": "00:00:00:00:00:00:00:02:2"}}
143
            ],
144
            "backup_path": []
145
        }
146
147
        # pylint: disable=protected-access
148
        evc_response = self.napp._evc_from_dict(payload)
149
        self.assertIsNotNone(evc_response)
150
        self.assertIsNotNone(evc_response.uni_a)
151
        self.assertIsNotNone(evc_response.uni_z)
152
        self.assertIsNotNone(evc_response.circuit_scheduler)
153
        self.assertIsNotNone(evc_response.name)
154
        self.assertEqual(len(evc_response.current_path), 0)
155
        self.assertEqual(len(evc_response.backup_path), 0)
156
        self.assertEqual(len(evc_response.primary_path), 1)
157
158
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
159
    @patch('napps.kytos.mef_eline.models.EVCBase._validate')
160
    @patch('kytos.core.Controller.get_interface_by_id')
161
    def test_evc_from_dict_links(self, _get_interface_by_id_mock,
162
                                 _validate_mock, uni_from_dict_mock):
163
        """
164
        Test the helper method that create an EVN from dict.
165
166
        Verify object creation with circuit data and schedule data.
167
        """
168
        _get_interface_by_id_mock.return_value = True
169
        _validate_mock.return_value = True
170
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
171
        payload = {
172
            "name": "my evc1",
173
            "uni_a": {
174
                "interface_id": "00:00:00:00:00:00:00:01:1",
175
                "tag": {
176
                    "tag_type": 1,
177
                    "value": 80
178
                }
179
            },
180
            "uni_z": {
181
                "interface_id": "00:00:00:00:00:00:00:02:2",
182
                "tag": {
183
                    "tag_type": 1,
184
                    "value": 1
185
                }
186
            },
187
            "primary_links": [
188
                {"endpoint_a": {"interface_id": "00:00:00:00:00:00:00:01:1"},
189
                 "endpoint_b": {"interface_id": "00:00:00:00:00:00:00:02:2"}}
190
            ],
191
            "backup_links": []
192
        }
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.assertEqual(len(evc_response.current_links_cache), 0)
202
        self.assertEqual(len(evc_response.backup_links), 0)
203
        self.assertEqual(len(evc_response.primary_links), 1)
204
205
    def test_list_without_circuits(self):
206
        """Test if list circuits return 'no circuit stored.'."""
207
        api = self.get_app_test_client(self.napp)
208
        url = f'{self.server_name_url}/v2/evc/'
209
        response = api.get(url)
210
        self.assertEqual(response.status_code, 200, response.data)
211
        self.assertEqual(json.loads(response.data.decode()), {})
212
213
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
214
    def test_list_no_circuits_stored(self, storehouse_data_mock):
215
        """Test if list circuits return all circuits stored."""
216
        circuits = {}
217
        storehouse_data_mock.return_value = circuits
218
219
        api = self.get_app_test_client(self.napp)
220
        url = f'{self.server_name_url}/v2/evc/'
221
222
        response = api.get(url)
223
        expected_result = circuits
224
        self.assertEqual(json.loads(response.data), expected_result)
225
226
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
227
    def test_list_with_circuits_stored(self, storehouse_data_mock):
228
        """Test if list circuits return all circuits stored."""
229
        circuits = {'1': {'name': 'circuit_1'},
230
                    '2': {'name': 'circuit_2'}}
231
        storehouse_data_mock.return_value = circuits
232
233
        api = self.get_app_test_client(self.napp)
234
        url = f'{self.server_name_url}/v2/evc/'
235
236
        response = api.get(url)
237
        expected_result = circuits
238
        self.assertEqual(json.loads(response.data), expected_result)
239
240 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...
241
    def test_circuit_with_valid_id(self, storehouse_data_mock):
242
        """Test if get_circuit return the circuit attributes."""
243
        circuits = {'1': {'name': 'circuit_1'},
244
                    '2': {'name': 'circuit_2'}}
245
        storehouse_data_mock.return_value = circuits
246
247
        api = self.get_app_test_client(self.napp)
248
        url = f'{self.server_name_url}/v2/evc/1'
249
        response = api.get(url)
250
        expected_result = circuits['1']
251
        self.assertEqual(json.loads(response.data), expected_result)
252
253 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...
254
    def test_circuit_with_invalid_id(self, storehouse_data_mock):
255
        """Test if get_circuit return invalid circuit_id."""
256
        circuits = {'1': {'name': 'circuit_1'},
257
                    '2': {'name': 'circuit_2'}}
258
        storehouse_data_mock.return_value = circuits
259
260
        api = self.get_app_test_client(self.napp)
261
        url = f'{self.server_name_url}/v2/evc/3'
262
        response = api.get(url)
263
        expected_result = {'response': 'circuit_id 3 not found'}
264
        self.assertEqual(json.loads(response.data), expected_result)
265
266
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
267
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
268
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
269
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
270
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
271
    @patch('napps.kytos.mef_eline.models.EVC._validate')
272
    def test_create_a_circuit_case_1(self, *args):
273
        """Test create a new circuit."""
274
        (validate_mock, evc_as_dict_mock, save_evc_mock,
275
         uni_from_dict_mock, sched_add_mock, storehouse_data_mock) = args
276
277
        validate_mock.return_value = True
278
        save_evc_mock.return_value = True
279
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
280
        evc_as_dict_mock.return_value = {}
281
        sched_add_mock.return_value = True
282
        storehouse_data_mock.return_value = {}
283
284
        api = self.get_app_test_client(self.napp)
285
        url = f'{self.server_name_url}/v2/evc/'
286
        payload = {
287
                   "name": "my evc1",
288
                   "frequency": "* * * * *",
289
                   "uni_a": {
290
                     "interface_id": "00:00:00:00:00:00:00:01:1",
291
                     "tag": {
292
                       "tag_type": 1,
293
                       "value": 80
294
                     }
295
                   },
296
                   "uni_z": {
297
                     "interface_id": "00:00:00:00:00:00:00:02:2",
298
                     "tag": {
299
                       "tag_type": 1,
300
                       "value": 1
301
                     }
302
                   }
303
                 }
304
305
        response = api.post(url, data=json.dumps(payload),
306
                            content_type='application/json')
307
        current_data = json.loads(response.data)
308
309
        # verify expected result from request
310
        self.assertEqual(201, response.status_code, response.data)
311
        self.assertIn('circuit_id', current_data)
312
313
        # verify uni called
314
        uni_from_dict_mock.called_twice()
315
        uni_from_dict_mock.assert_any_call(payload['uni_z'])
316
        uni_from_dict_mock.assert_any_call(payload['uni_a'])
317
318
        # verify validation called
319
        validate_mock.assert_called_once()
320
        validate_mock.assert_called_with(frequency='* * * * *',
321
                                         name='my evc1',
322
                                         uni_a='uni_a',
323
                                         uni_z='uni_z')
324
        # verify save method is called
325
        save_evc_mock.assert_called_once()
326
327
        # verify evc as dict is called to save in the box
328
        evc_as_dict_mock.assert_called_once()
329
        # verify add circuit in sched
330
        sched_add_mock.assert_called_once()
331
332
    @staticmethod
333
    def get_napp_urls(napp):
334
        """Return the kytos/mef_eline urls.
335
336
        The urls will be like:
337
338
        urls = [
339
            (options, methods, url)
340
        ]
341
342
        """
343
        controller = napp.controller
344
        controller.api_server.register_napp_endpoints(napp)
345
346
        urls = []
347
        for rule in controller.api_server.app.url_map.iter_rules():
348
            options = {}
349
            for arg in rule.arguments:
350
                options[arg] = "[{0}]".format(arg)
351
352
            if f'{napp.username}/{napp.name}' in str(rule):
353
                urls.append((options, rule.methods, f'{str(rule)}'))
354
355
        return urls
356
357
    @staticmethod
358
    def get_app_test_client(napp):
359
        """Return a flask api test client."""
360
        napp.controller.api_server.register_napp_endpoints(napp)
361
        return napp.controller.api_server.app.test_client()
362
363
    def test_create_a_circuit_case_2(self):
364
        """Test create a new circuit trying to send request without a json."""
365
        api = self.get_app_test_client(self.napp)
366
        url = f'{self.server_name_url}/v2/evc/'
367
368
        response = api.post(url)
369
        current_data = json.loads(response.data)
370
        expected_data = 'Bad request: The request do not have a json.'
371
372
        self.assertEqual(400, response.status_code, response.data)
373
        self.assertEqual(current_data, expected_data)
374
375
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
376
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
377
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
378
    @patch('napps.kytos.mef_eline.models.EVC._validate')
379
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
380
    def test_create_circuit_already_enabled(self, *args):
381
        """Test create an already created circuit."""
382
        (evc_as_dict_mock, validate_mock, save_evc_mock,
383
         uni_from_dict_mock, sched_add_mock) = args
384
385
        validate_mock.return_value = True
386
        save_evc_mock.return_value = True
387
        sched_add_mock.return_value = True
388
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z', 'uni_a', 'uni_z']
389
        payload1 = {'name': 'circuit_1'}
390
391
        api = self.get_app_test_client(self.napp)
392
        payload2 = {
393
            "name": "my evc1",
394
            "uni_a": {
395
                "interface_id": "00:00:00:00:00:00:00:01:1",
396
                "tag": {
397
                    "tag_type": 1,
398
                    "value": 80
399
                }
400
            },
401
            "uni_z": {
402
                "interface_id": "00:00:00:00:00:00:00:02:2",
403
                "tag": {
404
                    "tag_type": 1,
405
                    "value": 1
406
                }
407
            }
408
        }
409
410
        evc_as_dict_mock.return_value = payload1
411
        response = api.post(f'{self.server_name_url}/v2/evc/',
412
                            data=json.dumps(payload1),
413
                            content_type='application/json')
414
        self.assertEqual(201, response.status_code)
415
416
        evc_as_dict_mock.return_value = payload2
417
        response = api.post(f'{self.server_name_url}/v2/evc/',
418
                            data=json.dumps(payload2),
419
                            content_type='application/json')
420
        self.assertEqual(201, response.status_code)
421
422
        response = api.post(f'{self.server_name_url}/v2/evc/',
423
                            data=json.dumps(payload2),
424
                            content_type='application/json')
425
        current_data = json.loads(response.data)
426
        expected_data = 'Not Acceptable: This evc already exists.'
427
        self.assertEqual(current_data, expected_data)
428
        self.assertEqual(409, response.status_code)
429
430
    def test_load_circuits_by_interface(self):
431
        """Test if existing circuits are correctly loaded to the cache."""
432
        stored_circuits = {
433
            "182f5bac84074017a262a2321195dbb4": {
434
                "active": False,
435
                "archived": True,
436
                "backup_links": [],
437
                "backup_path": [],
438
                "bandwidth": 0,
439
                "circuit_scheduler": [
440
                    {
441
                        "action": "create",
442
                        "frequency": "*/3 * * * *",
443
                        "id": "db7f8a301e2b4ff69a2ad9a6267430e2"
444
                    },
445
                    {
446
                        "action": "remove",
447
                        "frequency": "2-59/3 * * * *",
448
                        "id": "b8a8bbe85bc144b0afc65181e4c069a1"
449
                    }
450
                ],
451
                "creation_time": "2019-08-09T19:25:06",
452
                "current_path": [],
453
                "dynamic_backup_path": True,
454
                "enabled": False,
455
                "end_date": "2018-12-29T15:16:50",
456
                "id": "182f5bac84074017a262a2321195dbb4",
457
                "name": "Teste2",
458
                "owner": None,
459
                "primary_links": [],
460
                "primary_path": [],
461
                "priority": 0,
462
                "request_time": "2019-08-09T19:25:06",
463
                "start_date": "2019-08-09T19:25:06",
464
                "uni_a": {
465
                    "interface_id": "00:00:00:00:00:00:00:03:12",
466
                    "tag": {
467
                        "tag_type": 1,
468
                        "value": 321
469
                    }
470
                },
471
                "uni_z": {
472
                    "interface_id": "00:00:00:00:00:00:00:06:11",
473
                    "tag": {
474
                        "tag_type": 1,
475
                        "value": 612
476
                    }
477
                }
478
            },
479
            "65c4582cc8f249c2a5947ef500c19e37": {
480
                "active": False,
481
                "archived": False,
482
                "backup_links": [],
483
                "backup_path": [],
484
                "bandwidth": 0,
485
                "circuit_scheduler": [
486
                    {
487
                        "action": "create",
488
                        "frequency": "*/3 * * * *",
489
                        "id": "0939dedf66ce431f85beb53daf578d73"
490
                    },
491
                    {
492
                        "action": "remove",
493
                        "frequency": "2-59/3 * * * *",
494
                        "id": "6cdcab31a11f44708e23776b4dad7893"
495
                    }
496
                ],
497
                "creation_time": "2019-07-22T16:01:24",
498
                "current_path": [],
499
                "dynamic_backup_path": True,
500
                "enabled": False,
501
                "end_date": "2018-12-29T15:16:50",
502
                "id": "65c4582cc8f249c2a5947ef500c19e37",
503
                "name": "Teste2",
504
                "owner": None,
505
                "primary_links": [],
506
                "primary_path": [
507
                    {
508
                        "active": False,
509
                        "enabled": True,
510
                        "endpoint_a": {
511
                            "active": False,
512
                            "enabled": True,
513
                            "id": "00:00:00:00:00:00:00:03:3",
514
                            "link": "0e2b5d7bc858b9f38db11b69",
515
                            "mac": "ae:6e:d3:96:83:5a",
516
                            "metadata": {},
517
                            "name": "s3-eth3",
518
                            "nni": True,
519
                            "port_number": 3,
520
                            "speed": 1250000000.0,
521
                            "switch": "00:00:00:00:00:00:00:03",
522
                            "type": "interface",
523
                            "uni": False
524
                        },
525
                        "endpoint_b": {
526
                            "active": False,
527
                            "enabled": True,
528
                            "id": "00:00:00:00:00:00:00:05:2",
529
                            "link": "0e2b5d7bc858b9f38db11b69",
530
                            "mac": "de:eb:d0:b0:14:cf",
531
                            "metadata": {},
532
                            "name": "s5-eth2",
533
                            "nni": True,
534
                            "port_number": 2,
535
                            "speed": 1250000000.0,
536
                            "switch": "00:00:00:00:00:00:00:05",
537
                            "type": "interface",
538
                            "uni": False
539
                        },
540
                        "id": "0e2b5d7bc858b9f38db11b69",
541
                        "metadata": {}
542
                    },
543
                    {
544
                        "active": False,
545
                        "enabled": True,
546
                        "endpoint_a": {
547
                            "active": False,
548
                            "enabled": True,
549
                            "id": "00:00:00:00:00:00:00:05:4",
550
                            "link": "53bd36ff55a5aa2029bd5d50",
551
                            "mac": "6e:c2:ea:c4:18:12",
552
                            "metadata": {},
553
                            "name": "s5-eth4",
554
                            "nni": True,
555
                            "port_number": 4,
556
                            "speed": 1250000000.0,
557
                            "switch": "00:00:00:00:00:00:00:05",
558
                            "type": "interface",
559
                            "uni": False
560
                        },
561
                        "endpoint_b": {
562
                            "active": False,
563
                            "enabled": True,
564
                            "id": "00:00:00:00:00:00:00:06:2",
565
                            "link": "53bd36ff55a5aa2029bd5d50",
566
                            "mac": "5a:25:7b:7c:0d:ac",
567
                            "metadata": {},
568
                            "name": "s6-eth2",
569
                            "nni": True,
570
                            "port_number": 2,
571
                            "speed": 1250000000.0,
572
                            "switch": "00:00:00:00:00:00:00:06",
573
                            "type": "interface",
574
                            "uni": False
575
                        },
576
                        "id": "53bd36ff55a5aa2029bd5d50",
577
                        "metadata": {}
578
                    }
579
                ],
580
                "priority": 0,
581
                "request_time": "2019-07-22T16:01:24",
582
                "start_date": "2019-07-22T16:01:24",
583
                "uni_a": {
584
                    "interface_id": "00:00:00:00:00:00:00:03:12",
585
                    "tag": {
586
                        "tag_type": 1,
587
                        "value": 321
588
                    }
589
                },
590
                "uni_z": {
591
                    "interface_id": "00:00:00:00:00:00:00:06:11",
592
                    "tag": {
593
                        "tag_type": 1,
594
                        "value": 612
595
                    }
596
                }
597
            }
598
        }
599
600
        expected_result = {
601
            '00:00:00:00:00:00:00:03:12':
602
                {'182f5bac84074017a262a2321195dbb4',
603
                 '65c4582cc8f249c2a5947ef500c19e37'},
604
            '00:00:00:00:00:00:00:06:11':
605
                {'182f5bac84074017a262a2321195dbb4',
606
                 '65c4582cc8f249c2a5947ef500c19e37'},
607
            '00:00:00:00:00:00:00:03:3':
608
                {'65c4582cc8f249c2a5947ef500c19e37'},
609
            '00:00:00:00:00:00:00:05:2':
610
                {'65c4582cc8f249c2a5947ef500c19e37'},
611
            '00:00:00:00:00:00:00:05:4':
612
                {'65c4582cc8f249c2a5947ef500c19e37'},
613
            '00:00:00:00:00:00:00:06:2':
614
                {'65c4582cc8f249c2a5947ef500c19e37'}
615
        }
616
        self.napp.load_circuits_by_interface(stored_circuits)
617
        # pylint: disable=protected-access
618
        self.assertEqual(self.napp._circuits_by_interface, expected_result)
619
620
    def test_list_schedules__no_data(self):
621
        """Test list of schedules."""
622
        api = self.get_app_test_client(self.napp)
623
        url = f'{self.server_name_url}/v2/evc/schedule'
624
        response = api.get(url)
625
        self.assertEqual(response.status_code, 200, response.data)
626
        self.assertEqual(json.loads(response.data.decode()), {})
627
628
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
629
    def test_list_schedules__no_data_stored(self, storehouse_data_mock):
630
        """Test if list circuits return all circuits stored."""
631
        circuits = {}
632
        storehouse_data_mock.return_value = circuits
633
634
        api = self.get_app_test_client(self.napp)
635
        url = f'{self.server_name_url}/v2/evc/schedule'
636
637
        response = api.get(url)
638
        expected_result = circuits
639
640
        self.assertEqual(response.status_code, 200, response.data)
641
        self.assertEqual(json.loads(response.data), expected_result)
642
643
    # pylint: disable=no-self-use
644
    def _add_storehouse_schedule_data(self, storehouse_data_mock):
645
        """Add schedule data to storehouse mock object."""
646
        circuits = {}
647
        payload_1 = {
648
            "id": "aa:aa:aa",
649
            "name": "my evc1",
650
            "uni_a": {
651
                "interface_id": "00:00:00:00:00:00:00:01:1",
652
                "tag": {
653
                    "tag_type": 1,
654
                    "value": 80
655
                }
656
            },
657
            "uni_z": {
658
                "interface_id": "00:00:00:00:00:00:00:02:2",
659
                "tag": {
660
                    "tag_type": 1,
661
                    "value": 1
662
                }
663
            },
664
            "circuit_scheduler": [
665
                {
666
                    "id": "1",
667
                    "frequency": "* * * * *",
668
                    "action": "create"
669
                },
670
                {
671
                    "id": "2",
672
                    "frequency": "1 * * * *",
673
                    "action": "remove"
674
                }
675
            ]
676
        }
677
        circuits.update({"aa:aa:aa": payload_1})
678
        payload_2 = {
679
            "id": "bb:bb:bb",
680
            "name": "my second evc2",
681
            "uni_a": {
682
                "interface_id": "00:00:00:00:00:00:00:01:2",
683
                "tag": {
684
                    "tag_type": 1,
685
                    "value": 90
686
                }
687
            },
688
            "uni_z": {
689
                "interface_id": "00:00:00:00:00:00:00:03:2",
690
                "tag": {
691
                    "tag_type": 1,
692
                    "value": 100
693
                }
694
            },
695
            "circuit_scheduler": [
696
                {
697
                    "id": "3",
698
                    "frequency": "1 * * * *",
699
                    "action": "create"
700
                },
701
                {
702
                    "id": "4",
703
                    "frequency": "2 * * * *",
704
                    "action": "remove"
705
                }
706
            ]
707
        }
708
        circuits.update({"bb:bb:bb": payload_2})
709
        payload_3 = {
710
            "id": "cc:cc:cc",
711
            "name": "my third evc3",
712
            "uni_a": {
713
                "interface_id": "00:00:00:00:00:00:00:03:1",
714
                "tag": {
715
                    "tag_type": 1,
716
                    "value": 90
717
                }
718
            },
719
            "uni_z": {
720
                "interface_id": "00:00:00:00:00:00:00:04:2",
721
                "tag": {
722
                    "tag_type": 1,
723
                    "value": 100
724
                }
725
            }
726
        }
727
        circuits.update({"cc:cc:cc": payload_3})
728
        # Add one circuit to the storehouse.
729
        storehouse_data_mock.return_value = circuits
730
731
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
732
    def test_list_schedules_from_storehouse(self, storehouse_data_mock):
733
        """Test if list circuits return specific circuits stored."""
734
        self._add_storehouse_schedule_data(storehouse_data_mock)
735
736
        api = self.get_app_test_client(self.napp)
737
        url = f'{self.server_name_url}/v2/evc/schedule'
738
739
        # Call URL
740
        response = api.get(url)
741
        # Expected JSON data from response
742
        expected = [{'circuit_id': 'aa:aa:aa',
743
                     'schedule': {'action': 'create',
744
                                  'frequency': '* * * * *', 'id': '1'},
745
                     'schedule_id': '1'},
746
                    {'circuit_id': 'aa:aa:aa',
747
                     'schedule': {'action': 'remove',
748
                                  'frequency': '1 * * * *', 'id': '2'},
749
                     'schedule_id': '2'},
750
                    {'circuit_id': 'bb:bb:bb',
751
                     'schedule': {'action': 'create',
752
                                  'frequency': '1 * * * *', 'id': '3'},
753
                     'schedule_id': '3'},
754
                    {'circuit_id': 'bb:bb:bb',
755
                     'schedule': {'action': 'remove',
756
                                  'frequency': '2 * * * *', 'id': '4'},
757
                     'schedule_id': '4'}]
758
759
        self.assertEqual(response.status_code, 200, response.data)
760
        self.assertEqual(expected, json.loads(response.data))
761
762
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
763
    def test_get_specific_schedule_from_storehouse(self, storehouse_data_mock):
764
        """Test get schedules from a circuit."""
765
        self._add_storehouse_schedule_data(storehouse_data_mock)
766
767
        requested_circuit_id = "bb:bb:bb"
768
        api = self.get_app_test_client(self.napp)
769
        url = f'{self.server_name_url}/v2/evc/{requested_circuit_id}'
770
771
        # Call URL
772
        response = api.get(url)
773
774
        # Expected JSON data from response
775
        expected = [{'action': 'create', 'frequency': '1 * * * *', 'id': '3'},
776
                    {'action': 'remove', 'frequency': '2 * * * *', 'id': '4'}]
777
778
        self.assertEqual(response.status_code, 200)
779
        self.assertEqual(expected,
780
                         json.loads(response.data)["circuit_scheduler"])
781
782
    def test_get_specific_schedules_from_storehouse_not_found(self):
783
        """Test get specific schedule ID that does not exist."""
784
        requested_id = "blah"
785
        api = self.get_app_test_client(self.napp)
786
        url = f'{self.server_name_url}/v2/evc/{requested_id}'
787
788
        # Call URL
789
        response = api.get(url)
790
791
        expected = {'response': 'circuit_id blah not found'}
792
        # Assert response not found
793
        self.assertEqual(response.status_code, 404, response.data)
794
        self.assertEqual(expected, json.loads(response.data))
795
796
    def _uni_from_dict_side_effect(self, uni_dict):
797
        interface_id = uni_dict.get("interface_id")
798
        tag_dict = uni_dict.get("tag")
799
        interface = Interface(interface_id, "0", "switch")
800
        return UNI(interface, tag_dict)
801
802
    @patch('apscheduler.schedulers.background.BackgroundScheduler.add_job')
803
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
804
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
805
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
806
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
807
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
808
    @patch('napps.kytos.mef_eline.models.EVC._validate')
809
    def test_create_schedule(self, *args):  # pylint: disable=too-many-locals
810
        """Test create a circuit schedule."""
811
        (validate_mock, evc_as_dict_mock, save_evc_mock,
812
         uni_from_dict_mock, sched_add_mock, storehouse_data_mock,
813
         scheduler_add_job_mock) = args
814
815
        validate_mock.return_value = True
816
        save_evc_mock.return_value = True
817
        uni_from_dict_mock.side_effect = self._uni_from_dict_side_effect
818
        evc_as_dict_mock.return_value = {}
819
        sched_add_mock.return_value = True
820
        storehouse_data_mock.return_value = {}
821
822
        self._add_storehouse_schedule_data(storehouse_data_mock)
823
824
        requested_id = "bb:bb:bb"
825
        api = self.get_app_test_client(self.napp)
826
        url = f'{self.server_name_url}/v2/evc/schedule/'
827
828
        payload = {
829
              "circuit_id": requested_id,
830
              "schedule": {
831
                "frequency": "1 * * * *",
832
                "action": "create"
833
              }
834
            }
835
836
        # Call URL
837
        response = api.post(url, data=json.dumps(payload),
838
                            content_type='application/json')
839
840
        response_json = json.loads(response.data)
841
842
        self.assertEqual(response.status_code, 201, response.data)
843
        scheduler_add_job_mock.assert_called_once()
844
        save_evc_mock.assert_called_once()
845
        self.assertEqual(payload["schedule"]["frequency"],
846
                         response_json["frequency"])
847
        self.assertEqual(payload["schedule"]["action"],
848
                         response_json["action"])
849
        self.assertIsNotNone(response_json["id"])
850
851
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
852
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
853
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
854
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
855
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
856
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
857
    @patch('napps.kytos.mef_eline.models.EVC._validate')
858
    def test_update_schedule(self, *args):  # pylint: disable=too-many-locals
859
        """Test create a circuit schedule."""
860
        (validate_mock, evc_as_dict_mock, save_evc_mock,
861
         uni_from_dict_mock, sched_add_mock, storehouse_data_mock,
862
         scheduler_remove_job_mock) = args
863
864
        storehouse_payload_1 = {
865
            "aa:aa:aa": {
866
                "id": "aa:aa:aa",
867
                "name": "my evc1",
868
                "uni_a": {
869
                    "interface_id": "00:00:00:00:00:00:00:01:1",
870
                    "tag": {
871
                        "tag_type": 1,
872
                        "value": 80
873
                    }
874
                },
875
                "uni_z": {
876
                    "interface_id": "00:00:00:00:00:00:00:02:2",
877
                    "tag": {
878
                        "tag_type": 1,
879
                        "value": 1
880
                    }
881
                },
882
                "circuit_scheduler": [{
883
                    "id": "1",
884
                    "frequency": "* * * * *",
885
                    "action": "create"
886
                }
887
                ]
888
            }
889
        }
890
891
        validate_mock.return_value = True
892
        save_evc_mock.return_value = True
893
        sched_add_mock.return_value = True
894
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
895
        evc_as_dict_mock.return_value = {}
896
        storehouse_data_mock.return_value = storehouse_payload_1
897
        scheduler_remove_job_mock.return_value = True
898
899
        requested_schedule_id = "1"
900
        api = self.get_app_test_client(self.napp)
901
        url = f'{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}'
902
903
        payload = {
904
            "frequency": "*/1 * * * *",
905
            "action": "create"
906
        }
907
908
        # Call URL
909
        response = api.patch(url, data=json.dumps(payload),
910
                             content_type='application/json')
911
912
        response_json = json.loads(response.data)
913
914
        self.assertEqual(response.status_code, 200, response.data)
915
        scheduler_remove_job_mock.assert_called_once()
916
        save_evc_mock.assert_called_once()
917
        self.assertEqual(payload["frequency"], response_json["frequency"])
918
        self.assertEqual(payload["action"], response_json["action"])
919
        self.assertIsNotNone(response_json["id"])
920
921
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
922
    @patch('napps.kytos.mef_eline.scheduler.Scheduler.add')
923
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
924
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
925
    @patch('napps.kytos.mef_eline.models.EVC._validate')
926
    def test_update_schedule_archived(self, *args):
927
        """Test create a circuit schedule."""
928
        # pylint: disable=too-many-locals
929
        (validate_mock, evc_as_dict_mock,
930
         uni_from_dict_mock, sched_add_mock, storehouse_data_mock) = args
931
932
        storehouse_payload_1 = {
933
            "aa:aa:aa": {
934
                "id": "aa:aa:aa",
935
                "name": "my evc1",
936
                "archived": True,
937
                "circuit_scheduler": [{
938
                    "id": "1",
939
                    "frequency": "* * * * *",
940
                    "action": "create"
941
                }
942
                ]
943
            }
944
        }
945
946
        validate_mock.return_value = True
947
        sched_add_mock.return_value = True
948
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
949
        evc_as_dict_mock.return_value = {}
950
        storehouse_data_mock.return_value = storehouse_payload_1
951
952
        requested_schedule_id = "1"
953
        api = self.get_app_test_client(self.napp)
954
        url = f'{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}'
955
956
        payload = {
957
            "frequency": "*/1 * * * *",
958
            "action": "create"
959
        }
960
961
        # Call URL
962
        response = api.patch(url, data=json.dumps(payload),
963
                             content_type='application/json')
964
965
        self.assertEqual(response.status_code, 403, response.data)
966
967
    @patch('apscheduler.schedulers.background.BackgroundScheduler.remove_job')
968
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
969
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
970
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.save_evc')
971
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
972
    @patch('napps.kytos.mef_eline.models.EVC._validate')
973
    def test_delete_schedule(self, *args):
974
        """Test create a circuit schedule."""
975
        (validate_mock, evc_as_dict_mock, save_evc_mock,
976
         uni_from_dict_mock, storehouse_data_mock,
977
         scheduler_remove_job_mock) = args
978
979
        storehouse_payload_1 = {
980
            "2": {
981
                "id": "2",
982
                "name": "my evc1",
983
                "uni_a": {
984
                    "interface_id": "00:00:00:00:00:00:00:01:1",
985
                    "tag": {
986
                        "tag_type": 1,
987
                        "value": 80
988
                    }
989
                },
990
                "uni_z": {
991
                    "interface_id": "00:00:00:00:00:00:00:02:2",
992
                    "tag": {
993
                        "tag_type": 1,
994
                        "value": 1
995
                    }
996
                },
997
                "circuit_scheduler": [{
998
                    "id": "1",
999
                    "frequency": "* * * * *",
1000
                    "action": "create"
1001
                }]
1002
            }
1003
        }
1004
        validate_mock.return_value = True
1005
        save_evc_mock.return_value = True
1006
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
1007
        evc_as_dict_mock.return_value = {}
1008
        storehouse_data_mock.return_value = storehouse_payload_1
1009
        scheduler_remove_job_mock.return_value = True
1010
1011
        requested_schedule_id = "1"
1012
        api = self.get_app_test_client(self.napp)
1013
        url = f'{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}'
1014
1015
        # Call URL
1016
        response = api.delete(url)
1017
1018
        self.assertEqual(response.status_code, 200, response.data)
1019
        scheduler_remove_job_mock.assert_called_once()
1020
        save_evc_mock.assert_called_once()
1021
        self.assertIn("Schedule removed", f"{response.data}")
1022
1023
    @patch('napps.kytos.mef_eline.storehouse.StoreHouse.get_data')
1024
    @patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
1025
    @patch('napps.kytos.mef_eline.main.EVC.as_dict')
1026
    @patch('napps.kytos.mef_eline.models.EVC._validate')
1027
    def test_delete_schedule_archived(self, *args):
1028
        """Test create a circuit schedule."""
1029
        (validate_mock, evc_as_dict_mock,
1030
         uni_from_dict_mock, storehouse_data_mock) = args
1031
1032
        storehouse_payload_1 = {
1033
            "2": {
1034
                "id": "2",
1035
                "name": "my evc1",
1036
                "archived": True,
1037
                "circuit_scheduler": [{
1038
                    "id": "1",
1039
                    "frequency": "* * * * *",
1040
                    "action": "create"
1041
                }]
1042
            }
1043
        }
1044
1045
        validate_mock.return_value = True
1046
        uni_from_dict_mock.side_effect = ['uni_a', 'uni_z']
1047
        evc_as_dict_mock.return_value = {}
1048
        storehouse_data_mock.return_value = storehouse_payload_1
1049
1050
        requested_schedule_id = "1"
1051
        api = self.get_app_test_client(self.napp)
1052
        url = f'{self.server_name_url}/v2/evc/schedule/{requested_schedule_id}'
1053
1054
        # Call URL
1055
        response = api.delete(url)
1056
1057
        self.assertEqual(response.status_code, 403, response.data)
1058