From 081482808c1ee407967e24bafeb27ffc0c0c24ba Mon Sep 17 00:00:00 2001 From: John Sharples Date: Mon, 24 Jul 2023 04:25:49 +0000 Subject: [PATCH] Feature #2253 conftest fixture to set pytest tmpdir Adds an autouse fixture to the pytest conftest.py file which overrides default location for temporary location used by pytest fixtures (e.g. tmpdir_factory) --- docs/Contributors_Guide/github_workflow.rst | 1 + docs/Contributors_Guide/testing.rst | 6 --- internal/tests/pytests/conftest.py | 44 ++++++++++++++++----- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/docs/Contributors_Guide/github_workflow.rst b/docs/Contributors_Guide/github_workflow.rst index 161e1c44d9..cde65598f0 100644 --- a/docs/Contributors_Guide/github_workflow.rst +++ b/docs/Contributors_Guide/github_workflow.rst @@ -482,6 +482,7 @@ Create a feature branch .. code-block:: ini + git fetch upstream develop git checkout develop * Verify the current development branch is active by running: diff --git a/docs/Contributors_Guide/testing.rst b/docs/Contributors_Guide/testing.rst index 1548dbe147..28574df4d7 100644 --- a/docs/Contributors_Guide/testing.rst +++ b/docs/Contributors_Guide/testing.rst @@ -37,12 +37,6 @@ permissions, navigate to the METplus directory, then call pytest:: cd METplus pytest internal/tests/pytests -Some of the tests use your default location for writing temporary files, -typically `/tmp`. If you do not have write permissions this may cause an -error. To override this behaviour you can specify the default directory:: - - pytest --basetemp=${METPLUS_TEST_OUTPUT_BASE}/tmp internal/tests/pytests - A report will be output showing which pytest categories failed. To view verbose test output, add the **-vv** argument:: diff --git a/internal/tests/pytests/conftest.py b/internal/tests/pytests/conftest.py index 968f96b736..c42b83635f 100644 --- a/internal/tests/pytests/conftest.py +++ b/internal/tests/pytests/conftest.py @@ -13,25 +13,48 @@ from metplus.util import config_metplus -output_base = os.environ.get('METPLUS_TEST_OUTPUT_BASE') +output_base = os.environ.get("METPLUS_TEST_OUTPUT_BASE") if not output_base: - print('ERROR: METPLUS_TEST_OUTPUT_BASE must be set to a path to write') + print("ERROR: METPLUS_TEST_OUTPUT_BASE must be set to a path to write") sys.exit(1) try: - test_output_dir = os.path.join(output_base, 'test_output') + test_output_dir = os.path.join(output_base, "test_output") if os.path.exists(test_output_dir): - print(f'Removing test output dir: {test_output_dir}') + print(f"Removing test output dir: {test_output_dir}") shutil.rmtree(test_output_dir) if not os.path.exists(test_output_dir): - print(f'Creating test output dir: {test_output_dir}') + print(f"Creating test output dir: {test_output_dir}") os.makedirs(test_output_dir) except PermissionError: - print(f'ERROR: Cannot write to $METPLUS_TEST_OUTPUT_BASE: {output_base}') + print(f"ERROR: Cannot write to $METPLUS_TEST_OUTPUT_BASE: {output_base}") sys.exit(2) +@pytest.fixture(scope="session", autouse=True) +def custom_tmpdir(): + """! Set the default output location for temp files produced by pytest + to METPLUS_TEST_OUTPUT_BASE env var. Causes default pytest fixtures, + such as tmpdir_factory, to write temp files to this dir. + + A sub directory named 'pytest_tmp' is created to ensure there will never + be name conflicts between files created by default pytest fixture and + other methods for writing temp files. + """ + original_var = os.environ.get("PYTEST_DEBUG_TEMPROOT", None) + output_base = os.environ.get("METPLUS_TEST_OUTPUT_BASE") + temp_base = os.path.join(output_base, "pytest_tmp") + + os.environ["PYTEST_DEBUG_TEMPROOT"] = temp_base + if not os.path.exists(temp_base): + os.mkdir(temp_base) + yield + # Restore original value, if existed + if original_var: + os.environ["PYTEST_DEBUG_TEMPROOT"] = original_var + + @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): """! This is used to capture the status of a test so the metplus_config @@ -58,19 +81,19 @@ def metplus_config(request): config = metplus_config. """ script_dir = os.path.dirname(__file__) - args = [os.path.join(script_dir, 'minimum_pytest.conf')] + args = [os.path.join(script_dir, "minimum_pytest.conf")] config = config_metplus.setup(args) yield config # don't remove output base if test fails if request.node.rep_call.failed: return - config_output_base = config.getdir('OUTPUT_BASE') + config_output_base = config.getdir("OUTPUT_BASE") if config_output_base and os.path.exists(config_output_base): shutil.rmtree(config_output_base) -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def metplus_config_files(): """! Create a METplus configuration object using minimum_pytest.conf settings and any list of config files.The metplus_config fixture is @@ -79,10 +102,11 @@ def metplus_config_files(): metplus_config_files as an argument to the test function and pass in a list of config files to it. Example: config = metplus_config_files([my_file]) """ + def read_configs(extra_configs): # Read in minimum pytest config file and any other extra configs script_dir = os.path.dirname(__file__) - minimum_conf = os.path.join(script_dir, 'minimum_pytest.conf') + minimum_conf = os.path.join(script_dir, "minimum_pytest.conf") args = extra_configs.copy() args.append(minimum_conf) config = config_metplus.setup(args)