Skip to content

Commit d8890df

Browse files
committed
Add unit tests for various components and ensure proper test marking
1 parent 1350050 commit d8890df

5 files changed

Lines changed: 38 additions & 2 deletions

File tree

tests/unit/test_base.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def mock_mapping(self):
3333
"positive": None,
3434
}
3535

36+
@pytest.mark.unit
3637
def test_init_with_valid_params(self, mock_vocab, mock_mapping, temp_dir):
3738
"""Test initialization with valid parameters."""
3839
cmoriser = CMIP6_CMORiser(
@@ -49,6 +50,7 @@ def test_init_with_valid_params(self, mock_vocab, mock_mapping, temp_dir):
4950
assert cmoriser.vocab == mock_vocab
5051
assert cmoriser.mapping == mock_mapping
5152

53+
@pytest.mark.unit
5254
def test_init_with_multiple_input_paths(self, mock_vocab, mock_mapping, temp_dir):
5355
"""Test initialization with multiple input files."""
5456
input_files = ["test1.nc", "test2.nc", "test3.nc"]
@@ -62,6 +64,7 @@ def test_init_with_multiple_input_paths(self, mock_vocab, mock_mapping, temp_dir
6264

6365
assert cmoriser.input_paths == input_files
6466

67+
@pytest.mark.unit
6568
def test_init_with_single_input_path_string(
6669
self, mock_vocab, mock_mapping, temp_dir
6770
):
@@ -76,6 +79,7 @@ def test_init_with_single_input_path_string(
7679

7780
assert cmoriser.input_paths == ["single_file.nc"]
7881

82+
@pytest.mark.unit
7983
def test_init_with_drs_root(self, mock_vocab, mock_mapping, temp_dir):
8084
"""Test initialization with DRS root path."""
8185
drs_root = temp_dir / "drs"
@@ -90,6 +94,7 @@ def test_init_with_drs_root(self, mock_vocab, mock_mapping, temp_dir):
9094

9195
assert cmoriser.drs_root == Path(drs_root)
9296

97+
@pytest.mark.unit
9398
def test_version_date_format(self, mock_vocab, mock_mapping, temp_dir):
9499
"""Test that version date is set correctly."""
95100
cmoriser = CMIP6_CMORiser(
@@ -105,6 +110,7 @@ def test_version_date_format(self, mock_vocab, mock_mapping, temp_dir):
105110
assert len(cmoriser.version_date) == 8
106111
assert cmoriser.version_date.isdigit()
107112

113+
@pytest.mark.unit
108114
def test_type_mapping_attribute(self, mock_vocab, mock_mapping, temp_dir):
109115
"""Test that type_mapping is available as class attribute."""
110116
cmoriser = CMIP6_CMORiser(
@@ -119,6 +125,7 @@ def test_type_mapping_attribute(self, mock_vocab, mock_mapping, temp_dir):
119125
assert hasattr(cmoriser, "type_mapping")
120126
assert cmoriser.type_mapping is not None
121127

128+
@pytest.mark.unit
122129
def test_dataset_proxy_methods(self, mock_vocab, mock_mapping, temp_dir):
123130
"""Test that the CMORiser can proxy dataset operations."""
124131
# Create a mock dataset
@@ -154,6 +161,7 @@ def test_dataset_proxy_methods(self, mock_vocab, mock_mapping, temp_dir):
154161
repr_result = repr(cmoriser)
155162
assert repr_result == "<Dataset representation>"
156163

164+
@pytest.mark.unit
157165
def test_dataset_none_initially(self, mock_vocab, mock_mapping, temp_dir):
158166
"""Test that dataset is None initially."""
159167
cmoriser = CMIP6_CMORiser(
@@ -166,6 +174,7 @@ def test_dataset_none_initially(self, mock_vocab, mock_mapping, temp_dir):
166174

167175
assert cmoriser.ds is None
168176

177+
@pytest.mark.unit
169178
def test_getattr_fallback(self, mock_vocab, mock_mapping, temp_dir):
170179
"""Test __getattr__ behavior when dataset is None."""
171180
cmoriser = CMIP6_CMORiser(

tests/unit/test_batch_cmoriser.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from unittest.mock import Mock, mock_open, patch
22

3+
import pytest
4+
35
from access_mopper.batch_cmoriser import create_job_script, submit_job
46
from tests.mocks.mock_pbs import MockPBSManager, mock_qsub_failure, mock_qsub_success
57

@@ -10,6 +12,7 @@ class TestBatchCmoriser:
1012
@patch("access_mopper.batch_cmoriser.Template")
1113
@patch("access_mopper.batch_cmoriser.files")
1214
@patch("os.chmod")
15+
@pytest.mark.unit
1316
def test_create_job_script(self, mock_chmod, mock_files, mock_template, temp_dir):
1417
"""Test job script creation."""
1518
# Mock template files
@@ -39,6 +42,7 @@ def test_create_job_script(self, mock_chmod, mock_files, mock_template, temp_dir
3942
mock_chmod.assert_called()
4043

4144
@patch("subprocess.run")
45+
@pytest.mark.unit
4246
def test_submit_job_success(self, mock_run):
4347
"""Test successful job submission."""
4448
mock_run.return_value = mock_qsub_success()
@@ -50,6 +54,7 @@ def test_submit_job_success(self, mock_run):
5054
mock_run.assert_called_once()
5155

5256
@patch("subprocess.run")
57+
@pytest.mark.unit
5358
def test_submit_job_failure(self, mock_run):
5459
"""Test failed job submission."""
5560
mock_run.return_value = mock_qsub_failure()
@@ -58,6 +63,7 @@ def test_submit_job_failure(self, mock_run):
5863

5964
assert job_id is None
6065

66+
@pytest.mark.unit
6167
def test_mock_pbs_manager(self):
6268
"""Test the MockPBSManager functionality."""
6369
with MockPBSManager() as pbs:

tests/unit/test_driver.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def valid_config(self):
2727
"activity_id": "CMIP",
2828
}
2929

30+
@pytest.mark.unit
3031
def test_init_with_minimal_params(self, valid_config, temp_dir):
3132
"""Test initialization with minimal required parameters."""
3233
with patch("access_mopper.driver.load_cmip6_mappings") as mock_load:
@@ -45,6 +46,7 @@ def test_init_with_minimal_params(self, valid_config, temp_dir):
4546
assert cmoriser.experiment_id == "historical"
4647
assert cmoriser.source_id == "ACCESS-ESM1-5"
4748

49+
@pytest.mark.unit
4850
def test_init_with_multiple_input_paths(self, valid_config, temp_dir):
4951
"""Test initialization with multiple input files."""
5052
input_files = ["file1.nc", "file2.nc", "file3.nc"]
@@ -61,6 +63,7 @@ def test_init_with_multiple_input_paths(self, valid_config, temp_dir):
6163

6264
assert cmoriser.input_paths == input_files
6365

66+
@pytest.mark.unit
6467
def test_init_with_parent_info(self, valid_config, temp_dir):
6568
"""Test initialization with parent experiment information."""
6669
parent_info = {
@@ -89,6 +92,7 @@ def test_init_with_parent_info(self, valid_config, temp_dir):
8992
# Should use provided parent info instead of defaults
9093
assert cmoriser.parent_info == parent_info
9194

95+
@pytest.mark.unit
9296
def test_init_with_drs_root(self, valid_config, temp_dir):
9397
"""Test initialization with DRS root specification."""
9498
drs_root = temp_dir / "drs_structure"
@@ -106,6 +110,7 @@ def test_init_with_drs_root(self, valid_config, temp_dir):
106110

107111
assert cmoriser.drs_root == Path(drs_root)
108112

113+
@pytest.mark.unit
109114
def test_compound_name_parsing(self, valid_config, temp_dir):
110115
"""Test that compound names are parsed correctly."""
111116
test_cases = [
@@ -131,6 +136,7 @@ def test_compound_name_parsing(self, valid_config, temp_dir):
131136
# Check that mappings were loaded for the correct compound name
132137
mock_load.assert_called_with(compound_name)
133138

139+
@pytest.mark.unit
134140
def test_output_path_conversion(self, valid_config):
135141
"""Test that output path is properly converted to Path object."""
136142
with patch("access_mopper.driver.load_cmip6_mappings") as mock_load:
@@ -147,6 +153,7 @@ def test_output_path_conversion(self, valid_config):
147153
assert isinstance(cmoriser.output_path, Path)
148154
assert cmoriser.output_path == Path("/tmp/test_output")
149155

156+
@pytest.mark.unit
150157
@patch("access_mopper.driver._default_parent_info")
151158
def test_default_parent_info_used(
152159
self, mock_default_parent, valid_config, temp_dir
@@ -167,6 +174,7 @@ def test_default_parent_info_used(
167174
# Should call default parent info function
168175
mock_default_parent.assert_called_once()
169176

177+
@pytest.mark.unit
170178
def test_variable_mapping_loaded(self, valid_config, temp_dir):
171179
"""Test that variable mapping is loaded correctly."""
172180
mock_mapping = {
@@ -190,6 +198,7 @@ def test_variable_mapping_loaded(self, valid_config, temp_dir):
190198
assert cmoriser.variable_mapping == mock_mapping
191199
mock_load.assert_called_once_with("Amon.tas")
192200

201+
@pytest.mark.unit
193202
def test_missing_required_params(self, temp_dir):
194203
"""Test that missing required parameters raise appropriate errors."""
195204
with patch("access_mopper.driver.load_cmip6_mappings") as mock_load:
@@ -207,6 +216,7 @@ def test_missing_required_params(self, temp_dir):
207216
# Missing experiment_id
208217
)
209218

219+
@pytest.mark.unit
210220
def test_drs_root_path_conversion(self, valid_config, temp_dir):
211221
"""Test DRS root path conversion from string to Path."""
212222
with patch("access_mopper.driver.load_cmip6_mappings") as mock_load:

tests/unit/test_templates.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import pytest
12
from jinja2 import Template
23

34

45
class TestTemplates:
56
"""Test Jinja2 template rendering for job scripts."""
67

8+
@pytest.mark.unit
79
def test_python_script_template_rendering(self, batch_config, temp_dir):
810
"""Test that Python script template renders correctly."""
911
# Mock template content based on your actual template
@@ -38,6 +40,7 @@ def main():
3840
assert "main()" in result
3941
assert batch_config["file_patterns"]["Amon.tas"] in result
4042

43+
@pytest.mark.unit
4144
def test_pbs_script_template_rendering(self, batch_config, temp_dir):
4245
"""Test that PBS script template renders correctly."""
4346
template_content = """#!/bin/bash
@@ -67,6 +70,7 @@ def test_pbs_script_template_rendering(self, batch_config, temp_dir):
6770
assert 'export VARIABLE="Amon.tas"' in result
6871
assert 'export EXPERIMENT_ID="historical"' in result
6972

73+
@pytest.mark.unit
7074
def test_template_variable_substitution(self):
7175
"""Test various Jinja2 variable substitutions used in templates."""
7276
template_content = """
@@ -92,4 +96,4 @@ def test_template_variable_substitution(self):
9296
assert "CMOR Name: tas" in result
9397
assert "CPUs: 8" in result
9498
assert "Memory: 32GB" in result
95-
assert '"/path/to/files/*.nc"' in result
99+
assert "/path/to/files/*.nc" in result

tests/unit/test_tracking.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import sqlite3
22

3+
import pytest
4+
35
from access_mopper.tracking import TaskTracker
46

57

68
class TestTaskTracker:
79
"""Unit tests for TaskTracker class."""
810

11+
@pytest.mark.unit
912
def test_init_creates_database(self, temp_dir):
1013
"""Test that initialization creates database and tables."""
1114
db_path = temp_dir / "test_tracker.db"
@@ -22,6 +25,7 @@ def test_init_creates_database(self, temp_dir):
2225

2326
assert "cmor_tasks" in tables
2427

28+
@pytest.mark.unit
2529
def test_add_task(self, temp_dir):
2630
"""Test adding a new task."""
2731
db_path = temp_dir / "test_tracker.db"
@@ -42,8 +46,9 @@ def test_add_task(self, temp_dir):
4246
assert result is not None
4347
assert result[1] == "Amon.tas" # variable
4448
assert result[2] == "historical" # experiment_id
45-
assert result[3] == "pending" # status
49+
assert result[3] == "running" # status
4650

51+
@pytest.mark.unit
4752
def test_mark_running(self, temp_dir):
4853
"""Test marking task as running."""
4954
db_path = temp_dir / "test_tracker.db"
@@ -55,6 +60,7 @@ def test_mark_running(self, temp_dir):
5560
status = tracker.get_status("Amon.tas", "historical")
5661
assert status == "running"
5762

63+
@pytest.mark.unit
5864
def test_mark_completed(self, temp_dir):
5965
"""Test marking task as completed."""
6066
db_path = temp_dir / "test_tracker.db"
@@ -67,6 +73,7 @@ def test_mark_completed(self, temp_dir):
6773
status = tracker.get_status("Amon.tas", "historical")
6874
assert status == "completed"
6975

76+
@pytest.mark.unit
7077
def test_is_done_functionality(self, temp_dir):
7178
"""Test the is_done method used in templates."""
7279
db_path = temp_dir / "test_tracker.db"

0 commit comments

Comments
 (0)