test_config.py 29.3 KB
Newer Older
"""Tests for config module"""
# coding=utf-8
from unittest import TestCase
import datetime
import os
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
from earthdiagnostics.config import (
    CMORConfig,
    ConfigException,
    THREDDSConfig,
    ReportConfig,
    ExperimentConfig,
    Config,
)
from earthdiagnostics.frequency import Frequencies
from earthdiagnostics.modelingrealm import ModelingRealms
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
from earthdiagnostics.data_convention import (
    SPECSConvention,
    PrimaveraConvention,
    PrefaceConvention,
    MeteoFranceConvention,
    CMIP6Convention,
)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """Mock for Variable"""

    def __init__(self):
        self.domain = ModelingRealms.ocean
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.short_name = "tos"
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        return (
            self.domain == other.domain and self.short_name == other.short_name
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """Mock for Variable manager"""

    def get_variable(self, alias, silent=False):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Return a VariableMock given an alias"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        if alias == "bad":
            return None
        var = VariableMock()
        var.short_name = alias
        return var


class ParserMock(mock.Mock):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """ConfigParser Mock"""
    def __init__(self, **kwargs):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        super(mock.Mock, self).__init__(**kwargs)
        self._values = {}

    def add_value(self, section, var, value):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Add value to the parser"""
        self._values[self.get_var_string(section, var)] = value

    def get_var_string(self, section, var):
        """Get var string"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        return "{0}:{1}".format(section, var)

    def get_value(self, section, var, default):
        """Get value from mock parser"""
        try:
            return self._values[self.get_var_string(section, var)]
        except KeyError:
            return default

    def get_bool_option(self, section, var, default):
        """Get bool option"""
        return self.get_value(section, var, default)

    def get_path_option(self, section, var, default=""):
        """Get path option"""
        return self.get_value(section, var, default)

    def get_int_option(self, section, var, default=0):
        """Get integer option"""
        return self.get_value(section, var, default)

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def get_choice_option(
        self, section, var, choices, default, ignore_case=True
    ):
        """Get choice option"""
        return self.get_value(section, var, default)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def get_int_list_option(self, section, var, default=list(), separator=" "):
        """Get integer list option"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            return [
                int(val)
                for val in self._values[
                    self.get_var_string(section, var)
                ].split(separator)
            ]
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def get_list_option(self, section, var, default=list(), separator=" "):
        """Get list option"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            return [
                val
                for val in self._values[
                    self.get_var_string(section, var)
                ].split(separator)
            ]
        except KeyError:
            return default

    def get_option(self, section, var, default=None):
        """get option"""
        return self.get_value(section, var, default)

    def has_section(self, section):
        """Check if section exists"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        start = "{0}:".format(section)
        return any(x.startswith(start) for x in self._values)

    def options(self, section):
        """Return all options for a given section"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        start = "{0}:".format(section)
        return [x[len(start):] for x in self._values if x.startswith(start)]

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """Tests for CMORConfig class"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Prepare tests"""
        self.mock_parser = ParserMock()
        self.var_manager = VariableManagerMock()

    def test_basic_config(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test minimum configuration"""
        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertEqual(config.ocean, True)
        self.assertEqual(config.atmosphere, True)
        self.assertEqual(config.force, False)
        self.assertEqual(config.force_untar, False)
        self.assertEqual(config.use_grib, True)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.activity, "CMIP")
        self.assertEqual(config.associated_experiment, "to be filled")
        self.assertEqual(config.associated_model, "to be filled")
        self.assertEqual(config.initialization_description, "to be filled")
        self.assertEqual(config.initialization_method, "1")
        self.assertEqual(config.initialization_number, 1)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.source, "to be filled")
        self.assertEqual(config.version, "")
        self.assertEqual(config.physics_version, "1")
        self.assertEqual(config.physics_description, "to be filled")
        self.assertEqual(config.filter_files, [])
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.default_atmos_grid, "gr")
        self.assertEqual(config.default_ocean_grid, "gn")
        self.assertEqual(config.min_cmorized_vars, 10)
        self.assertEqual(config.append_startdate, False)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test cmorize returns true always if list is not configured"""
        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertTrue(config.cmorize(VariableMock()))
        self.assertTrue(config.cmorize(None))

    def test_cmorize_list(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test cmorize return true for variables in the given list"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "CMOR", "VARIABLE_LIST", "ocean:thetao ocean:tos"
        )

        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertTrue(config.cmorize(VariableMock()))

        thetao_mock = VariableMock()
        thetao_mock.domain = ModelingRealms.ocean
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        thetao_mock.short_name = "thetao"
        self.assertTrue(config.cmorize(thetao_mock))

    def test_bad_list(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test cmorize return false for malformed variables"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("CMOR", "VARIABLE_LIST", "#ocean:tos")
        with self.assertRaises(ConfigException):
            CMORConfig(self.mock_parser, self.var_manager)

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("CMOR", "VARIABLE_LIST", "atmos:tos")
        with self.assertRaises(ConfigException):
            CMORConfig(self.mock_parser, self.var_manager)

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("CMOR", "VARIABLE_LIST", "ocean:bad")
        with self.assertRaises(ConfigException):
            CMORConfig(self.mock_parser, self.var_manager)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test cmorize return false for variables not in the given list"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("CMOR", "VARIABLE_LIST", "ocean:tos")

        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertTrue(config.cmorize(VariableMock()))

        self.assertFalse(config.cmorize(None))

        tas_mock = VariableMock()
        tas_mock.domain = ModelingRealms.atmos
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        tas_mock.short_name = "tas"
        self.assertFalse(config.cmorize(tas_mock))

        thetao_mock = VariableMock()
        thetao_mock.domain = ModelingRealms.ocean
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        thetao_mock.short_name = "thetao"
        self.assertFalse(config.cmorize(thetao_mock))

    def test_comment(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test cmorize return false for variables after the comment mark"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "CMOR", "VARIABLE_LIST", "ocean:tos #ocean:thetao "
        )

        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertTrue(config.cmorize(VariableMock()))

        thetao_mock = VariableMock()
        thetao_mock.domain = ModelingRealms.ocean
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        thetao_mock.short_name = "thetao"
        self.assertFalse(config.cmorize(thetao_mock))

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "CMOR", "VARIABLE_LIST", "#ocean:tos ocean:thetao "
        )
        with self.assertRaises(ConfigException):
            CMORConfig(self.mock_parser, self.var_manager)

    def test_cmorization_chunk(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test chunk cmorization requested returns true if not given a list"""
        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertTrue(config.chunk_cmorization_requested(1))

    def test_cmorize_only_some_chunks(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test chunk cmor requested returns true only if it is in the list"""
        self.mock_parser.add_value("CMOR", "CHUNKS", "3 5")
        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertTrue(config.chunk_cmorization_requested(3))
        self.assertTrue(config.chunk_cmorization_requested(5))
        self.assertFalse(config.chunk_cmorization_requested(1))
        self.assertFalse(config.chunk_cmorization_requested(4))
        self.assertFalse(config.chunk_cmorization_requested(6))

    def test_any_required(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test any_required method"""
        config = CMORConfig(self.mock_parser, self.var_manager)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertTrue(config.any_required(["tos"]))
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "CMOR", "VARIABLE_LIST", "ocean:tos ocean:thetao"
        )
        config = CMORConfig(self.mock_parser, self.var_manager)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertTrue(config.any_required(["tos", "thetao", "tas"]))
        self.assertTrue(config.any_required(["tos", "tas"]))
        self.assertTrue(config.any_required(["thetao"]))
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertFalse(config.any_required(["tas"]))

    def test_hourly_vars(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test hourly vars specification"""
        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertEqual(config.get_variables(Frequencies.six_hourly), {})
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "CMOR",
            "ATMOS_HOURLY_VARS",
            "128,129:1,130:1-2,131:1:10,132:0:10:5",
        )
        config = CMORConfig(self.mock_parser, self.var_manager)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_variables(Frequencies.six_hourly),
            {
                128: None,
                129: "1",
                130: "1,2",
                131: "1,2,3,4,5,6,7,8,9",
                132: "0,5",
            },
        )
        self.assertEqual(config.get_levels(Frequencies.six_hourly, 128), None)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_levels(Frequencies.six_hourly, 129), "1")
        self.assertEqual(config.get_levels(Frequencies.six_hourly, 130), "1,2")
        self.assertEqual(
            config.get_levels(Frequencies.six_hourly, 131),
            "1,2,3,4,5,6,7,8,9",
        )
        self.assertEqual(config.get_levels(Frequencies.six_hourly, 132), "0,5")

    def test_daily_vars(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test daily vars specification"""
        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertEqual(config.get_variables(Frequencies.daily), {})
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "CMOR", "ATMOS_DAILY_VARS", "128,129:1,130:1-2,131:1:10,132:0:10:5"
        )
        config = CMORConfig(self.mock_parser, self.var_manager)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_variables(Frequencies.daily),
            {
                128: None,
                129: "1",
                130: "1,2",
                131: "1,2,3,4,5,6,7,8,9",
                132: "0,5",
            },
        )
        self.assertEqual(config.get_levels(Frequencies.daily, 128), None)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_levels(Frequencies.daily, 129), "1")
        self.assertEqual(config.get_levels(Frequencies.daily, 130), "1,2")
        self.assertEqual(
            config.get_levels(Frequencies.daily, 131), "1,2,3,4,5,6,7,8,9",
        )
        self.assertEqual(config.get_levels(Frequencies.daily, 132), "0,5")

    def test_monthly_vars(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test monthly vars specification"""
        config = CMORConfig(self.mock_parser, self.var_manager)
        self.assertEqual(config.get_variables(Frequencies.monthly), {})
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "CMOR",
            "ATMOS_MONTHLY_VARS",
            "128,129:1,130:1-2,131:1:10,132:0:10:5",
        )
        config = CMORConfig(self.mock_parser, self.var_manager)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_variables(Frequencies.monthly),
            {
                128: None,
                129: "1",
                130: "1,2",
                131: "1,2,3,4,5,6,7,8,9",
                132: "0,5",
            },
        )
        self.assertEqual(config.get_levels(Frequencies.monthly, 128), None)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_levels(Frequencies.monthly, 129), "1")
        self.assertEqual(config.get_levels(Frequencies.monthly, 130), "1,2")
        self.assertEqual(
            config.get_levels(Frequencies.monthly, 131), "1,2,3,4,5,6,7,8,9",
        )
        self.assertEqual(config.get_levels(Frequencies.monthly, 132), "0,5")

    def test_bad_frequency_vars(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test get variables fails if a bada frequency is specified"""
        config = CMORConfig(self.mock_parser, self.var_manager)
        with self.assertRaises(ValueError):
            config.get_variables(Frequencies.climatology)

    def test_requested_codes(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test requested codes returns a set of codes at all frequencies"""
        self.mock_parser.add_value(
            "CMOR",
            "ATMOS_HOURLY_VARS",
            "128,129:1,130:1-2,131:1:10,132:0:10:5",
        )
        self.mock_parser.add_value(
            "CMOR", "ATMOS_DAILY_VARS", "128,129:1,130:1-2,131:1:10,132:0:10:5"
        )
        self.mock_parser.add_value(
            "CMOR",
            "ATMOS_MONTHLY_VARS",
            "128,129:1,130:1-2,131:1:10,132:0:10:5",
        )
        config = CMORConfig(self.mock_parser, self.var_manager)

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_requested_codes(), {128, 129, 130, 131, 132}
        )


