Skip to content

Commit 7a01835

Browse files
authored
Test manager
1 parent a2e8a8d commit 7a01835

File tree

9 files changed

+330
-16
lines changed

9 files changed

+330
-16
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
"""This module contains functional for test items management.
2+
3+
Copyright (c) 2018 http://reportportal.io .
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
"""
17+
from reportportal_client.helpers import generate_uuid, dict_to_payload
18+
from reportportal_client.items.rp_log_items.rp_log_item import RPLogItem
19+
from reportportal_client.items.rp_test_items.rp_child_test_item import \
20+
RPChildTestItem
21+
from reportportal_client.items.rp_test_items.rp_root_test_item import \
22+
RPRootTestItem
23+
24+
25+
class TestManager(object):
26+
"""Manage test items during single launch.
27+
28+
Test item types (item_type) can be:
29+
(SUITE, STORY, TEST, SCENARIO, STEP, BEFORE_CLASS,
30+
BEFORE_GROUPS, BEFORE_METHOD, BEFORE_SUITE, BEFORE_TEST, AFTER_CLASS,
31+
AFTER_GROUPS, AFTER_METHOD, AFTER_SUITE, AFTER_TEST).
32+
33+
'attributes' and 'parameters' should be a dictionary
34+
with the following format:
35+
{
36+
"<key1>": "<value1>",
37+
"<key2>": "<value2>",
38+
...
39+
}
40+
"""
41+
42+
def __init__(self, rp_url, session, api_version, launch_id, project_name):
43+
"""Initialize instance attributes.
44+
45+
:param rp_url: report portal url
46+
:param session: Session object
47+
:param api_version: RP API version
48+
:param launch_id: Parent launch UUID
49+
:param project_name: RP project name
50+
"""
51+
self.rp_url = rp_url
52+
self.session = session
53+
self.api_version = api_version
54+
self.launch_id = launch_id
55+
self.project_name = project_name
56+
self.__storage = []
57+
58+
def start_test_item(self,
59+
name,
60+
start_time,
61+
item_type,
62+
description=None,
63+
attributes=None,
64+
parameters=None,
65+
parent_item_id=None,
66+
has_stats=True,
67+
**kwargs):
68+
"""Start new test item.
69+
70+
:param name: test item name
71+
:param start_time: test item execution start time
72+
:param item_type: test item type (see class doc string)
73+
:param description: test item description
74+
:param attributes: test item attributes(tags)
75+
Pairs of key and value (see class doc string)
76+
:param parameters: test item set of parameters
77+
(for parametrized tests) (see class doc string)
78+
:param parent_item_id: UUID of parent test item
79+
:param has_stats: True - regular test item, False - test item
80+
without statistics (nested step)
81+
:param kwargs: other parameters
82+
:return: test item UUID
83+
"""
84+
if attributes and isinstance(attributes, dict):
85+
attributes = dict_to_payload(attributes)
86+
if parameters:
87+
parameters = dict_to_payload(parameters)
88+
89+
item_data = {
90+
"description": description,
91+
"attributes": attributes,
92+
"parameters": parameters,
93+
"has_stats": has_stats
94+
}
95+
kwargs and item_data.update(kwargs)
96+
uuid = generate_uuid()
97+
if not parent_item_id:
98+
test_item = RPRootTestItem(self.rp_url,
99+
self.session,
100+
self.api_version,
101+
self.project_name,
102+
name,
103+
item_type,
104+
self.launch_id,
105+
uuid,
106+
**item_data)
107+
self.__storage.append(test_item)
108+
else:
109+
parent_item = self.get_test_item(parent_item_id)
110+
test_item = RPChildTestItem(self.rp_url,
111+
self.session,
112+
self.api_version,
113+
self.project_name,
114+
parent_item,
115+
name,
116+
item_type,
117+
self.launch_id,
118+
uuid,
119+
**item_data)
120+
test_item.start(start_time)
121+
return uuid
122+
123+
def update_test_item(self, item_uuid, attributes=None, description=None,
124+
**kwargs):
125+
"""Update existing test item at the Report Portal.
126+
127+
:param str item_uuid: test item UUID returned on the item start
128+
:param str description: test item description
129+
:param dict attributes: test item attributes(tags)
130+
Pairs of key and value (see class doc string)
131+
"""
132+
self.get_test_item(item_uuid)
133+
raise NotImplementedError()
134+
135+
def finish_test_item(self,
136+
item_uuid,
137+
end_time,
138+
status,
139+
issue=None,
140+
attributes=None,
141+
**kwargs):
142+
"""Finish test item.
143+
144+
:param item_uuid: id of the test item
145+
:param end_time: time in UTC format
146+
:param status: status of the test
147+
:param issue: description of an issue
148+
:param attributes: dict with attributes
149+
:param kwargs: other parameters
150+
"""
151+
# check if the test is skipped, if not - do not mark as TO INVESTIGATE
152+
if issue is None and status == "SKIPPED":
153+
issue = {"issue_type": "NOT_ISSUE"}
154+
if attributes and isinstance(attributes, dict):
155+
attributes = dict_to_payload(attributes)
156+
self.get_test_item(item_uuid).finish(end_time, status, issue=issue,
157+
attributes=attributes, **kwargs)
158+
159+
def remove_test_item(self, item_uuid):
160+
"""Remove test item by uuid.
161+
162+
:param item_uuid: test item uuid
163+
"""
164+
self.get_test_item(item_uuid)
165+
raise NotImplementedError()
166+
167+
def log(self, time, message=None, level=None, attachment=None,
168+
item_id=None):
169+
"""Log message. Can be added to test item in any state.
170+
171+
:param time: log time
172+
:param message: log message
173+
:param level: log level
174+
:param attachment: attachments to log (images,files,etc.)
175+
:param item_id: parent item UUID
176+
:return: log item UUID
177+
"""
178+
uuid = generate_uuid()
179+
# Todo: Do we store log items?
180+
log_item = RPLogItem(self.rp_url,
181+
self.session,
182+
self.api_version,
183+
self.project_name,
184+
self.launch_id,
185+
uuid)
186+
log_item.create(time, attachment, item_id, level, message)
187+
return uuid
188+
189+
def get_test_item(self, item_uuid):
190+
"""Get test item by its uuid in the storage.
191+
192+
:param item_uuid: test item uuid
193+
:return: test item object if found else None
194+
"""
195+
# Todo: add 'force' parameter to get item from report portal server
196+
# instead of cache and update cache data according to this request
197+
return self._find_item(item_uuid, self.__storage)
198+
199+
def _find_item(self, item_uuid, storage):
200+
"""Find test item by its uuid in given storage.
201+
202+
:param item_uuid: test item uuid
203+
:param storage: list with test item objects
204+
:return: test item object if found else None
205+
"""
206+
for test_item in reversed(storage):
207+
if item_uuid == test_item.generated_id:
208+
return test_item
209+
else:
210+
if hasattr(test_item, "child_items") and test_item.child_items:
211+
found_item = self._find_item(item_uuid,
212+
test_item.child_items)
213+
if found_item:
214+
return found_item
215+
216+
def get_storage(self):
217+
"""Get storage.
218+
219+
:return: storage with test items
220+
"""
221+
return self.__storage
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from typing import Any, Optional, Dict, List
2+
3+
from requests import Session
4+
5+
from reportportal_client.core.rp_file import RPFile
6+
from reportportal_client.items.rp_test_items.rp_base_test_item import \
7+
RPBaseTestItem
8+
9+
10+
class TestManager:
11+
rp_url: str = ...
12+
session: Session = ...
13+
api_version: str = ...
14+
launch_id: str = ...
15+
project_name: str = ...
16+
__storage: List = ...
17+
18+
def __init__(self, rp_url: str, session: Session, api_version: str,
19+
launch_id: str, project_name: str) -> None: ...
20+
21+
def start_test_item(self, name: str, start_time: str, item_type: str,
22+
description: Optional[str] = ...,
23+
attributes: Optional[Dict] = ...,
24+
parameters: Optional[Dict] = ...,
25+
parent_item_id: Optional[str] = ...,
26+
has_stats: bool = ..., **kwargs: Any) -> str: ...
27+
28+
def update_test_item(self, item_uuid: str, attributes: Optional[Dict] = ...,
29+
description: Optional[str] = ...,
30+
**kwargs: Any) -> None: ...
31+
32+
def finish_test_item(self, item_uuid: str, end_time: str, status: str,
33+
issue: Optional[str] = ...,
34+
attributes: Optional[Dict] = ...,
35+
**kwargs: Any) -> None: ...
36+
37+
def remove_test_item(self, item_uuid: str) -> None: ...
38+
39+
def log(self, time: str, message: Optional[str] = ...,
40+
level: Optional[str] = ..., attachment: Optional[RPFile] = ...,
41+
item_id: Optional[str] = ...) -> str: ...
42+
43+
def get_test_item(self, item_uuid: str) -> RPBaseTestItem: ...
44+
45+
def get_storage(self) -> List: ...
46+
47+
def _find_item(self, item_uuid: str, storage: List) -> RPBaseTestItem: ...

