This guide shows you how to configure tenzir-test project hooks for setup and
cleanup tasks that belong next to your tests. You’ll learn how to select local
Tenzir binaries before discovery, set project-scoped environment variables, and
collect artifacts from failed tests.
Prerequisites
Section titled “Prerequisites”- A
tenzir-testproject with atests/directory. - Python code in the project can import
tenzir_test.
Choose a hook location
Section titled “Choose a hook location”Create a hooks/ package at the project root:
mkdir -p hookstouch hooks/__init__.pyThe harness also supports a single hooks.py file at the project root. Use one
form per project and keep hooks at the project root. The harness doesn’t load
hooks from nested directories such as tests/foo/hooks/.
Select local Tenzir binaries before discovery
Section titled “Select local Tenzir binaries before discovery”Use a startup hook when your project needs to choose tenzir and
tenzir-node before the harness resolves executables. This is useful when you
run tests against a local build instead of the binaries available on PATH.
Add the following hook to hooks/__init__.py:
import subprocessfrom pathlib import Path
from tenzir_test import hooks
@hooks.startupdef use_local_tenzir_build(ctx): # Use ctx.root to resolve paths from the invocation root. build_script = ctx.root / "scripts" / "build.sh"
# Run helper commands with ctx.env so earlier hook changes apply. build_dir = Path( subprocess.check_output( [build_script, "--print-build-dir"], cwd=ctx.root, env=ctx.env, text=True, ).strip() ) if not build_dir.is_absolute(): build_dir = ctx.root / build_dir
# ctx.path is a plain list that becomes PATH after the hook returns. bin_dir = build_dir / "bin" ctx.path.insert(0, str(bin_dir))
# Mutate ctx.env for variables that tenzir-test should apply globally. ctx.env["TENZIR_BINARY"] = str(bin_dir / "tenzir") ctx.env["TENZIR_NODE_BINARY"] = str(bin_dir / "tenzir-node")
# Use ctx.debug to emit optional diagnostics only in debug mode. if ctx.debug: print(f"using Tenzir binaries from {bin_dir}")This example uses the ctx object to:
- Resolve project-local paths with
ctx.root. - Run a helper command with
subprocess.check_output()andctx.env. - Update
PATHby editing the plainctx.pathlist. - Set global environment variables through
ctx.env. - Print extra details only when
ctx.debugis enabled.
Run the tests as usual:
uvx tenzir-testThe startup hook runs before settings and binary discovery. Changes to
ctx.env, ctx.path, TENZIR_BINARY, and TENZIR_NODE_BINARY affect the
whole invocation. To keep path handling predictable, edit ctx.path instead of
ctx.env["PATH"].
Set environment variables for one project
Section titled “Set environment variables for one project”Use project_start for environment values that should apply only to tests in
the current project:
from tenzir_test import hooks
@hooks.project_startdef configure_project(ctx): ctx.env["TENZIR_TEST_DATASET"] = ctx.project.root.nameThe mapping in ctx.env and the list in ctx.path are project-scoped.
Mutations apply to tests in that project and don’t leak into the next project in
a multi-project run.
Collect failed-test artifacts
Section titled “Collect failed-test artifacts”Use test_failure to copy files from the per-test scratch directory before the
harness removes it:
import shutil
from tenzir_test import hooks
@hooks.test_failuredef save_failure_artifacts(ctx): if ctx.tmp_dir is None: return relative_test = ctx.test.relative_to(ctx.project.root).with_suffix("") target = ctx.project.root / ".tenzir-test-failures" / relative_test shutil.copytree(ctx.tmp_dir, target, dirs_exist_ok=True) print(f"saved failure artifacts to {target}")This hook runs after test_finish and only for final failures. It doesn’t run
for intermediate retry attempts.
Understand hook ordering
Section titled “Understand hook ordering”For multi-project runs, root hooks wrap satellite hooks:
- Start events run from outer to inner: root, then satellite.
- Finish and failure events run from inner to outer: satellite, then root.
For a satellite test, the order is:
root.project_startsatellite.project_startroot.test_startsatellite.test_startrun testsatellite.test_finishroot.test_finishsatellite.test_failure # failed tests onlyroot.test_failure # failed tests onlysatellite.project_finishroot.project_finishA root invocation runs only the root startup hook, even when it selects
satellites. A satellite startup hook runs only when that satellite is the
invocation root.
Disable hooks during recovery
Section titled “Disable hooks during recovery”If a hook prevents the harness from starting, disable hooks for one invocation:
uvx tenzir-test --no-hooksYou can use the environment variable equivalent in scripts or CI:
TENZIR_TEST_DISABLE_HOOKS=1 uvx tenzir-testNext steps
Section titled “Next steps”- Use
shutdownto emit final telemetry or clean up resources created duringstartup. - Use
test_startandtest_finishto record per-test timing or status in an external system. - Review the test framework reference for the full event list and CLI options.