Skip to content

Commit bdd4bfc

Browse files
authored
Merge pull request #223 from reportportal/develop
Release
2 parents 4b968ae + f2a8e56 commit bdd4bfc

File tree

7 files changed

+85
-15
lines changed

7 files changed

+85
-15
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44
### Fixed
5+
- Attribute truncation for every method with attributes, by @HardNorth
6+
7+
## [5.5.1]
8+
### Fixed
59
- Multipart file upload for Async clients, by @HardNorth
610

711
## [5.5.0]

reportportal_client/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ def create_client(
7474
:type launch_uuid_print: bool
7575
:param print_output: Set output stream for Launch UUID printing.
7676
:type print_output: OutputType
77+
:param truncate_attributes: Truncate test item attributes to default maximum length.
78+
:type truncate_attributes: bool
7779
:param log_batch_size: Option to set the maximum number of logs that can be processed in one
7880
batch.
7981
:type log_batch_size: int

reportportal_client/aio/client.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class Client:
8888
mode: str
8989
launch_uuid_print: bool
9090
print_output: OutputType
91+
truncate_attributes: bool
9192
_skip_analytics: str
9293
_session: Optional[RetryingClientSession]
9394
__stat_task: Optional[asyncio.Task]
@@ -107,6 +108,7 @@ def __init__(
107108
mode: str = 'DEFAULT',
108109
launch_uuid_print: bool = False,
109110
print_output: OutputType = OutputType.STDOUT,
111+
truncate_attributes: bool = True,
110112
**kwargs: Any
111113
) -> None:
112114
"""Initialize the class instance with arguments.
@@ -125,6 +127,7 @@ def __init__(
125127
:param mode: Launch mode, all Launches started by the client will be in that mode.
126128
:param launch_uuid_print: Print Launch UUID into passed TextIO or by default to stdout.
127129
:param print_output: Set output stream for Launch UUID printing.
130+
:param truncate_attributes: Truncate test item attributes to default maximum length.
128131
"""
129132
self.api_v1, self.api_v2 = 'v1', 'v2'
130133
self.endpoint = endpoint
@@ -144,6 +147,7 @@ def __init__(
144147
self._session = None
145148
self.__stat_task = None
146149
self.api_key = api_key
150+
self.truncate_attributes = truncate_attributes
147151

148152
async def session(self) -> RetryingClientSession:
149153
"""Return aiohttp.ClientSession class instance, initialize it if necessary.
@@ -156,7 +160,7 @@ async def session(self) -> RetryingClientSession:
156160
if self.verify_ssl is None or (type(self.verify_ssl) == bool and not self.verify_ssl):
157161
ssl_config = False
158162
else:
159-
if type(self.verify_ssl) == str:
163+
if type(self.verify_ssl) is str:
160164
ssl_config = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=self.verify_ssl)
161165
else:
162166
ssl_config = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=certifi.where())
@@ -242,7 +246,7 @@ async def start_launch(self,
242246
request_payload = LaunchStartRequest(
243247
name=name,
244248
start_time=start_time,
245-
attributes=attributes,
249+
attributes=verify_value_length(attributes) if self.truncate_attributes else attributes,
246250
description=description,
247251
mode=self.mode,
248252
rerun=rerun,
@@ -306,7 +310,7 @@ async def start_test_item(self,
306310
start_time,
307311
item_type,
308312
launch_uuid,
309-
attributes=verify_value_length(attributes),
313+
attributes=verify_value_length(attributes) if self.truncate_attributes else attributes,
310314
code_ref=code_ref,
311315
description=description,
312316
has_stats=has_stats,
@@ -355,7 +359,7 @@ async def finish_test_item(self,
355359
end_time,
356360
launch_uuid,
357361
status,
358-
attributes=verify_value_length(attributes),
362+
attributes=verify_value_length(attributes) if self.truncate_attributes else attributes,
359363
description=description,
360364
is_skipped_an_issue=self.is_skipped_an_issue,
361365
issue=issue,
@@ -389,7 +393,7 @@ async def finish_launch(self,
389393
request_payload = LaunchFinishRequest(
390394
end_time,
391395
status=status,
392-
attributes=verify_value_length(attributes),
396+
attributes=verify_value_length(attributes) if self.truncate_attributes else attributes,
393397
description=kwargs.get('description')
394398
).payload
395399
response = await AsyncHttpRequest((await self.session()).put, url=url, json=request_payload,
@@ -415,7 +419,7 @@ async def update_test_item(self,
415419
"""
416420
data = {
417421
'description': description,
418-
'attributes': verify_value_length(attributes),
422+
'attributes': verify_value_length(attributes) if self.truncate_attributes else attributes,
419423
}
420424
item_id = await self.get_item_id_by_uuid(item_uuid)
421425
url = root_uri_join(self.base_url_v1, 'item', item_id, 'update')
@@ -650,6 +654,7 @@ def __init__(
650654
:param mode: Launch mode, all Launches started by the client will be in that mode.
651655
:param launch_uuid_print: Print Launch UUID into passed TextIO or by default to stdout.
652656
:param print_output: Set output stream for Launch UUID printing.
657+
:param truncate_attributes: Truncate test item attributes to default maximum length.
653658
:param client: ReportPortal async Client instance to use. If set, all above arguments
654659
will be ignored.
655660
:param launch_uuid: A launch UUID to use instead of starting own one.
@@ -1009,6 +1014,7 @@ def __init__(
10091014
:param mode: Launch mode, all Launches started by the client will be in that mode.
10101015
:param launch_uuid_print: Print Launch UUID into passed TextIO or by default to stdout.
10111016
:param print_output: Set output stream for Launch UUID printing.
1017+
:param truncate_attributes: Truncate test item attributes to default maximum length.
10121018
:param client: ReportPortal async Client instance to use. If set, all above arguments
10131019
will be ignored.
10141020
:param launch_uuid: A launch UUID to use instead of starting own one.
@@ -1384,6 +1390,7 @@ def __init__(
13841390
:param mode: Launch mode, all Launches started by the client will be in that mode.
13851391
:param launch_uuid_print: Print Launch UUID into passed TextIO or by default to stdout.
13861392
:param print_output: Set output stream for Launch UUID printing.
1393+
:param truncate_attributes: Truncate test item attributes to default maximum length.
13871394
:param client: ReportPortal async Client instance to use. If set, all above arguments
13881395
will be ignored.
13891396
:param launch_uuid: A launch UUID to use instead of starting own one.
@@ -1406,7 +1413,7 @@ def __init__(
14061413
self.shutdown_timeout = shutdown_timeout
14071414
self.__init_task_list(task_list, task_mutex)
14081415
self.__init_loop(loop)
1409-
if type(launch_uuid) == str:
1416+
if type(launch_uuid) is str:
14101417
super().__init__(endpoint, project,
14111418
launch_uuid=self.create_task(self.__return_value(launch_uuid)), **kwargs)
14121419
else:
@@ -1561,6 +1568,7 @@ def __init__(
15611568
:param mode: Launch mode, all Launches started by the client will be in that mode.
15621569
:param launch_uuid_print: Print Launch UUID into passed TextIO or by default to stdout.
15631570
:param print_output: Set output stream for Launch UUID printing.
1571+
:param truncate_attributes: Truncate test item attributes to default maximum length.
15641572
:param client: ReportPortal async Client instance to use. If set, all above arguments
15651573
will be ignored.
15661574
:param launch_uuid: A launch UUID to use instead of starting own one.
@@ -1588,7 +1596,7 @@ def __init__(
15881596
self.__init_task_list(task_list, task_mutex)
15891597
self.__last_run_time = datetime.time()
15901598
self.__init_loop(loop)
1591-
if type(launch_uuid) == str:
1599+
if type(launch_uuid) is str:
15921600
super().__init__(endpoint, project,
15931601
launch_uuid=self.create_task(self.__return_value(launch_uuid)), **kwargs)
15941602
else:

reportportal_client/client.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ class RPClient(RP):
363363
mode: str
364364
launch_uuid_print: Optional[bool]
365365
print_output: OutputType
366+
truncate_attributes: bool
366367
_skip_analytics: str
367368
_item_stack: LifoQueue
368369
_log_batcher: LogBatcher[RPRequestLog]
@@ -433,6 +434,7 @@ def __init__(
433434
launch_uuid_print: bool = False,
434435
print_output: OutputType = OutputType.STDOUT,
435436
log_batcher: Optional[LogBatcher[RPRequestLog]] = None,
437+
truncate_attributes: bool = True,
436438
**kwargs: Any
437439
) -> None:
438440
"""Initialize the class instance with arguments.
@@ -455,6 +457,7 @@ def __init__(
455457
:param launch_uuid_print: Print Launch UUID into passed TextIO or by default to stdout.
456458
:param print_output: Set output stream for Launch UUID printing.
457459
:param log_batcher: Use existing LogBatcher instance instead of creation of own one.
460+
:param truncate_attributes: Truncate test item attributes to default maximum length.
458461
"""
459462
set_current(self)
460463
self.api_v1, self.api_v2 = 'v1', 'v2'
@@ -490,6 +493,7 @@ def __init__(
490493
self._skip_analytics = getenv('AGENT_NO_ANALYTICS')
491494
self.launch_uuid_print = launch_uuid_print
492495
self.print_output = print_output
496+
self.truncate_attributes = truncate_attributes
493497

494498
self.api_key = api_key
495499
if not self.api_key:
@@ -505,7 +509,7 @@ def __init__(
505509
if not self.api_key:
506510
warnings.warn(
507511
message='Argument `api_key` is `None` or empty string, that is not supposed to happen '
508-
'because Report Portal is usually requires an authorization key. Please check '
512+
'because ReportPortal is usually requires an authorization key. Please check '
509513
'your code.',
510514
category=RuntimeWarning,
511515
stacklevel=2
@@ -538,7 +542,7 @@ def start_launch(self,
538542
request_payload = LaunchStartRequest(
539543
name=name,
540544
start_time=start_time,
541-
attributes=attributes,
545+
attributes=verify_value_length(attributes) if self.truncate_attributes else attributes,
542546
description=description,
543547
mode=self.mode,
544548
rerun=rerun,
@@ -601,7 +605,7 @@ def start_test_item(self,
601605
start_time,
602606
item_type,
603607
self.launch_uuid,
604-
attributes=verify_value_length(attributes),
608+
attributes=verify_value_length(attributes) if self.truncate_attributes else attributes,
605609
code_ref=code_ref,
606610
description=description,
607611
has_stats=has_stats,
@@ -655,7 +659,7 @@ def finish_test_item(self,
655659
end_time,
656660
self.launch_uuid,
657661
status,
658-
attributes=attributes,
662+
attributes=verify_value_length(attributes) if self.truncate_attributes else attributes,
659663
description=description,
660664
is_skipped_an_issue=self.is_skipped_an_issue,
661665
issue=issue,
@@ -691,7 +695,7 @@ def finish_launch(self,
691695
request_payload = LaunchFinishRequest(
692696
end_time,
693697
status=status,
694-
attributes=attributes,
698+
attributes=verify_value_length(attributes) if self.truncate_attributes else attributes,
695699
description=kwargs.get('description')
696700
).payload
697701
response = HttpRequest(self.session.put, url=url, json=request_payload,
@@ -718,7 +722,7 @@ def update_test_item(self, item_uuid: str, attributes: Optional[Union[list, dict
718722
"""
719723
data = {
720724
'description': description,
721-
'attributes': verify_value_length(attributes),
725+
'attributes': verify_value_length(attributes) if self.truncate_attributes else attributes,
722726
}
723727
item_id = self.get_item_id_by_uuid(item_uuid)
724728
url = uri_join(self.base_url_v1, 'item', item_id, 'update')

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from setuptools import setup, find_packages
66

7-
__version__ = '5.5.1'
7+
__version__ = '5.5.2'
88

99
TYPE_STUBS = ['*.pyi']
1010

tests/aio/test_aio_client.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,3 +772,31 @@ async def test_get_launch_ui_url(aio_client: Client):
772772
session.get.assert_called_once()
773773
call_args = session.get.call_args_list[0]
774774
assert expected_uri == call_args[0][0]
775+
776+
777+
@pytest.mark.skipif(sys.version_info < (3, 8),
778+
reason='the test requires AsyncMock which was introduced in Python 3.8')
779+
@pytest.mark.parametrize(
780+
'method, mock_method, call_method, arguments',
781+
[
782+
('start_launch', mock_basic_post_response, 'post', ['Test Launch', timestamp()]),
783+
('start_test_item', mock_basic_post_response, 'post', ['test_launch_uuid', 'Test Item', timestamp(),
784+
'SUITE']),
785+
('finish_test_item', mock_basic_post_response, 'put', ['test_launch_uuid', 'test_item_uuid',
786+
timestamp()]),
787+
('finish_launch', mock_basic_post_response, 'put', ['test_launch_uuid', timestamp()]),
788+
('update_test_item', mock_basic_post_response, 'put', ['test_item_uuid']),
789+
]
790+
)
791+
@pytest.mark.asyncio
792+
async def test_attribute_truncation(aio_client: Client, method, mock_method, call_method, arguments):
793+
# noinspection PyTypeChecker
794+
session: mock.AsyncMock = await aio_client.session()
795+
mock_method(session)
796+
797+
await getattr(aio_client, method)(*arguments, **{'attributes': {'key': 'value' * 26}})
798+
getattr(session, call_method).assert_called_once()
799+
kwargs = getattr(session, call_method).call_args_list[0][1]
800+
assert 'attributes' in kwargs['json']
801+
assert kwargs['json']['attributes']
802+
assert len(kwargs['json']['attributes'][0]['value']) == 128

tests/test_client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,27 @@ def test_client_pickling():
237237
pickled_client = pickle.dumps(client)
238238
unpickled_client = pickle.loads(pickled_client)
239239
assert unpickled_client is not None
240+
241+
242+
@pytest.mark.parametrize(
243+
'method, call_method, arguments',
244+
[
245+
('start_launch', 'post', ['Test Launch', timestamp()]),
246+
('start_test_item', 'post', ['Test Item', timestamp(), 'SUITE']),
247+
('finish_test_item', 'put', ['test_item_uuid', timestamp()]),
248+
('finish_launch', 'put', [timestamp()]),
249+
('update_test_item', 'put', ['test_item_uuid']),
250+
]
251+
)
252+
def test_attribute_truncation(rp_client: RPClient, method, call_method, arguments):
253+
# noinspection PyTypeChecker
254+
session: mock.Mock = rp_client.session
255+
if method != 'start_launch':
256+
rp_client._RPClient__launch_uuid = 'test_launch_id'
257+
258+
getattr(rp_client, method)(*arguments, **{'attributes': {'key': 'value' * 26}})
259+
getattr(session, call_method).assert_called_once()
260+
kwargs = getattr(session, call_method).call_args_list[0][1]
261+
assert 'attributes' in kwargs['json']
262+
assert kwargs['json']['attributes']
263+
assert len(kwargs['json']['attributes'][0]['value']) == 128

0 commit comments

Comments
 (0)