Skip to content

Commit 6b2d1c4

Browse files
authored
Merge pull request #422 from reportportal/develop
Release
2 parents 8bdb705 + 4920dd2 commit 6b2d1c4

5 files changed

Lines changed: 96 additions & 3 deletions

File tree

CHANGELOG.md

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

33
## [Unreleased]
44
### Added
5+
- Attribute splitting if they are passed as `str` in configs, by @HardNorth
6+
7+
## [5.6.6]
8+
### Added
59
- Microseconds precision for timestamps, by @HardNorth
610
### Changed
711
- Client version updated to [5.7.4](https://github.com/reportportal/client-Python/releases/tag/5.7.4), by @HardNorth

pytest_reportportal/config.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@
2323
from reportportal_client.helpers import to_bool
2424
from reportportal_client.logs import MAX_LOG_BATCH_PAYLOAD_SIZE
2525

26+
ATTRIBUTES_SEPARATOR = ";"
27+
28+
29+
def normalize_attributes(attributes: Optional[Any]) -> Optional[Any]:
30+
"""Split a string of attributes into a deduplicated list of attributes."""
31+
if not attributes:
32+
return attributes
33+
if not isinstance(attributes, str):
34+
return attributes
35+
normalized_attributes = []
36+
unique_attributes = set()
37+
for attribute in attributes.split(ATTRIBUTES_SEPARATOR):
38+
attribute = attribute.strip()
39+
if attribute and attribute not in unique_attributes:
40+
unique_attributes.add(attribute)
41+
normalized_attributes.append(attribute)
42+
return normalized_attributes
43+
2644

2745
class AgentConfig:
2846
"""Storage for the RP agent initialization attributes."""
@@ -115,8 +133,8 @@ def __init__(self, pytest_config: Config) -> None:
115133
)
116134
self.rp_launch_uuid = self.find_option(pytest_config, "rp_launch_uuid", self.rp_launch_uuid)
117135

118-
self.rp_launch_attributes = self.find_option(pytest_config, "rp_launch_attributes")
119-
self.rp_tests_attributes = self.find_option(pytest_config, "rp_tests_attributes")
136+
self.rp_launch_attributes = normalize_attributes(self.find_option(pytest_config, "rp_launch_attributes"))
137+
self.rp_tests_attributes = normalize_attributes(self.find_option(pytest_config, "rp_tests_attributes"))
120138
self.rp_launch_description = self.find_option(pytest_config, "rp_launch_description")
121139
self.rp_log_batch_size = int(self.find_option(pytest_config, "rp_log_batch_size"))
122140
batch_payload_size_limit = self.find_option(pytest_config, "rp_log_batch_payload_limit")

setup.py

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

1818
from setuptools import setup
1919

20-
__version__ = "5.6.6"
20+
__version__ = "5.6.7"
2121

2222

2323
def read_file(fname):

tests/integration/test_attributes.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,40 @@ def test_rp_tests_attributes_add(mock_client_init):
168168
assert len(attributes) == 2
169169
assert {"key": "scope", "value": "smoke"} in attributes
170170
assert {"key": "test_key", "value": "test_value"} in attributes
171+
172+
173+
@mock.patch(REPORT_PORTAL_SERVICE)
174+
def test_rp_tests_attributes_string_split_and_deduplicated(mock_client_init, monkeypatch):
175+
"""Verify string `rp_tests_attributes` are split and deduplicated."""
176+
monkeypatch.setenv("RP_TESTS_ATTRIBUTES", " test_key:test_value ; smoke ; test_key:test_value ")
177+
variables = {}
178+
variables.update(utils.DEFAULT_VARIABLES.items())
179+
result = utils.run_pytest_tests(tests=["examples/test_simple.py"], variables=variables)
180+
assert int(result) == 0, "Exit code should be 0 (no errors)"
181+
182+
mock_client = mock_client_init.return_value
183+
assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times'
184+
185+
call_args = mock_client.start_test_item.call_args_list
186+
step_call_args = call_args[-1][1]
187+
actual_attributes = step_call_args["attributes"]
188+
189+
assert utils.attributes_to_tuples(actual_attributes) == {("test_key", "test_value"), (None, "smoke")}
190+
191+
192+
@mock.patch(REPORT_PORTAL_SERVICE)
193+
def test_rp_launch_attributes_string_split_and_deduplicated(mock_client_init, monkeypatch):
194+
"""Verify string `rp_launch_attributes` are split and deduplicated."""
195+
monkeypatch.setenv("RP_LAUNCH_ATTRIBUTES", " launch_key:launch_value ; smoke ; launch_key:launch_value ")
196+
variables = {}
197+
variables.update(utils.DEFAULT_VARIABLES.items())
198+
result = utils.run_pytest_tests(tests=["examples/test_simple.py"], variables=variables)
199+
assert int(result) == 0, "Exit code should be 0 (no errors)"
200+
201+
mock_client = mock_client_init.return_value
202+
assert mock_client.start_launch.call_count > 0, '"start_launch" called incorrect number of times'
203+
204+
launch_call_args = mock_client.start_launch.call_args_list
205+
launch_attributes = launch_call_args[0][1]["attributes"]
206+
207+
assert {("launch_key", "launch_value"), (None, "smoke")} <= utils.attributes_to_tuples(launch_attributes)

tests/unit/test_config.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,37 @@ def test_env_var_overrides_log_level(monkeypatch, mocked_config):
7979
def test_env_var_not_set_falls_back_to_config(mocked_config):
8080
config = AgentConfig(mocked_config)
8181
assert config.rp_endpoint == "http://docker.local:8080/"
82+
83+
84+
@pytest.mark.parametrize(
85+
["option_name", "option_value", "expected_result"],
86+
[
87+
("rp_launch_attributes", " smoke ; launch:demo ; smoke ; launch:demo ", ["smoke", "launch:demo"]),
88+
("rp_tests_attributes", " test:key ; smoke ; test:key ", ["test:key", "smoke"]),
89+
],
90+
)
91+
def test_string_attributes_are_split_and_deduplicated(mocked_config, option_name, option_value, expected_result):
92+
mocked_config.option.rp_launch_attributes = None
93+
mocked_config.option.rp_tests_attributes = None
94+
mocked_config.getini.side_effect = lambda x: option_value if x == option_name else None
95+
96+
config = AgentConfig(mocked_config)
97+
98+
assert getattr(config, option_name) == expected_result
99+
100+
101+
@pytest.mark.parametrize(
102+
["option_name", "option_value"],
103+
[
104+
("rp_launch_attributes", ["smoke", "smoke"]),
105+
("rp_tests_attributes", ["test:key", "test:key"]),
106+
],
107+
)
108+
def test_attributes_not_split_if_not_string(mocked_config, option_name, option_value):
109+
mocked_config.option.rp_launch_attributes = None
110+
mocked_config.option.rp_tests_attributes = None
111+
mocked_config.getini.side_effect = lambda x: option_value if x == option_name else None
112+
113+
config = AgentConfig(mocked_config)
114+
115+
assert getattr(config, option_name) == option_value

0 commit comments

Comments
 (0)