Merge "Add traffic duration support in test case"
[yardstick.git] / yardstick / tests / unit / network_services / vnf_generic / vnf / test_tg_landslide.py
1 # Copyright (c) 2018 Intel Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import copy
16 import mock
17 import requests
18 import time
19 import unittest
20 import uuid
21
22 from yardstick.benchmark.contexts import base as ctx_base
23 from yardstick.common import exceptions
24 from yardstick.common import utils as common_utils
25 from yardstick.common import yaml_loader
26 from yardstick.network_services import utils as net_serv_utils
27 from yardstick.network_services.traffic_profile import landslide_profile
28 from yardstick.network_services.vnf_generic.vnf import sample_vnf
29 from yardstick.network_services.vnf_generic.vnf import tg_landslide
30
31
32 NAME = "tg__0"
33
34 EXAMPLE_URL = 'http://example.com/'
35 TCL_SUCCESS_RESPONSE = 'ls_ok'
36
37 TEST_SERVERS = [
38     {'ip': '192.168.122.101',
39      'phySubnets': [
40          {'mask': '/24',
41           'base': '10.42.32.100',
42           'numIps': 20,
43           'name': 'eth1'}
44      ],
45      'role': 'SGW_Node',
46      'name': 'TestServer_1'},
47     {'ip': '192.168.122.102',
48      'phySubnets': [
49          {'mask': '/24',
50           'base': '10.42.32.1',
51           'numIps': 100,
52           'name': 'eth1'
53           },
54          {'mask': '/24',
55           'base': '10.42.33.1',
56           'numIps': 100,
57           'name': 'eth2'}
58      ],
59      'preResolvedArpAddress': [
60          {'NumNodes': 1,
61           'StartingAddress': '10.42.33.5'}
62      ],
63      'role': 'SGW_Nodal',
64      'name': 'TestServer_2',
65      'thread_model': 'Fireball'
66      }
67 ]
68
69 TS1_SUTS = [
70     {'name': 'SGW - C TestNode',
71      'role': 'SgwControlAddr',
72      'managementIp': '12.0.1.1',
73      'ip': '10.42.32.100',
74      'phy': 'eth5',
75      'nextHop': '10.42.32.5'
76      },
77     {'name': 'SGW - U TestNode',
78      'role': 'SgwUserAddr',
79      'managementIp': '12.0.1.2',
80      'ip': '10.42.32.101',
81      'phy': 'eth5',
82      'nextHop': '10.42.32.5'
83      }
84 ]
85
86 TS2_SUTS = [
87     {'name': 'eNodeB TestNode',
88      'role': 'EnbUserAddr',
89      'managementIp': '12.0.2.1',
90      'ip': '10.42.32.2',
91      'phy': 'eth5',
92      'nextHop': '10.42.32.5'
93      },
94     {'name': 'MME TestNode',
95      'role': 'MmeControlAddr',
96      'managementIp': '12.0.3.1',
97      'ip': '10.42.32.1',
98      'phy': 'eth5',
99      'nextHop': '10.42.32.5'
100      },
101     {'name': 'NetHost TestNode',
102      'role': 'NetworkHostAddrLocal',
103      'managementIp': '12.0.4.1',
104      'ip': '10.42.33.1',
105      'phy': 'eth5',
106      'nextHop': '10.42.32.5'
107      },
108     {'name': 'PGW TestNode',
109      'role': 'PgwV4Sut',
110      'managementIp': '12.0.5.1',
111      'ip': '10.42.32.105',
112      'phy': 'eth5',
113      'nextHop': '10.42.32.5'
114      },
115     {'name': 'SGW - C SUT',
116      'role': 'SgwSut',
117      'managementIp': '12.0.6.1',
118      'ip': '10.42.32.100'
119      },
120     {'name': 'SGW - U SUT',
121      'role': 'SgwUserSut',
122      'managementIp': '12.0.6.2',
123      'ip': '10.42.32.101'}
124 ]
125
126 VNFD = {
127     'vnfd:vnfd-catalog': {
128         'vnfd': [{
129             'short-name': 'landslide',
130             'vdu': [{
131                 'description': 'AB client interface details',
132                 'name': 'abclient-baremetal',
133                 'id': 'abclient-baremetal',
134                 'external-interface': []}],
135             'description': 'Spirent Landslide traffic generator',
136             'config': [{'test_server': TEST_SERVERS[0], 'suts': TS1_SUTS},
137                        {'test_server': TEST_SERVERS[1], 'suts': TS2_SUTS}],
138             'mgmt-interface': {
139                 'vdu-id': 'landslide-tas',
140                 'user': 'user',
141                 'password': 'user',
142                 'super-user': 'super-user',
143                 'super-user-password': 'super-user-password',
144                 'cfguser_password': 'cfguser_password',
145                 'license': 48,
146                 'proto': 'http',
147                 'ip': '1.1.1.1'},
148             'benchmark': {
149                 'kpi': [
150                     'tx_throughput_mbps',
151                     'rx_throughput_mbps',
152                     'in_packets',
153                     'out_packets',
154                     'activation_rate_sessps',
155                     'deactivation_rate_sessps']},
156             'id': 'LandslideTrafficGen',
157             'name': 'LandslideTrafficGen'}]}}
158
159 TAS_INFO = VNFD['vnfd:vnfd-catalog']['vnfd'][0]['mgmt-interface']
160
161 DMF_CFG = {
162     "dmf": {
163         "library": "test",
164         "name": "Basic UDP"
165     },
166     "clientPort": {
167         "clientPort": 2002,
168         "isClientPortRange": "false"
169     },
170     "dataProtocol": "udp",
171     "serverPort": 2003
172 }
173
174 RESERVATIONS = [
175     {'tsName': TEST_SERVERS[0]['name'],
176      'phySubnets': TEST_SERVERS[0]['phySubnets'],
177      'tsId': TEST_SERVERS[0]['name'],
178      'tsIndex': 0},
179     {'tsName': TEST_SERVERS[1]['name'],
180      'phySubnets': TEST_SERVERS[1]['phySubnets'],
181      'tsId': TEST_SERVERS[1]['name'],
182      'tsIndex': 1}]
183
184 SESSION_PROFILE = {
185     'keywords': '',
186     'duration': 60,
187     'iterations': 1,
188     'description': 'UE default bearer creation test case',
189     'name': 'default_bearer_capacity',
190     'reportOptions': {'format': 'CSV'},
191     'reservePorts': 'false',
192     'tsGroups': [
193         {
194             'testCases': [{
195                 'type': 'SGW_Node',
196                 'name': '',
197                 'linked': "false",
198                 'AssociatedPhys': '',
199                 'parameters': {
200                     'SgiPtpTunnelEn': 'false',
201                     'Gtp2Imsi': '505024101215074',
202                     'Sessions': '100000',
203                     'S5Protocol': 'GTPv2',
204                     'TrafficMtu': '1500',
205                     'Gtp2Version': '13.6.0',
206                     'BearerV4AddrPool': '1.0.0.1',
207                     'Gtp2Imei': '50502410121507',
208                     'PgwNodeEn': 'true',
209                     'DedicatedsPerDefaultBearer': '0',
210                     'DefaultBearers': '1',
211                     'SgwUserAddr': {
212                         'numLinksOrNodes': 1,
213                         'phy': 'eth1',
214                         'forcedEthInterface': '',
215                         'ip': 'SGW_USER_IP',
216                         'class': 'TestNode',
217                         'ethStatsEnabled': "false",
218                         'mtu': 1500
219                     },
220                     'SgwControlAddr': {
221                         'numLinksOrNodes': 1,
222                         'phy': 'eth1',
223                         'forcedEthInterface': '',
224                         'ip': 'SGW_CONTROL_IP',
225                         'class': 'TestNode',
226                         'ethStatsEnabled': "false",
227                         'mtu': 1500,
228                         'nextHop': 'SGW_CONTROL_NEXT_HOP'
229                     },
230                     'BearerAddrPool': '2001::1',
231                     'TestType': 'SGW-NODE'
232                 }
233             }],
234             'tsId': TEST_SERVERS[0]['name']},
235         {
236             'testCases': [{
237                 'type': 'SGW_Nodal',
238                 'name': '',
239                 'parameters': {
240                     'DataTraffic': 'Continuous',
241                     'TrafficStartType': 'When All Sessions Established',
242                     'NetworkHost': 'Local',
243                     'Gtp2Imsi': '505024101215074',
244                     'Dmf': {
245                         'mainflows': [
246                             {
247                                 'name': 'Basic UDP',
248                                 'library': 'test'
249                             }
250                         ],
251                         'class': 'Dmf',
252                         'instanceGroups': [
253                             {
254                                 'startPaused': "false",
255                                 'rate': 0,
256                                 'mainflowIdx': 0,
257                                 'mixType': ''
258                             }
259                         ]
260                     },
261                     'S5Protocol': 'GTPv2',
262                     'DataUserCfgFileEn': 'false',
263                     'PgwUserSutEn': 'false',
264                     'MmeControlAddr': {
265                         'numLinksOrNodes': 1,
266                         'phy': 'eth1',
267                         'forcedEthInterface': '',
268                         'ip': 'MME_CONTROL_IP',
269                         'class': 'TestNode',
270                         'ethStatsEnabled': "false",
271                         'mtu': 1500
272                     },
273                     'SgwUserSut': {
274                         'class': 'Sut',
275                         'name': 'SGW_USER_NAME'
276                     },
277                     'TestActivity': 'Capacity Test',
278                     'NetworkHostAddrLocal': {
279                         'numLinksOrNodes': 1,
280                         'phy': 'eth2',
281                         'forcedEthInterface': '',
282                         'ip': 'NET_HOST_IP',
283                         'class': 'TestNode',
284                         'ethStatsEnabled': "false",
285                         'mtu': 1500
286                     },
287                     'DedicatedsPerDefaultBearer': '0',
288                     'DisconnectRate': '1000.0',
289                     'Sessions': '100000',
290                     'SgwSut': {
291                         'class': 'Sut',
292                         'name': 'SGW_CONTROL_NAME'
293                     },
294                     'TrafficMtu': '1500',
295                     'Gtp2Version': '13.6.0',
296                     'Gtp2Imei': '50502410121507',
297                     'PgwNodeEn': 'false',
298                     'StartRate': '1000.0',
299                     'PgwV4Sut': {
300                         'class': 'Sut',
301                         'name': 'PGW_SUT_NAME'
302                     },
303                     'DefaultBearers': '1',
304                     'EnbUserAddr': {
305                         'numLinksOrNodes': 1,
306                         'phy': 'eth1',
307                         'forcedEthInterface': '',
308                         'ip': 'ENB_USER_IP',
309                         'class': 'TestNode',
310                         'ethStatsEnabled': "false",
311                         'mtu': 1500
312                     },
313                     'TestType': 'SGW-NODAL'
314                 }
315             }],
316             'tsId': TEST_SERVERS[1]['name']
317         }
318     ]
319 }
320
321
322 class TestLandslideTrafficGen(unittest.TestCase):
323     SCENARIO_CFG = {
324         'session_profile': '/traffic_profiles/landslide/'
325                            'landslide_session_default_bearer.yaml',
326         'task_path': '',
327         'runner': {
328             'type': 'Iteration',
329             'iterations': 1
330         },
331         'nodes': {
332             'tg__0': 'tg__0.traffic_gen',
333             'vnf__0': 'vnf__0.vnf_epc'
334         },
335         'topology': 'landslide_tg_topology.yaml',
336         'type': 'NSPerf',
337         'traffic_profile': '../../traffic_profiles/landslide/'
338                            'landslide_dmf_udp.yaml',
339         'options': {
340             'traffic_duration': 71,
341             'test_cases': [
342                 {
343                     'BearerAddrPool': '2002::2',
344                     'type': 'SGW_Node',
345                     'BearerV4AddrPool': '2.0.0.2',
346                     'Sessions': '90000'
347                 },
348                 {
349                     'StartRate': '900.0',
350                     'type': 'SGW_Nodal',
351                     'DisconnectRate': '900.0',
352                     'Sessions': '90000'
353                 }
354             ],
355             'dmf':
356                 {
357                     'transactionRate': 1000,
358                     'packetSize': 512
359                 }
360         }
361     }
362
363     CONTEXT_CFG = {
364         'contexts': [
365             {
366                 'type': 'Node',
367                 'name': 'traffic_gen',
368                 'file': '/etc/yardstick/nodes/pod_landslide.yaml'
369             },
370             {
371                 'type': 'Node',
372                 'name': 'vnf_epc',
373                 'file': '/etc/yardstick/nodes/pod_vepc_sut.yaml'
374             }
375         ]
376     }
377
378     TRAFFIC_PROFILE = {
379         "schema": "nsb:traffic_profile:0.1",
380         "name": "LandslideProfile",
381         "description": "Spirent Landslide traffic profile",
382         "traffic_profile": {
383             "traffic_type": "LandslideProfile"
384         },
385         "dmf_config": {
386             "dmf": {
387                 "library": "test",
388                 "name": "Basic UDP"
389             },
390             "description": "Basic data flow using UDP/IP",
391             "keywords": "UDP",
392             "dataProtocol": "udp"
393         }
394     }
395
396     SUCCESS_CREATED_CODE = 201
397     SUCCESS_OK_CODE = 200
398     SUCCESS_RECORD_ID = 5
399     TEST_USER_ID = 11
400
401     def setUp(self):
402         self._id = uuid.uuid1().int
403
404         self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi')
405         self.mock_lsapi.start()
406
407         self.mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper')
408         self.mock_ssh_helper.start()
409         self.vnfd = VNFD['vnfd:vnfd-catalog']['vnfd'][0]
410         self.ls_tg = tg_landslide.LandslideTrafficGen(
411             NAME, self.vnfd, self._id)
412         self.session_profile = copy.deepcopy(SESSION_PROFILE)
413         self.ls_tg.session_profile = self.session_profile
414
415         self.addCleanup(self._cleanup)
416
417     def _cleanup(self):
418         self.mock_lsapi.stop()
419         self.mock_ssh_helper.stop()
420
421     @mock.patch.object(net_serv_utils, 'get_nsb_option')
422     def test___init__(self, mock_get_nsb_option, *args):
423         _path_to_nsb = 'path/to/nsb'
424         mock_get_nsb_option.return_value = _path_to_nsb
425         ls_tg = tg_landslide.LandslideTrafficGen(NAME, self.vnfd, self._id)
426         self.assertIsInstance(ls_tg.resource_helper,
427                               tg_landslide.LandslideResourceHelper)
428         mock_get_nsb_option.assert_called_once_with('bin_path')
429         self.assertEqual(_path_to_nsb, ls_tg.bin_path)
430         self.assertEqual(NAME, ls_tg.name)
431         self.assertTrue(ls_tg.runs_traffic)
432         self.assertFalse(ls_tg.traffic_finished)
433         self.assertIsNone(ls_tg.session_profile)
434
435     def test_listen_traffic(self):
436         _traffic_profile = {}
437         self.assertIsNone(self.ls_tg.listen_traffic(_traffic_profile))
438
439     def test_terminate(self, *args):
440         self.ls_tg.resource_helper._tcl = mock.Mock()
441         self.assertIsNone(self.ls_tg.terminate())
442         self.ls_tg.resource_helper._tcl.disconnect.assert_called_once()
443
444     @mock.patch.object(ctx_base.Context, 'get_context_from_server',
445                        return_value='fake_context')
446     def test_instantiate(self, *args):
447         self.ls_tg._tg_process = mock.Mock()
448         self.ls_tg._tg_process.start = mock.Mock()
449         self.ls_tg.resource_helper.connect = mock.Mock()
450         self.ls_tg.resource_helper.create_test_servers = mock.Mock()
451         self.ls_tg.resource_helper.create_suts = mock.Mock()
452         self.ls_tg._load_session_profile = mock.Mock()
453         self.assertIsNone(self.ls_tg.instantiate(self.SCENARIO_CFG,
454                                                  self.CONTEXT_CFG))
455         self.ls_tg.resource_helper.connect.assert_called_once()
456         self.ls_tg.resource_helper.create_test_servers.assert_called_once()
457         _suts_blocks_num = len([item['suts'] for item in self.vnfd['config']])
458         self.assertEqual(_suts_blocks_num,
459                          self.ls_tg.resource_helper.create_suts.call_count)
460         self.ls_tg._load_session_profile.assert_called_once()
461
462     @mock.patch.object(tg_landslide.LandslideResourceHelper,
463                        'get_running_tests')
464     def test_run_traffic(self, mock_get_tests, *args):
465         self.ls_tg.resource_helper._url = EXAMPLE_URL
466         self.ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG
467         mock_traffic_profile = mock.Mock(
468             spec=landslide_profile.LandslideProfile)
469         mock_traffic_profile.dmf_config = {'keywords': 'UDP',
470                                            'dataProtocol': 'udp'}
471         mock_traffic_profile.params = self.TRAFFIC_PROFILE
472         self.ls_tg.resource_helper._user_id = self.TEST_USER_ID
473         mock_get_tests.return_value = [{'id': self.SUCCESS_RECORD_ID,
474                                         'testStateOrStep': 'COMPLETE'}]
475         mock_post = mock.Mock()
476         mock_post.status_code = self.SUCCESS_CREATED_CODE
477         mock_post.json.return_value = {'id': self.SUCCESS_RECORD_ID}
478         mock_session = mock.Mock(spec=requests.Session)
479         mock_session.post.return_value = mock_post
480         self.ls_tg.resource_helper.session = mock_session
481         self.ls_tg.resource_helper._tcl = mock.Mock()
482         _tcl = self.ls_tg.resource_helper._tcl
483         self.assertIsNone(self.ls_tg.run_traffic(mock_traffic_profile))
484         self.assertEqual(self.SUCCESS_RECORD_ID,
485                          self.ls_tg.resource_helper.run_id)
486         mock_traffic_profile.update_dmf.assert_called_with(
487             self.ls_tg.scenario_helper.all_options)
488         _tcl.create_dmf.assert_called_with(mock_traffic_profile.dmf_config)
489         _tcl.create_test_session.assert_called_with(self.session_profile)
490
491     @mock.patch.object(tg_landslide.LandslideResourceHelper,
492                        'check_running_test_state')
493     def test_collect_kpi(self, mock_check_running_test_state, *args):
494         self.ls_tg.resource_helper.run_id = self.SUCCESS_RECORD_ID
495         mock_check_running_test_state.return_value = 'COMPLETE'
496         self.assertEqual({'done': True}, self.ls_tg.collect_kpi())
497         mock_check_running_test_state.assert_called_once()
498
499     def test_wait_for_instantiate(self):
500         self.assertIsNone(self.ls_tg.wait_for_instantiate())
501         self.ls_tg.wait_for_instantiate()
502
503     def test__update_session_suts_no_tc_role(self, *args):
504         _suts = [{'role': 'epc_role'}]
505         _testcase = {'parameters': {'diff_epc_role': {'class': 'Sut'}}}
506         res = self.ls_tg._update_session_suts(_suts, _testcase)
507         self.assertEqual(_testcase, res)
508
509     def test__update_session_suts(self, *args):
510
511         def get_testnode_param(role, key, session_prof):
512             """ Get value by key from the deep nested dict to avoid calls like:
513             e.g. session_prof['tsGroups'][0]['testCases'][1]['parameters'][key]
514             """
515             for group in session_prof['tsGroups']:
516                 for tc in group['testCases']:
517                     tc_params = tc['parameters']
518                     if tc_params.get(role):
519                         return tc_params[role][key]
520
521         def get_sut_param(role, key, suts):
522             """ Search list of dicts for one with specific role.
523             Return the value of related dict by key. Expect key presence.
524             """
525             for sut in suts:
526                 if sut.get('role') == role:
527                     return sut[key]
528
529         # TestNode to verify
530         testnode_role = 'SgwControlAddr'
531         # SUT to verify
532         sut_role = 'SgwUserSut'
533
534         config_suts = [config['suts'] for config in self.vnfd['config']]
535         session_tcs = [_tc for _ts_group in self.ls_tg.session_profile['tsGroups']
536                        for _tc in _ts_group['testCases']]
537         for suts, tc in zip(config_suts, session_tcs):
538             self.assertEqual(tc, self.ls_tg._update_session_suts(suts, tc))
539
540         # Verify TestNode class objects keys were updated
541         for _key in {'ip', 'phy', 'nextHop'}:
542             self.assertEqual(
543                 get_testnode_param(testnode_role, _key, self.ls_tg.session_profile),
544                 get_sut_param(testnode_role, _key, TS1_SUTS))
545         # Verify Sut class objects name was updated
546         self.assertEqual(
547             get_testnode_param(sut_role, 'name', self.ls_tg.session_profile),
548             get_sut_param(sut_role, 'name', TS2_SUTS))
549
550     def test__update_session_test_servers(self, *args):
551         for ts_index, ts in enumerate(TEST_SERVERS):
552             self.assertIsNone(
553                 self.ls_tg._update_session_test_servers(ts, ts_index))
554         # Verify preResolvedArpAddress key was added
555         self.assertTrue(any(
556             _item.get('preResolvedArpAddress')
557             for _item in self.ls_tg.session_profile['tsGroups']))
558         # Verify reservations key was added to session profile
559         self.assertEqual(RESERVATIONS,
560                          self.ls_tg.session_profile.get('reservations'))
561         self.assertEqual('true',
562                          self.ls_tg.session_profile.get('reservePorts'))
563
564     def test__update_session_tc_params_assoc_phys(self):
565         _tc_options = {'AssociatedPhys': 'eth1'}
566         _testcase = {}
567         _testcase_orig = copy.deepcopy(_testcase)
568         res = self.ls_tg._update_session_tc_params(_tc_options, _testcase)
569         self.assertNotEqual(_testcase_orig, res)
570         self.assertEqual(_tc_options, _testcase)
571
572     def test__update_session_tc_params(self, *args):
573
574         def get_session_tc_param_value(param, tc_type, session_prof):
575             """ Get param value from the deep nested dict to avoid calls like:
576             session_prof['tsGroups'][0]['testCases'][0]['parameters'][key]
577             """
578             for test_group in session_prof['tsGroups']:
579                 session_tc = test_group['testCases'][0]
580                 if session_tc['type'] == tc_type:
581                     return session_tc['parameters'].get(param)
582
583         session_tcs = [_tc for _ts_group in self.ls_tg.session_profile['tsGroups']
584                        for _tc in _ts_group['testCases']]
585         scenario_tcs = [_tc for _tc in
586                         self.SCENARIO_CFG['options']['test_cases']]
587         for tc_options, tc in zip(scenario_tcs, session_tcs):
588             self.assertEqual(
589                 tc,
590                 self.ls_tg._update_session_tc_params(tc_options, tc))
591
592         # Verify that each test case parameter was updated
593         # Params been compared are deeply nested. Using loops to ease access.
594         for _tc in self.SCENARIO_CFG['options']['test_cases']:
595             for _key, _val in _tc.items():
596                 if _key != 'type':
597                     self.assertEqual(
598                         _val,
599                         get_session_tc_param_value(_key, _tc.get('type'),
600                                                    self.ls_tg.session_profile))
601
602     @mock.patch.object(common_utils, 'open_relative_file')
603     @mock.patch.object(yaml_loader, 'yaml_load')
604     @mock.patch.object(tg_landslide.LandslideTrafficGen,
605                        '_update_session_test_servers')
606     @mock.patch.object(tg_landslide.LandslideTrafficGen,
607                        '_update_session_suts')
608     @mock.patch.object(tg_landslide.LandslideTrafficGen,
609                        '_update_session_tc_params')
610     def test__load_session_profile(self, mock_upd_ses_tc_params,
611                                    mock_upd_ses_suts, mock_upd_ses_ts,
612                                    mock_yaml_load, *args):
613         self.ls_tg.scenario_helper.scenario_cfg = \
614             copy.deepcopy(self.SCENARIO_CFG)
615         mock_yaml_load.return_value = copy.deepcopy(SESSION_PROFILE)
616         self.assertIsNone(self.ls_tg._load_session_profile())
617         self.assertIsNotNone(self.ls_tg.session_profile)
618         # Number of blocks in configuration files
619         # Number of test servers, suts and tc params blocks should be equal
620         _config_files_blocks_num = len([item['test_server']
621                                         for item in self.vnfd['config']])
622         self.assertEqual(_config_files_blocks_num,
623                          mock_upd_ses_ts.call_count)
624         self.assertEqual(_config_files_blocks_num,
625                          mock_upd_ses_suts.call_count)
626         self.assertEqual(_config_files_blocks_num,
627                          mock_upd_ses_tc_params.call_count)
628
629     @mock.patch.object(common_utils, 'open_relative_file')
630     @mock.patch.object(yaml_loader, 'yaml_load')
631     def test__load_session_profile_unequal_num_of_cfg_blocks(
632             self, mock_yaml_load, *args):
633         vnfd = copy.deepcopy(VNFD['vnfd:vnfd-catalog']['vnfd'][0])
634         ls_traffic_gen = tg_landslide.LandslideTrafficGen(NAME, vnfd, self._id)
635         ls_traffic_gen.scenario_helper.scenario_cfg = self.SCENARIO_CFG
636         mock_yaml_load.return_value = copy.deepcopy(SESSION_PROFILE)
637         # Delete test_servers item from pod file to make it not valid
638         ls_traffic_gen.vnfd_helper['config'].pop()
639         with self.assertRaises(RuntimeError):
640             ls_traffic_gen._load_session_profile()
641
642     @mock.patch.object(common_utils, 'open_relative_file')
643     @mock.patch.object(yaml_loader, 'yaml_load')
644     def test__load_session_profile_test_type_mismatch(self, mock_yaml_load,
645                                                       *args):
646         vnfd = copy.deepcopy(VNFD['vnfd:vnfd-catalog']['vnfd'][0])
647         # Swap test servers data in pod file
648         vnfd['config'] = list(reversed(vnfd['config']))
649         ls_tg = tg_landslide.LandslideTrafficGen(NAME, vnfd, self._id)
650         ls_tg.scenario_helper.scenario_cfg = self.SCENARIO_CFG
651         mock_yaml_load.return_value = SESSION_PROFILE
652         with self.assertRaises(RuntimeError):
653             ls_tg._load_session_profile()
654
655
656 class TestLandslideResourceHelper(unittest.TestCase):
657
658     PROTO_PORT = 8080
659     EXAMPLE_URL = ''.join([TAS_INFO['proto'], '://', TAS_INFO['ip'], ':',
660                            str(PROTO_PORT), '/api/'])
661     SUCCESS_CREATED_CODE = 201
662     SUCCESS_OK_CODE = 200
663     INVALID_REST_CODE = '400'
664     NOT_MODIFIED_CODE = 500810
665     ERROR_CODE = 500800
666     SUCCESS_RECORD_ID = 11
667     EXPIRE_DATE = '2020/01/01 12:00 FLE Standard Time'
668     TEST_USER = 'test'
669     TEST_TERMINATED = 1
670     AUTH_DATA = {'user': TAS_INFO['user'], 'password': TAS_INFO['password']}
671     TEST_SESSION_NAME = 'default_bearer_capacity'
672
673     USERS_DATA = {
674         "users": [{
675             "url": ''.join([EXAMPLE_URL, 'users/', str(SUCCESS_RECORD_ID)]),
676             "id": SUCCESS_RECORD_ID,
677             "level": 1,
678             "username": TEST_USER
679         }]
680     }
681
682     CREATE_USER_DATA = {'username': TAS_INFO['user'],
683                         'expiresOn': EXPIRE_DATE,
684                         'level': 1,
685                         'contactInformation': '',
686                         'fullName': 'Test User',
687                         'password': TAS_INFO['password'],
688                         'isActive': 'true'}
689
690     SUTS_DATA = {
691         "suts": [
692             {
693                 "url": ''.join([EXAMPLE_URL, 'suts/', str(SUCCESS_RECORD_ID)]),
694                 "id": SUCCESS_RECORD_ID,
695                 "name": "10.41.32.1"
696             }]}
697
698     TEST_SERVERS_DATA = {
699         "testServers": [
700             {
701                 "url": ''.join([EXAMPLE_URL, "testServers/1"]),
702                 "id": 1,
703                 "name": TEST_SERVERS[0]['name'],
704                 "state": "READY",
705                 "version": "16.4.0.10"
706             },
707             {
708                 "url": ''.join([EXAMPLE_URL, "testServers/2"]),
709                 "id": 2,
710                 "name": TEST_SERVERS[1]['name'],
711                 "state": "READY",
712                 "version": "16.4.0.10"
713             }
714
715         ]
716     }
717
718     RUN_ID = 3
719
720     RUNNING_TESTS_DATA = {
721         "runningTests": [{
722             "url": ''.join([EXAMPLE_URL, "runningTests/{}".format(RUN_ID)]),
723             "measurementsUrl": ''.join(
724                 [EXAMPLE_URL,
725                  "runningTests/{}/measurements".format(RUN_ID)]),
726             "criteriaUrl": ''.join(
727                 [EXAMPLE_URL,
728                  "runningTests/{}/criteria".format(RUN_ID)]),
729             "noteToUser": "",
730             "id": RUN_ID,
731             "library": SUCCESS_RECORD_ID,
732             "name": "default_bearer_capacity",
733             "user": TEST_USER,
734             "criteriaStatus": "NA",
735             "testStateOrStep": "COMPLETE"
736         }]}
737
738     TEST_RESULTS_DATA = {
739         "interval": 0,
740         "elapsedTime": 138,
741         "actualTime": 1521548057296,
742         "iteration": 1,
743         "tabs": {
744             "Test Summary": {
745                 "Start Time": "Tue Mar 20 07:11:55 CDT 2018",
746                 "Actual Dedicated Bearer Session Connects": "100",
747                 "Actual Dedicated Bearer Session Disconnects": "100",
748                 "Actual Disconnect Rate(Sessions / Second)(P - I)": "164.804",
749                 "Average Session Disconnect Time(P - I)": "5.024 s",
750                 "Total Data Sent + Received Packets / Sec(P - I)": "1,452.294"
751             }}}
752
753     def setUp(self):
754         self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi')
755         self.mock_lsapi.start()
756
757         mock_env_helper = mock.Mock()
758         self.res_helper = tg_landslide.LandslideResourceHelper(mock_env_helper)
759         self.res_helper._url = EXAMPLE_URL
760
761         self.addCleanup(self._cleanup)
762
763     def _cleanup(self):
764         self.mock_lsapi.stop()
765         self.res_helper._url = None
766
767     def test___init__(self, *args):
768         self.assertIsInstance(self.res_helper,
769                               tg_landslide.LandslideResourceHelper)
770         self.assertEqual({}, self.res_helper._result)
771         self.assertIsNone(self.res_helper.run_id)
772
773     @mock.patch.object(tg_landslide.LandslideResourceHelper,
774                        'stop_running_tests')
775     @mock.patch.object(tg_landslide.LandslideResourceHelper,
776                        'get_running_tests')
777     def test_abort_running_tests_no_running_tests(self, mock_get_tests,
778                                                   mock_stop_tests, *args):
779         tests_data = [{'id': self.SUCCESS_RECORD_ID,
780                        'testStateOrStep': 'COMPLETE'}]
781         mock_get_tests.return_value = tests_data
782         self.assertIsNone(self.res_helper.abort_running_tests())
783         mock_stop_tests.assert_not_called()
784
785     @mock.patch.object(time, 'sleep')
786     @mock.patch.object(tg_landslide.LandslideResourceHelper,
787                        'stop_running_tests')
788     @mock.patch.object(tg_landslide.LandslideResourceHelper,
789                        'get_running_tests')
790     def test_abort_running_tests(self, mock_get_tests, mock_stop_tests, *args):
791         test_states_seq = iter(['RUNNING', 'COMPLETE'])
792
793         def configure_mock(*args):
794             return [{'id': self.SUCCESS_RECORD_ID,
795                      'testStateOrStep': next(test_states_seq)}]
796
797         mock_get_tests.side_effect = configure_mock
798         self.assertIsNone(self.res_helper.abort_running_tests())
799         mock_stop_tests.assert_called_once_with(
800             running_test_id=self.SUCCESS_RECORD_ID,
801             force=True)
802         self.assertEqual(2, mock_get_tests.call_count)
803
804     @mock.patch.object(tg_landslide.LandslideResourceHelper,
805                        'stop_running_tests')
806     @mock.patch.object(tg_landslide.LandslideResourceHelper,
807                        'get_running_tests')
808     def test_abort_running_tests_error(self, mock_get_tests, mock_stop_tests,
809                                        *args):
810         tests_data = {'id': self.SUCCESS_RECORD_ID,
811                       'testStateOrStep': 'RUNNING'}
812         mock_get_tests.return_value = [tests_data]
813         with self.assertRaises(RuntimeError):
814             self.res_helper.abort_running_tests(timeout=1, delay=1)
815         mock_stop_tests.assert_called_with(
816             running_test_id=self.SUCCESS_RECORD_ID,
817             force=True)
818
819     def test__build_url(self, *args):
820         resource = 'users'
821         action = {'action': 'userCreate'}
822         expected_url = ''.join([EXAMPLE_URL, 'users?action=userCreate'])
823         self.assertEqual(expected_url,
824                          self.res_helper._build_url(resource, action))
825
826     def test__build_url_error(self, *args):
827         resource = ''
828         action = {'action': 'userCreate'}
829
830         with self.assertRaises(ValueError):
831             self.res_helper._build_url(resource, action)
832
833     def test_get_response_params(self, *args):
834         method = 'get'
835         resource = 'users'
836         mock_session = mock.Mock(spec=requests.Session)
837         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
838                          'json.return_value': self.USERS_DATA}
839         mock_session.get.return_value.configure_mock(**get_resp_data)
840         self.res_helper.session = mock_session
841         resp = self.res_helper.get_response_params(method, resource)
842         self.assertTrue(resp)
843
844     @mock.patch.object(tg_landslide.LandslideResourceHelper, '_get_users')
845     @mock.patch.object(time, 'time')
846     def test__create_user(self, mock_time, mock_get_users, *args):
847         mock_time.strftime.return_value = self.EXPIRE_DATE
848         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE,
849                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
850         mock_session = mock.Mock(spec=requests.Session)
851         mock_session.post.return_value.configure_mock(**post_resp_data)
852         self.res_helper.session = mock_session
853         self.assertEqual(self.SUCCESS_RECORD_ID,
854                          self.res_helper._create_user(self.AUTH_DATA))
855         mock_get_users.assert_not_called()
856
857     @mock.patch.object(tg_landslide.LandslideResourceHelper, '_modify_user')
858     @mock.patch.object(time, 'time')
859     def test__create_user_username_exists(self, mock_time, mock_modify_user,
860                                           *args):
861         mock_time.strftime.return_value = self.EXPIRE_DATE
862         mock_modify_user.return_value = {'id': self.SUCCESS_RECORD_ID,
863                                          'result': 'No changes requested'}
864         post_resp_data = {
865             'status_code': self.ERROR_CODE,
866             'json.return_value': {'id': self.SUCCESS_OK_CODE,
867                                   'apiCode': self.NOT_MODIFIED_CODE}}
868         mock_session = mock.Mock(spec=requests.Session)
869         mock_session.post.return_value.configure_mock(**post_resp_data)
870         self.res_helper.session = mock_session
871         res = self.res_helper._create_user(self.AUTH_DATA)
872         mock_modify_user.assert_called_once_with(TAS_INFO['user'],
873                                                  {'isActive': 'true'})
874         self.assertEqual(self.SUCCESS_RECORD_ID, res)
875
876     @mock.patch.object(time, 'time')
877     def test__create_user_error(self, mock_time, *args):
878         mock_time.strftime.return_value = self.EXPIRE_DATE
879         mock_session = mock.Mock(spec=requests.Session)
880         post_resp_data = {'status_code': self.SUCCESS_OK_CODE,
881                           'json.return_value': {'apiCode': self.ERROR_CODE}}
882         mock_session.post.return_value.configure_mock(**post_resp_data)
883         self.res_helper.session = mock_session
884         with self.assertRaises(exceptions.RestApiError):
885             self.res_helper._create_user(self.AUTH_DATA)
886
887     def test__modify_user(self, *args):
888         post_data = {'username': 'test_user'}
889         mock_session = mock.Mock(spec=requests.Session)
890         post_resp_data = {'status_code': self.SUCCESS_OK_CODE,
891                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
892         mock_session.post.return_value.configure_mock(**post_resp_data)
893         self.res_helper.session = mock_session
894         res = self.res_helper._modify_user(username=self.TEST_USER,
895                                            fields=post_data)
896         self.assertEqual(self.SUCCESS_RECORD_ID, res['id'])
897
898     def test__modify_user_rest_resp_fail(self, *args):
899         post_data = {'non-existing-key': ''}
900         mock_session = mock.Mock(spec=requests.Session)
901         mock_session.post.ok = False
902         self.res_helper.session = mock_session
903         self.assertRaises(exceptions.RestApiError,
904                           self.res_helper._modify_user,
905                           username=self.TEST_USER, fields=post_data)
906         mock_session.post.assert_called_once()
907
908     def test__delete_user(self, *args):
909         mock_session = mock.Mock(spec=requests.Session)
910         self.res_helper.session = mock_session
911         self.assertIsNone(self.res_helper._delete_user(
912             username=self.TEST_USER))
913
914     def test__get_users(self, *args):
915         mock_session = mock.Mock(spec=requests.Session)
916         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
917                          'json.return_value': self.USERS_DATA}
918         mock_session.get.return_value.configure_mock(**get_resp_data)
919         self.res_helper.session = mock_session
920         self.assertEqual(self.USERS_DATA['users'],
921                          self.res_helper._get_users())
922
923     def test_exec_rest_request(self, *args):
924         resource = 'testServers'
925         action = {'action': 'modify'}
926         expected_url = ''.join([EXAMPLE_URL, 'testServers?action=modify'])
927         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE,
928                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
929         mock_session = mock.Mock(spec=requests.Session)
930         mock_session.post.return_value.configure_mock(**post_resp_data)
931         self.res_helper.session = mock_session
932         self.res_helper.exec_rest_request('post', resource, action)
933         self.res_helper.session.post.assert_called_once_with(expected_url,
934                                                              json={})
935
936     def test_exec_rest_request_unsupported_method_error(self, *args):
937         resource = 'testServers'
938         action = {'action': 'modify'}
939         with self.assertRaises(ValueError):
940             self.res_helper.exec_rest_request('patch', resource, action)
941
942     def test_exec_rest_request_missed_action_arg(self, *args):
943         resource = 'testServers'
944         with self.assertRaises(ValueError):
945             self.res_helper.exec_rest_request('post', resource)
946
947     def test_exec_rest_request_raise_exc(self):
948         resource = 'users'
949         action = {'action': 'modify'}
950         post_resp_data = {'status_code': self.ERROR_CODE,
951                           'json.return_value': {
952                               'status_code': self.ERROR_CODE}}
953         mock_session = mock.Mock(spec=requests.Session)
954         mock_session.post.return_value.configure_mock(**post_resp_data)
955         self.assertRaises(exceptions.RestApiError,
956                           self.res_helper.exec_rest_request,
957                           'post', resource, action, raise_exc=True)
958
959     @mock.patch.object(time, 'time')
960     def test_connect(self, mock_time, *args):
961         vnfd = VNFD['vnfd:vnfd-catalog']['vnfd'][0]
962         mock_time.strftime.return_value = self.EXPIRE_DATE
963         self.res_helper.vnfd_helper = vnfd
964
965         self.res_helper._tcl = mock.Mock()
966         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE,
967                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
968         mock_session = mock.Mock(spec=requests.Session, headers={})
969         mock_session.post.return_value.configure_mock(**post_resp_data)
970         self.res_helper.session = mock_session
971         self.assertIsInstance(self.res_helper.connect(), requests.Session)
972         self.res_helper._tcl.connect.assert_called_once_with(
973             TAS_INFO['ip'],
974             TAS_INFO['user'],
975             TAS_INFO['password'])
976
977     def test_disconnect(self, *args):
978         self.res_helper._tcl = mock.Mock()
979         self.assertIsNone(self.res_helper.disconnect())
980         self.assertIsNone(self.res_helper.session)
981         self.res_helper._tcl.disconnect.assert_called_once()
982
983     def test_terminate(self, *args):
984         self.assertIsNone(self.res_helper.terminate())
985         self.assertEqual(self.TEST_TERMINATED,
986                          self.res_helper._terminated.value)
987
988     def test_create_dmf(self, *args):
989         self.res_helper._tcl = mock.Mock()
990         self.assertIsNone(self.res_helper.create_dmf(DMF_CFG))
991         self.res_helper._tcl.create_dmf.assert_called_once_with(DMF_CFG)
992
993     def test_create_dmf_as_list(self, *args):
994         self.res_helper._tcl = mock.Mock()
995         self.assertIsNone(self.res_helper.create_dmf([DMF_CFG]))
996         self.res_helper._tcl.create_dmf.assert_called_once_with(DMF_CFG)
997
998     def test_delete_dmf(self, *args):
999         self.res_helper._tcl = mock.Mock()
1000         self.assertIsNone(self.res_helper.delete_dmf(DMF_CFG))
1001         self.res_helper._tcl.delete_dmf.assert_called_once_with(DMF_CFG)
1002
1003     def test_delete_dmf_as_list(self, *args):
1004         self.res_helper._tcl = mock.Mock()
1005         self.assertIsNone(self.res_helper.delete_dmf([DMF_CFG]))
1006         self.res_helper._tcl.delete_dmf.assert_called_once_with(DMF_CFG)
1007
1008     @mock.patch.object(tg_landslide.LandslideResourceHelper, 'configure_sut')
1009     def test_create_suts(self, mock_configure_sut, *args):
1010         mock_session = mock.Mock(spec=requests.Session)
1011         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE}
1012         mock_session.post.return_value.configure_mock(**post_resp_data)
1013         self.res_helper.session = mock_session
1014         self.assertIsNone(self.res_helper.create_suts(TS1_SUTS))
1015         mock_configure_sut.assert_not_called()
1016
1017     @mock.patch.object(tg_landslide.LandslideResourceHelper, 'configure_sut')
1018     def test_create_suts_sut_exists(self, mock_configure_sut, *args):
1019         sut_name = 'test_sut'
1020         suts = [
1021             {'name': sut_name,
1022              'role': 'SgwControlAddr',
1023              'managementIp': '12.0.1.1',
1024              'ip': '10.42.32.100'
1025              }
1026         ]
1027         mock_session = mock.Mock(spec=requests.Session)
1028         post_resp_data = {'status_code': self.NOT_MODIFIED_CODE}
1029         mock_session.post.return_value.configure_mock(**post_resp_data)
1030         self.res_helper.session = mock_session
1031         self.assertIsNone(self.res_helper.create_suts(suts))
1032         mock_configure_sut.assert_called_once_with(
1033             sut_name=sut_name,
1034             json_data={k: v for k, v in suts[0].items()
1035                        if k not in {'phy', 'nextHop', 'role', 'name'}})
1036
1037     def test_get_suts(self, *args):
1038         mock_session = mock.Mock(spec=requests.Session)
1039         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1040                          'json.return_value': self.SUTS_DATA}
1041         mock_session.get.return_value.configure_mock(**get_resp_data)
1042         self.res_helper.session = mock_session
1043         self.assertIsInstance(self.res_helper.get_suts(), list)
1044
1045     def test_get_suts_single_id(self, *args):
1046         mock_session = mock.Mock(spec=requests.Session)
1047         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1048                          'json.return_value': self.SUTS_DATA['suts'][0]}
1049         mock_session.get.return_value.configure_mock(**get_resp_data)
1050         self.res_helper.session = mock_session
1051         self.assertIsInstance(self.res_helper.get_suts(suts_id=2), dict)
1052
1053     def test_configure_sut(self, *args):
1054         post_data = {'managementIp': '2.2.2.2'}
1055         mock_session = mock.Mock(spec=requests.Session)
1056         post_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1057                           'json.return_value': {'id': self.SUCCESS_RECORD_ID}}
1058         mock_session.post.return_value.configure_mock(**post_resp_data)
1059         self.res_helper.session = mock_session
1060         self.assertIsNone(self.res_helper.configure_sut('test_name',
1061                                                         post_data))
1062         mock_session.post.assert_called_once()
1063
1064     def test_configure_sut_error(self, *args):
1065         post_data = {'managementIp': '2.2.2.2'}
1066         mock_session = mock.Mock(spec=requests.Session)
1067         post_resp_data = {'status_code': self.NOT_MODIFIED_CODE}
1068         mock_session.post.return_value.configure_mock(**post_resp_data)
1069         self.res_helper.session = mock_session
1070         with self.assertRaises(exceptions.RestApiError):
1071             self.res_helper.configure_sut('test_name', post_data)
1072
1073     def test_delete_suts(self, *args):
1074         mock_session = mock.Mock(spec=requests.Session)
1075         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1076                          'json.return_value': self.SUTS_DATA}
1077         delete_resp_data = {'status_code': self.SUCCESS_OK_CODE}
1078         mock_session.get.return_value.configure_mock(**get_resp_data)
1079         mock_session.delete.return_value.configure_mock(**delete_resp_data)
1080         self.res_helper.session = mock_session
1081         self.assertIsNone(self.res_helper.delete_suts())
1082         mock_session.delete.assert_called_once()
1083
1084     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1085                        'get_test_servers')
1086     def test__check_test_servers_state(self, mock_get_test_servers, *args):
1087         mock_get_test_servers.return_value = \
1088             self.TEST_SERVERS_DATA['testServers']
1089         self.res_helper._check_test_servers_state()
1090         mock_get_test_servers.assert_called_once()
1091
1092     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1093                        'get_test_servers')
1094     def test__check_test_servers_state_server_not_ready(
1095             self, mock_get_test_servers, *args):
1096         test_servers_not_ready = [
1097             {
1098                 "url": ''.join([EXAMPLE_URL, "testServers/1"]),
1099                 "id": 1,
1100                 "name": "TestServer_1",
1101                 "state": "NOT_READY",
1102                 "version": "16.4.0.10"
1103             }
1104         ]
1105
1106         mock_get_test_servers.return_value = test_servers_not_ready
1107         with self.assertRaises(RuntimeError):
1108             self.res_helper._check_test_servers_state(timeout=1, delay=0)
1109
1110     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1111                        '_check_test_servers_state')
1112     def test_create_test_servers(self, mock_check_ts_state, *args):
1113         test_servers_ids = [
1114             ts['id'] for ts in self.TEST_SERVERS_DATA['testServers']]
1115
1116         self.res_helper.license_data['lic_id'] = TAS_INFO['license']
1117         self.res_helper._tcl.create_test_server = mock.Mock()
1118         self.res_helper._tcl.create_test_server.side_effect = test_servers_ids
1119         self.assertIsNone(self.res_helper.create_test_servers(TEST_SERVERS))
1120         mock_check_ts_state.assert_called_once_with(test_servers_ids)
1121
1122     @mock.patch.object(tg_landslide.LandslideTclClient,
1123                        'resolve_test_server_name')
1124     @mock.patch.object(tg_landslide.LsTclHandler, 'execute')
1125     def test_create_test_servers_error(self, mock_execute,
1126                                        mock_resolve_ts_name, *args):
1127         self.res_helper.license_data['lic_id'] = TAS_INFO['license']
1128         # Return message for case test server wasn't created
1129         mock_execute.return_value = 'TS not found'
1130         # Return message for case test server name wasn't resolved
1131         mock_resolve_ts_name.return_value = 'TS not found'
1132         with self.assertRaises(RuntimeError):
1133             self.res_helper.create_test_servers(TEST_SERVERS)
1134
1135     def test_get_test_servers(self, *args):
1136         mock_session = mock.Mock(spec=requests.Session)
1137         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1138                          'json.return_value': self.TEST_SERVERS_DATA}
1139         mock_session.get.return_value.configure_mock(**get_resp_data)
1140         self.res_helper.session = mock_session
1141         res = self.res_helper.get_test_servers()
1142         self.assertEqual(self.TEST_SERVERS_DATA['testServers'], res)
1143
1144     def test_get_test_servers_by_id(self, *args):
1145         mock_session = mock.Mock(spec=requests.Session)
1146
1147         _ts = self.TEST_SERVERS_DATA['testServers'][0]
1148         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1149                          'json.return_value': _ts}
1150         mock_session.get.return_value.configure_mock(**get_resp_data)
1151         self.res_helper.session = mock_session
1152         res = self.res_helper.get_test_servers(test_server_ids=[_ts['id']])
1153         self.assertEqual([_ts], res)
1154
1155     def test_configure_test_servers(self, *args):
1156         mock_session = mock.Mock(spec=requests.Session)
1157         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1158                          'json.return_value': self.TEST_SERVERS_DATA}
1159         mock_session.get.return_value.configure_mock(**get_resp_data)
1160         self.res_helper.session = mock_session
1161         res = self.res_helper.configure_test_servers(
1162             action={'action': 'recycle'})
1163         self.assertEqual(
1164             [x['id'] for x in self.TEST_SERVERS_DATA['testServers']],
1165             res)
1166         self.assertEqual(len(self.TEST_SERVERS_DATA['testServers']),
1167                          mock_session.post.call_count)
1168
1169     def test_delete_test_servers(self, *args):
1170         mock_session = mock.Mock(spec=requests.Session)
1171         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1172                          'json.return_value': self.TEST_SERVERS_DATA}
1173         mock_session.get.return_value.configure_mock(**get_resp_data)
1174         self.res_helper.session = mock_session
1175         self.assertIsNone(self.res_helper.delete_test_servers())
1176         self.assertEqual(len(self.TEST_SERVERS_DATA['testServers']),
1177                          mock_session.delete.call_count)
1178
1179     def test_create_test_session_res_helper(self, *args):
1180         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1181         self.res_helper._tcl = mock.Mock()
1182         self.res_helper.scenario_helper.all_options = {'traffic_duration': 71}
1183         _session = {'name': 'test', 'duration': 60}
1184         self.assertIsNone(self.res_helper.create_test_session(_session))
1185         self.res_helper._tcl.create_test_session.assert_called_once_with(
1186             {'name': _session['name'],
1187              'duration': 71,
1188              'library': self.SUCCESS_RECORD_ID})
1189
1190     def test_create_test_session_res_helper_no_traffic_duration(self, *args):
1191         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1192         self.res_helper._tcl = mock.Mock()
1193         self.res_helper.scenario_helper.all_options = {}
1194         _session = {'name': 'test', 'duration': 60}
1195         self.assertIsNone(self.res_helper.create_test_session(_session))
1196         self.res_helper._tcl.create_test_session.assert_called_once_with(
1197             {'name': _session['name'],
1198              'duration': 60,
1199              'library': self.SUCCESS_RECORD_ID})
1200
1201     @mock.patch.object(tg_landslide.LandslideTclClient,
1202                        'resolve_test_server_name',
1203                        return_value='Not Found')
1204     def test_create_test_session_ts_name_not_found(self, *args):
1205         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1206         test_session = {
1207             'duration': 60,
1208             'description': 'UE default bearer creation test case',
1209             'name': 'default_bearer_capacity',
1210             'tsGroups': [{'testCases': [{'type': 'SGW_Node',
1211                                          'name': ''}],
1212                           'tsId': 'TestServer_3'}]
1213         }
1214         with self.assertRaises(RuntimeError):
1215             self.res_helper.create_test_session(test_session)
1216
1217     def test_get_test_session(self, *args):
1218         test_session = {"name": self.TEST_SESSION_NAME}
1219         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1220         mock_session = mock.Mock(spec=requests.Session)
1221         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1222                          'json.return_value': test_session}
1223         mock_session.get.return_value.configure_mock(**get_resp_data)
1224         self.res_helper.session = mock_session
1225         res = self.res_helper.get_test_session(self.TEST_SESSION_NAME)
1226         self.assertEqual(test_session, res)
1227
1228     def test_configure_test_session(self, *args):
1229         test_session = {'name': self.TEST_SESSION_NAME}
1230         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1231         self.res_helper.user_lib_uri = 'libraries/{{}}/{}'.format(
1232             self.res_helper.test_session_uri)
1233         mock_session = mock.Mock(spec=requests.Session)
1234         self.res_helper.session = mock_session
1235         res = self.res_helper.configure_test_session(self.TEST_SESSION_NAME,
1236                                                      test_session)
1237         self.assertIsNotNone(res)
1238         mock_session.post.assert_called_once()
1239
1240     def test_delete_test_session(self, *args):
1241         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1242         self.res_helper.user_lib_uri = 'libraries/{{}}/{}'.format(
1243             self.res_helper.test_session_uri)
1244         mock_session = mock.Mock(spec=requests.Session)
1245         self.res_helper.session = mock_session
1246         res = self.res_helper.delete_test_session(self.TEST_SESSION_NAME)
1247         self.assertIsNotNone(res)
1248         mock_session.delete.assert_called_once()
1249
1250     def test_create_running_tests(self, *args):
1251         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1252         test_session = {'id': self.SUCCESS_RECORD_ID}
1253         mock_session = mock.Mock(spec=requests.Session)
1254         post_resp_data = {'status_code': self.SUCCESS_CREATED_CODE,
1255                           'json.return_value': test_session}
1256         mock_session.post.return_value.configure_mock(**post_resp_data)
1257         self.res_helper.session = mock_session
1258         self.res_helper.create_running_tests(self.TEST_SESSION_NAME)
1259         self.assertEqual(self.SUCCESS_RECORD_ID, self.res_helper.run_id)
1260
1261     def test_create_running_tests_error(self, *args):
1262         self.res_helper._user_id = self.SUCCESS_RECORD_ID
1263         mock_session = mock.Mock(spec=requests.Session)
1264         post_resp_data = {'status_code': self.NOT_MODIFIED_CODE}
1265         mock_session.post.return_value.configure_mock(**post_resp_data)
1266         self.res_helper.session = mock_session
1267         with self.assertRaises(exceptions.RestApiError):
1268             self.res_helper.create_running_tests(self.TEST_SESSION_NAME)
1269
1270     def test_get_running_tests(self, *args):
1271         mock_session = mock.Mock(spec=requests.Session)
1272         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1273                          'json.return_value': self.RUNNING_TESTS_DATA}
1274         mock_session.get.return_value.configure_mock(**get_resp_data)
1275         self.res_helper.session = mock_session
1276         res = self.res_helper.get_running_tests()
1277         self.assertEqual(self.RUNNING_TESTS_DATA['runningTests'], res)
1278
1279     def test_delete_running_tests(self, *args):
1280         mock_session = mock.Mock(spec=requests.Session)
1281         delete_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1282                             'json.return_value': self.RUNNING_TESTS_DATA}
1283         mock_session.delete.return_value.configure_mock(**delete_resp_data)
1284         self.res_helper.session = mock_session
1285         self.assertIsNone(self.res_helper.delete_running_tests())
1286
1287     def test__running_tests_action(self, *args):
1288         action = 'abort'
1289         mock_session = mock.Mock(spec=requests.Session)
1290         self.res_helper.session = mock_session
1291         res = self.res_helper._running_tests_action(self.SUCCESS_RECORD_ID,
1292                                                     action)
1293         self.assertIsNone(res)
1294
1295     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1296                        '_running_tests_action')
1297     def test_stop_running_tests(self, mock_tests_action, *args):
1298         res = self.res_helper.stop_running_tests(self.SUCCESS_RECORD_ID)
1299         self.assertIsNone(res)
1300         mock_tests_action.assert_called_once()
1301
1302     def test_check_running_test_state(self, *args):
1303         mock_session = mock.Mock(spec=requests.Session)
1304         get_resp_data = {
1305             'status_code': self.SUCCESS_OK_CODE,
1306             'json.return_value': self.RUNNING_TESTS_DATA["runningTests"][0]}
1307         mock_session.get.return_value.configure_mock(**get_resp_data)
1308         self.res_helper.session = mock_session
1309         res = self.res_helper.check_running_test_state(self.SUCCESS_RECORD_ID)
1310         self.assertEqual(
1311             self.RUNNING_TESTS_DATA["runningTests"][0]['testStateOrStep'],
1312             res)
1313
1314     def test_get_running_tests_results(self, *args):
1315         mock_session = mock.Mock(spec=requests.Session)
1316         get_resp_data = {'status_code': self.SUCCESS_OK_CODE,
1317                          'json.return_value': self.TEST_RESULTS_DATA}
1318         mock_session.get.return_value.configure_mock(**get_resp_data)
1319         self.res_helper.session = mock_session
1320         res = self.res_helper.get_running_tests_results(
1321             self.SUCCESS_RECORD_ID)
1322         self.assertEqual(self.TEST_RESULTS_DATA, res)
1323
1324     def test__write_results(self, *args):
1325         res = self.res_helper._write_results(self.TEST_RESULTS_DATA)
1326         exp_res = {
1327             "Test Summary::Actual Dedicated Bearer Session Connects": 100.0,
1328             "Test Summary::Actual Dedicated Bearer Session Disconnects": 100.0,
1329             "Test Summary::Actual Disconnect Rate(Sessions / Second)(P - I)": 164.804,
1330             "Test Summary::Average Session Disconnect Time(P - I)": 5.024,
1331             "Test Summary::Total Data Sent + Received Packets / Sec(P - I)": 1452.294
1332         }
1333         self.assertEqual(exp_res, res)
1334
1335     def test__write_results_no_tabs(self, *args):
1336         _res_data = copy.deepcopy(self.TEST_RESULTS_DATA)
1337         del _res_data['tabs']
1338         # Return None if tabs not found in test results dict
1339         self.assertIsNone(self.res_helper._write_results(_res_data))
1340
1341     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1342                        'check_running_test_state')
1343     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1344                        'get_running_tests_results')
1345     def test_collect_kpi_test_running(self, mock_tests_results,
1346                                       mock_tests_state, *args):
1347         self.res_helper.run_id = self.SUCCESS_RECORD_ID
1348         mock_tests_state.return_value = 'RUNNING'
1349         mock_tests_results.return_value = self.TEST_RESULTS_DATA
1350         res = self.res_helper.collect_kpi()
1351         self.assertNotIn('done', res)
1352         mock_tests_state.assert_called_once_with(self.res_helper.run_id)
1353         mock_tests_results.assert_called_once_with(self.res_helper.run_id)
1354
1355     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1356                        'check_running_test_state')
1357     @mock.patch.object(tg_landslide.LandslideResourceHelper,
1358                        'get_running_tests_results')
1359     def test_collect_kpi_test_completed(self, mock_tests_results,
1360                                         mock_tests_state, *args):
1361         self.res_helper.run_id = self.SUCCESS_RECORD_ID
1362         mock_tests_state.return_value = 'COMPLETE'
1363         res = self.res_helper.collect_kpi()
1364         self.assertIsNotNone(res)
1365         mock_tests_state.assert_called_once_with(self.res_helper.run_id)
1366         mock_tests_results.assert_not_called()
1367         self.assertDictContainsSubset({'done': True}, res)
1368
1369
1370 class TestLandslideTclClient(unittest.TestCase):
1371     def setUp(self):
1372         self.mock_tcl_handler = mock.Mock(spec=tg_landslide.LsTclHandler)
1373         self.ls_res_helper = mock.Mock(
1374             spec=tg_landslide.LandslideResourceHelper)
1375         self.ls_tcl_client = tg_landslide.LandslideTclClient(
1376             self.mock_tcl_handler,
1377             self.ls_res_helper)
1378
1379     def test___init__(self, *args):
1380         self.ls_tcl_client = tg_landslide.LandslideTclClient(
1381             self.mock_tcl_handler,
1382             self.ls_res_helper)
1383         self.assertIsNone(self.ls_tcl_client.tcl_server_ip)
1384         self.assertIsNone(self.ls_tcl_client._user)
1385         self.assertIsNone(self.ls_tcl_client._library_id)
1386         self.assertIsNone(self.ls_tcl_client._basic_library_id)
1387         self.assertEqual(set(), self.ls_tcl_client.ts_ids)
1388         self.assertIsInstance(self.ls_tcl_client._tc_types, set)
1389         self.assertIsNotNone(self.ls_tcl_client._tc_types)
1390
1391     def test_connect_login_success(self, *args):
1392         lib_id = '123'
1393         exec_responses = ['java0x2', lib_id, lib_id]
1394         auth = ('user', 'password')
1395         self.mock_tcl_handler.execute.side_effect = exec_responses
1396         self.ls_tcl_client.connect(TAS_INFO['ip'], *auth)
1397         self.assertEqual(lib_id, self.ls_tcl_client._library_id)
1398         self.assertEqual(lib_id, self.ls_tcl_client._basic_library_id)
1399         self.assertEqual(TAS_INFO['ip'], self.ls_tcl_client.tcl_server_ip)
1400         self.assertEqual(auth[0], self.ls_tcl_client._user)
1401         self.assertEqual(len(exec_responses),
1402                          self.mock_tcl_handler.execute.call_count)
1403         self.mock_tcl_handler.execute.assert_has_calls([
1404             mock.call("ls::login 1.1.1.1 user password"),
1405             mock.call("ls::get [ls::query LibraryInfo -userLibraryName user] -Id"),
1406         ])
1407
1408     def test_connect_login_failed(self, *args):
1409         exec_responses = ['Login failed']
1410         auth = ('user', 'password')
1411         self.mock_tcl_handler.execute.side_effect = exec_responses
1412         self.assertRaises(exceptions.LandslideTclException,
1413                           self.ls_tcl_client.connect,
1414                           TAS_INFO['ip'],
1415                           *auth)
1416         self.assertIsNone(self.ls_tcl_client._library_id)
1417         self.assertIsNone(self.ls_tcl_client._basic_library_id)
1418         self.assertIsNone(self.ls_tcl_client.tcl_server_ip)
1419         self.assertIsNone(self.ls_tcl_client._user)
1420         self.assertEqual(len(exec_responses),
1421                          self.mock_tcl_handler.execute.call_count)
1422         self.mock_tcl_handler.execute.assert_called_with(
1423             "ls::login 1.1.1.1 user password")
1424
1425     def test_disconnect(self, *args):
1426         self.ls_tcl_client.disconnect()
1427         self.mock_tcl_handler.execute.assert_called_once_with("ls::logout")
1428         self.assertIsNone(self.ls_tcl_client.tcl_server_ip)
1429         self.assertIsNone(self.ls_tcl_client._user)
1430         self.assertIsNone(self.ls_tcl_client._library_id)
1431         self.assertIsNone(self.ls_tcl_client._basic_library_id)
1432
1433     def test_create_test_server(self, *args):
1434         return_value = '2'
1435         self.ls_tcl_client._ts_context.vnfd_helper = \
1436             VNFD['vnfd:vnfd-catalog']['vnfd'][0]
1437         self.ls_tcl_client._ts_context.license_data = {'lic_id': return_value}
1438         self.mock_tcl_handler.execute.return_value = return_value
1439         self.ls_tcl_client._set_thread_model = mock.Mock()
1440         res = self.ls_tcl_client.create_test_server(TEST_SERVERS[1])
1441         self.assertEqual(3, self.mock_tcl_handler.execute.call_count)
1442         self.mock_tcl_handler.execute.assert_has_calls([
1443             mock.call('ls::query TsId TestServer_2'),
1444             mock.call('set ts [ls::retrieve TsInfo -Name "TestServer_2"]'),
1445             mock.call('ls::get $ts -RequestedLicense'),
1446         ])
1447         self.ls_tcl_client._set_thread_model.assert_called_once_with(
1448             TEST_SERVERS[1]['name'],
1449             TEST_SERVERS[1]['thread_model'])
1450         self.assertEqual(int(return_value), res)
1451
1452     def test_create_test_server_fail_limit_reach(self, *args):
1453         self.mock_tcl_handler.execute.side_effect = ['TS not found',
1454                                                      'Add failed']
1455         self.assertRaises(RuntimeError,
1456                           self.ls_tcl_client.create_test_server,
1457                           TEST_SERVERS[0])
1458         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1459         self.mock_tcl_handler.execute.assert_has_calls([
1460             mock.call('ls::query TsId TestServer_1'),
1461             mock.call('ls::perform AddTs -Name "TestServer_1" '
1462                       '-Ip "192.168.122.101"'),
1463         ])
1464
1465     def test__add_test_server(self):
1466         ts_id = '2'
1467         self.mock_tcl_handler.execute.side_effect = ['TS not found', ts_id]
1468         self.assertEqual(ts_id,
1469                          self.ls_tcl_client._add_test_server('name', 'ip'))
1470         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1471         self.mock_tcl_handler.execute.assert_has_calls([
1472             mock.call('ls::query TsId name'),
1473             mock.call('ls::perform AddTs -Name "name" -Ip "ip"'),
1474         ])
1475
1476     def test__add_test_server_failed(self):
1477         self.mock_tcl_handler.execute.side_effect = ['TS not found',
1478                                                      'Add failed']
1479         self.assertRaises(RuntimeError, self.ls_tcl_client._add_test_server,
1480                           'name', 'ip')
1481         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1482         self.mock_tcl_handler.execute.assert_has_calls([
1483             mock.call('ls::query TsId name'),
1484             mock.call('ls::perform AddTs -Name "name" -Ip "ip"'),
1485         ])
1486
1487     def test__update_license(self):
1488         curr_lic_id = '111'
1489         new_lic_id = '222'
1490         exec_resp = ['java0x4',
1491                      curr_lic_id,
1492                      TCL_SUCCESS_RESPONSE,
1493                      TCL_SUCCESS_RESPONSE]
1494         self.ls_tcl_client._ts_context.license_data = {'lic_id': new_lic_id}
1495         self.mock_tcl_handler.execute.side_effect = exec_resp
1496         self.ls_tcl_client._update_license('name')
1497         self.assertEqual(len(exec_resp),
1498                          self.mock_tcl_handler.execute.call_count)
1499
1500         self.mock_tcl_handler.execute.assert_has_calls([
1501             mock.call('set ts [ls::retrieve TsInfo -Name "name"]'),
1502             mock.call('ls::get $ts -RequestedLicense'),
1503             mock.call('ls::config $ts -RequestedLicense 222'),
1504             mock.call('ls::perform ModifyTs $ts'),
1505         ])
1506
1507     def test__update_license_same_as_current(self):
1508         curr_lic_id = '111'
1509         new_lic_id = '111'
1510         exec_resp = ['java0x4', curr_lic_id]
1511         self.ls_tcl_client._ts_context.license_data = {'lic_id': new_lic_id}
1512         self.mock_tcl_handler.execute.side_effect = exec_resp
1513         self.ls_tcl_client._update_license('name')
1514         self.assertEqual(len(exec_resp),
1515                          self.mock_tcl_handler.execute.call_count)
1516         self.mock_tcl_handler.execute.assert_has_calls([
1517             mock.call('set ts [ls::retrieve TsInfo -Name "name"]'),
1518             mock.call('ls::get $ts -RequestedLicense'),
1519         ])
1520
1521     def test__set_thread_model_update_needed(self):
1522         self.ls_tcl_client._ts_context.vnfd_helper = {
1523             'mgmt-interface': {
1524                 'cfguser_password': 'cfguser_password'
1525             }
1526         }
1527         exec_resp = ['java0x4', 'V0', '', '']
1528         self.mock_tcl_handler.execute.side_effect = exec_resp
1529         self.ls_tcl_client._set_thread_model('name', 'Fireball')
1530         self.assertEqual(len(exec_resp),
1531                          self.mock_tcl_handler.execute.call_count)
1532         self.mock_tcl_handler.execute.assert_has_calls([
1533             mock.call('set tsc [ls::perform RetrieveTsConfiguration '
1534                       '-name "name" cfguser_password]'),
1535             mock.call('ls::get $tsc -ThreadModel'),
1536             mock.call('ls::config $tsc -ThreadModel "V1_FB3"'),
1537             mock.call('ls::perform ApplyTsConfiguration $tsc cfguser_password'),
1538         ])
1539
1540     def test__set_thread_model_no_update_needed(self):
1541         self.ls_tcl_client._ts_context.vnfd_helper = {
1542             'mgmt-interface': {
1543                 'cfguser_password': 'cfguser_password'
1544             }
1545         }
1546         exec_resp = ['java0x4', 'V0']
1547         self.mock_tcl_handler.execute.side_effect = exec_resp
1548         self.ls_tcl_client._set_thread_model('name', 'Legacy')
1549         self.assertEqual(len(exec_resp),
1550                          self.mock_tcl_handler.execute.call_count)
1551         self.mock_tcl_handler.execute.assert_has_calls([
1552             mock.call('set tsc [ls::perform RetrieveTsConfiguration '
1553                       '-name "name" cfguser_password]'),
1554             mock.call('ls::get $tsc -ThreadModel'),
1555         ])
1556
1557     @mock.patch.object(tg_landslide.LandslideTclClient,
1558                        'resolve_test_server_name', side_effect=['4', '2'])
1559     def test_create_test_session(self, *args):
1560         _session_profile = copy.deepcopy(SESSION_PROFILE)
1561         _session_profile['reservations'] = RESERVATIONS
1562         self.ls_tcl_client._save_test_session = mock.Mock()
1563         self.ls_tcl_client._configure_ts_group = mock.Mock()
1564         self.ls_tcl_client._library_id = 42
1565         self.ls_tcl_client.create_test_session(_session_profile)
1566         self.assertEqual(17, self.mock_tcl_handler.execute.call_count)
1567         self.mock_tcl_handler.execute.assert_has_calls([
1568             mock.call('set test_ [ls::create TestSession]'),
1569             mock.call('ls::config $test_ -Library 42 '
1570                       '-Name "default_bearer_capacity"'),
1571             mock.call('ls::config $test_ -Description ' \
1572                       '"UE default bearer creation test case"'),
1573             mock.call('ls::config $test_ -Keywords ""'),
1574             mock.call('ls::config $test_ -Duration "60"'),
1575             mock.call('ls::config $test_ -Iterations "1"'),
1576             # _configure_reservation
1577             mock.call('set reservation_ [ls::create Reservation -under $test_]'),
1578             mock.call('ls::config $reservation_ -TsIndex 0 '
1579                       '-TsId 4 -TsName "TestServer_1"'),
1580             mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'),
1581             mock.call('ls::config $physubnet_ -Name "eth1" -Base "10.42.32.100" '
1582                       '-Mask "/24" -NumIps 20'),
1583             # _configure_reservation
1584             mock.call('set reservation_ [ls::create Reservation -under $test_]'),
1585             mock.call('ls::config $reservation_ -TsIndex 1 '
1586                       '-TsId 2 -TsName "TestServer_2"'),
1587             mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'),
1588             mock.call('ls::config $physubnet_ -Name "eth1" -Base "10.42.32.1" '
1589                       '-Mask "/24" -NumIps 100'),
1590             mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'),
1591             mock.call('ls::config $physubnet_ -Name "eth2" -Base "10.42.33.1" '
1592                       '-Mask "/24" -NumIps 100'),
1593             # _configure_report_options
1594             mock.call('ls::config $test_.ReportOptions -Format 1 -Ts -3 -Tc -3'),
1595         ])
1596
1597     def test_create_dmf(self):
1598         self.mock_tcl_handler.execute.return_value = '2'
1599         self.ls_tcl_client._save_dmf = mock.Mock()
1600         self.ls_tcl_client.create_dmf(copy.deepcopy(DMF_CFG))
1601         self.assertEqual(6, self.mock_tcl_handler.execute.call_count)
1602         # This is needed because the dictionary is unordered and the arguments
1603         # can come in either order
1604         call1 = mock.call(
1605             'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"')
1606         call2 = mock.call(
1607             'ls::config $dmf_ -isClientPortRange "false" -clientPort 2002')
1608         self.assertTrue(
1609             call1 in self.mock_tcl_handler.execute.mock_calls or
1610             call2 in self.mock_tcl_handler.execute.mock_calls)
1611
1612         self.mock_tcl_handler.execute.assert_has_calls([
1613             mock.call('set dmf_ [ls::create Dmf]'),
1614             mock.call(
1615                 'ls::get [ls::query LibraryInfo -systemLibraryName test] -Id'),
1616             mock.call('ls::config $dmf_ -Library 2 -Name "Basic UDP"'),
1617             mock.call('ls::config $dmf_ -dataProtocol "udp"'),
1618             # mock.call(
1619             #    'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"'),
1620             mock.call('ls::config $dmf_ -serverPort 2003'),
1621         ], any_order=True)
1622
1623     def test_configure_dmf(self):
1624         self.mock_tcl_handler.execute.return_value = '2'
1625         self.ls_tcl_client._save_dmf = mock.Mock()
1626         self.ls_tcl_client.configure_dmf(DMF_CFG)
1627         self.assertEqual(6, self.mock_tcl_handler.execute.call_count)
1628         # This is need because the dictionary is unordered and the arguments
1629         # can come in either order
1630         call1 = mock.call(
1631             'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"')
1632         call2 = mock.call(
1633             'ls::config $dmf_ -isClientPortRange "false" -clientPort 2002')
1634         self.assertTrue(
1635             call1 in self.mock_tcl_handler.execute.mock_calls or
1636             call2 in self.mock_tcl_handler.execute.mock_calls)
1637
1638         self.mock_tcl_handler.execute.assert_has_calls([
1639             mock.call('set dmf_ [ls::create Dmf]'),
1640             mock.call(
1641                 'ls::get [ls::query LibraryInfo -systemLibraryName test] -Id'),
1642             mock.call('ls::config $dmf_ -Library 2 -Name "Basic UDP"'),
1643             mock.call('ls::config $dmf_ -dataProtocol "udp"'),
1644             # mock.call(
1645             #    'ls::config $dmf_ -clientPort 2002 -isClientPortRange "false"'),
1646             mock.call('ls::config $dmf_ -serverPort 2003'),
1647         ], any_order=True)
1648
1649     def test_delete_dmf(self):
1650         self.assertRaises(NotImplementedError,
1651                           self.ls_tcl_client.delete_dmf,
1652                           DMF_CFG)
1653
1654     def test__save_dmf_valid(self):
1655         exec_resp = [TCL_SUCCESS_RESPONSE, TCL_SUCCESS_RESPONSE]
1656         self.mock_tcl_handler.execute.side_effect = exec_resp
1657         self.ls_tcl_client._save_dmf()
1658         self.assertEqual(len(exec_resp),
1659                          self.mock_tcl_handler.execute.call_count)
1660         self.mock_tcl_handler.execute.assert_has_calls([
1661            mock.call('ls::perform Validate -Dmf $dmf_'),
1662            mock.call('ls::save $dmf_ -overwrite'),
1663         ])
1664
1665     def test__save_dmf_invalid(self):
1666         exec_resp = ['Invalid', 'List of errors and warnings']
1667         self.mock_tcl_handler.execute.side_effect = exec_resp
1668         self.assertRaises(exceptions.LandslideTclException,
1669                           self.ls_tcl_client._save_dmf)
1670         self.assertEqual(len(exec_resp),
1671                          self.mock_tcl_handler.execute.call_count)
1672         self.mock_tcl_handler.execute.assert_has_calls([
1673            mock.call('ls::perform Validate -Dmf $dmf_'),
1674            mock.call('ls::get $dmf_ -ErrorsAndWarnings'),
1675         ])
1676
1677     def test__configure_report_options(self):
1678         _options = {'format': 'CSV', 'PerInterval': 'false'}
1679         self.ls_tcl_client._configure_report_options(_options)
1680         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1681         self.mock_tcl_handler.execute.assert_has_calls([
1682            mock.call('ls::config $test_.ReportOptions -Format 1 -Ts -3 -Tc -3'),
1683            mock.call('ls::config $test_.ReportOptions -PerInterval false'),
1684            ],
1685            any_order=True)
1686
1687     def test___configure_ts_group(self, *args):
1688         _ts_group = copy.deepcopy(SESSION_PROFILE['tsGroups'][0])
1689         self.ls_tcl_client._configure_tc_type = mock.Mock()
1690         self.ls_tcl_client._configure_preresolved_arp = mock.Mock()
1691         self.ls_tcl_client.resolve_test_server_name = mock.Mock(
1692             return_value='2')
1693         self.ls_tcl_client._configure_ts_group(_ts_group, 0)
1694         self.mock_tcl_handler.execute.assert_called_once_with(
1695             'set tss_ [ls::create TsGroup -under $test_ -tsId 2 ]')
1696
1697     def test___configure_ts_group_resolve_ts_fail(self, *args):
1698         _ts_group = copy.deepcopy(SESSION_PROFILE['tsGroups'][0])
1699         self.ls_tcl_client._configure_tc_type = mock.Mock()
1700         self.ls_tcl_client._configure_preresolved_arp = mock.Mock()
1701         self.ls_tcl_client.resolve_test_server_name = mock.Mock(
1702             return_value='TS Not Found')
1703         self.assertRaises(RuntimeError, self.ls_tcl_client._configure_ts_group,
1704                           _ts_group, 0)
1705         self.mock_tcl_handler.execute.assert_not_called()
1706
1707     def test__configure_tc_type(self):
1708         _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0])
1709         self.mock_tcl_handler.execute.return_value = TCL_SUCCESS_RESPONSE
1710         self.ls_tcl_client._configure_parameters = mock.Mock()
1711         self.ls_tcl_client._configure_tc_type(_tc, 0)
1712         self.assertEqual(7, self.mock_tcl_handler.execute.call_count)
1713
1714     def test__configure_tc_type_optional_param_omitted(self):
1715         _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0])
1716         del _tc['linked']
1717         self.mock_tcl_handler.execute.return_value = TCL_SUCCESS_RESPONSE
1718         self.ls_tcl_client._configure_parameters = mock.Mock()
1719         self.ls_tcl_client._configure_tc_type(_tc, 0)
1720         self.assertEqual(6, self.mock_tcl_handler.execute.call_count)
1721
1722     def test__configure_tc_type_wrong_type(self):
1723         _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0])
1724         _tc['type'] = 'not_supported'
1725         self.ls_tcl_client._configure_parameters = mock.Mock()
1726         self.assertRaises(RuntimeError,
1727                           self.ls_tcl_client._configure_tc_type,
1728                           _tc, 0)
1729         self.mock_tcl_handler.assert_not_called()
1730
1731     def test__configure_tc_type_not_found_basic_lib(self):
1732         _tc = copy.deepcopy(SESSION_PROFILE['tsGroups'][0]['testCases'][0])
1733         self.ls_tcl_client._configure_parameters = mock.Mock()
1734         self.mock_tcl_handler.execute.return_value = 'Invalid'
1735         self.assertRaises(RuntimeError,
1736                           self.ls_tcl_client._configure_tc_type,
1737                           _tc, 0)
1738
1739     def test__configure_parameters(self):
1740         _params = copy.deepcopy(
1741             SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters'])
1742         self.ls_tcl_client._configure_parameters(_params)
1743         self.assertEqual(16, self.mock_tcl_handler.execute.call_count)
1744
1745     def test__configure_array_param(self):
1746         _array = {"class": "Array",
1747                   "array": ["0"]}
1748         self.ls_tcl_client._configure_array_param('name', _array)
1749         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1750         self.mock_tcl_handler.execute.assert_has_calls([
1751             mock.call('ls::create -Array-name -under $p_ ;'),
1752             mock.call('ls::create ArrayItem -under $p_.name -Value "0"'),
1753         ])
1754
1755     def test__configure_test_node_param(self):
1756         _params = copy.deepcopy(
1757             SESSION_PROFILE['tsGroups'][0]['testCases'][0]['parameters'])
1758         self.ls_tcl_client._configure_test_node_param('SgwUserAddr',
1759                                                       _params['SgwUserAddr'])
1760         cmd = ('ls::create -TestNode-SgwUserAddr -under $p_ -Type "eth" '
1761         '-Phy "eth1" -Ip "SGW_USER_IP" -NumLinksOrNodes 1 '
1762         '-NextHop "SGW_CONTROL_NEXT_HOP" -Mac "" -MTU 1500 '
1763         '-ForcedEthInterface "" -EthStatsEnabled false -VlanId 0 '
1764         '-VlanUserPriority 0 -NumVlan 1 -UniqueVlanAddr false;')
1765         self.mock_tcl_handler.execute.assert_called_once_with(cmd)
1766
1767     def test__configure_sut_param(self):
1768         _params = {'name': 'name'}
1769         self.ls_tcl_client._configure_sut_param('name', _params)
1770         self.mock_tcl_handler.execute.assert_called_once_with(
1771             'ls::create -Sut-name -under $p_ -Name "name";')
1772
1773     def test__configure_dmf_param(self):
1774         _params = {"mainflows": [{"library": '111',
1775                                   "name": "Basic UDP"}],
1776                    "instanceGroups": [{
1777                        "mainflowIdx": 0,
1778                        "mixType": "",
1779                        "rate": 0.0,
1780                        "rows": [{
1781                            "clientPort": 0,
1782                            "context": 0,
1783                            "node": 0,
1784                            "overridePort": "false",
1785                            "ratingGroup": 0,
1786                            "role": 0,
1787                            "serviceId": 0,
1788                            "transport": "Any"}]
1789                    }]}
1790         self.ls_tcl_client._get_library_id = mock.Mock(return_value='111')
1791         res = self.ls_tcl_client._configure_dmf_param('name', _params)
1792         self.assertEqual(5, self.mock_tcl_handler.execute.call_count)
1793         self.assertIsNone(res)
1794         self.mock_tcl_handler.execute.assert_has_calls([
1795             mock.call('ls::create -Dmf-name -under $p_ ;'),
1796             mock.call('ls::perform AddDmfMainflow $p_.Dmf 111 "Basic UDP"'),
1797             mock.call('ls::config $p_.Dmf.InstanceGroup(0) -mixType '),
1798             mock.call('ls::config $p_.Dmf.InstanceGroup(0) -rate 0.0'),
1799             mock.call('ls::config $p_.Dmf.InstanceGroup(0).Row(0) -Node 0 '
1800                       '-OverridePort false -ClientPort 0 -Context 0 -Role 0 '
1801                       '-PreferredTransport Any -RatingGroup 0 '
1802                       '-ServiceID 0'),
1803         ])
1804
1805     def test__configure_dmf_param_no_instance_groups(self):
1806         _params = {"mainflows": [{"library": '111',
1807                                   "name": "Basic UDP"}]}
1808         self.ls_tcl_client._get_library_id = mock.Mock(return_value='111')
1809         res = self.ls_tcl_client._configure_dmf_param('name', _params)
1810         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1811         self.assertIsNone(res)
1812         self.mock_tcl_handler.execute.assert_has_calls([
1813             mock.call('ls::create -Dmf-name -under $p_ ;'),
1814             mock.call('ls::perform AddDmfMainflow $p_.Dmf 111 "Basic UDP"'),
1815         ])
1816
1817     def test__configure_reservation(self):
1818         _reservation = copy.deepcopy(RESERVATIONS[0])
1819         self.ls_tcl_client.resolve_test_server_name = mock.Mock(
1820             return_value='4')
1821         res = self.ls_tcl_client._configure_reservation(_reservation)
1822         self.assertIsNone(res)
1823         self.assertEqual(4, self.mock_tcl_handler.execute.call_count)
1824         self.mock_tcl_handler.execute.assert_has_calls([
1825             mock.call('set reservation_ [ls::create Reservation -under $test_]'),
1826             mock.call('ls::config $reservation_ -TsIndex 0 -TsId 4 ' + \
1827                       '-TsName "TestServer_1"'),
1828             mock.call('set physubnet_ [ls::create PhySubnet -under $reservation_]'),
1829             mock.call('ls::config $physubnet_ -Name "eth1" ' + \
1830                       '-Base "10.42.32.100" -Mask "/24" -NumIps 20'),
1831         ])
1832
1833     def test__configure_preresolved_arp(self):
1834         _arp = [{'StartingAddress': '10.81.1.10',
1835                  'NumNodes': 1}]
1836         res = self.ls_tcl_client._configure_preresolved_arp(_arp)
1837         self.mock_tcl_handler.execute.assert_called_once()
1838         self.assertIsNone(res)
1839         self.mock_tcl_handler.execute.assert_called_once_with(
1840             'ls::create PreResolvedArpAddress -under $tss_ ' + \
1841             '-StartingAddress "10.81.1.10" -NumNodes 1')
1842
1843     def test__configure_preresolved_arp_none(self):
1844         res = self.ls_tcl_client._configure_preresolved_arp(None)
1845         self.assertIsNone(res)
1846         self.mock_tcl_handler.execute.assert_not_called()
1847
1848     def test_delete_test_session(self):
1849         self.assertRaises(NotImplementedError,
1850                           self.ls_tcl_client.delete_test_session, {})
1851
1852     def test__save_test_session(self):
1853         self.mock_tcl_handler.execute.side_effect = [TCL_SUCCESS_RESPONSE,
1854                                                      TCL_SUCCESS_RESPONSE]
1855         res = self.ls_tcl_client._save_test_session()
1856         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1857         self.assertIsNone(res)
1858         self.mock_tcl_handler.execute.assert_has_calls([
1859             mock.call('ls::perform Validate -TestSession $test_'),
1860             mock.call('ls::save $test_ -overwrite'),
1861         ])
1862
1863     def test__save_test_session_invalid(self):
1864         self.mock_tcl_handler.execute.side_effect = ['Invalid', 'Errors']
1865         self.assertRaises(exceptions.LandslideTclException,
1866                           self.ls_tcl_client._save_test_session)
1867         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1868         self.mock_tcl_handler.execute.assert_has_calls([
1869             mock.call('ls::perform Validate -TestSession $test_'),
1870             mock.call('ls::get $test_ -ErrorsAndWarnings'),
1871         ])
1872
1873     def test__get_library_id_system_lib(self):
1874         self.mock_tcl_handler.execute.return_value = '111'
1875         res = self.ls_tcl_client._get_library_id('name')
1876         self.mock_tcl_handler.execute.assert_called_once()
1877         self.assertEqual('111', res)
1878         self.mock_tcl_handler.execute.assert_called_with(
1879             'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id')
1880
1881     def test__get_library_id_user_lib(self):
1882         self.mock_tcl_handler.execute.side_effect = ['Not found', '222']
1883         res = self.ls_tcl_client._get_library_id('name')
1884         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1885         self.assertEqual('222', res)
1886         self.mock_tcl_handler.execute.assert_has_calls([
1887             mock.call(
1888                 'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id'),
1889             mock.call(
1890                 'ls::get [ls::query LibraryInfo -userLibraryName name] -Id'),
1891         ])
1892
1893     def test__get_library_id_exception(self):
1894         self.mock_tcl_handler.execute.side_effect = ['Not found', 'Not found']
1895         self.assertRaises(exceptions.LandslideTclException,
1896                           self.ls_tcl_client._get_library_id,
1897                           'name')
1898         self.assertEqual(2, self.mock_tcl_handler.execute.call_count)
1899         self.mock_tcl_handler.execute.assert_has_calls([
1900             mock.call(
1901                 'ls::get [ls::query LibraryInfo -systemLibraryName name] -Id'),
1902             mock.call(
1903                 'ls::get [ls::query LibraryInfo -userLibraryName name] -Id'),
1904         ])
1905
1906
1907 class TestLsTclHandler(unittest.TestCase):
1908
1909     def setUp(self):
1910         self.mock_lsapi = mock.patch.object(tg_landslide, 'LsApi')
1911         self.mock_lsapi.start()
1912
1913         self.addCleanup(self._cleanup)
1914
1915     def _cleanup(self):
1916         self.mock_lsapi.stop()
1917
1918     def test___init__(self, *args):
1919         self.ls_tcl_handler = tg_landslide.LsTclHandler()
1920         self.assertEqual({}, self.ls_tcl_handler.tcl_cmds)
1921         self.ls_tcl_handler._ls.tcl.assert_called_once()
1922
1923     def test_execute(self, *args):
1924         self.ls_tcl_handler = tg_landslide.LsTclHandler()
1925         self.ls_tcl_handler.execute('command')
1926         self.assertIn('command', self.ls_tcl_handler.tcl_cmds)