Skip to content

Add invariant tests - #4326

Merged
denik merged 25 commits into
mainfrom
denik/invariant-tests
Jan 22, 2026
Merged

Add invariant tests#4326
denik merged 25 commits into
mainfrom
denik/invariant-tests

Conversation

@denik

Copy link
Copy Markdown
Contributor

Changes

Add a new kind of test - invariant test for DABs (a subtype of acceptance test).

Invariant tests are acceptance tests that can be run against many configs to check for certain properties.
Unlike regular acceptance tests full output is not recorded, unless the condition is not met.

In this PR there is one invariant test added - no_drift, that checks that there are no actions planned after successful deploy. If that's not the case, the test will dump full JSON plan to the output.

Why

Simplify resource implementation testing - implementors only need to provide a config to get all invariants check.

With no_drift in particular, we've had several cases where this condition is not met and it's still the case for some configurations of permissions and grants. It's also going to become more important as we replace "server_side_default" with something more precise.

The other use of invariant tests is fuzzing - since they work on any config, they can be used on randomly generated configs to find bugs.

@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jan 19, 2026

Copy link
Copy Markdown
Collaborator

Commit: 73a1501

Run: 21247404414

no_drift test checks that there are no actions planned after successful deploy. If that's not the case, the
test will dump full JSON plan to the output.

In order to add a new test, add a config to configs/ and include it in test.toml.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ones in this PR are specific to bundles. Will they generalize? If not, they can be moved the bundles dir.

@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""
Check that all actions in plan are "skip".

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe verify_no_drift.py?

foo:
warehouse_id: $TEST_DEFAULT_WAREHOUSE_ID
display_name: test-alert-$UNIQUE_NAME
file_path: ./alert.dbalert.json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shreyas-goenka Do we need one with the alert inlined?

cat LOG.deploy | contains.py '!panic' '!internal error' > /dev/null

# Special message to fuzzer that generated config was fine.
# Any failures after this point will be considered as "bug detected" by fuzzer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fuzzer == vary over input configs?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

@denik
denikforce-pushed the denik/invariant-tests branch from 39b9307 to 3de7df5CompareJanuary 21, 2026 13:25
denikand others added 14 commits January 22, 2026 12:25
Add 9 minimal resource configuration templates to test the no-drift invariant
across different resource types (jobs, pipelines, experiments, models, volumes,
schemas, clusters, model serving endpoints).
Changes:
- Add configs/ directory with minimal .yml.tmpl files for each resource type
- Add data/ directory for supporting files (pipeline.py)
- Update no_drift/script to copy data files at test start
- Update test.toml to include new configs and ignore *.py files
- Update out.test.toml with expanded config matrix
All configs tested and verified on both testserver and AWS cloud with direct
and terraform deployment engines.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add 4 more resource configurations to the no_drift invariant test, bringing
the total to 13 working configs.
New configs:
- alerts (with .dbalert.json file)
- dashboards (with .lvdash.json file)
- apps (with source_code_path directory)
- secret_scopes
Also created sql_warehouse.yml.tmpl but excluded from test due to drift issues.
Changes:
- Add 5 new config templates in configs/
- Add 3 new data files in data/ (alert.dbalert.json, dashboard.lvdash.json, app/)
- Update test.toml to include new configs and ignore *.json and app directory
- Update out.test.toml with expanded config matrix
All 13 configs tested on testserver with both direct and terraform engines.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Complete the no_drift invariant test coverage by adding the remaining
resource types, bringing the total to 17 working configs.
New configs:
- quality_monitor (with dependent schema)
- database_instance
- database_catalog (with dependent database_instance)
- synced_database_table (with dependent instance and catalog)
Changes:
- Add 3 new config templates in configs/
- Fix quality_monitor to use $CURRENT_USER_NAME
- Update test.toml with 4 additional configs
- Update out.test.toml with full config matrix
All 17 configs tested successfully on testserver with both direct and
terraform deployment engines, showing zero drift after deploy.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
App names must be between 2-30 characters. Changed from 'test-app-'
to 'app-' to fit within the limit.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
@denik
denikforce-pushed the denik/invariant-tests branch from 3de7df5 to 10b8a2fCompareJanuary 22, 2026 11:26
@denik
denik enabled auto-merge January 22, 2026 11:51
@denik
denik disabled auto-merge January 22, 2026 14:56
@denik
denik merged commit 93b59f2 into mainJan 22, 2026
17 of 18 checks passed
@denik
denik deleted the denik/invariant-tests branch January 22, 2026 14:57
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Commit: 93b59f2

