From 040fd10cc0adc2c6591c4fe86511b54790e0a81c Mon Sep 17 00:00:00 2001 From: belthlemar Date: Thu, 29 Feb 2024 15:12:48 +0100 Subject: [PATCH] fix(outputs): build outputs config even when using cache --- .../rawstudy/model/filesystem/config/files.py | 4 +- .../rawstudy/model/filesystem/factory.py | 5 +- .../variant_blueprint/test_variant_manager.py | 54 +++++++++++++++++++ .../filesystem/config/test_config_files.py | 4 +- 4 files changed, 62 insertions(+), 5 deletions(-) diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/files.py b/antarest/study/storage/rawstudy/model/filesystem/config/files.py index 3727f320ec..3248b6560a 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/files.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/files.py @@ -74,7 +74,7 @@ def build(study_path: Path, study_id: str, output_path: t.Optional[Path] = None) version=_parse_version(study_path), areas=_parse_areas(study_path), sets=_parse_sets(study_path), - outputs=_parse_outputs(outputs_dir), + outputs=parse_outputs(outputs_dir), bindings=_parse_bindings(study_path), store_new_set=sns, archive_input_series=asi, @@ -232,7 +232,7 @@ def _parse_areas(root: Path) -> t.Dict[str, Area]: return {transform_name_to_id(a): parse_area(root, a) for a in areas} -def _parse_outputs(output_path: Path) -> t.Dict[str, Simulation]: +def parse_outputs(output_path: Path) -> t.Dict[str, Simulation]: if not output_path.is_dir(): return {} sims = {} diff --git a/antarest/study/storage/rawstudy/model/filesystem/factory.py b/antarest/study/storage/rawstudy/model/filesystem/factory.py index 1899ec1bb4..040e747629 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/factory.py +++ b/antarest/study/storage/rawstudy/model/filesystem/factory.py @@ -10,7 +10,7 @@ from antarest.core.interfaces.cache import CacheConstants, ICache from antarest.matrixstore.service import ISimpleMatrixService from antarest.matrixstore.uri_resolver_service import UriResolverService -from antarest.study.storage.rawstudy.model.filesystem.config.files import build +from antarest.study.storage.rawstudy.model.filesystem.config.files import build, parse_outputs from antarest.study.storage.rawstudy.model.filesystem.config.model import FileStudyTreeConfig, FileStudyTreeConfigDTO from antarest.study.storage.rawstudy.model.filesystem.context import ContextServer from antarest.study.storage.rawstudy.model.filesystem.root.filestudytree import FileStudyTree @@ -93,6 +93,9 @@ def _create_from_fs_unsafe( if from_cache is not None: logger.info(f"Study {study_id} read from cache") config = FileStudyTreeConfigDTO.parse_obj(from_cache).to_build_config() + if output_path: + config.output_path = output_path + config.outputs = parse_outputs(output_path) return FileStudy(config, FileStudyTree(self.context, config)) start_time = time.time() config = build(path, study_id, output_path) diff --git a/tests/integration/variant_blueprint/test_variant_manager.py b/tests/integration/variant_blueprint/test_variant_manager.py index 5af256dbbe..9ee10ad61b 100644 --- a/tests/integration/variant_blueprint/test_variant_manager.py +++ b/tests/integration/variant_blueprint/test_variant_manager.py @@ -1,8 +1,11 @@ +import io import logging +import time from starlette.testclient import TestClient from antarest.core.tasks.model import TaskDTO, TaskStatus +from tests.integration.assets import ASSETS_DIR def test_variant_manager(client: TestClient, admin_access_token: str, study_id: str, caplog) -> None: @@ -186,3 +189,54 @@ def test_variant_manager(client: TestClient, admin_access_token: str, study_id: res = client.get(f"/v1/studies/{variant_id}", headers=admin_headers) assert res.status_code == 404 + + +def test_outputs(client: TestClient, admin_access_token: str, tmp_path: str) -> None: + # ======================= + # SET UP + # ======================= + + admin_headers = {"Authorization": f"Bearer {admin_access_token}"} + res = client.post(f"/v1/studies?name=foo", headers=admin_headers) + parent_id = res.json() + res = client.post(f"/v1/studies/{parent_id}/variants?name=variant_foo", headers=admin_headers) + variant_id = res.json() + + # Only done to generate the variant folder + res = client.post(f"/v1/launcher/run/{variant_id}", headers=admin_headers) + job_id = res.json()["job_id"] + status = client.get(f"/v1/launcher/jobs/{job_id}", headers=admin_headers).json()["status"] + while status != "failed": + time.sleep(0.2) + status = client.get(f"/v1/launcher/jobs/{job_id}", headers=admin_headers).json()["status"] + + # Import an output to the study folder + output_path_zip = ASSETS_DIR / "output_adq.zip" + client.post( + f"/v1/studies/{variant_id}/output", + headers=admin_headers, + files={"output": io.BytesIO(output_path_zip.read_bytes())}, + ) + + # ======================= + # ASSERTS GENERATING THE VARIANT DOES NOT `HIDE` OUTPUTS FROM THE ENDPOINT + # ======================= + + # Get output + res = client.get(f"/v1/studies/{variant_id}/outputs", headers=admin_headers).json() + assert len(res) == 1 + + # Generates the study + res = client.put(f"/v1/studies/{variant_id}/generate?denormalize=false&from_scratch=true", headers=admin_headers) + task_id = res.json() + # Wait for task completion + res = client.get(f"/v1/tasks/{task_id}", headers=admin_headers, params={"wait_for_completion": True}) + assert res.status_code == 200 + task_result = TaskDTO.parse_obj(res.json()) + assert task_result.status == TaskStatus.COMPLETED + assert task_result.result is not None + assert task_result.result.success + + # Get outputs again + res = client.get(f"/v1/studies/{variant_id}/outputs", headers=admin_headers).json() + assert len(res) == 1 diff --git a/tests/storage/repository/filesystem/config/test_config_files.py b/tests/storage/repository/filesystem/config/test_config_files.py index 4f88115291..a8d8d2fecc 100644 --- a/tests/storage/repository/filesystem/config/test_config_files.py +++ b/tests/storage/repository/filesystem/config/test_config_files.py @@ -11,12 +11,12 @@ ) from antarest.study.storage.rawstudy.model.filesystem.config.files import ( _parse_links, - _parse_outputs, _parse_renewables, _parse_sets, _parse_st_storage, _parse_thermal, build, + parse_outputs, ) from antarest.study.storage.rawstudy.model.filesystem.config.model import ( Area, @@ -222,7 +222,7 @@ def test_parse_outputs__nominal(tmp_path: Path, assets_name: str, expected: Dict with ZipFile(pkg_dir) as zf: zf.extractall(tmp_path) output_path = tmp_path.joinpath("output") - actual = _parse_outputs(output_path) + actual = parse_outputs(output_path) assert actual == expected