How do you run TestGen from Prefect?

You run DataOps TestGen from Prefect with a task that calls the TestGen REST API: start a test run, poll the job until it finishes, fetch the result counts, and raise an exception when any test failed. Prefect marks the task and the flow run Failed. No connector is needed; the task makes plain HTTP calls.

Key points

  • DataOps TestGen runs from Prefect through its REST API: POST /api/v1/test-suites/{test_suite_id}/test-runs starts a run, GET /api/v1/jobs/{job_id} polls it, and GET /api/v1/test-runs/{job_id} returns result counts and a score.
  • A Prefect task that raises an exception ends Failed, and a flow whose function raises ends Failed, per Prefect's states documentation (checked October 2026), so a failed TestGen test can fail the flow run.
  • Run TestGen test suites after every load and profiling every two weeks to a month, as TestGen's scheduling docs recommend; POST /api/v1/table-groups/{table_group_id}/profiling-runs starts a profiling run from the same flow code.
  • Open-source TestGen authenticates API calls with an OAuth 2.1 client whose access tokens last one hour and refresh tokens 30 days; Enterprise adds personal access tokens.
  • DataKitchen documents no DataOps Observability agent for Prefect as of October 2026.

A Prefect flow that loads a table and then reports Completed has told you the code ran. It hasn’t told you the data is right. Add one task that asks DataOps TestGen.

TestGen runs from Prefect through its REST API. No connector, and none needed. The Airflow answer and the CI/CD answer cover the same calls in those tools.

The calls

From Run Profiling and Tests, each with Authorization: Bearer <token>:

StepCall
Start a test runPOST /api/v1/test-suites/{test_suite_id}/test-runs
Start a profiling runPOST /api/v1/table-groups/{table_group_id}/profiling-runs
Poll either oneGET /api/v1/jobs/{job_id} until completed, error, or canceled
Read a test runGET /api/v1/test-runs/{job_id}

Submissions return 202 Accepted with a job id and don’t wait. So the task polls, with a timeout.

The task

import os, time, requests
from prefect import flow, task

API = os.environ["TESTGEN_API_URL"]  # http://<host>:8530 by default
HDR = {"Authorization": f"Bearer {os.environ['TESTGEN_TOKEN']}"}  # one-hour OAuth access token (or an Enterprise PAT)

class DataTestsFailed(Exception):
    pass

@task(retries=2, retry_delay_seconds=60)
def testgen_run(suite_id: str, timeout_s: int = 1800) -> dict:
    job_id = requests.post(f"{API}/api/v1/test-suites/{suite_id}/test-runs",
                           headers=HDR, timeout=30).json()["id"]
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        job = requests.get(f"{API}/api/v1/jobs/{job_id}", headers=HDR, timeout=30).json()
        if job["status"] in ("completed", "error", "canceled"):
            break
        time.sleep(15)
    else:
        raise TimeoutError(f"TestGen job {job_id} did not finish")
    if job["status"] != "completed":
        raise RuntimeError(f"TestGen job {job_id}: {job['status']} {job['error_message']}")
    return requests.get(f"{API}/api/v1/test-runs/{job_id}", headers=HDR, timeout=30).json()["result"]

@flow
def load_orders():
    # ... your load tasks ...
    result = testgen_run(os.environ["TG_SUITE_ORDERS"])
    counts = result["result_counts"]
    if counts["failed"] or counts["error"]:
        raise DataTestsFailed(f"{counts['failed']} failed, score {result['score']}")
    # ... downstream tasks run only past this line ...

The check sits in the flow, not the task, so a retry never re-runs the verdict. Prefect’s states docs say an exception raised in the flow function marks the flow run Failed (checked October 2026). Retries cover the HTTP calls: a TestGen run that found bad data finds it again on a retry.

Test every load, profile every few weeks

Tests are cheap and belong after every load. Profiling reads every column, and a column’s shape changes slowly, so TestGen’s scheduling docs recommend it every two weeks to a month. Put profiling-runs in a separate flow on its own Prefect schedule, or skip Prefect for it and use TestGen’s scheduler.

What counts as a failure

TestGen tests carry a severity. One set to warn returns warning, not failed, per the testing docs. The flow above blocks on failed and error and lets warnings through. DataKitchen calls this a tripwire, and its medallion post puts one between each layer.

Where results land

In TestGen’s Test Results page. The test-run call takes an optional body with external_url and metadata; send the Prefect flow run URL and it appears under Link. The flow keeps the score and counts in its logs.

Open source authenticates with an OAuth 2.1 client. Access tokens last an hour and refresh tokens 30 days, so a flow that runs for a month needs a renewed refresh token, and renewing it takes a browser sign-in. Enterprise adds personal access tokens. There’s no Observability agent for Prefect, though TestGen can export results to Observability.

Documentation: TestGen API, Run Profiling and Tests, API Authentication, OAuth 2.1 Clients, Connect to Observability

Frequently asked questions

Short answers to the follow-up questions people ask next.

Is there a Prefect integration for TestGen?

No, and none is needed. DataOps TestGen exposes a REST API, and a Prefect task calls it with plain HTTP requests: POST /api/v1/test-suites/{test_suite_id}/test-runs to start a run, GET /api/v1/jobs/{job_id} to poll it, and GET /api/v1/test-runs/{job_id} for the counts. DataKitchen documents no Prefect package or Observability agent as of October 2026.

Should a TestGen warning fail my Prefect flow?

No. In DataOps TestGen, a test whose severity is set to warn returns a warning status instead of failed. Raise an exception in the Prefect task only when the run summary shows failed or error results, and log warnings. The severity setting then lives in TestGen, where a data steward can change it without touching the flow code.

Should Prefect retry a failed TestGen task?

Retry the HTTP call, not the verdict. Prefect tasks accept retries with a delay, which helps when the TestGen API is briefly unreachable. A TestGen run that completes with failed tests will fail again on retry, because the data hasn't changed. Raise a distinct exception for failed tests and keep retries for connection errors.

Does any data leave my environment when Prefect runs TestGen?

No. DataOps TestGen runs its profiling and tests as read-only SQL inside your database, and TestGen runs on your own infrastructure. The Prefect task receives IDs, counts, and a score, never table rows. TestGen stores computed results plus, for display, the most frequent values and the minimum and maximum text values that profiling records.

Try it on your own data

DataOps TestGen is free and open source. Profile a table and generate its tests this afternoon.