class TestTHREDDSConfig(TestCase):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """Test THREDDS config"""

    def setUp(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Prepare tests"""
        self.mock_parser = ParserMock()

    def test_basic_config(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test basic configuration"""
        config = THREDDSConfig(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.server_url, "")

    def test_url(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test SERVER_URL parameter"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("THREDDS", "SERVER_URL", "test_url")
        config = THREDDSConfig(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.server_url, "test_url")


class TestReportConfig(TestCase):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """Test report config"""

    def setUp(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Prepare tests"""
        self.mock_parser = ParserMock()

    def test_basic_config(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """test default config"""
        config = ReportConfig(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.path, "")
        self.assertEqual(config.maximum_priority, 10)

    def test_path(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test path configuration"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("REPORT", "PATH", "new_path")
        config = ReportConfig(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.path, "new_path")

    def test_priority(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Test maximum priority configuration"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("REPORT", "MAXIMUM_PRIORITY", 3)
        config = ReportConfig(self.mock_parser)
        self.assertEqual(config.maximum_priority, 3)


class TestExperimentConfig(TestCase):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """Test experiment config"""
        """Set up tests"""
        self.mock_parser = ParserMock()

    def test_basic_config(self):
        """Test default values"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
        self.assertEqual(config.startdates, [])
        self.assertEqual(config.members, [])
        self.assertEqual(config.chunk_size, 0)
        self.assertEqual(config.num_chunks, 0)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.atmos_grid, "")
        self.assertEqual(config.atmos_timestep, 6)
        self.assertEqual(config.ocean_timestep, 6)
    def test_members(self):
        """
        Test all ways of specifing the members

        Including:
        - Adding the prefix string or not
        - Providing them as a space separated list
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        - Providing them as a range with start and end separated by -
            (both extremes included)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "MEMBERS", "fc0 1")
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
        self.assertEqual(config.members, [0, 1])
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "MEMBERS", "fc00 fc01")
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
        self.assertEqual(config.members, [0, 1])
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "MEMBERS", "fc1-fc3")
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
        self.assertEqual(config.members, [1, 2, 3])
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "MEMBERS", "1-3")
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
        self.assertEqual(config.members, [1, 2, 3])
    def test_startdates(self):
        """
        Test startadates parsing

        Two options:
        - A simple list
        - Using a regex

        """
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "EXPERIMENT", "STARTDATES", "20001101 20011101"
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.startdates, ["20001101", "20011101"])
        """
        Test parsing startdates using the automatic generation


Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        Reference syntax: {START,STOP,INTERVAL} where start and stop are
        dates and the interval is given with the code NI where N is the number
        of intervals (default 1) and I is the base interval (Y,M,W,D)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "EXPERIMENT", "STARTDATES", "{2000,2001,1Y}"
        )
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.startdates, ["20000101", "20010101"])
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "EXPERIMENT", "STARTDATES", "{20001101,20011101,1Y}"
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.startdates, ["20001101", "20011101"])
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "EXPERIMENT", "STARTDATES", "{20001101,20011101,6M}  "
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.startdates, ["20001101", "20010501", "20011101"]
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "EXPERIMENT", "STARTDATES", "{20001101,20001201,1W}"
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.startdates,
            ["20001101", "20001108", "20001115", "20001122", "20001129"],
        )

        self.mock_parser.add_value(
            "EXPERIMENT", "STARTDATES", "{20001101,20001201,W}"
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.startdates,
            ["20001101", "20001108", "20001115", "20001122", "20001129"],
        )

        self.mock_parser.add_value(
            "EXPERIMENT", "STARTDATES", "{20001101,20001201,7D}"
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.startdates,
            ["20001101", "20001108", "20001115", "20001122", "20001129"],
        )

        self.mock_parser.add_value(
            "EXPERIMENT", "STARTDATES", "{20001101,20001201,7F}"
        )
        with self.assertRaises(ConfigException):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            config = ExperimentConfig()
            config.parse_ini(self.mock_parser)
    def test_get_member_str(self):
        """Test get member str"""
        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_member_str(1), "fc1")

    def test_get_full_years(self):
        """Test get full years method"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "CHUNK_SIZE", 3)
        self.mock_parser.add_value("EXPERIMENT", "CHUNKS", 15)

        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_full_years("20000601"), [2001, 2002, 2003, 2004]
        )
        self.assertEqual(
            config.get_full_years("20000101"), [2000, 2001, 2002, 2003]
        )

    def test_get_year_chunks(self):
        """Test get chunk years"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "CHUNK_SIZE", 3)
        self.mock_parser.add_value("EXPERIMENT", "CHUNKS", 13)

        config = ExperimentConfig()
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_year_chunks("20000601", 2003), [11, 12, 13]
        )
        self.assertEqual(
            config.get_year_chunks("20000601", 2001), [3, 4, 5, 6, 7]
        )
        self.assertEqual(
            config.get_year_chunks("20000101", 2000), [1, 2, 3, 4]
        )

        self.assertEqual(config.get_year_chunks("20000601", 2000), [1, 2, 3])
        self.assertEqual(config.get_year_chunks("20000601", 1999), [])

    def test_get_chunk_list(self):
        """Test get complete chunk list"""
        config = ExperimentConfig()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config.startdates = ("20010101",)
        config.members = (0, 1, 2)
        config.chunk_list = [0]
        config.num_chunks = 2
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_chunk_list(),
            [("20010101", 0, 0), ("20010101", 1, 0), ("20010101", 2, 0)],
        )

        config.chunk_list = []
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_chunk_list(),
            [
                ("20010101", 0, 1),
                ("20010101", 0, 2),
                ("20010101", 1, 1),
                ("20010101", 1, 2),
                ("20010101", 2, 1),
                ("20010101", 2, 2),
            ],
        )

    def test_get_member_list(self):
        """Test get member list"""
        config = ExperimentConfig()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config.startdates = ("20010101",)
        config.members = (0, 1, 2)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.get_member_list(),
            [("20010101", 0), ("20010101", 1), ("20010101", 2)],
        )

    def test_get_chunk_start_str(self):
        """Test get_chunk_start_str"""
        config = ExperimentConfig()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "CHUNK_SIZE", 12)
        self.mock_parser.add_value("EXPERIMENT", "CHUNKS", 3)
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_chunk_start_str("20001101", 3), "20021101")

    def test_get_chunk_start_str_datetime(self):
        """Test get_chunk_start_str when receiving a date object"""
        config = ExperimentConfig()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "CHUNK_SIZE", 12)
        self.mock_parser.add_value("EXPERIMENT", "CHUNKS", 3)
        date = datetime.datetime(year=2000, month=11, day=1)
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_chunk_start_str(date, 3), "20021101")

    def test_get_chunk_end_str(self):
        """Test get_chunk_end_str"""
        config = ExperimentConfig()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("EXPERIMENT", "CHUNK_SIZE", 12)
        self.mock_parser.add_value("EXPERIMENT", "CHUNKS", 3)
        config.parse_ini(self.mock_parser)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_chunk_end_str("20001101", 3), "20031101")