reportportal_client/helpers.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,46 @@
1111
See the License for the specific language governing permissions and
1212
limitations under the License.
1313
"""
14-
1514
import logging
16-
from pkg_resources import DistributionNotFound, get_distribution
15+
import uuid
1716
from platform import machine, processor, system
1817

18+
import six
19+
from pkg_resources import DistributionNotFound, get_distribution
20+
1921
logger = logging.getLogger(__name__)
2022

2123

24+
def generate_uuid():
25+
"""Generate Uuid."""
26+
return str(uuid.uuid4())
27+
28+
29+
def convert_string(value):
30+
"""Support and convert strings in py2 and py3.
31+
32+
:param value: input string
33+
:return value: converted string
34+
"""
35+
if isinstance(value, six.text_type):
36+
# Don't try to encode 'unicode' in Python 2.
37+
return value
38+
return str(value)
39+
40+
41+
def dict_to_payload(dictionary):
42+
"""Convert dict to list of dicts.
43+
44+
:param dictionary: initial dict
45+
:return list: list of dicts
46+
"""
47+
system = dictionary.pop('system', False)
48+
return [
49+
{'key': key, 'value': convert_string(value), 'system': system}
50+
for key, value in sorted(dictionary.items())
51+
]
52+
53+
2254
def gen_attributes(rp_attributes):
2355
"""Generate list of attributes for the API request.
2456

