tenzir-test 0.12.0__tar.gz → 0.13.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/PKG-INFO +1 -1
  2. tenzir_test-0.13.0/changelog/config.yaml +4 -0
  3. tenzir_test-0.13.0/changelog/releases/v0.11.0/entries/01-expose-tenzir-test-as-a-library.md +27 -0
  4. tenzir_test-0.13.0/changelog/releases/v0.11.0/manifest.yaml +4 -0
  5. tenzir_test-0.13.0/changelog/releases/v0.11.0/notes.md +23 -0
  6. tenzir_test-0.13.0/changelog/releases/v0.12.0/entries/01-honor-no-color-for-python-api-consumers.md +16 -0
  7. tenzir_test-0.13.0/changelog/releases/v0.12.0/manifest.yaml +4 -0
  8. tenzir_test-0.13.0/changelog/releases/v0.12.0/notes.md +17 -0
  9. tenzir_test-0.13.0/changelog/releases/v0.13.0/entries/01-improve-diagnostics-when-tenzir-node-fails-to-start.md +12 -0
  10. tenzir_test-0.13.0/changelog/releases/v0.13.0/entries/01-library-mode-and-package-dirs.md +32 -0
  11. tenzir_test-0.13.0/changelog/releases/v0.13.0/manifest.yaml +4 -0
  12. tenzir_test-0.13.0/changelog/releases/v0.13.0/notes.md +29 -0
  13. tenzir_test-0.13.0/example-library/README.md +43 -0
  14. tenzir_test-0.13.0/example-library/bar/operators/double.tql +1 -0
  15. tenzir_test-0.13.0/example-library/bar/package.yaml +4 -0
  16. tenzir_test-0.13.0/example-library/bar/test.yaml +2 -0
  17. tenzir_test-0.13.0/example-library/bar/tests/use-foo.tql +2 -0
  18. tenzir_test-0.13.0/example-library/bar/tests/use-foo.txt +3 -0
  19. tenzir_test-0.13.0/example-library/foo/operators/increment.tql +1 -0
  20. tenzir_test-0.13.0/example-library/foo/package.yaml +4 -0
  21. tenzir_test-0.13.0/example-library/foo/test.yaml +2 -0
  22. tenzir_test-0.13.0/example-library/foo/tests/use-bar.tql +2 -0
  23. tenzir_test-0.13.0/example-library/foo/tests/use-bar.txt +3 -0
  24. tenzir_test-0.13.0/example-package/operators/deeply/nested/twist.tql +7 -0
  25. tenzir_test-0.13.0/example-package/operators/filter.tql +1 -0
  26. tenzir_test-0.13.0/example-package/operators/parse.tql +2 -0
  27. tenzir_test-0.13.0/example-package/package.yaml +29 -0
  28. tenzir_test-0.13.0/example-package/tests/context/01-context-list.tql +2 -0
  29. tenzir_test-0.13.0/example-package/tests/context/01-context-list.txt +5 -0
  30. tenzir_test-0.13.0/example-package/tests/context/02-context-update.tql +4 -0
  31. tenzir_test-0.13.0/example-package/tests/context/03-context-inspect.tql +1 -0
  32. tenzir_test-0.13.0/example-package/tests/context/test.yaml +2 -0
  33. tenzir_test-0.13.0/example-package/tests/inputs/sample.log +12 -0
  34. tenzir_test-0.13.0/example-package/tests/ops.tql +4 -0
  35. tenzir_test-0.13.0/example-package/tests/ops.txt +15 -0
  36. tenzir_test-0.13.0/example-package/tests/twist.tql +4 -0
  37. tenzir_test-0.13.0/example-package/tests/twist.txt +12 -0
  38. tenzir_test-0.13.0/example-project/tests/context/03-context-inspect.txt +12 -0
  39. tenzir_test-0.13.0/example-satellite/README.md +27 -0
  40. tenzir_test-0.13.0/example-satellite/fixtures.py +14 -0
  41. tenzir_test-0.13.0/example-satellite/inputs/input.txt +1 -0
  42. tenzir_test-0.13.0/example-satellite/tests/hex/reuse.txt +2 -0
  43. tenzir_test-0.13.0/example-satellite/tests/hex/reuse.xxd +1 -0
  44. tenzir_test-0.13.0/example-satellite/tests/satellite/input.sh +2 -0
  45. tenzir_test-0.13.0/example-satellite/tests/satellite/input.txt +2 -0
  46. tenzir_test-0.13.0/example-satellite/tests/satellite/marker.sh +4 -0
  47. tenzir_test-0.13.0/example-satellite/tests/satellite/marker.txt +1 -0
  48. tenzir_test-0.13.0/example-satellite/tests/satellite/test.yaml +3 -0
  49. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/pyproject.toml +10 -7
  50. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/cli.py +19 -0
  51. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/config.py +1 -1
  52. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/fixtures/node.py +83 -6
  53. tenzir_test-0.13.0/src/tenzir_test/py.typed +0 -0
  54. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/run.py +161 -3
  55. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/tests/test_run.py +61 -0
  56. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/tests/test_run_config.py +72 -4
  57. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/.gitignore +0 -0
  58. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/LICENSE +0 -0
  59. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/README.md +0 -0
  60. {tenzir_test-0.12.0/example-project → tenzir_test-0.13.0/example-package}/tests/context/02-context-update.txt +0 -0
  61. {tenzir_test-0.12.0/example-project → tenzir_test-0.13.0/example-package}/tests/context/03-context-inspect.txt +0 -0
  62. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/README.md +0 -0
  63. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/fixtures/README.md +0 -0
  64. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/fixtures/__init__.py +0 -0
  65. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/fixtures/http.py +0 -0
  66. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/fixtures/server.py +0 -0
  67. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/inputs/events.ndjson +0 -0
  68. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/runners/__init__.py +0 -0
  69. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/runners/xxd.py +0 -0
  70. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/context/01-context-create.tql +0 -0
  71. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/context/01-context-create.txt +0 -0
  72. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/context/02-context-update.tql +0 -0
  73. /tenzir_test-0.12.0/example-project/tests/lazy.txt → /tenzir_test-0.13.0/example-project/tests/context/02-context-update.txt +0 -0
  74. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/context/03-context-inspect.tql +0 -0
  75. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/context/test.yaml +0 -0
  76. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/fail.tql +0 -0
  77. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/fail.txt +0 -0
  78. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/hex/hello.txt +0 -0
  79. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/hex/hello.xxd +0 -0
  80. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/http-fixture.tql +0 -0
  81. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/http-fixture.txt +0 -0
  82. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/lazy.tql +0 -0
  83. /tenzir_test-0.12.0/example-project/tests/shell/http-fixture-check.txt → /tenzir_test-0.13.0/example-project/tests/lazy.txt +0 -0
  84. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/node-fixture.tql +0 -0
  85. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/node-fixture.txt +0 -0
  86. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/executor-only/sum.py +0 -0
  87. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/executor-only/sum.txt +0 -0
  88. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/executor-with-http-fixture/request.py +0 -0
  89. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/executor-with-http-fixture/request.txt +0 -0
  90. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/executor-with-http-fixture/test.yaml +0 -0
  91. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/executor-with-node-fixture/context-manager.py +0 -0
  92. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/executor-with-node-fixture/context-manager.txt +0 -0
  93. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/fixture-driving/manual_control.py +0 -0
  94. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/fixture-driving/manual_control.txt +0 -0
  95. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/pure-python/flaky_coin.py +0 -0
  96. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/pure-python/flaky_coin.txt +0 -0
  97. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/pure-python/hello_world.py +0 -0
  98. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/python/pure-python/hello_world.txt +0 -0
  99. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/read-inputs.tql +0 -0
  100. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/read-inputs.txt +0 -0
  101. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/shell/exit-code-test.sh +0 -0
  102. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/shell/exit-code-test.txt +0 -0
  103. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/shell/http-fixture-check.sh +0 -0
  104. /tenzir_test-0.12.0/src/tenzir_test/py.typed → /tenzir_test-0.13.0/example-project/tests/shell/http-fixture-check.txt +0 -0
  105. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/shell/tmp-dir.sh +0 -0
  106. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/example-project/tests/shell/tmp-dir.txt +0 -0
  107. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/__init__.py +0 -0
  108. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/_python_runner.py +0 -0
  109. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/checks.py +0 -0
  110. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/engine/__init__.py +0 -0
  111. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/engine/operations.py +0 -0
  112. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/engine/registry.py +0 -0
  113. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/engine/state.py +0 -0
  114. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/engine/worker.py +0 -0
  115. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/fixtures/__init__.py +0 -0
  116. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/packages.py +0 -0
  117. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/__init__.py +0 -0
  118. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/_utils.py +0 -0
  119. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/custom_python_fixture_runner.py +0 -0
  120. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/diff_runner.py +0 -0
  121. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/ext_runner.py +0 -0
  122. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/runner.py +0 -0
  123. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/shell_runner.py +0 -0
  124. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/tenzir_runner.py +0 -0
  125. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/src/tenzir_test/runners/tql_runner.py +0 -0
  126. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/tests/test_cli.py +0 -0
  127. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/tests/test_config.py +0 -0
  128. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/tests/test_engine_operations.py +0 -0
  129. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/tests/test_python_runner.py +0 -0
  130. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/tests/test_runner_registry.py +0 -0
  131. {tenzir_test-0.12.0 → tenzir_test-0.13.0}/tests/test_shell_runner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tenzir-test
