Skip to content

Commit 8e99672

Browse files
committed
Config variables override by environment variables logic, fixes #408
1 parent 5b84bff commit 8e99672

File tree

4 files changed

+72
-14
lines changed

4 files changed

+72
-14
lines changed

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+
- Config variables override by environment variables logic, by @HardNorth
46

57
## [5.6.0]
68
### Added

pytest_reportportal/config.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
"""This module contains class that stores RP agent configuration data."""
1515

16+
import logging
1617
import warnings
1718
from os import getenv
1819
from typing import Any, Optional, Union
@@ -22,12 +23,6 @@
2223
from reportportal_client.helpers import to_bool
2324
from reportportal_client.logs import MAX_LOG_BATCH_PAYLOAD_SIZE
2425

25-
try:
26-
# This try/except can go away once we support pytest >= 5.4.0
27-
from _pytest.logging import get_actual_log_level
28-
except ImportError:
29-
from _pytest.logging import get_log_level_for_setting as get_actual_log_level
30-
3126

3227
class AgentConfig:
3328
"""Storage for the RP agent initialization attributes."""
@@ -86,9 +81,9 @@ class AgentConfig:
8681

8782
def __init__(self, pytest_config: Config) -> None:
8883
"""Initialize required attributes."""
89-
self.rp_enabled = to_bool(getattr(pytest_config.option, "rp_enabled", True))
90-
self.rp_rerun = pytest_config.option.rp_rerun or pytest_config.getini("rp_rerun")
91-
self.rp_endpoint = getenv("RP_ENDPOINT") or self.find_option(pytest_config, "rp_endpoint")
84+
self.rp_enabled = to_bool(self.find_option(pytest_config, "rp_enabled", True))
85+
self.rp_rerun = self.find_option(pytest_config, "rp_rerun")
86+
self.rp_endpoint = self.find_option(pytest_config, "rp_endpoint")
9287
self.rp_hierarchy_code = to_bool(self.find_option(pytest_config, "rp_hierarchy_code"))
9388
self.rp_dir_level = int(self.find_option(pytest_config, "rp_hierarchy_dirs_level"))
9489
self.rp_hierarchy_dirs = to_bool(self.find_option(pytest_config, "rp_hierarchy_dirs"))
@@ -133,7 +128,13 @@ def __init__(self, pytest_config: Config) -> None:
133128
else:
134129
self.rp_log_batch_payload_limit = MAX_LOG_BATCH_PAYLOAD_SIZE
135130

136-
self.rp_log_level = get_actual_log_level(pytest_config, "rp_log_level")
131+
log_level = self.find_option(pytest_config, "rp_log_level")
132+
if not log_level:
133+
self.rp_log_level = None
134+
elif isinstance(log_level, int):
135+
self.rp_log_level = log_level
136+
else:
137+
self.rp_log_level = int(getattr(logging, str(log_level).upper(), log_level))
137138
self.rp_log_format = self.find_option(pytest_config, "rp_log_format")
138139
self.rp_thread_logging = to_bool(self.find_option(pytest_config, "rp_thread_logging") or False)
139140
self.rp_mode = self.find_option(pytest_config, "rp_mode")
@@ -145,7 +146,7 @@ def __init__(self, pytest_config: Config) -> None:
145146
self.rp_api_retries = rp_api_retries_str and int(rp_api_retries_str)
146147

147148
# API key auth parameter
148-
self.rp_api_key = getenv("RP_API_KEY") or self.find_option(pytest_config, "rp_api_key")
149+
self.rp_api_key = self.find_option(pytest_config, "rp_api_key")
149150

