Skip to content

Commit

Permalink
Add model testing w/ Docker container
Browse files Browse the repository at this point in the history
  • Loading branch information
BSchilperoort committed Jan 24, 2024
1 parent 828b69b commit 8bae092
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 5 deletions.
23 changes: 19 additions & 4 deletions PyStemmusScope/bmi/docker_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@
docker = None


def wait_for_model(phrase: bytes, socket: Any) -> None:
def _wait_for_model(phrase: bytes, socket: Any, client: Any, container_id: Any) -> None:
"""Wait for the model to be ready to receive (more) commands, or is finalized."""
output = b""

error_msg = b"Error in "
while phrase not in output:
if error_msg in output:
client.stop(container_id)
logs = client.logs(container_id).decode("utf-8")
raise ValueError(
f"Error in container '{container_id['Id']}'. Please inspect logs."
"\nDOCKER LOGS:\n" + logs
)

data = socket.read(1)
if data is None:
msg = "Could not read data from socket. Docker container might be dead."
Expand Down Expand Up @@ -62,7 +70,9 @@ def __init__(self, cfg_file: str):

def wait_for_model(self) -> None:
"""Wait for the model to be ready to receive (more) commands."""
wait_for_model(self._process_ready_phrase, self.socket)
_wait_for_model(
self._process_ready_phrase, self.socket, self.client, self.container_id
)

def is_alive(self) -> bool:
"""Return if the process is alive."""
Expand Down Expand Up @@ -99,7 +109,12 @@ def finalize(self) -> None:
"""Finalize the model."""
if self.is_alive():
os.write(self.socket.fileno(), b"finalize\n")
wait_for_model(self._process_finalized_phrase, self.socket)
_wait_for_model(
self._process_finalized_phrase,
self.socket,
self.client,
self.container_id,
)
sleep(0.5) # Ensure the container can stop cleanly.
self.client.stop(self.container_id)
self.client.remove_container(self.container_id, v=True)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ docs = [
]

[tool.hatch.envs.default]
features = ["dev"]
features = ["dev", "docker"]

[tool.hatch.envs.default.scripts]
lint = [
Expand Down
16 changes: 16 additions & 0 deletions tests/test_data/config_file_docker.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
WorkDir=tests/test_data/directories/
SoilPropertyPath=tests/test_data/directories/model_parameters/soil_property/
ForcingPath=tests/test_data/directories/forcing/plumber2_data/
Location=XX-Xxx
directional=tests/test_data/directories/model_parameters/vegetation_property/directional/
fluspect_parameters=tests/test_data/directories/model_parameters/vegetation_property/fluspect_parameters/
leafangles=tests/test_data/directories/model_parameters/vegetation_property/leafangles/
radiationdata=tests/test_data/directories/model_parameters/vegetation_property/radiationdata/
soil_spectrum=tests/test_data/directories/model_parameters/vegetation_property/soil_spectrum/
input_data=tests/test_data/directories/model_parameters/vegetation_property/dummy_data.xlsx
InitialConditionPath=tests/test_data/directories/model_parameters/soil_initialcondition/
StartTime=1996-01-01T00:00
EndTime=1996-01-01T02:00
InputPath=
OutputPath=
DockerImage=ghcr.io/ecoextreml/stemmus_scope:1.5.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fluspect_parameters/Optipar2017_ProspectD.mat
radiationdata/FLEX-S3_std.atm
soil_spectrum/soilnew.txt
Binary file not shown.
79 changes: 79 additions & 0 deletions tests/test_docker_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from pathlib import Path
from PyStemmusScope.bmi.implementation import StemmusScopeBmi
from PyStemmusScope import config_io, forcing_io, soil_io
from distutils.dir_util import copy_tree
import requests

from . import data_folder
import pytest


SCOPE_INPUTDATA_v2_1 = "https://github.com/Christiaanvandertol/SCOPE/raw/2.1/input/"
SCOPE_INPUTDATA_v1_7 = "https://github.com/Christiaanvandertol/SCOPE/raw/1.73/data/input/"


cfg_file = data_folder / "config_file_docker.txt"
vegetation_property_dir = data_folder / "directories" / "model_parameters" / "vegetation_property"


def write_config_file(cfg: dict, file: Path) -> None:
with file.open("w") as f:
for key, val in cfg.items():
f.write(f"{key}={val}\n")


@pytest.fixture(scope="session")
def prep_input_data():
optipar_path = vegetation_property_dir / "fluspect_parameters" / "Optipar2017_ProspectD.mat"
if not optipar_path.exists():
r = requests.get( # Older version due to v2 compatibility issues
SCOPE_INPUTDATA_v1_7 + "fluspect_parameters/Optipar2017_ProspectD.mat"
)
assert r.status_code == 200
optipar_path.open("wb").write(r.content)

flex_s3_path = vegetation_property_dir / "radiationdata" / "FLEX-S3_std.atm"
if not flex_s3_path.exists():
r = requests.get(
SCOPE_INPUTDATA_v2_1 + "radiationdata/FLEX-S3_std.atm"
)
assert r.status_code == 200
flex_s3_path.open("wb").write(r.content)

soil_path = vegetation_property_dir / "soil_spectrum" / "soilnew.txt"
if not soil_path.exists():
r = requests.get(
SCOPE_INPUTDATA_v2_1 + "soil_spectra/soilnew.txt"
)
assert r.status_code == 200
soil_path.open("wb").write(r.content)


@pytest.fixture(scope="session")
def prepare_data_config(tmpdir_factory, prep_input_data) -> Path:
tempdir = Path(tmpdir_factory.mktemp("tempdir"))
output_dir = tempdir / "output_dir"
input_dir = tempdir / "input_dir"
output_dir.mkdir()
input_dir.mkdir()
config = config_io.read_config(cfg_file)
config["OutputPath"] = str(output_dir) + "/"
config["InputPath"] = str(input_dir) + "/"

forcing_io.prepare_forcing(config)
soil_io.prepare_soil_data(config)
soil_io.prepare_soil_init(config)

copy_tree(src=str(vegetation_property_dir), dst=str(input_dir))

config_dir = tempdir / "config.txt"
write_config_file(config, config_dir)

return config_dir


def test_initialize(prepare_data_config):
model = StemmusScopeBmi()
model.initialize(str(prepare_data_config))
model.update()
model.finalize()

0 comments on commit 8bae092

Please sign in to comment.