Skip to content

Commit

Permalink
[qatl] fixing #7 'tl.getProjects'
Browse files Browse the repository at this point in the history
+ lang fix on enum
+ renamed param on base_handler
+ added tests to True/False login
+ first steps with 'tl.getProjects' method
+ added models: Test Project objects
  • Loading branch information
crypto netzulo committed Dec 8, 2017
1 parent c6e2feb commit 796a824
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 51 deletions.
Empty file.
50 changes: 50 additions & 0 deletions qatestlink/core/models/tl_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
"""TODO: doc module"""


class ModelBase(object):
"""TODO: doc class"""

def __init__(self):
"""TODO: doc method"""
pass


class TProject(ModelBase):
"""TODO: doc class"""

_res_members = None

# Testlink object properties
id = None
name = None
is_public = None

def __init__(self, res_members):
"""TODO: doc method"""
super(TProject, self).__init__()
if res_members is None:
raise Exception('Bad param, res_member can\'t be None')
if len(res_members) <= 0:
raise Exception(
'Bad param, res_member can\'t be empty list')
self._res_members = res_members
self._load()

def _load(self):
for res_member in self._res_members:
name = res_member.name
value = res_member.value
if name == 'id':
self.id = value
if name == 'name':
self.name = value
if name == 'is_public':
self.is_public = value

def __repr__(self):
return "TProject: id={}, name={}, is_public={}".format(
self.id,
self.name,
self.is_public
)
105 changes: 70 additions & 35 deletions qatestlink/core/testlink_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
import json
import logging
import requests
from qatestlink.core.utils.logger_manager import LoggerManager
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.request_handler import RequestHandler
from qatestlink.core.xmls.response_handler import ResponseHandler
from qatestlink.core.xmls.base_handler import BaseHandler
from qatestlink.core.models.tl_models import TProject


PATH_CONFIG = 'qatestlink/configs/settings.json'
Expand Down Expand Up @@ -70,7 +73,25 @@ def api_login(self, dev_key=None):
dev_key = self._settings.get('dev_key')
req_data = self._xml_manager.req_check_dev_key(dev_key)
res = self._conn.post(self._xml_manager.headers, req_data)
self._xml_manager.res_check_dev_key(res.status_code, res.text)
res_xml = self._xml_manager.res_check_dev_key(
res.status_code, res.text)
node_boolean = self._xml_manager.handler.find_node(
'boolean', xml_str=res_xml)
if node_boolean is None:
return False
return bool(node_boolean.text)

def api_get_tprojects(self, dev_key=None):
"""Call to method naed ''"""
if dev_key is None:
dev_key = self._settings.get('dev_key')
req_data = self._xml_manager.req_get_tprojects(dev_key)
res = self._conn.post(self._xml_manager.headers, req_data)
res_as_models = self._xml_manager.res_get_tprojects(
res.status_code, res.text, as_models=True)
# TODO: filter by name and/or value
return res_as_models


class XMLRPCManager(object):
"""
Expand All @@ -85,13 +106,15 @@ class XMLRPCManager(object):

log = None
headers = None
handler = None

def __init__(self, log):
self.log = log
self._request_handler = RequestHandler(self.log)
self._response_handler = ResponseHandler(self.log)
self._error_handler = None
self.headers = {'Content-Type': 'application/xml'}
self.handler = BaseHandler(self.log)

def req_check_dev_key(self, dev_key):
"""
Expand All @@ -113,43 +136,55 @@ def res_check_dev_key(self, status_code, res_str):
raise Exception(
"status_code invalid: code={}".format(
status_code))
res = self._response_handler.create(
RouteType.TLINK_CHECK_DEV_KEY,
res_str)
self.log.info("XML response for: {}".format(
RouteType.TLINK_CHECK_DEV_KEY.value))
return res
return self._response_handler.create(
RouteType.TLINK_CHECK_DEV_KEY, 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
:return:
List of TProject objects containing all database
data loaded
"""
req = self._request_handler.create(
RouteType.TPROJECTS)
return self._request_handler.add_param(
req, 'struct', 'devKey', dev_key)

def res_get_tprojects(self, status_code, res_str, as_models=True):
"""
Parse and validate response for method
named 'tl.getProjects', by default response list
of TProject objects, can response xml string too
:return:
if as_models is True
list of objects 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.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)
tprojects.append(tproject)
return tprojects

class LoggerManager(object):
"""
Start logger named 'qatestlink'
with DEBUG level and just with console reporting
"""

log = None

def __init__(self, log_level=None):
"""Start logger"""
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('qatestlink')
logger_stream = logging.StreamHandler()
if log_level is None or log_level == 'DEBUG':
log_level = logging.DEBUG
elif log_level == 'INFO':
log_level = logging.INFO
elif log_level == 'WARNING':
log_level = logging.WARNING
elif log_level == 'ERROR':
log_level = logging.ERROR
elif log_level == 'CRITICAL':
log_level = logging.CRITICAL
logger.setLevel(log_level)
logger_stream.setLevel(log_level)
logger_stream.setFormatter(formatter)
logger.addHandler(logger_stream)
# alias to improve logging calls
self.log = logger

37 changes: 37 additions & 0 deletions qatestlink/core/utils/logger_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
"""TODO: doc module"""


