Source code for schrodinger.test.pytest.fixture
"""
Features that a developer might use when writing tests.
"""
import contextlib
import os
import pathlib
import shutil
import sys
from unittest.mock import patch
import pytest
from schrodinger import get_mmshare_version
from schrodinger.infra import mmjob
from schrodinger.test import mmshare_testfile
from . import exetest
[docs]@pytest.fixture
def unittest_preset_manager():
"""
A fixture that mocks out the PresetManager with a PresetManager
that uses the current working directory as the presets directory.
This prevents reliance on system state.
"""
def _getPresetsDirectory(self):
return os.path.join('.', 'foo', self._panel_name)
with patch('schrodinger.models.presets.PresetManager._getPresetsDirectory',
_getPresetsDirectory):
yield
[docs]@pytest.fixture
def json_version():
"""
A fixture that mocks out the version used by
schrodinger.models.json.JsonableClassMixin. By default, the version returned
will be the current mmshare version. The return_value of the fixture can be
adjusted to change the version. Example::
def my_test(json_version):
from schrodinger.models import json
from schrodinger import get_mmshare_version
foo = json.JsonableClassMixin()
assert foo.get_version() == get_mmshare_version()
json_version.return_value = 10
assert foo.get_version() == 10
"""
with patch('schrodinger.models.json.JsonableClassMixin.get_version'
) as get_version_mock:
get_version_mock.return_value = get_mmshare_version()
yield get_version_mock
[docs]@pytest.fixture
def tmp_cwd(tmpdir_factory, request, monkeypatch):
nodeid = os.path.basename(request.node.nodeid)
nodeid = nodeid.replace(':', '_').replace('.', '_')
# nodeid = 'sort_test.sdaf'
d = tmpdir_factory.mktemp(nodeid)
setattr(request.node, 'schro_tmp_cwd', str(d))
cwd = os.getcwd()
try:
os.chdir(d)
yield str(d)
finally:
os.chdir(cwd)
[docs]@pytest.fixture
def log_to_stdout():
"""Log to stdout instead of files"""
with patch('logging.FileHandler._open', return_value=sys.stdout):
yield
class _allow_memtest:
"""
Run a command from a Python test.
For legacy mmlibs tests
Raises an exception if the command fails or if memtest fails.
"""
def __init__(self, request):
self.node = request.node
def check_call(self, cmd, env=None, stdout=None, stderr=None):
# This is all stuff that is required for memtest to accurately
# find suppressions, for instance.
t = exetest.ExecutableTest.from_parent(name=self.node.fspath.basename,
parent=self.node)
exe_candidates = [cmd[0], f"{cmd[0]}.exe"]
exe_candidates.extend([shutil.which(exe) for exe in exe_candidates])
exe_candidates = [
pathlib.Path(exe) for exe in exe_candidates if exe is not None
]
executable = None
for cand in exe_candidates:
if cand.exists():
executable = os.fspath(cand.absolute())
break
if executable is None:
raise RuntimeError(f"executable {cmd[0]} not found")
cmd = [executable] + cmd[1:]
t.command = cmd
t.runtest(capture=False, env=env, stdout=stdout, stderr=stderr)
[docs]@pytest.fixture
def allow_memtest(request):
# class-based fixtures are not supported.
return _allow_memtest(request)
[docs]@pytest.fixture
def fast_jobdj():
"""
Use this fixture to make jobDJ use minimal delays in updating, at the
expense of throttling the CPU.
"""
with patch("schrodinger.job.queue.USE_JOB_CONTROL_MESSAGES", False):
with patch("schrodinger.job.queue.MONITOR_DELAY", 0.1):
yield
[docs]@pytest.fixture
def mock_gpgpu_hosts_env():
try:
with patch.dict(os.environ, {
"SCHRODINGER_HOSTS":
mmshare_testfile("job_test_files/gpgpu.hosts")
}):
mmjob.mmjob_hosts_reload()
yield
finally:
mmjob.mmjob_hosts_reload()
class _MockTaskHelper(contextlib.ExitStack):
"""
Helper class to mock task methods that are needed for the task to finish.
The mocked task will have task.status == task.FAILED
"""
def patch_run(self, task):
"""
Patch task.run and force the task to fail
:rtype: mock.Mock
"""
return self._patch_task(task, "run")
def patch__launchCmd(self, task):
"""
Patch task._launchCmd and force the task to fail
:rtype: mock.Mock
"""
return self._patch_task(task, "_launchCmd")
def _patch_task(self, task, method_name):
patcher = patch.object(task, method_name, side_effect=RuntimeError)
return self.enter_context(patcher)
[docs]@pytest.fixture
def mock_task_helper():
"""
Fixture for mocking task methods that are required for the task to finish
without leaving the task with status RUNNING.
Usage::
def test_foo_task(mock_task_helper):
task = FooTask()
mock_task_helper.patch_run(task)
task.start()
assert task.status is task.FAILED
"""
with _MockTaskHelper() as helper:
yield helper