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