Skip to content

Commit

Permalink
Fix #2578: Allow instances of generic data tests to be documented (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
aranke authored Oct 15, 2024
1 parent ef9abe6 commit cd6bb9e
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .changes/unreleased/Fixes-20241014-212135.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Fixes
body: Allow instances of generic data tests to be documented
time: 2024-10-14T21:21:35.767115+01:00
custom:
Author: aranke
Issue: "2578"
11 changes: 11 additions & 0 deletions core/dbt/parser/generic_test_builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,17 @@ def __init__(
if self.namespace is not None:
self.package_name = self.namespace

# If the user has provided a description for this generic test, use it
# Then delete the "description" argument to:
# 1. Avoid passing it into the test macro
# 2. Avoid passing it into the test name synthesis
# Otherwise, use an empty string
self.description: str = ""

if "description" in self.args:
self.description = self.args["description"]
del self.args["description"]

# If the user has provided a custom name for this generic test, use it
# Then delete the "name" argument to avoid passing it into the test macro
# Otherwise, use an auto-generated name synthesized from test inputs
Expand Down
3 changes: 3 additions & 0 deletions core/dbt/parser/schema_generic_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def create_test_node(
test_metadata: Dict[str, Any],
file_key_name: str,
column_name: Optional[str],
description: str,
) -> GenericTestNode:

HASH_LENGTH = 10
Expand Down Expand Up @@ -134,6 +135,7 @@ def get_hashable_md(data: Union[str, int, float, List, Dict]) -> Union[str, List
"column_name": column_name,
"checksum": FileHash.empty().to_dict(omit_none=True),
"file_key_name": file_key_name,
"description": description,
}
try:
GenericTestNode.validate(dct)
Expand Down Expand Up @@ -229,6 +231,7 @@ def parse_generic_test(
column_name=column_name,
test_metadata=metadata,
file_key_name=file_key_name,
description=builder.description,
)
self.render_test_update(node, config, builder, schema_file_id)

Expand Down
34 changes: 34 additions & 0 deletions tests/functional/generic_test_description/fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
models__my_model_sql = """
with my_cte as (
select 1 as id, 'blue' as color
union all
select 2 as id, 'green' as red
union all
select 3 as id, 'red' as red
)
select * from my_cte
"""

models__schema_yml = """
models:
- name: my_model
columns:
- name: id
tests:
- unique:
description: "id must be unique"
- not_null
- name: color
tests:
- accepted_values:
values: ['blue', 'green', 'red']
description: "{{ doc('color_accepted_values') }}"
"""

models__doc_block_md = """
{% docs color_accepted_values %}
The `color` column must be one of 'blue', 'green', or 'red'.
{% enddocs %}
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest

from dbt.tests.util import get_artifact, run_dbt
from tests.functional.generic_test_description.fixtures import (
models__doc_block_md,
models__my_model_sql,
models__schema_yml,
)


class TestBuiltinGenericTestDescription:
@pytest.fixture(scope="class")
def models(self):
return {
"my_model.sql": models__my_model_sql,
"schema.yml": models__schema_yml,
"doc_block.md": models__doc_block_md,
}

def test_compile(self, project):
run_dbt(["compile"])
manifest = get_artifact(project.project_root, "target", "manifest.json")
assert len(manifest["nodes"]) == 4

nodes = {node["alias"]: node for node in manifest["nodes"].values()}

assert nodes["unique_my_model_id"]["description"] == "id must be unique"
assert nodes["not_null_my_model_id"]["description"] == ""
assert (
nodes["accepted_values_my_model_color__blue__green__red"]["description"]
== "The `color` column must be one of 'blue', 'green', or 'red'."
)
4 changes: 3 additions & 1 deletion tests/unit/parser/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ def assertEqualNodes(node_one, node_two):
- not_null:
severity: WARN
- accepted_values:
description: Only primary colors are allowed in here
values: ['red', 'blue', 'green']
- foreign_package.test_case:
arg: 100
Expand Down Expand Up @@ -631,6 +632,7 @@ def test__parse_basic_model_tests(self):
self.assertEqual(tests[0].tags, [])
self.assertEqual(tests[0].refs, [RefArgs(name="my_model")])
self.assertEqual(tests[0].column_name, "color")
self.assertEqual(tests[0].description, "Only primary colors are allowed in here")
self.assertEqual(tests[0].package_name, "snowplow")
self.assertTrue(tests[0].name.startswith("accepted_values_"))
self.assertEqual(tests[0].fqn, ["snowplow", tests[0].name])
Expand All @@ -654,7 +656,7 @@ def test__parse_basic_model_tests(self):
self.assertEqual(tests[1].tags, [])
self.assertEqual(tests[1].refs, [RefArgs(name="my_model")])
self.assertEqual(tests[1].column_name, "color")
self.assertEqual(tests[1].column_name, "color")
self.assertEqual(tests[1].description, "")
self.assertEqual(tests[1].fqn, ["snowplow", tests[1].name])
self.assertTrue(tests[1].name.startswith("foreign_package_test_case_"))
self.assertEqual(tests[1].package_name, "snowplow")
Expand Down

0 comments on commit cd6bb9e

Please sign in to comment.