Skip to content

Commit e2fc8d0

Browse files
author
Yaroslav Nikonorov
authored
Merge pull request #7 from QualiSystems/feature_get_test_configuration
Feature get test configuration
2 parents 58403c5 + f358033 commit e2fc8d0

File tree

10 files changed

+156
-40
lines changed

10 files changed

+156
-40
lines changed

.coveragerc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[report]
2+
omit =
3+
*__init__*

.travis.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ python:
33
- "2.7"
44

55
install:
6-
- 'if [ ${TRAVIS_BRANCH} = "master" ]; then
7-
pip install --extra-index-url https://testpypi.python.org/pypi -r src/requirements.txt;
8-
else
6+
- 'if [ ${TRAVIS_BRANCH} \!= "master" ] && [ -f dev_requirements.txt ]; then
97
pip install --extra-index-url https://testpypi.python.org/pypi -r dev_requirements.txt;
8+
else
9+
pip install -r src/requirements.txt;
1010
fi'
1111
- pip install -r test_requirements.txt
1212
- pip install coveralls
1313

1414
script:
15-
- nosetests --with-coverage --cover-package=src --where=tests
15+
- nosetests --with-coverage --cover-package=src tests
1616

1717
after_success:
1818
- coveralls

datamodel/datamodel.xml

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,60 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<DataModelInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.qualisystems.com/ResourceManagement/DataModelSchema.xsd">
2+
<DataModelInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
3+
xmlns="http://schemas.qualisystems.com/ResourceManagement/DataModelSchema.xsd">
34

4-
<Attributes>
5-
<AttributeInfo Name="Client Install Path" Type="String" DefaultValue="" IsReadOnly="false"
6-
Description="The path in which the traffic client is installed on the Execution Server. For example 'C:/Program Files (x86)/Ixia/IxOS/6.90-EA'.">
7-
<Rules>
8-
<Rule Name="Configuration" />
9-
</Rules>
10-
</AttributeInfo>
11-
<AttributeInfo Name="Controller Address" Type="String" DefaultValue="" IsReadOnly="false"
12-
Description="The IP address of the traffic server. Relevant only in case an external server is configured.">
13-
<Rules>
14-
<Rule Name="Configuration" />
15-
</Rules>
16-
</AttributeInfo>
17-
<AttributeInfo Name="Controller TCP Port" Type="String" DefaultValue="" IsReadOnly="false"
18-
Description="The TCP port of the traffic server. Relevant only in case an external server is configured. Default TCP port should be used if kept empty.">
19-
<Rules>
20-
<Rule Name="Configuration" />
21-
</Rules>
22-
</AttributeInfo>
5+
<Attributes>
6+
<AttributeInfo Name="Client Install Path" Type="String" DefaultValue="" IsReadOnly="false"
7+
Description="The path in which the traffic client is installed on the Execution Server. For example 'C:/Program Files (x86)/Ixia/IxOS/6.90-EA'.">
8+
<Rules>
9+
<Rule Name="Configuration"/>
10+
</Rules>
11+
</AttributeInfo>
12+
<AttributeInfo Name="Controller Address" Type="String" DefaultValue="" IsReadOnly="false"
13+
Description="The IP address of the traffic server. Relevant only in case an external server is configured.">
14+
<Rules>
15+
<Rule Name="Configuration"/>
16+
</Rules>
17+
</AttributeInfo>
18+
<AttributeInfo Name="Controller TCP Port" Type="String" DefaultValue="" IsReadOnly="false"
19+
Description="The TCP port of the traffic server. Relevant only in case an external server is configured. Default TCP port should be used if kept empty.">
20+
<Rules>
21+
<Rule Name="Configuration"/>
22+
</Rules>
23+
</AttributeInfo>
2324
<AttributeInfo Name="Password" Type="Password" DefaultValue="" IsReadOnly="false"
24-
Description="">
25+
Description="">
2526
<Rules>
2627
<Rule Name="Configuration"/>
2728
</Rules>
2829
</AttributeInfo>
2930
<AttributeInfo Name="User" Type="String" DefaultValue="" IsReadOnly="false"
30-
Description="">
31+
Description="">
32+
<Rules>
33+
<Rule Name="Configuration"/>
34+
</Rules>
35+
</AttributeInfo>
36+
<AttributeInfo Name="Test Files Location" Type="String" DefaultValue="" IsReadOnly="false"
37+
Description="Location for test related files">
3138
<Rules>
3239
<Rule Name="Configuration"/>
3340
</Rules>
3441
</AttributeInfo>
35-
</Attributes>
42+
</Attributes>
3643

