tutor/tests/helpers.py

79 lines
2.2 KiB
Python

import os
import tempfile
import typing as t
import unittest
import unittest.result
from tutor import hooks
from tutor.commands.context import BaseJobContext
from tutor.jobs import BaseJobRunner
from tutor.types import Config
class TestJobRunner(BaseJobRunner):
"""
Mock job runner for unit testing.
This runner does nothing except print the service name and command,
separated by dashes.
"""
def run_job(self, service: str, command: str) -> int:
print(os.linesep.join([f"Service: {service}", "-----", command, "----- "]))
return 0
def temporary_root() -> "tempfile.TemporaryDirectory[str]":
"""
Context manager to handle temporary test root.
This function can be used as follows:
with temporary_root() as root:
config = tutor_config.load_full(root)
...
"""
return tempfile.TemporaryDirectory(prefix="tutor-test-root-")
class TestContext(BaseJobContext):
"""
Click context that will use only test job runners.
"""
def job_runner(self, config: Config) -> TestJobRunner:
return TestJobRunner(self.root, config)
class PluginsTestCase(unittest.TestCase):
"""
This test case class clears the hooks created during tests. It also makes sure that
we don't accidentally load entrypoint/dict plugins from the user.
"""
def setUp(self) -> None:
self.clean()
self.addCleanup(self.clean)
super().setUp()
def clean(self) -> None:
# We clear hooks created in some contexts, such that user plugins are never loaded.
for context in [
hooks.Contexts.PLUGINS.name,
hooks.Contexts.PLUGINS_V0_ENTRYPOINT.name,
hooks.Contexts.PLUGINS_V0_YAML.name,
"unittests",
]:
hooks.filters.clear_all(context=context)
hooks.actions.clear_all(context=context)
def run(
self, result: t.Optional[unittest.result.TestResult] = None
) -> t.Optional[unittest.result.TestResult]:
"""
Run all actions and filters with a test context, such that they can be cleared
from one run to the next.
"""
with hooks.contexts.enter("unittests"):
return super().run(result=result)