Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACCESS-ESM1.5: QA Tests #41

Merged
merged 14 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "model_config_tests"
version = "0.0.2"
version = "0.0.3"
authors = [
{ name = "ACCESS-NRI" },
]
Expand Down
4 changes: 4 additions & 0 deletions src/model_config_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,7 @@ def pytest_configure(config):
config.addinivalue_line(
"markers", "access_om3: mark as access-om3 specific tests in quick QA CI checks"
)
config.addinivalue_line(
"markers",
"access_esm1p5: mark as access-esm1.5 specific tests in quick QA CI checks",
)
186 changes: 186 additions & 0 deletions src/model_config_tests/qa/test_access_esm1p5_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# Copyright 2024 ACCESS-NRI and contributors. See the top-level COPYRIGHT file for details.
# SPDX-License-Identifier: Apache-2.0

"""ACCESS-ESM1.5 specific configuration tests"""

import re
import warnings
from typing import Any

import pytest

from model_config_tests.qa.test_config import check_manifest_exes_in_spack_location
from model_config_tests.util import get_git_branch_name

# Name of module on NCI
ACCESS_ESM1P5_MODULE_NAME = "access-esm1p5"
# Name of Model Repository - used for retrieving spack location files for released versions
ACCESS_ESM1P5_REPOSITORY_NAME = "ACCESS-ESM1.5"

######################################
# Bunch of expected values for tests #
######################################
VALID_REALMS: set[str] = {"atmosphere", "land", "ocean", "ocnBgchm", "seaIce"}
VALID_KEYWORDS: set[str] = {"global", "access-esm1.5"}
VALID_NOMINAL_RESOLUTION: str = "100 km"
VALID_REFERENCE: str = "https://doi.org/10.1071/ES19035"
VALID_PREINDUSTRIAL_START: dict[str, int] = {"year": 101, "month": 1, "day": 1}
VALID_HISTORICAL_START: dict[str, int] = {"year": 1850, "month": 1, "day": 1}
VALID_RUNTIME: dict[str, int] = {"year": 1, "month": 0, "day": 0}
VALID_RESTART_FREQ: str = "10YS"
VALID_MPPNCCOMBINE_EXE: str = "mppnccombine.spack"


### Some functions to avoid copying assertion error text
def error_field_nonexistence(field: str, file: str) -> str:
return f"Field '{field}' is null or does not exist in {file}."

Check warning on line 36 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L36

Added line #L36 was not covered by tests


def error_field_incorrect(field: str, file: str, expected: Any) -> str:
return f"Field '{field}' in {file} is not expected value: {expected}"

Check warning on line 40 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L40

Added line #L40 was not covered by tests


class AccessEsm1p5Branch:
"""Use the naming patterns of the branch name to infer information of
the ACCESS-ESM1.5 config"""

def __init__(self, branch_name):
self.branch_name = branch_name
self.config_scenario = self.set_config_scenario()
self.config_modifiers = self.set_config_modifiers()

Check warning on line 50 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L48-L50

Added lines #L48 - L50 were not covered by tests

def set_config_scenario(self) -> str:
# Regex below is split into three sections:
# Config type start section: '(?:release|dev)-' for 'release-' or 'dev-'
# Scenario section: '([^+]+)' for 'preindustrial', 'historical'...anything that isn't the '+' modifier sigil
# Modifiers end section: '(?:\+.+)*' any amount of '+modifer' sections
scenario_match = re.match(

Check warning on line 57 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L57

Added line #L57 was not covered by tests
r"^(?:release|dev)-(?P<scenario>[^+]+)(?:\+.+)*$", self.branch_name
)
if not scenario_match or "scenario" not in scenario_match.groupdict():
pytest.fail(

Check warning on line 61 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L60-L61

Added lines #L60 - L61 were not covered by tests
f"Could not find a scenario in the branch {self.branch_name}. "
+ "Branches must be of the form 'type-scenario[+modifier...]'. "
+ "See README.md for more information."
)
return scenario_match.group("scenario")

Check warning on line 66 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L66

Added line #L66 was not covered by tests

def set_config_modifiers(self) -> list[str]:
# Regex below is essentially 'give me the 'modifier' part in all the '+modifier's in the branch name'
return re.findall(r"\+([^+]+)", self.branch_name)

Check warning on line 70 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L70

Added line #L70 was not covered by tests
aidanheerdegen marked this conversation as resolved.
Show resolved Hide resolved


@pytest.fixture(scope="class")
def branch(control_path, target_branch):
branch_name = target_branch
if branch_name is None:

Check warning on line 76 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L75-L76

Added lines #L75 - L76 were not covered by tests
# Default to current branch name
branch_name = get_git_branch_name(control_path)
assert (

Check warning on line 79 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L78-L79

Added lines #L78 - L79 were not covered by tests
branch_name is not None
), f"Failed getting git branch name of control path: {control_path}"
warnings.warn(

Check warning on line 82 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L82

Added line #L82 was not covered by tests
"Target branch is not specifed, defaulting to current git branch: "
f"{branch_name}. As some ACCESS-ESM1.5 tests infer information, "
"such as scenario and modifiers, from the target branch name, some "
"tests may not be run. To set use --target-branch flag in pytest call"
)