37-
<ResourceFamilies>
38-
<ResourceFamily Description="" IsService="true" Name="Traffic Generator Controller" ServiceType="Regular">
39-
<Models />
40-
<Categories />
41-
</ResourceFamily>
42-
</ResourceFamilies>
44+
<ResourceFamilies>
45+
<ResourceFamily Description="" IsService="true" Name="Traffic Generator Controller" ServiceType="Regular">
46+
<AttachedAttributes>
47+
<AttachedAttribute Name="Test Files Location" IsOverridable="true" IsLocal="true" UserInput="true">
48+
<AllowedValues/>
49+
</AttachedAttribute>
50+
</AttachedAttributes>
51+
<Models/>
52+
<Categories/>
53+
</ResourceFamily>
54+
</ResourceFamilies>
4355

44-
<DriverDescriptors>
45-
<DriverDescriptor Name="BreakingPointControllerDriver" DriverType="PythonDriver" />
46-
</DriverDescriptors>
56+
<DriverDescriptors>
57+
<DriverDescriptor Name="BreakingPointControllerDriver" DriverType="PythonDriver"/>
58+
</DriverDescriptors>
4759

4860
</DataModelInfo>

src/bp_controller/actions/test_configuration_actions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ def import_pcap(self, pcap_file_path):
5454
def export_test(self, test_name):
5555
self._logger.debug('Exporting test {0}'.format(test_name))
5656
uri = '/api/v1/bps/export/bpt/testname/' + test_name
57-
data = self._rest_service.request_get(uri)
58-
result = data
57+
data = self._rest_service.request_get_files(uri)
58+
result = data.content
5959
return result
6060

6161
def reserve_port(self, slot, port_list):
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from bp_controller.actions.test_configuration_actions import TestConfigurationActions
2+
from cloudshell.tg.breaking_point.flows.bp_flow import BPFlow
3+
4+
5+
class BPDownloadTestFileFlow(BPFlow):
6+
def download_test_file(self, test_name):
7+
with self._session_context_manager as rest_service:
8+
configuration_actions = TestConfigurationActions(rest_service, self._logger)
9+
test_file_content = configuration_actions.export_test(test_name)
10+
return test_file_content

src/bp_controller/runners/bp_test_runner.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import csv
22
import json
3+
import os
4+
5+
from bp_controller.flows.bp_download_test_file_flow import BPDownloadTestFileFlow
36
from bp_controller.helpers.port_reservation_helper import PortReservationHelper
47
import re
58

@@ -34,6 +37,7 @@ def __init__(self, context, logger, api):
3437
self.__test_statistics_flow = None
3538
self.__test_results_flow = None
3639
self.__test_configuration_file_flow = None
40+
self.__download_test_file_flow = None
3741
self.__reservation_details = None
3842
self.__port_reservation_helper = None
3943

@@ -104,6 +108,13 @@ def _test_configuration_file_flow(self):
104108
self.logger)
105109
return self.__test_configuration_file_flow
106110

111+
@property
112+
def _download_test_file_flow(self):
113+
if not self.__download_test_file_flow:
114+
self.__download_test_file_flow = BPDownloadTestFileFlow(self._session_context_manager,
115+
self.logger)
116+
return self.__download_test_file_flow
117+
107118
@property
108119
def _cs_reservation_details(self):
109120
"""
@@ -151,12 +162,29 @@ def _port_reservation_helper(self):
151162
self.logger)
152163
return self.__port_reservation_helper
153164

165+
def _get_existing_path(self, file_path):
166+
"""
167+
Looking for existing path
168+
:return:
169+
:rtype: basestring
170+
"""
171+
search_order = [os.path.join(self.context.resource.attributes.get('Test Files Location') or '', file_path),
172+
file_path]
173+
for path in search_order:
174+
if os.path.exists(path):
175+
return path
176+
raise BPRunnerException(self.__class__.__name__,
177+
'File {} does not exists or "Test Files Location" attribute was not specified'.format(
178+
file_path))
179+
154180
def load_configuration(self, file_path):
155181
"""
156182
Upload configuration file and reserve ports
157183
:param file_path:
158184
:return:
159185
"""
186+
file_path = self._get_existing_path(file_path)
187+
160188
self._test_name = self._test_configuration_file_flow.load_configuration(file_path)
161189
test_model = ElementTree.parse(file_path).getroot().find('testmodel')
162190
network_name = test_model.get('network')
@@ -247,6 +275,23 @@ def get_results(self):
247275
file_stream=pdf_result)
248276
return "Please check attachments for results"
249277

278+
def get_test_file(self, test_name):
279+
test_files_location = self.context.resource.attributes.get('Test Files Location')
280+
if not test_files_location:
281+
raise BPRunnerException(self.__class__.__name__, "Test Files Location attribute is not defined")
282+
if not os.path.exists(test_files_location) or os.access(test_files_location, os.W_OK) is not True:
283+
raise BPRunnerException(self.__class__.__name__,
284+
'The location of the test files "{}" does not exist or is not writable'.format(
285+
test_files_location))
286+
reservation_files = os.path.join(test_files_location, self.context.reservation.reservation_id)
287+
if not os.path.exists(reservation_files):
288+
os.makedirs(reservation_files)
289+
test_file_path = os.path.join(reservation_files, test_name + '.bpt', )
290+
test_file_content = self._download_test_file_flow.download_test_file(test_name)
291+
with open(test_file_path, 'w') as f:
292+
f.write(test_file_content)
293+
return test_file_path
294+
250295
def close(self):
251296
"""
252297
Destroy