import logging


class LoggerManager(object):
"""
Start logger named 'qatestlink'
with DEBUG level and just with console reporting
"""

log = None

def __init__(self, log_level=None):
"""Start logger"""
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('qatestlink')
logger_stream = logging.StreamHandler()
if log_level is None or log_level == 'DEBUG':
log_level = logging.DEBUG
elif log_level == 'INFO':
log_level = logging.INFO
elif log_level == 'WARNING':
log_level = logging.WARNING
elif log_level == 'ERROR':
log_level = logging.ERROR
elif log_level == 'CRITICAL':
log_level = logging.CRITICAL
logger.setLevel(log_level)
logger_stream.setLevel(log_level)
logger_stream.setFormatter(formatter)
logger.addHandler(logger_stream)
# alias to improve logging calls
self.log = logger

49 changes: 44 additions & 5 deletions qatestlink/core/xmls/base_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,26 +54,65 @@ def create_node(self, tag, parent=None, text=None):
MSG_ADDED_TEXT.format(tag, text))
return node

def find_node(self, tag, req_str=None, parent=None):
def find_node(self, tag, xml_str=None, parent=None):
"""
Returns firt node obtained iter
by tag name on string 'request'
"""
err_msg = 'Can\'t use this function like this, read documentation'
if req_str is None and parent is None:
if xml_str is None and parent is None:
raise Exception(err_msg)
if req_str is not None and parent is not None:
if xml_str is not None and parent is not None:
raise Exception(err_msg)
if parent is not None:
root = parent
if req_str is not None:
root = self.xml_parse(req_str)
if xml_str is not None:
root = self.xml_parse(xml_str)
# Search element
for node in ElementTree(element=root).iter(tag=tag):
if node.tag == tag:
self.log.debug(MSG_FOUND_NODE.format(node.tag, node.text))
return node

def find_nodes(self, tag, xml_str=None, parent=None):
"""
Returns list of nodes obtained itering
by tag name on string 'request'
"""
err_msg = 'Can\'t use this function like this, read documentation'
if xml_str is None and parent is None:
raise Exception(err_msg)
if xml_str is not None and parent is not None:
raise Exception(err_msg)
if parent is not None:
root = parent
if xml_str is not None:
root = self.xml_parse(xml_str)
# Search element
nodes_found = list()
for node in ElementTree(element=root).iter(tag=tag):
if node.tag == tag:
self.log.debug(MSG_FOUND_NODE.format(node.tag, node.text))
nodes_found.append(node)
return nodes_found

def parse_node_value(self, node_value):
"""
Parse and validate XML value member and return it
parsed to each valid type
"""
value_node_string = self.find_node(
'string', parent=node_value)
value_node_struct = self.find_node(
'string', parent=node_value)
if value_node_string is not None:
return value_node_string.text
if value_node_struct is not None:
# TODO: i don't know how to do this yet
raise NotImplementedError(
'Response node_member struct not handled yet')


def xml_parse(self, xml_str):
"""
Parse request string and return it
Expand Down
68 changes: 68 additions & 0 deletions qatestlink/core/xmls/response_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,71 @@ def create(self, route_type, xml_str):
super(ResponseHandler, self).is_route_type(route_type)
root = self.xml_parse(xml_str)
return xml_to_str(root)

def get_response_members(self, xml_str):
"""
Allow to parse string XML to ResponseMember
object list
:Args:
xml_str: must be XML format string
<data><value><struct><member></..close all elements>
"""
node_data = self.find_node('data', xml_str=xml_str)
nodes_value = self.find_nodes('value', parent=node_data)
res_members_list = list()
for node_value in nodes_value:
node_struct = self.find_node('struct', parent=node_value) # all okey
# import pdb; pdb.set_trace()
if node_struct is None:
self.log.error("node_struct haven't <member> child tag")
else:
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)
res_members_list.append(res_members)
return res_members_list


class ResponseMember(BaseHandler):
"""
Class to parse member XML node
:usage:
<member>
<name>property_name</name>
<value>
<string>property_value</string>
</value>
</member>
"""

_log = None
_node_member = None

name = None
value = None

def __init__(self, log, node_member, is_load=True):
"""TODO: doc method"""
super(ResponseMember, self).__init__(log)
if log is None:
raise Exception('log param can\'t be None')
self._log = log
if node_member is None:
raise Exception('node_member param can\'t be None')
self._node_member = node_member
if is_load:
self._load()

def _load(self):
node_name = self.find_node(
'name', parent=self._node_member)
node_value = self.find_node(
'value', parent=self._node_member)
self.name = node_name.text
self.value = self.parse_node_value(node_value)
self.log.info(
'ResponseMember instance: name={}, value={}'.format(
self.name, self.value))
4 changes: 2 additions & 2 deletions qatestlink/core/xmls/route_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ class RouteType(Enum):
use intellisense to improve development
"""

# TestProyects
# TestProjects

"""TODO
Args:
devKey:string
authorization dev key
"""
TPROYECT_CREATE = 'tl.createTestProject'
TPROJECT_CREATE = 'tl.createTestProject'

"""TODO
Args:
Expand Down
Loading

0 comments on commit 796a824

Please sign in to comment.