reportportal_client/helpers.pyi

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ from typing import Dict, List, Text
33

44
logger: Logger
55

6+
7+
def generate_uuid() -> str: ...
8+
9+
10+
def convert_string(value: str) -> str: ...
11+
12+
13+
def dict_to_payload(value: Dict) -> List[Dict]: ...
14+
15+
616
def gen_attributes(rp_attributes: List) -> List[Dict]: ...
717

818
def get_launch_sys_attrs() -> Dict[Text]: ...

reportportal_client/items/rp_log_items/rp_log_item.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
limitations under the License.
1717
"""
1818

19-
from reportportal_client.items.rp_base_item import BaseRPItem
2019
from reportportal_client.core.rp_requests import RPRequestLog
20+
from reportportal_client.items.item_weight import ItemWeight
21+
from reportportal_client.items.rp_base_item import BaseRPItem
2122
from reportportal_client.static.defines import RP_LOG_LEVELS
22-
from reportportal_client.items.helpers import ItemWeight
2323

2424

2525
class RPLogItem(BaseRPItem):
@@ -44,7 +44,7 @@ def __init__(self, rp_url, session, api_version, project_name,
4444
@property
4545
def response(self):
4646
"""Get the response object for RP log item."""
47-
return self._responses[0]
47+
return self.responses[0]
4848

4949
@response.setter
5050
def response(self, value):

0 commit comments

Comments
 (0)