6
0
mirror of https://github.com/ChristianLight/tutor.git synced 2024-12-12 14:17:46 +00:00
tutor/tests/helpers.py
Régis Behmo 16e6131f96 feat: pluggable local/dev/k8s do <job> commands
We introduce a new filter to implement custom commands in arbitrary containers.
It becomes easy to write convenient ad-hoc commands that users will
then be able to run either on Kubernetes or locally using a documented CLI.

Pluggable jobs are declared as Click commands and are responsible for
parsing their own arguments. See the new CLI_DO_COMMANDS filter.

Close https://github.com/overhangio/2u-tutor-adoption/issues/75
2022-11-15 09:46:08 +01:00

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 BaseTaskContext
from tutor.tasks import BaseTaskRunner
from tutor.types import Config
class TestTaskRunner(BaseTaskRunner):
"""
Mock job runner for unit testing.
This runner does nothing except print the service name and command,
separated by dashes.
"""
def run_task(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(BaseTaskContext):
"""
Click context that will use only test job runners.
"""
def job_runner(self, config: Config) -> TestTaskRunner:
return TestTaskRunner(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)