150151
# OAuth 2.0 parameters
151152
self.rp_oauth_uri = self.find_option(pytest_config, "rp_oauth_uri")
@@ -197,15 +198,23 @@ def find_option(self, pytest_config: Config, option_name: str, default: Any = No
197198
198199
The value is retrieved in the following places in priority order:
199200
200-
1. From `self.pconfig.option.[option_name]`.
201-
2. From `self.pconfig.getini(option_name)`.
201+
1. From environment variable ``option_name.upper()`` (e.g. ``rp_endpoint`` -> ``RP_ENDPOINT``).
202+
2. From ``pytest_config.option.<option_name>``.
203+
3. From ``pytest_config.getini(option_name)``.
204+
4. ``default`` value.
202205
203206
:param pytest_config: config object of PyTest
204207
:param option_name: name of the option
205208
:param default: value to be returned if not found
206209
:return: option value
207210
"""
208-
value = getattr(pytest_config.option, option_name, None) or pytest_config.getini(option_name)
211+
env_value = getenv(option_name.upper())
212+
if env_value:
213+
return env_value
214+
value = getattr(pytest_config.option, option_name, None)
215+
if value is not None:
216+
return value
217+
value = pytest_config.getini(option_name)
209218
if isinstance(value, bool):
210219
return value
211220
return value or default

tests/unit/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ def getoption_side_effect(name, default=None):
7070
mocked_config.option.rp_hierarchy_dirs = "False"
7171
mocked_config.option.rp_hierarchy_test_file = "True"
7272
mocked_config.option.rp_skip_connection_test = "False"
73+
mocked_config.option.rp_enabled = True
74+
mocked_config.option.rp_log_level = "debug"
7375
return mocked_config
7476

7577

tests/unit/test_config.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,48 @@ def test_verify_ssl_true(mocked_config, verify_ssl, expected_result):
3434
config = AgentConfig(mocked_config)
3535

3636
assert config.rp_verify_ssl == expected_result
37+
38+
39+
@pytest.mark.parametrize(
40+
["env_var", "env_value", "config_attr", "expected"],
41+
[
42+
("RP_ENDPOINT", "http://env.example.com", "rp_endpoint", "http://env.example.com"),
43+
("RP_PROJECT", "env_project", "rp_project", "env_project"),
44+
("RP_LAUNCH", "env_launch", "rp_launch", "env_launch"),
45+
("RP_API_KEY", "env_api_key", "rp_api_key", "env_api_key"),
46+
("RP_LAUNCH_ID", "env_launch_id", "rp_launch_id", "env_launch_id"),
47+
("RP_MODE", "DEBUG", "rp_mode", "DEBUG"),
48+
("RP_PARENT_ITEM_ID", "env_parent_id", "rp_parent_item_id", "env_parent_id"),
49+
("RP_RERUN_OF", "env_rerun_of", "rp_rerun_of", "env_rerun_of"),
50+
],
51+
)
52+
def test_env_var_overrides_config(monkeypatch, mocked_config, env_var, env_value, config_attr, expected):
53+
monkeypatch.setenv(env_var, env_value)
54+
config = AgentConfig(mocked_config)
55+
assert getattr(config, config_attr) == expected
56+
57+
58+
def test_env_var_overrides_verify_ssl(monkeypatch, mocked_config):
59+
monkeypatch.setenv("RP_VERIFY_SSL", "False")
60+
config = AgentConfig(mocked_config)
61+
assert config.rp_verify_ssl is False
62+
63+
64+
def test_env_var_overrides_enabled(monkeypatch, mocked_config):
65+
mocked_config.option.rp_enabled = False
66+
monkeypatch.setenv("RP_ENABLED", "True")
67+
config = AgentConfig(mocked_config)
68+
assert config.rp_enabled is True
69+
70+
71+
def test_env_var_overrides_log_level(monkeypatch, mocked_config):
72+
import logging
73+
74+
monkeypatch.setenv("RP_LOG_LEVEL", "ERROR")
75+
config = AgentConfig(mocked_config)
76+
assert config.rp_log_level == logging.ERROR
77+
78+
79+
def test_env_var_not_set_falls_back_to_config(mocked_config):
80+
config = AgentConfig(mocked_config)
81+
assert config.rp_endpoint == "http://docker.local:8080/"

0 commit comments

Comments
 (0)