Skip to content

Commit

Permalink
[qatl] added method named 'tl.getTestProjectByName' + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
crypto netzulo committed Dec 24, 2017
1 parent fa29f10 commit ec947d7
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 25 deletions.
79 changes: 68 additions & 11 deletions qatestlink/core/testlink_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from qatestlink.core.connections.connection_base import ConnectionBase
from qatestlink.core.utils.Utils import read_file
from qatestlink.core.xmls.route_type import RouteType
from qatestlink.core.xmls.error_handler import ErrorHandler
from qatestlink.core.xmls.request_handler import RequestHandler
from qatestlink.core.xmls.response_handler import ResponseHandler
from qatestlink.core.xmls.base_handler import BaseHandler
Expand Down Expand Up @@ -81,8 +82,8 @@ def api_login(self, dev_key=None):
return False
return bool(node_boolean.text)

def api_get_tprojects(self, dev_key=None):
"""Call to method naed ''"""
def api_tprojects(self, dev_key=None):
"""Call to method named 'tl.getProjects'"""
if dev_key is None:
dev_key = self._settings.get('dev_key')
req_data = self._xml_manager.req_get_tprojects(dev_key)
Expand All @@ -92,6 +93,19 @@ def api_get_tprojects(self, dev_key=None):
# TODO: filter by name and/or value
return res_as_models

def api_tproject(self, tproject_name, dev_key=None):
"""Call to method named 'tl.getTestProjectByName'"""
if dev_key is None:
dev_key = self._settings.get('dev_key')
req_data = self._xml_manager.req_get_tproject_by_name(
dev_key, tproject_name)
res = self._conn.post(self._xml_manager.headers, req_data)
# TODO: parse errors on ALL requests
err = self._xml_manager.parse_errors(res.text)
res_as_model = self._xml_manager.res_get_tproject_by_name(
res.status_code, res.text, as_model=True)
return res_as_model


