diff --git a/src/ert/config/model_config.py b/src/ert/config/model_config.py index bdde2ab1089..a9f492c8409 100644 --- a/src/ert/config/model_config.py +++ b/src/ert/config/model_config.py @@ -54,6 +54,16 @@ def __init__( self.history_source = history_source self.jobname_format_string = _replace_runpath_format(jobname_format_string) self.eclbase_format_string = _replace_runpath_format(eclbase_format_string) + + count_placeholders = ( + runpath_format_string.count("%d") if runpath_format_string else 0 + ) + + if not count_placeholders in (0, 2): + raise ConfigValidationError( + f"RUNPATH provided is invalid: `{runpath_format_string}`. Valid example `{DEFAULT_RUNPATH}`" + ) + self.runpath_format_string = _replace_runpath_format(runpath_format_string) if self.runpath_format_string is not None and not any( diff --git a/tests/unit_tests/config/test_parser_error_collection.py b/tests/unit_tests/config/test_parser_error_collection.py index e5fa12bfa95..93f066a50cf 100644 --- a/tests/unit_tests/config/test_parser_error_collection.py +++ b/tests/unit_tests/config/test_parser_error_collection.py @@ -942,7 +942,7 @@ def test_that_executable_directory_errors(dirname): ( """ NUM_REALIZATIONS 1 -RUNPATH %d +RUNPATH %d/%d RELPERM MULTZ Hehe 2 l 1 2 diff --git a/tests/unit_tests/test_run_path_creation.py b/tests/unit_tests/test_run_path_creation.py index 4b716e1c4f5..016ccba1d6e 100644 --- a/tests/unit_tests/test_run_path_creation.py +++ b/tests/unit_tests/test_run_path_creation.py @@ -5,7 +5,7 @@ import pytest -from ert.config import ErtConfig +from ert.config import ConfigValidationError, ErtConfig from ert.enkf_main import create_run_path, ensemble_context, sample_prior from ert.run_context import RunContext from ert.runpaths import Runpaths @@ -469,3 +469,35 @@ def test_num_cpu_subst(monkeypatch, tmp_path, append, numcpu, storage): with open("simulations/realization-0/iter-0/jobs.json", encoding="utf-8") as f: assert f'"argList": ["{numcpu}"]' in f.read() + + +@pytest.mark.parametrize( + "run_path, expected_raise", + [ + ("simulations/realizations-/iter-", False), + ("simulations/realizations-/iter-%d", True), + ("simulations/realizations-%d", True), + ("simulations/realizations-%d/iter-%d", False), + ("simulations/realizations-%d/iter-%d/more-%d", True), + ], +) +@pytest.mark.usefixtures("use_tmpdir") +def test_that_runpath_shall_contain_zero_or_two_substitutions(run_path, expected_raise): + """ + This checks that RUNPATH does not include too many or few substitution placeholders + """ + config_text = dedent( + """ + NUM_REALIZATIONS 2 + """ + ) + Path("config.ert").write_text(config_text + f"RUNPATH {run_path}", encoding="utf-8") + + if expected_raise: + with pytest.raises( + ConfigValidationError, + match=f"RUNPATH provided is invalid: `.*{run_path}`.", + ): + _ = ErtConfig.from_file("config.ert") + else: + _ = ErtConfig.from_file("config.ert")