3
- Version: 0.12.0
3
+ Version: 0.13.0
4
4
  Summary: Reusable test execution framework extracted from the Tenzir repository.
5
5
  Project-URL: Homepage, https://github.com/tenzir/test
6
6
  Project-URL: Repository, https://github.com/tenzir/test
@@ -0,0 +1,4 @@
1
+ id: tenzir-test
2
+ name: Tenzir Test
3
+ description: A testing framework for the Tenzir ecosystem
4
+ repository: tenzir/test
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Expose tenzir-test as a library
3
+ type: feature
4
+ authors:
5
+ - mavam
6
+ - codex
7
+ created: 2025-11-04
8
+ ---
9
+
10
+ The test framework now exposes its harness as a reusable Python library,
11
+ returning structured execution results instead of exiting the process. Callers
12
+ can import the new `execute` helper and receive an `ExecutionResult` with
13
+ project summaries, exit codes, and failure details for downstream automation.
14
+
15
+ Example:
16
+
17
+ ```python
18
+ from pathlib import Path
19
+
20
+ from tenzir_test import ExecutionResult, execute
21
+
22
+ result: ExecutionResult = execute(tests=[Path("tests/pipeline.tql")])
23
+ if result.exit_code:
24
+ raise SystemExit(result.exit_code)
25
+ for project in result.project_results:
26
+ print(project.selection.root, project.summary.total)
27
+ ```
@@ -0,0 +1,4 @@
1
+ created: 2025-11-04
2
+ title: Tenzir Test v0.11.0
3
+ intro: >-
4
+ Expose tenzir-test as a reusable Python library.
@@ -0,0 +1,23 @@
1
+ Expose tenzir-test as a reusable Python library.
2
+
3
+ ## 🚀 Features
4
+
5
+ ### Expose tenzir-test as a library
6
+
7
+ The test framework now exposes its harness as a reusable Python library, returning structured execution results instead of exiting the process. Callers can import the new `execute` helper and receive an `ExecutionResult` with project summaries, exit codes, and failure details for downstream automation.
8
+
9
+ Example:
10
+
11
+ ```python
12
+ from pathlib import Path
13
+
14
+ from tenzir_test import ExecutionResult, execute
15
+
16
+ result: ExecutionResult = execute(tests=[Path("tests/pipeline.tql")])
17
+ if result.exit_code:
18
+ raise SystemExit(result.exit_code)
19
+ for project in result.project_results:
20
+ print(project.selection.root, project.summary.total)
21
+ ```
22
+
23
+ *By @mavam and @codex.*
@@ -0,0 +1,16 @@
1
+ ---
2
+ title: Add configurable color output control
3
+ type: feature
4
+ authors:
5
+ - codex
6
+ - mavam
7
+ created: 2025-11-05
8
+ ---
9
+
10
+ We default library consumers to plain output, keep the CLI smart about ANSI usage, and honour `NO_COLOR` across every helper while locking the behaviour down with tests.
11
+
12
+ When you `import tenzir_test.run`, the harness now emits unstyled text so CI logs stay machine-readable. You can still opt back into colours via `run.set_color_mode(run.ColorMode.ALWAYS)` or let auto-detection pick the best option.
13
+
14
+ Running `tenzir-test` in a terminal still shows coloured summaries, but redirecting stdout—or exporting `NO_COLOR=1`—forces the palette to plain text, covering diff hunks, failure trees, retry banners, and runner diagnostics.
15
+
16
+ A single palette helper now drives every glyph and symbol, and pytest coverage exercises CLI, library, and `NO_COLOR` modes to catch regressions immediately.
@@ -0,0 +1,4 @@
1
+ created: 2025-11-05
2
+ title: Tenzir Test 0.12.0
3
+ intro: >-
4
+ Minor release with improved NO_COLOR handling.
@@ -0,0 +1,17 @@
1
+ Minor release with improved NO_COLOR handling.
2
+
3
+ ## 🚀 Features
4
+
5
+ ### Add configurable color output control
6
+
7
+ We switched library consumers to plain output by default and added full `NO_COLOR` support, keeping ANSI colors only where they enhance the interactive experience.
8
+
9
+ When you `import tenzir_test.run` directly, the harness now emits unstyled text by default—perfect for log parsers, CI systems, and automation scripts that expect machine-readable output. If you need colors back, call `run.set_color_mode(run.ColorMode.ALWAYS)` to force ANSI sequences on, or use `run.ColorMode.AUTO` to let the harness detect terminal capabilities.
10
+
11
+ The `tenzir-test` CLI continues to auto-detect your terminal and renders colors when you run tests interactively. Redirect stdout to a file or pipe, and it automatically switches to plain mode. Set `NO_COLOR=1` in your environment, and every output—failure trees, diff hunks, retry banners—strips its color codes.
12
+
13
+ All palette logic now lives in a single helper that colorizes checkmarks, crosses, diff lines, and progress indicators consistently. This unification means `run.print_diff(...)` respects your color mode choice everywhere, whether you invoke it from the CLI or from library code.
14
+
15
+ We added pytest coverage for all three modes—CLI with colors, library without colors, and `NO_COLOR=1` forcing plain output—so future changes won't break the contract.
16
+
17
+ *By @codex and @mavam.*
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Improve diagnostics when Tenzir Node fails to start
3
+ type: change
4
+ authors:
5
+ - Alainx277
6
+ - claude
7
+ prs:
8
+ - 2
9
+ created: 2025-12-02
10
+ ---
11
+
12
+ The `node` fixture now reports the exit code and stderr output when `tenzir-node` fails to start, making it easier to diagnose startup failures. Previously, the error message provided no context about why the node failed to produce an endpoint.
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Library mode and extra packages
3
+ type: feature
4
+ authors:
5
+ - codex
6
+ - mavam
7
+ prs:
8
+ - 4
9
+ created: 2025-12-02
10
+ ---
11
+
12
+ Explicit package loading for tests: use `--package-dirs` (repeatable, accepts
13
+ comma-separated lists) to point the harness at package directories. The same
14
+ flag is passed to the Tenzir binaries, and it merges with any `package-dirs:`
15
+ declared in directory `test.yaml` files. Entries are normalized and
16
+ de-duplicated, then exported via `TENZIR_PACKAGE_DIRS` for fixtures.
17
+
18
+ The test configuration uses the same spelling: add
19
+
20
+ ```yaml
21
+ package-dirs:
22
+ - ../shared-packages
23
+ - /opt/tenzir/packages/foo
24
+ ```
25
+
26
+ to a directory `test.yaml` when you want those packages available for the tests
27
+ below it.
28
+
29
+ Example: `uvx tenzir-test --package-dirs example-library example-library`
30
+ loads both `foo` and `bar` packages so their operators can cross-import. The
31
+ example-library `test.yaml` files demonstrate the config-based approach if you
32
+ prefer not to pass the `--package-dirs` flag.
@@ -0,0 +1,4 @@
1
+ created: 2025-12-03
2
+ title: Tenzir Test v0.13.0
3
+ intro: >-
4
+ This release adds `--package-dirs` support and improves startup diagnostics.
@@ -0,0 +1,29 @@
1
+ This release adds `--package-dirs` support and improves startup diagnostics.
2
+
3
+ ## 🚀 Features
4
+
5
+ ### Library mode and extra packages
6
+
7
+ Explicit package loading for tests: use `--package-dirs` (repeatable, accepts comma-separated lists) to point the harness at package directories. The same flag is passed to the Tenzir binaries, and it merges with any `package-dirs:` declared in directory `test.yaml` files. Entries are normalized and de-duplicated, then exported via `TENZIR_PACKAGE_DIRS` for fixtures.
8
+
9
+ The test configuration uses the same spelling: add
10
+
11
+ ```yaml
12
+ package-dirs:
13
+ - ../shared-packages
14
+ - /opt/tenzir/packages/foo
15
+ ```
16
+
17
+ to a directory `test.yaml` when you want those packages available for the tests below it.
18
+
19
+ Example: `uvx tenzir-test --package-dirs example-library example-library` loads both `foo` and `bar` packages so their operators can cross-import. The example-library `test.yaml` files demonstrate the config-based approach if you prefer not to pass the `--package-dirs` flag.
20
+
21
+ *By @codex and @mavam in [#4](https://github.com/tenzir/test/pull/4).*
22
+
23
+ ## 🔧 Changes
24
+
25
+ ### Improve diagnostics when Tenzir Node fails to start
26
+
27
+ The `node` fixture now reports the exit code and stderr output when `tenzir-node` fails to start, making it easier to diagnose startup failures. Previously, the error message provided no context about why the node failed to produce an endpoint.
28
+
29
+ *By @Alainx277 and @claude in [#2](https://github.com/tenzir/test/pull/2).*
@@ -0,0 +1,43 @@
1
+ # Example Library
2
+
3
+ This directory contains two sibling packages, `foo` and `bar`, to demonstrate
4
+ explicit package loading. Point `tenzir-test` at the directory and add
5
+ `--package-dirs example-library` so both packages are visible to every test:
6
+
7
+ ```sh
8
+ uvx tenzir-test --package-dirs example-library example-library
9
+ ```
10
+
11
+ ## Layout
12
+
13
+ ```
14
+ example-library/
15
+ ├── foo/
16
+ │ ├── package.yaml
17
+ │ ├── test.yaml
18
+ │ ├── operators/
19
+ │ │ └── increment.tql
20
+ │ └── tests/
21
+ │ ├── use-bar.tql
22
+ │ └── use-bar.txt
23
+ └── bar/
24
+ ├── package.yaml
25
+ ├── test.yaml
26
+ ├── operators/
27
+ │ └── double.tql
28
+ └── tests/
29
+ ├── use-foo.tql
30
+ └── use-foo.txt
31
+ ```
32
+
33
+ ## Cross-package usage
34
+
35
+ - `foo/tests/use-bar.tql` calls `bar::double`.
36
+ - `bar/tests/use-foo.tql` calls `foo::increment`.
37
+
38
+ Because `--package-dirs` points at the library, both packages are visible to
39
+ every test without additional flags.
40
+
41
+ You can also pin package discovery in a directory `test.yaml` by setting
42
+ `package-dirs:` there. This example keeps the entries commented so the CLI
43
+ flag remains the primary, explicit mechanism.
@@ -0,0 +1,4 @@
1
+ id: bar
2
+ name: Bar Package
3
+ description: |
4
+ Demonstrates a library package that consumes operators from a sibling package.
@@ -0,0 +1,2 @@
1
+ #package-dirs:
2
+ # - ..
@@ -0,0 +1,2 @@
1
+ from {x: 42}
2
+ foo::increment
@@ -0,0 +1,3 @@
1
+ {
2
+ x: 43,
3
+ }
@@ -0,0 +1,4 @@
1
+ id: foo
2
+ name: Foo Package
3
+ description: |
4
+ Demonstrates a library package that provides an operator used by sibling packages.
@@ -0,0 +1,2 @@
1
+ #package-dirs:
2
+ # - ..
@@ -0,0 +1,2 @@
1
+ from {x: 42}
2
+ bar::double
@@ -0,0 +1,3 @@
1
+ {
2
+ x: 84,
3
+ }
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: |
3
+ This operator performs a simple transformation on the input data.
4
+ ---
5
+
6
+ where x > 0
7
+ set x = x + 1
@@ -0,0 +1 @@
1
+ where actor == "admin"
@@ -0,0 +1,2 @@
1
+ // Parse our sample.log.
2
+ read_grok r"(?<timestamp>\d{4}-\d{2}-\d{2}) \[(?<actor>\w+)\] %{GREEDYDATA:message}"
@@ -0,0 +1,29 @@
1
+ # The package ID defines the top-level module name. For example, placing a
2
+ # user-defined operator `foo` in operators/foo.tql makes it callable via
3
+ # `example::foo`.
4
+ #
5
+ # If you do not specify an ID, the directory name of this package.yaml will be
6
+ # used as the ID. Package installation fails if the ID or directory name
7
+ # contains invalid characters. Allowed characters are alphanumeric and
8
+ # underscore, e.g., `my-package` is invalid but `my_package` is okay.
9
+ id: example
10
+
11
+ # The name should be a short, human-readable description of the package.
12
+ name: Example Package
13
+
14
+ # The description should provide a brief overview of the package's purpose and
15
+ # functionality. Markdown is supported.
16
+ description: |
17
+ This is an example package that demonstrates how to write tests for Tenzir
18
+ packages.
19
+
20
+ # Contexts live inside a node. The test harness passes --package-dirs to the node
21
+ # fixture, making contexts also available in the fixture. The harness also
22
+ # passes --package-dirs to the Tenzir running that invokes the the `tenzir`
23
+ # binary. In this case the context configuration gets ignored.
24
+ contexts:
25
+ ctx:
26
+ type: lookup-table
27
+ description: |
28
+ An example context that gets installed by the test framework when the
29
+ harness passes --package-dirs to the node fixture.
@@ -0,0 +1,2 @@
1
+ // Show our example context that ships with the package.
2
+ context::list
@@ -0,0 +1,5 @@
1
+ {
2
+ num_entries: 0,
3
+ name: "ctx",
4
+ configured: true,
5
+ }
@@ -0,0 +1,4 @@
1
+ from {x: 42, y: "foo"},
2
+ {x: 43, y: "bar"},
3
+ {x: 44, y: "baz"}
4
+ context::update "ctx", key=x, value=y
@@ -0,0 +1 @@
1
+ context::inspect "ctx"
@@ -0,0 +1,2 @@
1
+ suite: context
2
+ fixtures: [node]
@@ -0,0 +1,12 @@
1
+ 2025-09-23 [root] All your base are belong to us
2
+ 2025-09-24 [user] System takeover initiated by root user
3
+ 2025-09-25 [admin] Security breach detected in main database
4
+ 2025-09-26 [root] Access privileges escalated successfully
5
+ 2025-09-27 [system] Firewall rules modified by unauthorized user
6
+ 2025-09-28 [user] Connection established to remote server
7
+ 2025-09-29 [root] Database backup corrupted during transfer
8
+ 2025-09-30 [admin] Emergency protocols activated
9
+ 2025-10-01 [system] Network traffic redirected to external host
10
+ 2025-10-02 [root] All security measures have been bypassed
11
+ 2025-10-03 [user] Mission accomplished - standing by for orders
12
+ 2025-10-04 [admin] System shutdown imminent
@@ -0,0 +1,4 @@
1
+ from_file f"{env("TENZIR_INPUTS")}/sample.log" {
2
+ example::parse
3
+ }
4
+ example::filter
@@ -0,0 +1,15 @@
1
+ {
2
+ timestamp: 2025-09-25T00:00:00Z,
3
+ actor: "admin",
4
+ message: "Security breach detected in main database",
5
+ }
6
+ {
7
+ timestamp: 2025-09-30T00:00:00Z,
8
+ actor: "admin",
9
+ message: "Emergency protocols activated",
10
+ }
11
+ {
12
+ timestamp: 2025-10-04T00:00:00Z,
13
+ actor: "admin",
14
+ message: "System shutdown imminent",
15
+ }
@@ -0,0 +1,4 @@
1
+ from {}
2
+ repeat 5
3
+ enumerate x
4
+ example::deeply::nested::twist
@@ -0,0 +1,12 @@
1
+ {
2
+ x: 2,
3
+ }
4
+ {
5
+ x: 3,
6
+ }
7
+ {
8
+ x: 4,
9
+ }
10
+ {
11
+ x: 5,
12
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ key: 42,
3
+ value: "foo",
4
+ }
5
+ {
6
+ key: 44,
7
+ value: "baz",
8
+ }
9
+ {
10
+ key: 43,
11
+ value: "bar",
12
+ }
@@ -0,0 +1,27 @@
1
+ # Example Satellite Project
2
+
3
+ This companion project demonstrates how a satellite can reuse runners and
4
+ fixtures from the root `example-project` while adding its own customizations.
5
+
6
+ ## Layout
7
+
8
+ ```
9
+ example-satellite/
10
+ ├── fixtures.py
11
+ └── tests/
12
+ ├── hex/reuse.{xxd,txt}
13
+ └── satellite/marker.{sh,txt}
14
+ ```
15
+
16
+ - `fixtures.py` registers the `satellite_marker` fixture that the shell test
17
+ consumes.
18
+ - `tests/hex/reuse.xxd` exercises the `xxd` runner exported by the root project;
19
+ no additional runners are needed in the satellite.
20
+ - `tests/satellite/marker.sh` verifies that the local fixture is loaded when the
21
+ satellite participates in a multi-project run.
22
+
23
+ Run the example together with the main project:
24
+
25
+ ```sh
26
+ uvx tenzir-test --root example-project example-satellite
27
+ ```
@@ -0,0 +1,14 @@
1
+ """Fixtures defined by the example satellite project."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Iterator
6
+
7
+ from tenzir_test import fixture
8
+
9
+
10
+ @fixture(name="satellite_marker")
11
+ def satellite_marker_fixture() -> Iterator[dict[str, str]]:
12
+ """Expose a marker so tests can assert fixture inheritance works."""
13
+
14
+ yield {"SATELLITE_MARKER": "example-satellite"}
@@ -0,0 +1 @@
1
+ hello world
@@ -0,0 +1,2 @@
1
+ 00000000: 53 61 74 65 6c 6c 69 74 65 20 72 75 6e 6e 65 72 Satellite runner
2
+ 00000010: 20 72 65 75 73 65 21 0a reuse!.
@@ -0,0 +1 @@
1
+ Satellite runner reuse!
@@ -0,0 +1,2 @@
1
+ printf "Inputs are in ${TENZIR_INPUTS}\n"
2
+ cat ${TENZIR_INPUTS}/input.txt
@@ -0,0 +1,2 @@
1
+ Inputs are in inputs
2
+ hello world
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ printf '%s\n' "satellite fixture: ${SATELLITE_MARKER:-<missing>}"
@@ -0,0 +1 @@
1
+ satellite fixture: example-satellite
@@ -0,0 +1,3 @@
1
+ timeout: 5
2
+ fixtures:
3
+ - satellite_marker
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tenzir-test"
3
- version = "0.12.0"
3
+ version = "0.13.0"
4
4
  description = "Reusable test execution framework extracted from the Tenzir repository."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -48,14 +48,17 @@ packages = ["src/tenzir_test"]
48
48
 
49
49
  [tool.hatch.build.targets.sdist]
50
50
  include = [
51
- "/src/**/*",
52
- "/tests",
53
- "/example-project",
54
- "/scripts",
55
- "/README.md",
56
- "/CHANGELOG.md",
57
51
  "/LICENSE",
52
+ "/README.md",
53
+ "/changelog",
54
+ "/example-library",
55
+ "/example-package",
56
+ "/example-project",
57
+ "/example-satellite",
58
58
  "/pyproject.toml",
59
+ "/scripts",
60
+ "/src/**/*",
61
+ "/tests",
59
62
  ]
60
63
  exclude = [
61
64
  "*.pyc",
@@ -51,6 +51,15 @@ def _normalize_exit_code(value: object) -> int:
51
51
  type=click.Path(path_type=Path, dir_okay=False, writable=False, resolve_path=False),
52
52
  help="Path to the tenzir-node executable.",
53
53
  )
54
+ @click.option(
55
+ "package_dirs",
56
+ "--package-dirs",
57
+ multiple=True,
58
+ help=(
59
+ "Comma-separated list of package directories to load (repeatable). "
60
+ "These only control package visibility; test selection still follows the usual --root/args."
61
+ ),
62
+ )
54
63
  @click.argument(
55
64
  "tests",
56
65
  nargs=-1,
@@ -137,6 +146,7 @@ def cli(
137
146
  root: Path | None,
138
147
  tenzir_binary: Path | None,
139
148
  tenzir_node_binary: Path | None,
149
+ package_dirs: tuple[str, ...],
140
150
  tests: tuple[Path, ...],
141
151
  update: bool,
142
152
  debug: bool,
@@ -155,6 +165,14 @@ def cli(
155
165
  ) -> int:
156
166
  """Execute tenzir-test scenarios."""
157
167
 
168
+ package_paths: list[Path] = []
169
+ for entry in package_dirs:
170
+ for piece in entry.split(","):
171
+ piece = piece.strip()
172
+ if not piece:
173
+ continue
174
+ package_paths.append(Path(piece))
175
+
158
176
  jobs_source = ctx.get_parameter_source("jobs")
159
177
  jobs_overridden = jobs_source is not click.core.ParameterSource.DEFAULT
160
178
 
@@ -163,6 +181,7 @@ def cli(
163
181
  root=root,
164
182
  tenzir_binary=tenzir_binary,
165
183
  tenzir_node_binary=tenzir_node_binary,
184
+ package_dirs=package_paths,
166
185
  tests=list(tests),
167
186
  update=update,
168
187
  debug=debug,
@@ -41,7 +41,7 @@ def discover_settings(
41
41
  ) -> Settings:
42
42
  """Produce harness settings by combining CLI overrides with environment defaults."""
43
43
 
44
- environment = dict(env or os.environ)
44
+ environment = dict(os.environ if env is None else env)
45
45
 
46
46
  chosen_root = root or environment.get("TENZIR_TEST_ROOT") or Path.cwd()
47
47
  root_path = Path(chosen_root).resolve()