Skip to content

Commit c1d1065

Browse files
authored
♻️ Maintenance: Unify ApplicationSettings Testing Across Services and Prepare for External Env File Support (#7919)
1 parent 6903354 commit c1d1065

File tree

26 files changed

+230
-109
lines changed

26 files changed

+230
-109
lines changed

.vscode/launch.template.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,28 @@
4444
"justMyCode": false
4545
},
4646
{
47+
// This test adds --external-envfile and expects a file named ".secrets" in the workspace root.
48+
"name": "Python: Test w/ repo.config",
49+
"type": "debugpy",
50+
"request": "launch",
51+
"module": "pytest",
52+
"args": [
53+
"--ff",
54+
"--log-cli-level=INFO",
55+
"--external-envfile=${workspaceFolder}/.secrets",
56+
"--pdb",
57+
"--setup-show",
58+
"--durations=5",
59+
"-s",
60+
"-vv",
61+
"${file}"
62+
],
63+
"cwd": "${workspaceFolder}",
64+
"console": "integratedTerminal",
65+
"justMyCode": false
66+
},
67+
{
68+
// This tests enables the httpx spy and dumps captures in a json. Mainly for api-server
4769
"name": "Python: Test-Httpx-Spy",
4870
"type": "debugpy",
4971
"request": "launch",

packages/pytest-simcore/src/pytest_simcore/environment_configs.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# pylint: disable=unused-variable
44

55

6+
import logging
67
import re
78
from pathlib import Path
89
from typing import Any
@@ -12,6 +13,8 @@
1213
from .helpers.monkeypatch_envs import load_dotenv, setenvs_from_dict
1314
from .helpers.typing_env import EnvVarsDict
1415

16+
_logger = logging.getLogger(__name__)
17+
1518

1619
def pytest_addoption(parser: pytest.Parser):
1720
simcore_group = parser.getgroup("simcore")
@@ -20,12 +23,17 @@ def pytest_addoption(parser: pytest.Parser):
2023
action="store",
2124
type=Path,
2225
default=None,
23-
help="Path to an env file. Consider passing a link to repo configs, i.e. `ln -s /path/to/osparc-ops-config/repo.config`",
26+
help="Path to an env file. Replaces .env-devel in the tests by an external envfile."
27+
"e.g. consider "
28+
" `ln -s /path/to/osparc-ops-config/repo.config .secrets` and then "
29+
" `pytest --external-envfile=.secrets --pdb tests/unit/test_core_settings.py`",
2430
)
2531

2632

2733
@pytest.fixture(scope="session")
28-
def external_envfile_dict(request: pytest.FixtureRequest) -> EnvVarsDict:
34+
def external_envfile_dict(
35+
request: pytest.FixtureRequest, osparc_simcore_root_dir: Path
36+
) -> EnvVarsDict:
2937
"""
3038
If a file under test folder prefixed with `.env-secret` is present,
3139
then this fixture captures it.
@@ -35,19 +43,43 @@ def external_envfile_dict(request: pytest.FixtureRequest) -> EnvVarsDict:
3543
"""
3644
envs = {}
3745
if envfile := request.config.getoption("--external-envfile"):
38-
print("🚨 EXTERNAL `envfile` option detected. Loading", envfile, "...")
46+
_logger.warning(
47+
"🚨 EXTERNAL `envfile` option detected. Loading '%s' ...", envfile
48+
)
3949

4050
assert isinstance(envfile, Path)
4151
assert envfile.exists()
4252
assert envfile.is_file()
4353

54+
envfile = envfile.resolve()
55+
osparc_simcore_root_dir = osparc_simcore_root_dir.resolve()
56+
57+
if osparc_simcore_root_dir in envfile.parents and not any(
58+
term in envfile.name.lower() for term in ("ignore", "secret")
59+
):
60+
_logger.warning(
61+
"🚨 CAUTION: The external envfile '%s' may contain sensitive data and could be accidentally versioned. "
62+
"To prevent this, include the words 'secret' or 'ignore' in the filename.",
63+
envfile.name,
64+
)
65+
4466
envs = load_dotenv(envfile)
4567

68+
if envs:
69+
response = input(
70+
f"🚨 CAUTION: You are about to run tests using environment variables loaded from '{envfile}'.\n"
71+
"This may cause tests to interact with or modify real external systems (e.g., production or staging environments).\n"
72+
"Proceeding could result in data loss or unintended side effects.\n"
73+
"Are you sure you want to continue? [y/N]: "
74+
)
75+
if response.strip().lower() not in ("y", "yes"):
76+
pytest.exit("Aborted by user due to external envfile usage.")
77+
4678
return envs
4779

4880

4981
@pytest.fixture(scope="session")
50-
def skip_if_external_envfile_dict(external_envfile_dict: EnvVarsDict) -> None:
82+
def skip_if_no_external_envfile(external_envfile_dict: EnvVarsDict) -> None:
5183
if not external_envfile_dict:
5284
pytest.skip(reason="Skipping test since external-envfile is not set")
5385

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# pylint: disable=unused-variable
2+
# pylint: disable=unused-argument
3+
# pylint: disable=redefined-outer-name
4+
5+
6+
from pytest_simcore.helpers.monkeypatch_envs import (
7+
EnvVarsDict,
8+
)
9+
from simcore_service_agent.core.settings import ApplicationSettings
10+
11+
12+
def test_valid_application_settings(mock_environment: EnvVarsDict):
13+
assert mock_environment
14+
15+
settings = ApplicationSettings() # type: ignore
16+
assert settings
17+
18+
assert settings == ApplicationSettings.create_from_envs()

