Skip to content

Commit 05f3f6b

Browse files
committed
Avoid mkdir(parents=True) in save_response
This can impliclity create a corrupted storage if it has been deleted in-flight (cherry picked from commit 2760247)
1 parent b859087 commit 05f3f6b

2 files changed

Lines changed: 52 additions & 1 deletion

File tree

src/ert/storage/local_ensemble.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ def save_response(
890890
)
891891

892892
output_path = self._realization_dir(realization)
893-
Path.mkdir(output_path, parents=True, exist_ok=True)
893+
Path(output_path).mkdir(exist_ok=True)
894894

895895
self._storage._to_parquet_transaction(
896896
output_path / f"{response_type}.parquet", data

tests/ert/unit_tests/storage/test_local_storage.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,57 @@ def test_set_failure_will_not_recreate_ensemble_directory(storage):
11131113
assert not dummy_ensemble._path.exists()
11141114

11151115

1116+
def test_save_response_will_create_realization_directory(storage):
1117+
# Given a fresh ensemble storage with no realizations
1118+
dummy_ensemble = storage.create_experiment(
1119+
responses=[SummaryConfig(keys=["DUMMY"])]
1120+
).create_ensemble(name="dummy", ensemble_size=1)
1121+
assert dummy_ensemble._path.exists(), "Assumptions for test has changed"
1122+
assert not (dummy_ensemble._path / "realization-0").exists()
1123+
1124+
# When a response is saved:
1125+
dummy_ensemble.save_response(
1126+
"summary",
1127+
pl.DataFrame(
1128+
{
1129+
"response_key": ["DUMMY"],
1130+
"time": pl.Series([datetime(2000, 1, 1)]).dt.cast_time_unit("ms"),
1131+
"values": pl.Series([0.0], dtype=pl.Float32),
1132+
}
1133+
),
1134+
0,
1135+
)
1136+
1137+
# Then the realization directory was implicitly created
1138+
assert (dummy_ensemble._path / "realization-0").exists()
1139+
assert list(dummy_ensemble._path.glob("realization-0/*.parquet"))
1140+
1141+
1142+
def test_save_response_will_not_recreate_ensemble_directory(storage):
1143+
dummy_ensemble = storage.create_experiment().create_ensemble(
1144+
name="dummy", ensemble_size=1
1145+
)
1146+
# Emulate a user deleting storage:
1147+
shutil.rmtree(dummy_ensemble._path)
1148+
1149+
# Function test will raise:
1150+
with pytest.raises(FileNotFoundError):
1151+
dummy_ensemble.save_response(
1152+
"summary",
1153+
pl.DataFrame(
1154+
{
1155+
"response_key": ["DUMMY"],
1156+
"time": pl.Series([datetime(2000, 1, 1)]).dt.cast_time_unit("ms"),
1157+
"values": pl.Series([0.0], dtype=pl.Float32),
1158+
}
1159+
),
1160+
0,
1161+
)
1162+
1163+
# and the ensemble path will not be created
1164+
assert not dummy_ensemble._path.exists()
1165+
1166+
11161167
@dataclass
11171168
class Ensemble:
11181169
uuid: UUID

0 commit comments

Comments
 (0)