Build Datus Plugin E2E
Create reproducible workflows under tests/e2e/ and execute them through pytest. Let Datus use the LLM to perform the task, but let only independent programmatic oracles decide correctness.
Guardrails
- Work from the Datus-Plugins repository root. Reuse
tests/e2e/harness; do not add a wrapper CLI or console script.
- Keep normal pytest offline. Provision minikube and call an LLM only when the invocation explicitly requests a live run; live execution requires
--run-live.
- Pin environment images/charts in
environment.lock.yml. Resolve the requested datus-agent ref to a full commit SHA; the harness records that SHA.
- Pack the current plugin checkout with the tested agent's
datus plugin pack --with-deps, then install that exact zip through the run-scoped agent config.
- Scope every run to its own minikube profile, namespace, workspace, Datus home, session scope, kubeconfig, bucket prefix, and artifact directory.
- Never treat an LLM statement, generated report, exit code alone, or log text alone as proof of success. The oracle must inspect the real external state independently of the plugin under test.
- Never weaken the target, oracle, or efficiency budget merely to make a failure pass.
Build the workflow
- Inspect the target plugin's manifest, commands, permissions, bundled skills, unit tests, and configuration schema. Identify support plugins needed to observe or deploy the result.
- State one deterministic target before editing. Define exact inputs, final state, and failure conditions. Prefer bounded data, fixed IDs/ranges, exact schemas, exact counts/checksums, and named Kubernetes resources.
- Choose the closest checked-in example:
flink2paimon-datagen: runnable Flink Operator + Paimon golden workflow.
s3-minio-roundtrip: runnable object checksum smoke workflow.
airflow-dag-to-minio, flink-paimon-recovery, kafka-flink-paimon-upsert, and k8s-namespace-guard: reference designs whose extra fixtures/oracles must be implemented before removing the reference tag.
- Add
tests/e2e/workflows/<name>/workflow.yml, prompt.md, and environment.lock.yml; add deterministic seed/golden files only when required.
- Use
apiVersion: datus.ai/v1alpha1 and kind: PluginE2EWorkflow. Keep all paths relative and inside the workflow/workspace. Declare:
- target and support plugin distribution/path/name/profile;
- prompt timeout and pinned environment components;
- every generated output pattern;
- only the
datus <plugin> command prefixes the agent needs;
- at least one deterministic oracle;
- explicit tool-call, LLM-turn, token, failed-call, expected-command, and forbidden-command budgets when applicable;
- namespace and bucket-prefix cleanup policy.
- Reuse an implemented oracle from
tests/e2e/harness/oracles.py: files, kubernetes_resource, minio_object, or flink_paimon. Add a trusted harness oracle when the external state cannot be proven by these. Do not implement an oracle by calling the plugin being tested.
- Add or update offline contract/unit tests for every schema, parser, artifact, or oracle behavior changed.
Validate offline
Run these before any live test:
uv run --group e2e pytest tests/e2e/test_workflow_contracts.py tests/e2e/test_harness_unit.py -q
python3 -m compileall -q tests/e2e
Also run the target plugin's existing unit and manifest-contract tests. Fix offline failures before provisioning infrastructure.
Run live
Create an ephemeral YAML file outside source control with this contract:
agent:
repo: https://github.com/Datus-ai/Datus-agent.git
ref: <branch-tag-or-full-sha>
config: <absolute-path-to-existing-agent.yml>
pluginRoot: <absolute-path-to-Datus-Plugins>
modelTarget: <optional-model-target>
repeats: 1
keepSuite: false
artifactsRoot: <absolute-or-config-relative-artifact-directory>
cacheRoot: <absolute-or-config-relative-agent-cache-directory>
Do not commit this file because the referenced agent config can contain credential references. Run exactly through pytest:
uv run --group e2e pytest tests/e2e/test_workflows.py \
--run-live --workflow <name> --run-config <run-config.yml> -q -s
The harness performs environment initialization, agent installation/configuration, plugin packing/install from zip:, datus -p, artifact capture, session export, deterministic oracles, process scoring, and cleanup.
Interpret results
Read each run directory in this order:
summary.json: PASS, PRODUCT_FAIL, or HARNESS_FAIL; pinned agent SHA; quality result.
oracle.json: authoritative correctness verdict and observed evidence.
process.json: tool sequence, duplicate commands, unexpected failures, LLM turns, tokens, and budget violations.
session/session.jsonl: redacted conversation/tool details; prefer this over the raw copied session database.
generated.patch, workspace-manifest.json, generated-files/, and command/environment logs.
Classify a failed environment/install/parser/cleanup as HARNESS_FAIL. Classify a completed run that misses the external target as PRODUCT_FAIL. A run can be correct but fail the quality budget; report both dimensions without allowing process analysis to override the oracle.
Report
Return the deterministic target, files added/changed, agent SHA, plugin bundle hashes, exact test commands, correctness evidence, process-budget result, artifact path, and any live prerequisites not exercised. If the plugin needs iterative improvement, hand the artifacts to $optimize-datus-plugin.
1---2name: build-datus-plugin-e2e3description: Build and run deterministic, LLM-driven end-to-end workflows for Datus plugins using the repository's pytest harness. Use when creating plugin E2E coverage, testing a plugin through a pinned datus-agent branch, provisioning isolated minikube/MinIO/Flink fixtures, defining programmatic pass/fail oracles, or diagnosing an E2E harness run. Invoke directly from Claude Code or Codex; do not create a standalone test CLI.4---56# Build Datus Plugin E2E78Create reproducible workflows under `tests/e2e/` and execute them through pytest. Let Datus use the LLM to perform the task, but let only independent programmatic oracles decide correctness.910## Guardrails1112- Work from the Datus-Plugins repository root. Reuse `tests/e2e/harness`; do not add a wrapper CLI or console script.13- Keep normal pytest offline. Provision minikube and call an LLM only when the invocation explicitly requests a live run; live execution requires `--run-live`.14- Pin environment images/charts in `environment.lock.yml`. Resolve the requested datus-agent ref to a full commit SHA; the harness records that SHA.15- Pack the current plugin checkout with the tested agent's `datus plugin pack --with-deps`, then install that exact zip through the run-scoped agent config.16- Scope every run to its own minikube profile, namespace, workspace, Datus home, session scope, kubeconfig, bucket prefix, and artifact directory.17- Never treat an LLM statement, generated report, exit code alone, or log text alone as proof of success. The oracle must inspect the real external state independently of the plugin under test.18- Never weaken the target, oracle, or efficiency budget merely to make a failure pass.1920## Build the workflow21221. Inspect the target plugin's manifest, commands, permissions, bundled skills, unit tests, and configuration schema. Identify support plugins needed to observe or deploy the result.232. State one deterministic target before editing. Define exact inputs, final state, and failure conditions. Prefer bounded data, fixed IDs/ranges, exact schemas, exact counts/checksums, and named Kubernetes resources.243. Choose the closest checked-in example:25 - `flink2paimon-datagen`: runnable Flink Operator + Paimon golden workflow.26 - `s3-minio-roundtrip`: runnable object checksum smoke workflow.27 - `airflow-dag-to-minio`, `flink-paimon-recovery`, `kafka-flink-paimon-upsert`, and `k8s-namespace-guard`: reference designs whose extra fixtures/oracles must be implemented before removing the `reference` tag.284. Add `tests/e2e/workflows/<name>/workflow.yml`, `prompt.md`, and `environment.lock.yml`; add deterministic seed/golden files only when required.295. Use `apiVersion: datus.ai/v1alpha1` and `kind: PluginE2EWorkflow`. Keep all paths relative and inside the workflow/workspace. Declare:30 - target and support plugin distribution/path/name/profile;31 - prompt timeout and pinned environment components;32 - every generated output pattern;33 - only the `datus <plugin>` command prefixes the agent needs;34 - at least one deterministic oracle;35 - explicit tool-call, LLM-turn, token, failed-call, expected-command, and forbidden-command budgets when applicable;36 - namespace and bucket-prefix cleanup policy.376. Reuse an implemented oracle from `tests/e2e/harness/oracles.py`: `files`, `kubernetes_resource`, `minio_object`, or `flink_paimon`. Add a trusted harness oracle when the external state cannot be proven by these. Do not implement an oracle by calling the plugin being tested.387. Add or update offline contract/unit tests for every schema, parser, artifact, or oracle behavior changed.3940## Validate offline4142Run these before any live test:4344```bash45uv run --group e2e pytest tests/e2e/test_workflow_contracts.py tests/e2e/test_harness_unit.py -q46python3 -m compileall -q tests/e2e47```4849Also run the target plugin's existing unit and manifest-contract tests. Fix offline failures before provisioning infrastructure.5051## Run live5253Create an ephemeral YAML file outside source control with this contract:5455```yaml56agent:57 repo: https://github.com/Datus-ai/Datus-agent.git58 ref: <branch-tag-or-full-sha>59 config: <absolute-path-to-existing-agent.yml>60pluginRoot: <absolute-path-to-Datus-Plugins>61modelTarget: <optional-model-target>62repeats: 163keepSuite: false64artifactsRoot: <absolute-or-config-relative-artifact-directory>65cacheRoot: <absolute-or-config-relative-agent-cache-directory>66```6768Do not commit this file because the referenced agent config can contain credential references. Run exactly through pytest:6970```bash71uv run --group e2e pytest tests/e2e/test_workflows.py \72 --run-live --workflow <name> --run-config <run-config.yml> -q -s73```7475The harness performs environment initialization, agent installation/configuration, plugin packing/install from `zip:`, `datus -p`, artifact capture, session export, deterministic oracles, process scoring, and cleanup.7677## Interpret results7879Read each run directory in this order:80811. `summary.json`: `PASS`, `PRODUCT_FAIL`, or `HARNESS_FAIL`; pinned agent SHA; quality result.822. `oracle.json`: authoritative correctness verdict and observed evidence.833. `process.json`: tool sequence, duplicate commands, unexpected failures, LLM turns, tokens, and budget violations.844. `session/session.jsonl`: redacted conversation/tool details; prefer this over the raw copied session database.855. `generated.patch`, `workspace-manifest.json`, `generated-files/`, and command/environment logs.8687Classify a failed environment/install/parser/cleanup as `HARNESS_FAIL`. Classify a completed run that misses the external target as `PRODUCT_FAIL`. A run can be correct but fail the quality budget; report both dimensions without allowing process analysis to override the oracle.8889## Report9091Return the deterministic target, files added/changed, agent SHA, plugin bundle hashes, exact test commands, correctness evidence, process-budget result, artifact path, and any live prerequisites not exercised. If the plugin needs iterative improvement, hand the artifacts to `$optimize-datus-plugin`.