src/driver.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ def get_results(self, context):
7777
with self._runners_pool.actual_runner(context) as runner:
7878
return runner.get_results()
7979

80+
def get_test_file(self, context, test_name):
81+
"""
82+
Download test file configuration and put to the folder defined in Test Files Location attribute
83+
:param context:
84+
:param test_name: Name of the test
85+
:return:
86+
"""
87+
with self._runners_pool.actual_runner(context) as runner:
88+
return runner.get_test_file(test_name)
89+
8090
def cleanup(self):
8191
"""
8292
Close runners

src/drivermetadata.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,12 @@
3838
DisplayName="Output Type" DefaultValue="csv" Description="CSV or JSON"/>
3939
</Parameters>
4040
</Command>
41+
<Command Name="get_test_file" DisplayName="Get Test File" Description="Download test file to the folder specified in the Test Files Location attribute">
42+
<Parameters>
43+
<Parameter Name="test_name" Type="String" Mandatory="True"
44+
DisplayName="Test Name"
45+
Description="Name of the Test"/>
46+
</Parameters>
47+
</Command>
4148
</Layout>
4249
</Driver>

tests/bp_controller/runners/test_bp_test_runner.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import re
22

3-
from mock import Mock, patch, PropertyMock
3+
from mock import Mock, patch, PropertyMock, call
44
from unittest2 import TestCase
55

66
from bp_controller.runners.bp_test_runner import BPTestRunner
@@ -171,6 +171,8 @@ def test_port_reservation_helper(self, port_reservation_helper_class, logger_pro
171171
@patch('bp_controller.runners.bp_test_runner.BPTestRunner._port_reservation_helper', new_callable=PropertyMock)
172172
@patch('bp_controller.runners.bp_test_runner.ElementTree')
173173
def test_load_configuration(self, element_tree_class, port_reservation_helper_prop, configuration_file_flow_prop):
174+
file_path = Mock()
175+
self._instance._get_existing_path = Mock(return_value=file_path)
174176
port_reservation_helper = Mock()
175177
configuration_file_flow = Mock()
176178
port_reservation_helper_prop.return_value = port_reservation_helper
@@ -188,7 +190,6 @@ def test_load_configuration(self, element_tree_class, port_reservation_helper_pr
188190
interface = Mock()
189191
test_model.findall.return_value = [interface]
190192
interface.get.return_value = '3'
191-
file_path = Mock()
192193
self._instance.load_configuration(file_path)
193194
configuration_file_flow.load_configuration.assert_called_once_with(file_path)
194195
self.assertIs(self._instance._test_name, test_name)
@@ -389,3 +390,23 @@ def test_get_results_flow(self, create_quali_api_instance, test_results_flow_pro
389390
def test_close(self, port_reservation_helper_prop):
390391
self._context.reservation.reservation_id = 'test'
391392
port_reservation_helper_prop.unreserve_ports.assewrt_called_once_with()
393+
394+
@patch('bp_controller.runners.bp_test_runner.os')
395+
def test_get_existing_path(self, os_instance):
396+
path1 = Mock()
397+
path2 = Mock()
398+
os_instance.path.join.return_value = path2
399+
os_instance.path.exists.side_effect = [False, True]
400+
self.assertIs(self._instance._get_existing_path(path1), path1)
401+
os_instance.path.join.assert_called_once_with(self._context.resource.attributes.get('Test Files Location'),
402+
path1)
403+
os_instance.path.exists.assert_has_calls([call(path2), call(path1)])
404+
405+
@patch('bp_controller.runners.bp_test_runner.os')
406+
def test_get_existing_path_exception(self, os_instance):
407+
path1 = Mock()
408+
path2 = Mock()
409+
os_instance.path.join.return_value = path2
410+
os_instance.path.exists.side_effect = [False, False]
411+
with self.assertRaisesRegex(BPRunnerException, 'does not exists'):
412+
self._instance._get_existing_path(path1)

tests/test_driver.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ def test_get_results(self):
7575
self._runners_pool.actual_runner.assert_called_once_with(self._context)
7676
self._runner.get_results.assert_called_once_with()
7777

78+
def test_get_test_file(self):
79+
result = Mock()
80+
self._runner.get_test_file.return_value = result
81+
test_name = Mock()
82+
self.assertIs(self._instance.get_test_file(self._context, test_name), result)
83+
self._runners_pool.actual_runner.assert_called_once_with(self._context)
84+
self._runner.get_test_file.assert_called_once_with(test_name)
85+
7886
def test_cleanup(self):
7987
self._instance.cleanup()
8088
self._runners_pool.close_all_runners.assert_called_once_with()

0 commit comments

Comments
 (0)