Public Access
DEVX-67: refactor: make molecule weights configurable via pyproject.toml
Post-merge / detect-type (push) Successful in 1m22s
Post-merge / validate-commit-msg (push) Successful in 1m4s
Post-merge / release (push) Successful in 1m15s
Post-merge / sync-wiki (push) Successful in 1m16s
Post-merge / vikunja (push) Successful in 55s
Post-merge / badges (push) Successful in 1m33s
Post-merge / configure-repo (push) Successful in 51s
Post-merge / publish (push) Successful in 1m4s
Post-merge / detect-type (push) Successful in 1m22s
Post-merge / validate-commit-msg (push) Successful in 1m4s
Post-merge / release (push) Successful in 1m15s
Post-merge / sync-wiki (push) Successful in 1m16s
Post-merge / vikunja (push) Successful in 55s
Post-merge / badges (push) Successful in 1m33s
Post-merge / configure-repo (push) Successful in 51s
Post-merge / publish (push) Successful in 1m4s
This commit was merged in pull request #107.
This commit is contained in:
@@ -13,6 +13,7 @@ from devx.molecule.distribute_molecule import (
|
||||
PLATFORMS,
|
||||
MultiRoleTestPair,
|
||||
TestPair,
|
||||
_load_molecule_weights,
|
||||
_lpt_distribute,
|
||||
_scenario_weight,
|
||||
build_multi_role_pairs,
|
||||
@@ -482,42 +483,90 @@ class TestCliMultiRole:
|
||||
|
||||
|
||||
class TestScenarioWeight:
|
||||
def test_known_heavy_scenario(self) -> None:
|
||||
assert _scenario_weight("nextcloud") == 15
|
||||
assert _scenario_weight("gitea") == 8
|
||||
|
||||
def test_known_light_scenario(self) -> None:
|
||||
assert _scenario_weight("binary") == 2
|
||||
|
||||
def test_default_weight(self) -> None:
|
||||
def test_default_weight_no_config(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Without pyproject.toml, all scenarios get the default weight."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
scenario_w, role_w = _load_molecule_weights()
|
||||
assert scenario_w == {}
|
||||
assert role_w == {}
|
||||
assert _scenario_weight("unknown-scenario") == 3
|
||||
|
||||
def test_case_insensitive(self) -> None:
|
||||
assert _scenario_weight("NextCloud") == 15
|
||||
assert _scenario_weight("GITEA") == 8
|
||||
def test_load_weights_from_pyproject(self, tmp_path: Path) -> None:
|
||||
"""Weights are loaded from [tool.devx.molecule.weights] in pyproject.toml."""
|
||||
pyproject = tmp_path / "pyproject.toml"
|
||||
pyproject.write_text(
|
||||
"[tool.devx.molecule.weights]\n"
|
||||
'"nextcloud" = 15\n'
|
||||
'"default" = 3\n'
|
||||
'"binary" = 2\n'
|
||||
'"app_container/customer-apps" = 11\n'
|
||||
'"restore/default" = 11\n'
|
||||
)
|
||||
scenario_w, role_w = _load_molecule_weights(str(pyproject))
|
||||
assert scenario_w == {"nextcloud": 15, "default": 3, "binary": 2}
|
||||
assert role_w == {("app_container", "customer-apps"): 11, ("restore", "default"): 11}
|
||||
|
||||
def test_substring_match(self) -> None:
|
||||
assert _scenario_weight("nextcloud-with-redis") == 15
|
||||
assert _scenario_weight("custom-gitea-setup") == 8
|
||||
|
||||
def test_role_specific_weight(self) -> None:
|
||||
"""Role+scenario pairs take priority over scenario-name-only weights."""
|
||||
assert _scenario_weight("default", "restore") == 11
|
||||
assert _scenario_weight("default", "zitadel") == 10
|
||||
def test_role_specific_takes_priority(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Role-specific weights take priority over scenario-name-only weights."""
|
||||
pyproject = tmp_path / "pyproject.toml"
|
||||
pyproject.write_text(
|
||||
'[tool.devx.molecule.weights]\n"default" = 3\n"docker_base/default" = 8\n"restore/default" = 11\n'
|
||||
)
|
||||
scenario_w, role_w = _load_molecule_weights(str(pyproject))
|
||||
monkeypatch.setattr("devx.molecule.distribute_molecule._SCENARIO_WEIGHTS", scenario_w)
|
||||
monkeypatch.setattr("devx.molecule.distribute_molecule._ROLE_SCENARIO_WEIGHTS", role_w)
|
||||
assert _scenario_weight("default", "docker_base") == 8
|
||||
assert _scenario_weight("default", "app_hardening") == 4
|
||||
assert _scenario_weight("default", "restore") == 11
|
||||
assert _scenario_weight("default", "app_container") == 3
|
||||
assert _scenario_weight("default", "storage") == 3
|
||||
assert _scenario_weight("default", "observability") == 3
|
||||
|
||||
def test_role_specific_overrides_scenario_name(self) -> None:
|
||||
"""vaultwarden has a scenario-name weight of 2, but role-specific is also 2."""
|
||||
assert _scenario_weight("vaultwarden", "app_container") == 2
|
||||
assert _scenario_weight("vaultwarden") == 2
|
||||
def test_case_insensitive(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Weight keys are matched case-insensitively."""
|
||||
pyproject = tmp_path / "pyproject.toml"
|
||||
pyproject.write_text('[tool.devx.molecule.weights]\n"nextcloud" = 15\n')
|
||||
scenario_w, role_w = _load_molecule_weights(str(pyproject))
|
||||
monkeypatch.setattr("devx.molecule.distribute_molecule._SCENARIO_WEIGHTS", scenario_w)
|
||||
monkeypatch.setattr("devx.molecule.distribute_molecule._ROLE_SCENARIO_WEIGHTS", role_w)
|
||||
assert _scenario_weight("NextCloud") == 15
|
||||
assert _scenario_weight("NEXTCLOUD") == 15
|
||||
|
||||
def test_customer_apps_weight(self) -> None:
|
||||
assert _scenario_weight("customer-apps", "app_container") == 11
|
||||
assert _scenario_weight("customer-apps") == 11
|
||||
def test_substring_match(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Scenario-name weights use substring matching."""
|
||||
pyproject = tmp_path / "pyproject.toml"
|
||||
pyproject.write_text('[tool.devx.molecule.weights]\n"nextcloud" = 15\n')
|
||||
scenario_w, role_w = _load_molecule_weights(str(pyproject))
|
||||
monkeypatch.setattr("devx.molecule.distribute_molecule._SCENARIO_WEIGHTS", scenario_w)
|
||||
monkeypatch.setattr("devx.molecule.distribute_molecule._ROLE_SCENARIO_WEIGHTS", role_w)
|
||||
assert _scenario_weight("nextcloud-with-redis") == 15
|
||||
|
||||
def test_no_pyproject_returns_empty(self, tmp_path: Path) -> None:
|
||||
"""Missing pyproject.toml returns empty weight dicts."""
|
||||
scenario_w, role_w = _load_molecule_weights(str(tmp_path / "nonexistent.toml"))
|
||||
assert scenario_w == {}
|
||||
assert role_w == {}
|
||||
|
||||
def test_invalid_weights_ignored(self, tmp_path: Path) -> None:
|
||||
"""Non-integer weight values are silently ignored."""
|
||||
pyproject = tmp_path / "pyproject.toml"
|
||||
pyproject.write_text('[tool.devx.molecule.weights]\n"good" = 5\n"bad" = "not an int"\n')
|
||||
scenario_w, role_w = _load_molecule_weights(str(pyproject))
|
||||
assert scenario_w == {"good": 5}
|
||||
assert role_w == {}
|
||||
|
||||
def test_malformed_toml_returns_empty(self, tmp_path: Path) -> None:
|
||||
"""Malformed TOML returns empty weight dicts."""
|
||||
pyproject = tmp_path / "pyproject.toml"
|
||||
pyproject.write_text("this is not valid toml = = =")
|
||||
scenario_w, role_w = _load_molecule_weights(str(pyproject))
|
||||
assert scenario_w == {}
|
||||
assert role_w == {}
|
||||
|
||||
def test_non_dict_weights_returns_empty(self, tmp_path: Path) -> None:
|
||||
"""If [tool.devx.molecule.weights] is not a table, returns empty dicts."""
|
||||
pyproject = tmp_path / "pyproject.toml"
|
||||
pyproject.write_text('[tool.devx.molecule]\nweights = "not a table"\n')
|
||||
scenario_w, role_w = _load_molecule_weights(str(pyproject))
|
||||
assert scenario_w == {}
|
||||
assert role_w == {}
|
||||
|
||||
|
||||
class TestLptDistribute:
|
||||
|
||||
Reference in New Issue
Block a user