return AccessEsm1p5Branch(branch_name)

Check warning on line 89 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L89

Added line #L89 was not covered by tests


@pytest.mark.access_esm1p5
class TestAccessEsm1p5:
"""ACCESS-ESM1.5 Specific configuration and metadata tests"""

def test_access_esm1p5_manifest_exe_in_release_spack_location(
self, config, control_path
):
check_manifest_exes_in_spack_location(

Check warning on line 99 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L99

Added line #L99 was not covered by tests
model_module_name=ACCESS_ESM1P5_MODULE_NAME,
model_repo_name=ACCESS_ESM1P5_REPOSITORY_NAME,
control_path=control_path,
config=config,
)

@pytest.mark.parametrize(
"field,expected", [("realm", VALID_REALMS), ("keyword", VALID_KEYWORDS)]
)
def test_metadata_field_equal_expected_sequence(self, field, expected, metadata):

assert (

Check warning on line 111 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L111

Added line #L111 was not covered by tests
field in metadata and metadata[field] is not None
), error_field_nonexistence(field, "metadata.yaml")

field_set: set[str] = set(metadata[field])

Check warning on line 115 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L115

Added line #L115 was not covered by tests

assert field_set == expected, error_field_incorrect(

Check warning on line 117 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L117

Added line #L117 was not covered by tests
field, "metadata.yaml", "sequence", expected
)

@pytest.mark.parametrize(
"field,expected",
[
("nominal_resolution", VALID_NOMINAL_RESOLUTION),
("reference", VALID_REFERENCE),
],
)
def test_metadata_field_equal_expected_value(self, field, expected, metadata):
assert field in metadata and metadata[field] == expected, error_field_incorrect(

Check warning on line 129 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L129

Added line #L129 was not covered by tests
field, "metadata.yaml", expected
)

def test_config_start(self, branch, config):
assert (

Check warning on line 134 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L134

Added line #L134 was not covered by tests
"calendar" in config
and config["calendar"] is not None
and "start" in config["calendar"]
and config["calendar"]["start"] is not None
), error_field_nonexistence("calendar.start", "config.yaml")

start: dict[str, int] = config["calendar"]["start"]

Check warning on line 141 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L141

Added line #L141 was not covered by tests

if branch.config_scenario == "preindustrial":
assert start == VALID_PREINDUSTRIAL_START, error_field_incorrect(

Check warning on line 144 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L143-L144

Added lines #L143 - L144 were not covered by tests
"calendar.start", "config.yaml", VALID_PREINDUSTRIAL_START
)
elif branch.config_scenario == "historical":
assert start == VALID_HISTORICAL_START, error_field_incorrect(

Check warning on line 148 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L147-L148

Added lines #L147 - L148 were not covered by tests
"calendar.start", "config.yaml", VALID_HISTORICAL_START
)
else:
pytest.fail(f"Cannot test unknown scenario {branch.config_scenario}.")

Check warning on line 152 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L152

Added line #L152 was not covered by tests

def test_config_runtime(self, config):
assert (

Check warning on line 155 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L155

Added line #L155 was not covered by tests
"calendar" in config
and config["calendar"] is not None
and "runtime" in config["calendar"]
and config["calendar"]["runtime"] is not None
), error_field_nonexistence("calendar.runtime", "config.yaml")

runtime: dict[str, int] = config["calendar"]["runtime"]

Check warning on line 162 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L162

Added line #L162 was not covered by tests

assert runtime == VALID_RUNTIME, error_field_incorrect(

Check warning on line 164 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L164

Added line #L164 was not covered by tests
"calendar.runtime", "config.yaml", VALID_RUNTIME
)

def test_config_restart_freq(self, config):
assert (

Check warning on line 169 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L169

Added line #L169 was not covered by tests
"restart_freq" in config and config["restart_freq"] is not None
), error_field_nonexistence("restart_freq", "config.yaml")
assert config["restart_freq"] == VALID_RESTART_FREQ, error_field_incorrect(

Check warning on line 172 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L172

Added line #L172 was not covered by tests
"restart_freq", "config.yaml", VALID_RESTART_FREQ
)

def test_mppnccombine_fast_collate_exe(self, config):
if "collate" in config:
assert (

Check warning on line 178 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L177-L178

Added lines #L177 - L178 were not covered by tests
config["collate"]["exe"] == VALID_MPPNCCOMBINE_EXE
), error_field_incorrect(
"collate.exe", "config.yaml", VALID_MPPNCCOMBINE_EXE
)

assert config["collate"]["mpi"], error_field_incorrect(

Check warning on line 184 in src/model_config_tests/qa/test_access_esm1p5_config.py

View check run for this annotation

Codecov / codecov/patch

src/model_config_tests/qa/test_access_esm1p5_config.py#L184

Added line #L184 was not covered by tests
"collate.mpi", "config.yaml", "true"
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import f90nml
import pytest

from model_config_tests.test_config import check_manifest_exes_in_spack_location
from model_config_tests.qa.test_config import check_manifest_exes_in_spack_location
from model_config_tests.util import get_git_branch_name

# Mutually exclusive topic keywords
Expand Down
29 changes: 0 additions & 29 deletions src/model_config_tests/test_access_esm1p5_config.py

This file was deleted.

Loading