class TestConfig(TestCase):
    """Tests for Config class"""
        """Prepare tests"""
        self.mock_parser = ParserMock()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("DIAGNOSTICS", "FREQUENCY", "mon")
        self.mock_parser.add_value("DIAGNOSTICS", "DIAGS", "diag1 diag2")
        self.mock_parser.add_value("DIAGNOSTICS", "SCRATCH_DIR", "scratch")
        self._environ = dict(os.environ)
    def tearDown(self):
        """Cleanup"""
        os.environ.clear()
        os.environ.update(self._environ)
    def _parse(self, config):
        def mock_new():
            return self.mock_parser

        def mock_new_exp():
            mock_exp = mock.Mock()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            mock_exp.expid = "expid"
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

        with mock.patch("earthdiagnostics.config.ConfigParser", new=mock_new):
            with mock.patch("earthdiagnostics.config.VariableManager"):
                with mock.patch(
                    "earthdiagnostics.config.ExperimentConfig",
                    new=mock_new_exp,
                ):
                    with mock.patch("earthdiagnostics.config.CMORConfig"):
                        with mock.patch(
                            "earthdiagnostics.config.THREDDSConfig"
                        ):
                            with mock.patch("os.path.isfile"):
                                config.parse("path")

    def test_diags(self):
        """Test diags parsing"""
        config = Config()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "DIAGNOSTICS", "DIAGS", "diag1 diag2,opt1,opt2  # Commented diag"
        )
        self._parse(config)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_commands(), (["diag1", "diag2,opt1,opt2"]))
    def test_file_not_found(self):
        """Test value error is raised if config file is not found"""
        config = Config()
        with self.assertRaises(ValueError):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            config.parse("path")
    def test_parse(self):
        """Test parse minimal config"""
        config = Config()
        self._parse(config)
        self.assertEqual(config.frequency, Frequencies.monthly)
        self.assertEqual(config.auto_clean, True)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.cdftools_path, "")
        self.assertEqual(config.con_files, "")
        self.assertEqual(config.data_adaptor, "CMOR")
        self.assertEqual(config.get_commands(), (["diag1", "diag2"]))
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertIsInstance(config.data_convention, SPECSConvention)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.scratch_masks, "/scratch/Earth/ocean_masks")
        namelist = os.path.abspath(
            os.path.join(
                os.path.dirname(__file__),
                "..",
                "..",
                "earthdiagnostics/CDFTOOLS_specs.namlist",
            )
        )
        self.assertEqual(os.environ["NAM_CDF_NAMES"], namelist)

    def test_alias(self):
        """Test alias parsing"""
        config = Config()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("ALIAS", "diag1", "diag3")
        self._parse(config)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.get_commands(), ["diag3", "diag2"])
    def test_empty_alias(self):
        """Test alias parsing"""
        config = Config()
        self.mock_parser.add_value("ALIAS", "diag1", "")
        self._parse(config)
        self.assertEqual(config.get_commands(), ["diag2"])

    def test_auto_clean_ram_disk(self):
        """Test that USE_RAMDISK forces AUTO_CLEAN to true"""
        config = Config()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("DIAGNOSTICS", "AUTO_CLEAN", False)
        self.mock_parser.add_value("DIAGNOSTICS", "USE_RAMDISK", True)
        self._parse(config)
        self.assertEqual(config.auto_clean, True)
        self.assertEqual(config.use_ramdisk, True)

    def test_data_convention_primavera(self):
        """Test parsing data convention PRIMAVERA"""
        config = Config()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "DIAGNOSTICS", "DATA_CONVENTION", "primavera"
        )
        self._parse(config)
        self.assertIsInstance(config.data_convention, PrimaveraConvention)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.scratch_masks, "/scratch/Earth/ocean_masks/primavera"
        )
        namelist = os.path.abspath(
            os.path.join(
                os.path.dirname(__file__),
                "..",
                "..",
                "earthdiagnostics/CDFTOOLS_primavera.namlist",
            )
        )
        self.assertEqual(os.environ["NAM_CDF_NAMES"], namelist)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    def test_data_convention_cmip6(self):
        """Test parsing data convention CMIP6"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = Config()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("DIAGNOSTICS", "DATA_CONVENTION", "cmip6")
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self._parse(config)
        self.assertIsInstance(config.data_convention, CMIP6Convention)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(
            config.scratch_masks, "/scratch/Earth/ocean_masks/cmip6"
        )
        namelist = os.path.abspath(
            os.path.join(
                os.path.dirname(__file__),
                "..",
                "..",
                "earthdiagnostics/CDFTOOLS_cmip6.namlist",
            )
        )
        self.assertEqual(os.environ["NAM_CDF_NAMES"], namelist)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    def test_data_convention_meteofrance(self):
        """Test parsing data convention MeteoFrance"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = Config()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value(
            "DIAGNOSTICS", "DATA_CONVENTION", "meteofrance"
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self._parse(config)
        self.assertIsInstance(config.data_convention, MeteoFranceConvention)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.scratch_masks, "/scratch/Earth/ocean_masks")
        namelist = os.path.abspath(
            os.path.join(
                os.path.dirname(__file__),
                "..",
                "..",
                "earthdiagnostics/CDFTOOLS_meteofrance.namlist",
            )
        )
        self.assertEqual(os.environ["NAM_CDF_NAMES"], namelist)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    def test_data_convention_preface(self):
        """Test parsing data convention Preface"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        config = Config()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.mock_parser.add_value("DIAGNOSTICS", "DATA_CONVENTION", "preface")
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self._parse(config)
        self.assertIsInstance(config.data_convention, PrefaceConvention)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.assertEqual(config.scratch_masks, "/scratch/Earth/ocean_masks")
        namelist = os.path.abspath(
            os.path.join(
                os.path.dirname(__file__),
                "..",
                "..",
                "earthdiagnostics/CDFTOOLS_preface.namlist",
            )
        )
        self.assertEqual(os.environ["NAM_CDF_NAMES"], namelist)