services/api-server/src/simcore_service_api_server/api/dependencies/models_schemas_jobs_filters.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ def get_job_metadata_filter(
1818
*Format*: `key:pattern` where pattern can contain glob wildcards
1919
"""
2020
),
21-
example=["key1:val*", "key2:exactval"],
21+
examples=[
22+
["key1:val*", "key2:exactval"],
23+
],
2224
),
2325
] = None,
2426
) -> JobMetadataFilter | None:

services/api-server/tests/unit/test_core_settings.py

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,16 @@
33
# pylint: disable=redefined-outer-name
44

55

6-
import pytest
76
from pytest_simcore.helpers.monkeypatch_envs import (
87
EnvVarsDict,
9-
delenvs_from_dict,
10-
setenvs_from_dict,
118
)
129
from simcore_service_api_server.core.settings import ApplicationSettings
1310

1411

15-
@pytest.fixture
16-
def app_environment(
17-
monkeypatch: pytest.MonkeyPatch,
18-
app_environment: EnvVarsDict,
19-
external_envfile_dict: EnvVarsDict,
20-
) -> EnvVarsDict:
21-
"""
22-
NOTE: To run against repo.config in osparc-config repo
23-
24-
ln -s /path/to/osparc-config/deployments/mydeploy.com/repo.config .secrets
25-
pytest --external-envfile=.secrets tests/unit/test_core_settings.py
26-
27-
"""
28-
if external_envfile_dict:
29-
delenvs_from_dict(monkeypatch, app_environment, raising=False)
30-
return setenvs_from_dict(
31-
monkeypatch,
32-
{**external_envfile_dict},
33-
)
34-
return app_environment
12+
def test_valid_application_settings(app_environment: EnvVarsDict):
13+
assert app_environment
3514

15+
settings = ApplicationSettings() # type: ignore
16+
assert settings
3617

37-
def test_unit_app_environment(app_environment: EnvVarsDict):
38-
assert app_environment
39-
settings = ApplicationSettings.create_from_envs()
40-
print("captured settings: \n", settings.model_dump_json(indent=2))
18+
assert settings == ApplicationSettings.create_from_envs()

services/autoscaling/tests/unit/test_core_settings.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
# pylint: disable=redefined-outer-name
33
# pylint: disable=unused-argument
44
# pylint: disable=unused-variable
5+
"""
6+
We can validate actual .env files (also refered as `repo.config` files) by passing them via the CLI
57
8+
$ ln -s /path/to/osparc-config/deployments/mydeploy.com/repo.config .secrets
9+
$ pytest --external-envfile=.secrets --pdb tests/unit/test_core_settings.py
10+
11+
"""
612
import datetime
713
import json
814
import logging

services/autoscaling/tests/unit/test_modules_auto_scaling_dynamic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ async def test_cluster_scaling_up_and_down(
10691069
],
10701070
)
10711071
async def test_cluster_scaling_up_and_down_against_aws(
1072-
skip_if_external_envfile_dict: None,
1072+
skip_if_no_external_envfile: None,
10731073
external_ec2_instances_allowed_types: None | dict[str, EC2InstanceBootSpecific],
10741074
with_labelize_drain_nodes: EnvVarsDict,
10751075
app_with_docker_join_drained: EnvVarsDict,

services/autoscaling/tests/unit/test_modules_buffer_machine_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ def pre_pull_images(
532532

533533

534534
async def test_monitor_buffer_machines_against_aws(
535-
skip_if_external_envfile_dict: None,
535+
skip_if_no_external_envfile: None,
536536
disable_buffers_pool_background_task: None,
537537
disable_autoscaling_background_task: None,
538538
disabled_rabbitmq: None,

services/catalog/tests/unit/conftest.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@
1515
import pytest
1616
import respx
1717
import simcore_service_catalog
18-
import simcore_service_catalog.core.application
1918
import simcore_service_catalog.core.events
20-
import simcore_service_catalog.repository
21-
import simcore_service_catalog.repository.events
2219
import yaml
2320
from asgi_lifespan import LifespanManager
2421
from faker import Faker

services/catalog/tests/unit/test_core_settings.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,13 @@
33
# pylint: disable=unused-variable
44
# pylint: disable=too-many-arguments
55

6-
76
from pytest_simcore.helpers.typing_env import EnvVarsDict
87
from simcore_service_catalog.core.settings import ApplicationSettings
98

109

11-
def test_valid_web_application_settings(app_environment: EnvVarsDict):
12-
"""
13-
We can validate actual .env files (also refered as `repo.config` files) by passing them via the CLI
14-
15-
$ ln -s /path/to/osparc-config/deployments/mydeploy.com/repo.config .secrets
16-
$ pytest --external-envfile=.secrets --pdb tests/unit/test_core_settings.py
10+
def test_valid_application_settings(app_environment: EnvVarsDict):
11+
assert app_environment
1712

18-
"""
1913
settings = ApplicationSettings() # type: ignore
2014
assert settings
2115

0 commit comments

Comments
 (0)