Skip to content

Commit

Permalink
Use client factory, add several configuration variables
Browse files Browse the repository at this point in the history
  • Loading branch information
HardNorth committed Oct 16, 2023
1 parent de2124e commit 8a1c1a8
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 66 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Changelog

## [Unreleased]
### Added
- `RP_CLIENT_TYPE` configuration variable, by @HardNorth
- `RP_CONNECT_TIMEOUT` and `RP_READ_TIMEOUT` configuration variables, by @HardNorth
### Changed
- Client version updated on [5.5.0](https://github.com/reportportal/client-Python/releases/tag/5.5.0), by @HardNorth
### Removed
- Dependency on `six`, by @HardNorth

Expand Down
28 changes: 7 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![PyPI](https://img.shields.io/pypi/v/robotframework-reportportal.svg?maxAge=259200)](https://pypi.python.org/pypi/robotframework-reportportal)
[![Python versions](https://img.shields.io/pypi/pyversions/robotframework-reportportal.svg)](https://pypi.org/project/robotframework-reportportal)
[![Build Status](https://github.com/reportportal/agent-Python-RobotFramework/actions/workflows/tests.yml/badge.svg)](https://github.com/reportportal/agent-Python-RobotFramework/actions/workflows/tests.yml)
[![codecov.io](https://codecov.io/gh/reportportal/agent-Python-RobotFramework/branch/master/graph/badge.svg)](https://codecov.io/gh/reportportal/agent-Python-RobotFramework)
[![codecov.io](https://codecov.io/gh/reportportal/agent-Python-RobotFramework/branch/develop/graph/badge.svg)](https://codecov.io/gh/reportportal/agent-Python-RobotFramework)
[![Join Slack chat!](https://slack.epmrpp.reportportal.io/badge.svg)](https://slack.epmrpp.reportportal.io/)
[![stackoverflow](https://img.shields.io/badge/reportportal-stackoverflow-orange.svg?style=flat)](http://stackoverflow.com/questions/tagged/reportportal)
[![Build with Love](https://img.shields.io/badge/build%20with-❤%EF%B8%8F%E2%80%8D-lightgrey.svg)](http://reportportal.io?style=flat)
Expand All @@ -26,26 +26,6 @@ The latest stable version of library is available on PyPI:

pip install robotframework-reportportal

[reportportal-client](https://github.com/reportportal/client-Python)
and [six](https://pypi.org/project/six/) will be installed as dependencies

**IMPORTANT!**
The latest version **does not** support Report Portal versions below 5.0.0.

Specify the last one release of the client version 3 to install or update the
client for other versions of Report Portal below 5.0.0:

```
pip install robotframework-reportportal~=3.0
```

## Contribution

All the fixes for the agent that supports Report Portal versions below 5.0.0
should go into the v3 branch.
The master branch will store the code base for the agent for Report Portal
versions 5 and above.

## Usage

### Properties
Expand All @@ -66,6 +46,8 @@ REQUIRED:
NOT REQUIRED:

```
--variable RP_CLIENT_TYPE:"SYNC"
- Type of the under-the-hood ReportPortal client implamentation. Possible values: [SYNC, ASYNC_THREAD, ASYNC_BATCHED].
--variable RP_LAUNCH_UUID:"id_of_existing_rp_launch"
- ID of existing Report Portal launch
--variable RP_LAUNCH_DOC:"some_documentation_for_launch"
Expand All @@ -78,6 +60,10 @@ NOT REQUIRED:
- Default value is "stdout", Launch UUID print output. Possible values: [stderr, stdout].
--variable RP_TEST_ATTRIBUTES:"key1:value1 key1:value2 tag key2:value3"
- Space-separated list of tags/attributes for the tests
--variable RP_CONNECT_TIMEOUT:"20"
- Default value is "10.0", connection timeout to ReportPortal server.
--variable RP_READ_TIMEOUT:"20"
- Default value is "10.0", response read timeout for ReportPortal connection.
--variable RP_LOG_BATCH_SIZE:"10"
- Default value is "20", affects size of async batch log requests
--variable RP_LOG_BATCH_PAYLOAD_SIZE:"10240000"
Expand Down
13 changes: 3 additions & 10 deletions robotframework_reportportal/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from queue import LifoQueue
from warnings import warn

from reportportal_client.helpers import gen_attributes
from reportportal_client.helpers import gen_attributes, LifoQueue

from .model import Keyword, Launch, Test, LogMessage, Suite
from .service import RobotService
Expand All @@ -32,13 +32,6 @@
logger = logging.getLogger(__name__)


class _LifoQueue(LifoQueue):
def last(self):
with self.mutex:
if self._qsize():
return self.queue[-1]


def check_rp_enabled(func):
"""Verify is RP is enabled in config."""
@wraps(func)
Expand All @@ -54,14 +47,14 @@ def wrap(*args, **kwargs):
class listener:
"""Robot Framework listener interface for reporting to Report Portal."""

_items: _LifoQueue = ...
_items: LifoQueue = ...
_service: Optional[RobotService] = ...
_variables: Optional[Variables] = ...
ROBOT_LISTENER_API_VERSION = 2

def __init__(self) -> None:
"""Initialize listener attributes."""
self._items = _LifoQueue()
self._items = LifoQueue()
self._service = None
self._variables = None

Expand Down
35 changes: 12 additions & 23 deletions robotframework_reportportal/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,6 @@

from typing import Optional

# Copyright (c) 2023 EPAM Systems
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

from dateutil.parser import parse
import logging

Expand All @@ -38,7 +25,7 @@
get_package_version,
timestamp
)
from reportportal_client.client import RPClient
from reportportal_client import RP, create_client

from .model import Launch, Suite, Test, Keyword, LogMessage
from .variables import Variables
Expand Down Expand Up @@ -70,7 +57,7 @@ class RobotService(object):

agent_name: str
agent_version: str
rp: Optional[RPClient]
rp: Optional[RP]

def __init__(self) -> None:
"""Initialize service attributes."""
Expand All @@ -95,28 +82,30 @@ def init_service(self, variables: Variables) -> None:
:param variables: Report Portal variables
"""
if self.rp is None:
logger.debug(f'ReportPortal - Init service: endpoint={variables.endpoint}, project={variables.project}, '
f'api_key={variables.api_key}')
self.rp = RPClient(
logger.debug(f'ReportPortal - Init service: endpoint={variables.endpoint}, '
f'project={variables.project}, api_key={variables.api_key}')

self.rp = create_client(
client_type=variables.client_type,
endpoint=variables.endpoint,
project=variables.project,
api_key=variables.api_key,
is_skipped_an_issue=variables.skipped_issue,
log_batch_size=variables.log_batch_size,
retries=True,
retries=5,
verify_ssl=variables.verify_ssl,
max_pool_size=variables.pool_size,
log_batch_payload_size=variables.log_batch_payload_size,
launch_id=variables.launch_id,
launch_uuid_print=variables.launch_uuid_print,
print_output=variables.launch_uuid_print_output
print_output=variables.launch_uuid_print_output,
http_timeout=variables.http_timeout
)
self.rp.start()

def terminate_service(self) -> None:
"""Terminate common reportportal client."""
"""Terminate common ReportPortal client."""
if self.rp:
self.rp.terminate()
self.rp.close()

def start_launch(self, launch: Launch, mode: Optional[str] = None, rerun: bool = False,
rerun_of: Optional[str] = None,
Expand Down
21 changes: 18 additions & 3 deletions robotframework_reportportal/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@

from distutils.util import strtobool
from os import path
from typing import Optional, Union, Dict, Any
from typing import Optional, Union, Dict, Tuple, Any
from warnings import warn

from reportportal_client import OutputType
from reportportal_client import OutputType, ClientType
from reportportal_client.logs import MAX_LOG_BATCH_PAYLOAD_SIZE
from robot.libraries.BuiltIn import BuiltIn, RobotNotRunningError

Expand Down Expand Up @@ -65,7 +65,8 @@ class Variables:
log_batch_payload_size: int = ...
launch_uuid_print: bool
launch_uuid_print_output: Optional[OutputType]
client_type: []
client_type: Optional[ClientType]
http_timeout: Optional[Union[Tuple[float, float], float]]

def __init__(self) -> None:
"""Initialize instance attributes."""
Expand Down Expand Up @@ -102,6 +103,20 @@ def __init__(self) -> None:
self.launch_uuid_print = bool(strtobool(get_variable('RP_LAUNCH_UUID_PRINT', default='False')))
output_type = get_variable('RP_LAUNCH_UUID_PRINT_OUTPUT')
self.launch_uuid_print_output = OutputType[output_type.upper()] if output_type else None
client_type = get_variable('RP_CLIENT_TYPE')
self.client_type = ClientType[client_type.upper()] if client_type else ClientType.SYNC
connect_timeout = get_variable('RP_CONNECT_TIMEOUT')
connect_timeout = float(connect_timeout) if connect_timeout else None

read_timeout = get_variable('RP_READ_TIMEOUT')
read_timeout = float(read_timeout) if read_timeout else None

if connect_timeout is None and read_timeout is None:
self.http_timeout = None
elif connect_timeout is not None and read_timeout is not None:
self.http_timeout = (connect_timeout, read_timeout)
else:
self.http_timeout = connect_timeout or read_timeout

self.api_key = get_variable('RP_API_KEY')
if not self.api_key:
Expand Down
2 changes: 1 addition & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
limitations under the License
"""

REPORT_PORTAL_SERVICE = 'robotframework_reportportal.service.RPClient'
REPORT_PORTAL_SERVICE = 'reportportal_client.RPClient'
61 changes: 53 additions & 8 deletions tests/integration/test_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import sys
import warnings
from unittest import mock

# noinspection PyPackageRequirements
import pytest
from reportportal_client import OutputType, RPClient, ThreadedRPClient, BatchedRPClient

from reportportal_client import OutputType
from tests import REPORT_PORTAL_SERVICE
from tests.helpers import utils

Expand Down Expand Up @@ -56,9 +56,6 @@ def test_agent_pass_launch_uuid_variable(mock_client_init):
assert mock_client.start_launch.call_count == 0


@pytest.mark.skipif(sys.version_info < (3, 6),
reason='For some reasons the test passes only for the '
'first variable for Python 2.7')
@pytest.mark.parametrize('variable, warn_num',
[('RP_PROJECT', 1), ('RP_API_KEY', 2),
('RP_ENDPOINT', 1), ('RP_LAUNCH', 1)])
Expand Down Expand Up @@ -188,7 +185,8 @@ def test_launch_uuid_print(mock_client_init):
def test_launch_uuid_print_stderr(mock_client_init):
print_uuid = True
variables = utils.DEFAULT_VARIABLES.copy()
variables.update({'RP_LAUNCH_UUID_PRINT': str(print_uuid), 'RP_LAUNCH_UUID_PRINT_OUTPUT': 'stderr'}.items())
variables.update(
{'RP_LAUNCH_UUID_PRINT': str(print_uuid), 'RP_LAUNCH_UUID_PRINT_OUTPUT': 'stderr'}.items())

result = utils.run_robot_tests(['examples/simple.robot'], variables=variables)

Expand Down Expand Up @@ -216,10 +214,57 @@ def test_launch_uuid_print_invalid_output(mock_client_init):
def test_no_launch_uuid_print(mock_client_init):
variables = utils.DEFAULT_VARIABLES.copy()

result = utils.run_robot_tests(['examples/simple.robot'],
variables=variables)
result = utils.run_robot_tests(['examples/simple.robot'], variables=variables)

assert int(result) == 0, 'Exit code should be 0 (no errors)'
assert mock_client_init.call_count == 1
assert mock_client_init.call_args_list[0][1]['launch_uuid_print'] is False
assert mock_client_init.call_args_list[0][1]['print_output'] is None


@pytest.mark.parametrize(
'variable_value, expected_type',
[('SYNC', RPClient), ('ASYNC_THREAD', ThreadedRPClient),
('ASYNC_BATCHED', BatchedRPClient), (None, RPClient)]
)
@mock.patch('reportportal_client.aio.client.Client')
@mock.patch(REPORT_PORTAL_SERVICE)
def test_client_types(mock_client_init, mock_async_client_init, variable_value, expected_type):
variables = utils.DEFAULT_VARIABLES.copy()
if variable_value:
variables['RP_CLIENT_TYPE'] = variable_value

result = utils.run_robot_tests(['examples/simple.robot'], variables=variables)

assert int(result) == 0, 'Exit code should be 0 (no errors)'
if expected_type is RPClient:
assert mock_async_client_init.call_count == 0
assert mock_client_init.call_count == 1
else:
assert mock_async_client_init.call_count == 1
assert mock_client_init.call_count == 0


@pytest.mark.parametrize(
'connect_value, read_value, expected_result',
[
('5', '15', (5.0, 15.0)),
('5.5', '15.5', (5.5, 15.5)),
(None, None, None),
(None, '5', 5),
('5', None, 5)
]
)
@mock.patch(REPORT_PORTAL_SERVICE)
def test_client_types(mock_client_init, connect_value, read_value, expected_result):
variables = utils.DEFAULT_VARIABLES.copy()
if connect_value:
variables['RP_CONNECT_TIMEOUT'] = connect_value
if read_value:
variables['RP_READ_TIMEOUT'] = read_value

result = utils.run_robot_tests(['examples/simple.robot'], variables=variables)

assert int(result) == 0, 'Exit code should be 0 (no errors)'
assert mock_client_init.call_count == 1
assert mock_client_init.call_args_list[0][1]['http_timeout'] == expected_result

0 comments on commit 8a1c1a8

Please sign in to comment.