class XMLRPCManager(object):
"""
Expand All @@ -112,18 +126,23 @@ def __init__(self, log):
self.log = log
self._request_handler = RequestHandler(self.log)
self._response_handler = ResponseHandler(self.log)
self._error_handler = None
self._error_handler = ErrorHandler(self.log)
self.headers = {'Content-Type': 'application/xml'}
self.handler = BaseHandler(self.log)

def parse_errors(self, xml_str):
"""Raise an exception if response have error structure"""
#TODO: make enum and custom exception for each exception number
self._error_handler.get_response_error(xml_str)

def req_check_dev_key(self, dev_key):
"""
:return:
string xml object ready to use on API call
"""
req = self._request_handler.create(
RouteType.TLINK_CHECK_DEV_KEY)
return self._request_handler.add_param(
return self._request_handler.create_param(
req, 'struct', 'devKey', dev_key)

def res_check_dev_key(self, status_code, res_str):
Expand All @@ -142,16 +161,16 @@ def res_check_dev_key(self, status_code, res_str):
def req_get_tprojects(self, dev_key):
"""
Obtains all test projects created on remote
testlink database, can filter with any property+value
combination
testlink database,
TODO: can filter with any property+value combination
:return:
List of TProject objects containing all database
data loaded
"""
req = self._request_handler.create(
RouteType.TPROJECTS)
return self._request_handler.add_param(
return self._request_handler.create_param(
req, 'struct', 'devKey', dev_key)

def res_get_tprojects(self, status_code, res_str, as_models=True):
Expand All @@ -175,16 +194,54 @@ def res_get_tprojects(self, status_code, res_str, as_models=True):
RouteType.TPROJECTS, res_str)
if not as_models:
return res
# TODO: create objects and return them as list
res_members_list = self._response_handler.get_response_members(
xml_str=res)
# TODO: build objects
tprojects = list()
for res_members in res_members_list:
#TODO: all members by project
tproject = TProject(res_members)
tproject = TProject(res_members)
tprojects.append(tproject)
return tprojects


def req_get_tproject_by_name(self, dev_key, tproject_name):
"""
Obtains all test projects created on remote
testlink database, can filter by name
:return:
TProject object containing all database
data loaded
"""
if tproject_name is None:
raise Exception("Can't call XMLRPC without param, tproject_name")
req = self._request_handler.create(
RouteType.TPROJECT_BY_NAME)
req = self._request_handler.create_param(
req, 'struct', 'devKey', dev_key)
req = self._request_handler.add_param(
req, 'testprojectname', tproject_name)
return req

def res_get_tproject_by_name(self, status_code, res_str, as_model=True):
"""
Parse and validate response for method
named 'tl.getTestProjectByName', by default response
TProject object, can response xml string too
:return:
if as_models is True
object instanced with Model classes
if as_models is False
string xml object ready to
parse/write/find/add Elements on it
"""
if status_code != 200:
raise Exception(
"status_code invalid: code={}".format(
status_code))
res = self._response_handler.create(
RouteType.TPROJECT_BY_NAME, res_str)
if not as_model:
return res
res_members_list = self._response_handler.get_response_struct_members(
xml_str=res)
return TProject(res_members_list)
2 changes: 1 addition & 1 deletion qatestlink/core/utils/Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def read_file(is_json=False, file_path=None, encoding='utf-8',
return json.loads(text)
return text

def settings(file_path='qacode/configs/', file_name='settings.json',
def settings(file_path='qatestlink/configs/', file_name='settings.json',
is_abspath=True):
"""Returns file settings as a dict to be use on qacode lib"""
return read_file(is_json=True,
Expand Down
2 changes: 2 additions & 0 deletions qatestlink/core/utils/logger_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def __init__(self, log_level=None):
logger.setLevel(log_level)
logger_stream.setLevel(log_level)
logger_stream.setFormatter(formatter)
for old_handler in logger.handlers:
logger.removeHandler(old_handler)
logger.addHandler(logger_stream)
# alias to improve logging calls
self.log = logger
81 changes: 81 additions & 0 deletions qatestlink/core/xmls/error_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
"""TODO: doc module"""


from xml.etree.ElementTree import tostring as xml_to_str
from qatestlink.core.xmls.base_handler import BaseHandler


class ErrorHandler(BaseHandler):
"""TODO: doc class"""

def __init__(self, *args, **kwargs):
"""Instance handler"""
super(ErrorHandler, self).__init__(*args, **kwargs)

def create(self, route_type, xml_str):
"""Create response by router_type"""
super(ErrorHandler, self).is_route_type(route_type)
root = self.xml_parse(xml_str)
return xml_to_str(root)

def get_response_error(self, xml_str):
"""
Allow to parse string XML object list response to
ResponseMember object list
:Args:
xml_str: must be XML format string
<param>
<value>
<array>
<data>
<value>
<struct>
<member>
<name>code</name><value><int>some int</int></value>
</member>
<member>
<name>message</name><value>some message string</value>
</member>
</..close all elements>
"""
node_param = self.find_node('param', xml_str=xml_str)
node_param_value = self.find_node('value', parent=node_param)
node_array = self.find_node('array', parent=node_param_value)
# not an exception
if node_array is None:
return
node_data = self.find_node('data', parent=node_array)
node_data_value = self.find_node('value', parent=node_data)
node_struct = self.find_node('struct', parent=node_data_value)
node_struct_members = self.find_nodes('member', parent=node_struct)
# check error found, not safe, silenced errors here
if len(node_struct_members) != 2:
return
# 1º member
node_name_one = self.find_node('name', parent=node_struct_members[0])
node_value_one = self.find_node('value', parent=node_struct_members[0])
node_value_type_one = self.find_node('int', parent=node_value_one)
# 2º member
node_name_second = self.find_node('name', parent=node_struct_members[1])
node_value_second = self.find_node('value', parent=node_struct_members[1])
node_value_type_second = self.find_node('string', parent=node_value_second)
# build response error
code = int(node_value_type_one.text)
message = str(node_value_type_second.text)
raise ResponseException(code, self.log, message=message)


class ResponseException(Exception):
"""Inherits exception, just for raises testlink XMLRPC errors"""

def __init__(self, code, log,
message='Response Exception message not defined at raise',
err=None):
"""Raise an exception from any part of qacode package"""
super(ResponseException, self).__init__(err, message)
self._code = code
self._message = message
log.error(
"Response exception detected: \n code={}\n message={}".format(
self._code, self._message))
32 changes: 30 additions & 2 deletions qatestlink/core/xmls/request_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ def create(self, route_type):
self.log.info(MSG_CREATED_XMLREQUEST.format(xml_to_str(root)))
return xml_to_str(root)

def add_param(self, req_str, param_type, param_name, param_value):
def create_param(self, req_str, param_type, param_name, param_value):
"""
Add param to created xml request
obtained as string
"""
root = self.xml_parse(req_str)
self.log.debug("Adding param:")
self.log.debug("Creating param:")
self.log.debug(" type={}".format(param_type))
self.log.debug(" name={}".format(param_name))
self.log.debug(" value={}".format(param_value))
Expand All @@ -57,3 +57,31 @@ def add_param(self, req_str, param_type, param_name, param_value):
raise Exception('param_type not supported, can\'t add_param')
self.log.info(MSG_CREATED_XMLPARAM.format(xml_to_str(root)))
return xml_to_str(root)

def add_param(self, req_str, param_name, param_value):
"""
Add param to created xml request
obtained as string
"""
"""
Add param to created xml request
obtained as string
"""
root = self.xml_parse(req_str)
self.log.debug("Adding param:")
self.log.debug(" name={}".format(param_name))
self.log.debug(" value={}".format(param_value))
n_params = self.find_node('params', parent=root)
n_param = self.find_node('param', parent=n_params)
n_value = self.find_node('value', parent=n_param)
# TODO: type XML validation for params
# just struct handleded
n_struct = self.find_node('struct', parent=n_value)
n_member = self.create_node('member', parent=n_struct)
n_name = self.create_node(
'name', parent=n_member, text=param_name)
n_value = self.create_node('value', parent=n_member)
n_value_string = self.create_node(
'string', parent=n_value, text=param_value)
self.log.info(MSG_CREATED_XMLPARAM.format(xml_to_str(root)))
return xml_to_str(root)
41 changes: 36 additions & 5 deletions qatestlink/core/xmls/response_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,23 @@ def create(self, route_type, xml_str):

def get_response_members(self, xml_str):
"""
Allow to parse string XML to ResponseMember
object list
Allow to parse string XML object list response to
ResponseMember object list
:Args:
xml_str: must be XML format string
<data><value><struct><member></..close all elements>
<param>
<value>
<array>
<data>
<value>
<struct>
<member>
</..close all elements>
"""
node_data = self.find_node('data', xml_str=xml_str)
node_param = self.find_node('param', xml_str=xml_str)
node_param_value = self.find_node('array', parent=node_param)
node_array = self.find_node('array', parent=node_param_value)
node_data = self.find_node('data', parent=node_array)
nodes_value = self.find_nodes('value', parent=node_data)
res_members_list = list()
for node_value in nodes_value:
Expand All @@ -44,6 +54,27 @@ def get_response_members(self, xml_str):
res_members_list.append(res_members)
return res_members_list

def get_response_struct_members(self, xml_str):
"""
Allow to parse string XML object list response to
ResponseMember object list
:Args:
xml_str: must be XML format string
<param>
<struct>
<member>
</..close all elements>
"""
node_param = self.find_node('param', xml_str=xml_str)
node_struct = self.find_node('struct', parent=node_param)
nodes_member = self.find_nodes('member', parent=node_struct)
res_members = list()
for node_member in nodes_member:
res_member = ResponseMember(self.log, node_member)
res_members.append(res_member)
return res_members



class ResponseMember(BaseHandler):
"""
Expand Down Expand Up @@ -83,6 +114,6 @@ def _load(self):
'value', parent=self._node_member)
self.name = node_name.text
self.value = self.parse_node_value(node_value)
self.log.info(
self.log.debug(
'ResponseMember instance: name={}, value={}'.format(
self.name, self.value))

0 comments on commit ec947d7

Please sign in to comment.