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

feature #2253 tests for config_validate, mock logger in conftest #2320

Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 20 additions & 0 deletions internal/tests/pytests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytest
import getpass
import shutil
from unittest import mock
from pathlib import Path
from netCDF4 import Dataset

Expand Down Expand Up @@ -80,12 +81,30 @@ def metplus_config(request):
the failed tests. To use this fixture, add metplus_config to the test
function arguments and set a variable called config to metplus_config, e.g.
config = metplus_config.

This fixture also replaces config.logger with a MagicMock object. This
allows tests to assert the logger was called with a specific message.

e.g.
def test_example(metplus_config):
config = metplus_config
some_function(config)
config.logger.info.assert_called_once_with("Info message")
config.logger.error.assert_not_called()

See documentation for unittest.mock for full functionality.
"""
script_dir = os.path.dirname(__file__)
args = [os.path.join(script_dir, "minimum_pytest.conf")]
config = config_metplus.setup(args)

# Set mock logger
old_logger = config.logger
config.logger = mock.MagicMock()

yield config

config.logger = old_logger
# don't remove output base if test fails
if request.node.rep_call.failed:
return
Expand Down Expand Up @@ -115,6 +134,7 @@ def read_configs(extra_configs):

return read_configs


@pytest.fixture(scope="module")
def make_dummy_nc():
return make_nc
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
////////////////////////////////////////////////////////////////////////////////
// Fake config for testing config_validate.py
//
censor_thresh = [];
censor_val = [];
cat_thresh = [ NA ];
cnt_thresh = [ NA ];

//
// Forecast and observation fields to be verified
//
fcst = {
${METPLUS_FCST_FILE_TYPE}
${METPLUS_FCST_FIELD}
}

obs = {
${METPLUS_OBS_FILE_TYPE}
${METPLUS_OBS_FIELD}
}
////////////////////////////////////////////////////////////////////////////////
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/usr/bin/env python3

import pytest

from unittest import mock
import pprint
import os
from datetime import datetime

from metplus.util.config_validate import *
from metplus.util import config_validate as cv


@pytest.mark.parametrize(
Expand Down Expand Up @@ -51,7 +51,7 @@
@pytest.mark.util
def test_is_var_item_valid(metplus_config, item_list, extension, is_valid):
conf = metplus_config
assert is_var_item_valid(item_list, '1', extension, conf)[0] == is_valid
assert cv.is_var_item_valid(item_list, '1', extension, conf)[0] == is_valid


@pytest.mark.parametrize(
Expand Down Expand Up @@ -97,4 +97,94 @@ def test_is_var_item_valid_levels(metplus_config, item_list, configs_to_set, is_
for key, value in configs_to_set.items():
conf.set('config', key, value)

assert is_var_item_valid(item_list, '1', 'LEVELS', conf)[0] == is_valid
assert cv.is_var_item_valid(item_list, '1', 'LEVELS', conf)[0] == is_valid



@pytest.mark.parametrize(
'deprecated_list, expected',
[
([], (True, [])),
(['METPLUS_FCST_FILE_TYPE'], (False, [])),
(['SOME_OTHER_CONFIG_ITEM'], (True, [])),
]
)
@pytest.mark.util
def test_check_for_deprecated_met_config(metplus_config, deprecated_list, expected):
script_dir = os.path.dirname(__file__)
met_config = os.path.join(script_dir, 'met_config_validate.conf')

metplus_config.set('config', 'TEST_CONFIG_FILE', met_config)

with mock.patch.object(cv, 'DEPRECATED_MET_LIST', deprecated_list):
actual = cv.check_for_deprecated_met_config(metplus_config)
assert actual == expected


@pytest.mark.util
def test_check_for_deprecated_config_simple(metplus_config):
actual = cv.check_for_deprecated_config(metplus_config)
assert actual == (True, [])
metplus_config.logger.error.assert_not_called


@pytest.mark.parametrize(
'dep_item,deprecated_dict, expected, err_msgs',
[
(
"TEST_DEPRECATED",
{
'upgrade': 'ensemble',
'alt': 'ice cream',
'copy': True
},
(False, ["sed -i 's|^TEST_DEPRECATED|ice cream|g' dir/config1.conf", "sed -i 's|{TEST_DEPRECATED}|{ice cream}|g' dir/config1.conf"]),
['DEPRECATED CONFIG ITEMS WERE FOUND. PLEASE FOLLOW THE INSTRUCTIONS TO UPDATE THE CONFIG FILES',
'TEST_DEPRECATED should be replaced with ice cream'],
),
(
"TEST_DEPRECATED_<n>",
{
'upgrade': 'ensemble',
'alt': 'nth degree',
'copy': False
},
(False, []),
['DEPRECATED CONFIG ITEMS WERE FOUND. PLEASE FOLLOW THE INSTRUCTIONS TO UPDATE THE CONFIG FILES'],
),
(
"TEST_DEPRECATED_NO_ALT",
{},
(False, []),
['DEPRECATED CONFIG ITEMS WERE FOUND. PLEASE FOLLOW THE INSTRUCTIONS TO UPDATE THE CONFIG FILES',
'TEST_DEPRECATED_NO_ALT should be removed'],
),
(
"TEST_DEPRECATED_NO_dict",
[],
(True, []),
[],
),
]
)
@pytest.mark.util
def test_check_for_deprecated_config(metplus_config,
dep_item,
deprecated_dict,
expected,
err_msgs):

depr_dict = {dep_item: deprecated_dict}
config = metplus_config
config.set('config', dep_item.replace('<n>','2'), 'old value')
config.set('config', 'CONFIG_INPUT', 'dir/config1.conf')

with mock.patch.object(cv, 'DEPRECATED_DICT', depr_dict):
actual = cv.check_for_deprecated_config(metplus_config)
assert actual == expected

if err_msgs:
for msg in err_msgs:
config.logger.error.assert_any_call(msg)
else:
config.logger.error.assert_not_called
19 changes: 19 additions & 0 deletions internal/tests/pytests/util/constants/test_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import pytest
from metplus.util.constants import DEPRECATED_DICT

@pytest.mark.util
def test_deprecated_dict():
"""
Test that the structure of DEPRECATED_DICT is as expected.
If not config_validate may give unexpected answers, and
will not necessarily raise an error.
"""
allowed_keys = {'alt','copy','upgrade'}
allowed_upgrade_values = {'ensemble'}

for _, v in DEPRECATED_DICT.items():
assert isinstance(v, dict)
assert set(v.keys()).issubset(allowed_keys)

if 'upgrade' in v.keys():
assert v['upgrade'] in allowed_upgrade_values