Skip to content

Commit 6c31046

Browse files
tharunbhuk-dbIsaac
andcommitted
Run pipelines test against the pipeline's testing.sources
The pipelines test acceptance bundles declare testing, as the service requires testing.sources for a test-only update. When Start Update fails with PIPELINE_TEST_NO_TEST_SOURCES and the bundle sets testing for the pipeline, the error says to deploy first: the bundle changed after its last deploy. Add a live acceptance test that deploys a bundle with testing, including a local test dependency after -e, and runs its tests. Locally it uses stubs for the test run. Against a real workspace it runs only when TEST_PIPELINES_TESTING_ENABLED is set. Co-authored-by: Isaac <no-reply@databricks.com>
1 parent 79fe493 commit 6c31046

21 files changed

Lines changed: 230 additions & 2 deletions

File tree

‎acceptance/pipelines/test/immutable/databricks.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ resources:
1111
libraries:
1212
- file:
1313
path: pipeline_file.py
14+
testing:
15+
sources:
16+
- glob:
17+
include: ./tests/**
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
bundle:
2+
name: test-pipelines-test-live-$UNIQUE_NAME
3+
4+
resources:
5+
pipelines:
6+
orders:
7+
# The Pipelines API rejects duplicate names, so the name is unique per run.
8+
name: test-pipelines-test-live-$UNIQUE_NAME
9+
catalog: main
10+
schema: default
11+
serverless: true
12+
root_path: .
13+
libraries:
14+
- file:
15+
path: ./transformations/orders.py
16+
testing:
17+
sources:
18+
- glob:
19+
include: ./tests/**
20+
environment:
21+
dependencies:
22+
- -e ./helpers
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def order_total(amounts):
2+
return sum(amounts)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[build-system]
2+
requires = ["setuptools>=61"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "order-helpers"
7+
version = "0.1.0"
8+
9+
[tool.setuptools]
10+
py-modules = ["order_helpers"]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Cloud = true
2+
CloudSlow = true
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
>>> [CLI] bundle deploy
3+
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-pipelines-test-live-[UNIQUE_NAME]/default/files...
4+
Created pipelines.orders
5+
Files: 6 uploaded, 0 deleted
6+
Resources: 1 created, 0 changed, 0 deleted, 0 unchanged
7+
8+
=== Run the tests and wait for the results
9+
Done. PASSED=1 FAILED=0 SKIPPED=0 ERROR=0 TOTAL=1
10+
name="test_order_total"
11+
12+
>>> [CLI] bundle destroy --auto-approve
13+
The following resources will be deleted:
14+
delete resources.pipelines.orders
15+
16+
This action will result in the deletion of the following Lakeflow Spark Declarative Pipelines along with the
17+
Streaming Tables (STs) and Materialized Views (MVs) managed by them. Set 'cascade_on_destroy: false' on a pipeline to retain datasets on pipeline deletion:
18+
delete resources.pipelines.orders
19+
20+
All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-pipelines-test-live-[UNIQUE_NAME]/default
21+
22+
Destroy: 1 deleted
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
if [ -n "$CLOUD_ENV" ] && [ -z "${TEST_PIPELINES_TESTING_ENABLED:-}" ]; then
2+
echo "SKIP_TEST set TEST_PIPELINES_TESTING_ENABLED for a workspace with pipeline testing enabled"
3+
exit 0
4+
fi
5+
6+
envsubst < databricks.yml.tmpl > databricks.yml
7+
8+
cleanup() {
9+
trace $CLI bundle destroy --auto-approve
10+
}
11+
trap cleanup EXIT
12+
13+
trace $CLI bundle deploy
14+
15+
title "Run the tests and wait for the results\n"
16+
# Durations and test IDs differ between runs, so only the summary line and the case names are
17+
# compared. The script stops if the command fails.
18+
$CLI pipelines test --junit-xml junit.xml &> LOG.test
19+
tail -1 LOG.test
20+
grep -o ' name="test_[^"]*"' junit.xml
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Also runs against a real workspace, when that workspace has pipeline testing enabled.
2+
# The script skips the cloud run unless TEST_PIPELINES_TESTING_ENABLED is set.
3+
Cloud = true
4+
CloudSlow = true
5+
RecordRequests = false
6+
Ignore = [".databricks", "databricks.yml", "junit.xml"]
7+
8+
# Locally, the test server stands in for the service's test run. Start Update is the test server's.
9+
[[Server]]
10+
Pattern = "GET /api/2.0/pipelines/{pipeline_id}/updates/{update_id}"
11+
Response.Body = '{"update": {"update_id": "00000000-0000-0000-0000-0000000000a1", "state": "COMPLETED", "test_only": true}}'
12+
13+
[[Server]]
14+
Pattern = "GET /api/2.0/pipelines/{pipeline_id}/events"
15+
Response.Body = '''
16+
{"events": [
17+
{"id": "e1", "event_type": "test_case_progress", "timestamp": "2026-01-01T00:00:01.000Z", "origin": {"test_case_id": "/Workspace/tests/test_orders.py::test_order_total"}, "details": {"test_case_progress": {"status": "PASSED"}}},
18+
{"id": "e2", "event_type": "test_run_summary", "timestamp": "2026-01-01T00:00:02.000Z", "details": {"test_run_summary": {"total": 1, "passed": 1, "failed": 0, "skipped": 0, "errored": 0}}}
19+
]}
20+
'''
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# order_helpers is not on the import path; only its installation as a test dependency provides it.
2+
from order_helpers import order_total
3+
4+
5+
def test_order_total():
6+
assert order_total([1, 2, 3]) == 6
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from pyspark import pipelines as dp
2+
3+
4+
@dp.materialized_view
5+
def orders():
6+
return spark.range(3)

0 commit comments

Comments
 (0)