Run: 21253144045

Env❌​FAIL🟨​KNOWN🔄​flaky💚​RECOVERED🙈​SKIP✅​pass🙈​skipTime
🟨​aws linux325644568348:12
🟨​aws windows35644968145:30
❌​aws-ucws linux4385650550149:50
❌​aws-ucws windows43285650548144:07
💚​azure linux2844768246:45
🔄​azure windows42844568058:25
❌​azure-ucws linux51447641549122:06
❌​azure-ucws windows5147647547116:32
💚​gcp linux2842769147:10
🔄​gcp windows12842868952:54
33 interesting tests: 12 flaky, 8 RECOVERED, 5 SKIP, 5 FAIL, 3 KNOWN
Test Nameaws linuxaws windowsaws-ucws linuxaws-ucws windowsazure linuxazure windowsazure-ucws linuxazure-ucws windowsgcp linuxgcp windows
🟨​TestAccept🟨​K🟨​K🟨​K🟨​K💚​R💚​R🟨​K🟨​K💚​R💚​R
🙈​TestAccept/bundle/deployment/bind/alert🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/generate/alert🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
❌​TestAccept/bundle/invariant/no_drift🙈​s🙈​s❌​F❌​F🙈​s🙈​s❌​F❌​F🙈​s🙈​s
❌​TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=alert.yml.tmpl❌​F❌​F❌​F❌​F
❌​TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=cluster.yml.tmpl✅​p✅​p❌​F❌​F
❌​TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl❌​F❌​F❌​F❌​F
❌​TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl❌​F❌​F❌​F❌​F
🙈​TestAccept/bundle/resources/alerts/basic🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/alerts/with_file🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🔄​TestAccept/bundle/resources/clusters/run/spark_python_task✅​p✅​p✅​p✅​p✅​p🔄​f✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/clusters/run/spark_python_task/DATABRICKS_BUNDLE_ENGINE=terraform✅​p✅​p✅​p✅​p✅​p🔄​f✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/dashboards/change-embed-credentials✅​p✅​p✅​p✅​p✅​p🔄​f✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/dashboards/change-embed-credentials/DATABRICKS_BUNDLE_ENGINE=terraform✅​p✅​p✅​p✅​p✅​p🔄​f✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/dashboards/detect-change✅​p✅​p✅​p🔄​f✅​p✅​p🔄​f✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/dashboards/detect-change/DATABRICKS_BUNDLE_ENGINE=direct✅​p✅​p✅​p✅​p✅​p✅​p🔄​f✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/dashboards/detect-change/DATABRICKS_BUNDLE_ENGINE=terraform✅​p✅​p✅​p🔄​f✅​p✅​p✅​p✅​p✅​p✅​p
🙈​TestAccept/bundle/resources/permissions🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🟨​TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions🟨​K🟨​K🟨​K🟨​K🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🟨​TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct🟨​K🟨​K🟨​K🟨​K
💚​TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform💚​R💚​R💚​R💚​R
💚​TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions💚​R💚​R💚​R💚​R🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
💚​TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct💚​R💚​R💚​R💚​R
💚​TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform💚​R💚​R💚​R💚​R
💚​TestAccept/bundle/resources/synced_database_tables/basic🙈​S🙈​S💚​R💚​R🙈​S🙈​S💚​R💚​R🙈​S🙈​S
💚​TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct💚​R💚​R💚​R💚​R
💚​TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform💚​R💚​R💚​R💚​R
🔄​TestAccept/bundle/run/app-with-job✅​p✅​p✅​p✅​p✅​p✅​p🔄​f✅​p✅​p✅​p
🔄​TestAccept/bundle/run/app-with-job/DATABRICKS_BUNDLE_ENGINE=terraform✅​p✅​p✅​p✅​p✅​p✅​p🔄​f✅​p✅​p✅​p
🔄​TestAccept/bundle/templates/default-python/combinations/classic🔄​f✅​p✅​p✅​p✅​p✅​p✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=direct/DLT=no/NBOOK=yes/PY=no/READPLAN=🔄​f✅​p✅​p✅​p✅​p✅​p✅​p✅​p✅​p✅​p
💚​TestAccept/ssh/connection💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R
🔄​TestSyncNestedFolderDoesntFailOnNonEmptyDirectory✅​p✅​p✅​p✅​p✅​p✅​p✅​p✅​p✅​p🔄​f
Top 50 slowest tests (at least 2 minutes):
durationenvtestname
13:39gcp windowsTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=SINGLE_USER
13:24gcp windowsTestAccept/bundle/integration_whl/interactive_single_user/DATABRICKS_BUNDLE_ENGINE=terraform
13:13aws-ucws linuxTestAccept/bundle/integration_whl/custom_params/DATABRICKS_BUNDLE_ENGINE=terraform
12:55aws-ucws windowsTestAccept/bundle/resources/model_serving_endpoints/running-endpoint/DATABRICKS_BUNDLE_ENGINE=terraform
12:51gcp linuxTestAccept/bundle/integration_whl/interactive_single_user/DATABRICKS_BUNDLE_ENGINE=terraform
12:47gcp windowsTestAccept/bundle/integration_whl/base/DATABRICKS_BUNDLE_ENGINE=direct
11:51azure windowsTestAccept/bundle/resources/clusters/run/spark_python_task/DATABRICKS_BUNDLE_ENGINE=direct
11:41gcp linuxTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=SINGLE_USER
11:13aws-ucws windowsTestAccept/bundle/resources/model_serving_endpoints/running-endpoint/DATABRICKS_BUNDLE_ENGINE=direct
11:10aws-ucws linuxTestAccept/bundle/resources/model_serving_endpoints/running-endpoint/DATABRICKS_BUNDLE_ENGINE=terraform
11:10aws-ucws linuxTestAccept/bundle/resources/model_serving_endpoints/running-endpoint/DATABRICKS_BUNDLE_ENGINE=direct
10:37aws-ucws linuxTestAccept/bundle/integration_whl/base/DATABRICKS_BUNDLE_ENGINE=direct
9:48azure-ucws linuxTestAccept/bundle/integration_whl/interactive_single_user/DATABRICKS_BUNDLE_ENGINE=direct
9:24azure-ucws linuxTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=USER_ISOLATION
9:11azure-ucws windowsTestAccept/bundle/integration_whl/interactive_cluster/DATABRICKS_BUNDLE_ENGINE=direct
9:00azure-ucws windowsTestAccept/bundle/integration_whl/interactive_cluster/DATABRICKS_BUNDLE_ENGINE=terraform
8:59azure-ucws linuxTestAccept/bundle/integration_whl/interactive_single_user/DATABRICKS_BUNDLE_ENGINE=terraform
8:54aws-ucws windowsTestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
8:44aws-ucws linuxTestAccept/bundle/integration_whl/custom_params/DATABRICKS_BUNDLE_ENGINE=direct
8:37azure windowsTestAccept/bundle/integration_whl/interactive_cluster/DATABRICKS_BUNDLE_ENGINE=direct
8:31gcp windowsTestAccept/bundle/integration_whl/custom_params/DATABRICKS_BUNDLE_ENGINE=terraform
8:26azure windowsTestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
8:25azure-ucws windowsTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=SINGLE_USER
8:13gcp linuxTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=direct/DATA_SECURITY_MODE=SINGLE_USER
8:09gcp windowsTestAccept/bundle/integration_whl/interactive_cluster/DATABRICKS_BUNDLE_ENGINE=direct
7:59aws windowsTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=SINGLE_USER
7:59aws linuxTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=direct/DATA_SECURITY_MODE=SINGLE_USER
7:58gcp windowsTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=direct/DATA_SECURITY_MODE=USER_ISOLATION
7:57azure-ucws windowsTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=USER_ISOLATION
7:54aws-ucws linuxTestAccept/bundle/integration_whl/interactive_single_user/DATABRICKS_BUNDLE_ENGINE=terraform
7:53gcp windowsTestAccept/bundle/integration_whl/base/DATABRICKS_BUNDLE_ENGINE=terraform
7:46gcp linuxTestAccept/bundle/integration_whl/base/DATABRICKS_BUNDLE_ENGINE=terraform
7:42aws windowsTestAccept/bundle/integration_whl/interactive_single_user/DATABRICKS_BUNDLE_ENGINE=terraform
7:42gcp windowsTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=direct/DATA_SECURITY_MODE=SINGLE_USER
7:40aws linuxTestAccept/bundle/integration_whl/interactive_cluster/DATABRICKS_BUNDLE_ENGINE=terraform
7:40aws windowsTestAccept/bundle/integration_whl/base/DATABRICKS_BUNDLE_ENGINE=direct
7:39aws windowsTestAccept/bundle/integration_whl/interactive_cluster/DATABRICKS_BUNDLE_ENGINE=direct
7:36aws linuxTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=SINGLE_USER
7:32azure-ucws windowsTestSparkJarTaskDeployAndRunOnVolumes/Databricks_Runtime_13.3_LTS
7:31gcp linuxTestAccept/bundle/integration_whl/base/DATABRICKS_BUNDLE_ENGINE=direct
7:26gcp windowsTestAccept/bundle/integration_whl/custom_params/DATABRICKS_BUNDLE_ENGINE=direct
7:26aws linuxTestAccept/bundle/integration_whl/interactive_single_user/DATABRICKS_BUNDLE_ENGINE=terraform
7:26aws-ucws linuxTestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
7:26gcp linuxTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=USER_ISOLATION
7:26azure-ucws linuxTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=direct/DATA_SECURITY_MODE=USER_ISOLATION
7:25gcp windowsTestAccept/bundle/integration_whl/interactive_single_user/DATABRICKS_BUNDLE_ENGINE=direct
7:23aws-ucws linuxTestAccept/bundle/integration_whl/interactive_cluster/DATABRICKS_BUNDLE_ENGINE=terraform
7:22aws-ucws windowsTestAccept/bundle/integration_whl/interactive_cluster_dynamic_version/DATABRICKS_BUNDLE_ENGINE=terraform/DATA_SECURITY_MODE=SINGLE_USER
7:22azure windowsTestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
7:21azure linuxTestAccept/bundle/resources/permissions/factcheck/DATABRICKS_BUNDLE_ENGINE=terraform

denik added a commit that referenced this pull request May 20, 2026
## Changes
Add a new kind of test - invariant test for DABs (a subtype of
acceptance test).
Invariant tests are acceptance tests that can be run against many
configs to check for certain properties.
Unlike regular acceptance tests full output is not recorded, unless the
condition is not met.
In this PR there is one invariant test added - no_drift, that checks
that there are no actions planned after successful deploy. If that's not
the case, the test will dump full JSON plan to the output.
## Why
Simplify resource implementation testing - implementors only need to
provide a config to get all invariants check.
With no_drift in particular, we've had several cases where this
condition is not met and it's still the case for some configurations of
permissions and grants. It's also going to become more important as we
replace "server_side_default" with something more precise.
The other use of invariant tests is fuzzing - since they work on any
config, they can be used on randomly generated configs to find bugs.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@denik@eng-dev-ecosystem-bot@pietern