Skip to content

Commit 1f5a788

Browse files
committed
Attribute splitting
1 parent 9bc9165 commit 1f5a788

4 files changed

Lines changed: 93 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Changelog
22

33
## [Unreleased]
4+
### Added
5+
- Attribute splitting if they are passed as `str` in configs, by @HardNorth
46

57
## [5.6.6]
68
### Added

pytest_reportportal/config.py

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

2626

27+
ATTRIBUTES_SEPARATOR = ";"
28+
29+
30+
def normalize_attributes(attributes: Optional[Any]) -> Optional[Any]:
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+
44+
2745
class AgentConfig:
2846
"""Storage for the RP agent initialization attributes."""
2947

@@ -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")

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)