Skip to content

Commit

Permalink
add builder config to test node config (#10767)
Browse files Browse the repository at this point in the history
* add builder config to node config

* add changie

* raise expected exceptions

* add code comment and additional tests

* update tests

* update tests
  • Loading branch information
colin-rogers-dbt authored Oct 10, 2024
1 parent f6cdacc commit 6743e32
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 27 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/Fixes-20240925-154514.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Fixes
body: Pass test user config to adapter pre_hook by explicitly adding test builder config to node
time: 2024-09-25T15:45:14.459598-07:00
custom:
Author: colin-rogers-dbt
Issue: "10484"
10 changes: 8 additions & 2 deletions core/dbt/context/context_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
from dbt.adapters.factory import get_config_class_by_name
from dbt.config import IsFQNResource, Project, RuntimeConfig
from dbt.contracts.graph.model_config import get_config_for
from dbt.exceptions import SchemaConfigError
from dbt.flags import get_flags
from dbt.node_types import NodeType
from dbt.utils import fqn_search
from dbt_common.contracts.config.base import BaseConfig, merge_config_dicts
from dbt_common.dataclass_schema import ValidationError
from dbt_common.exceptions import DbtInternalError


Expand Down Expand Up @@ -237,8 +239,12 @@ def calculate_node_config_dict(
base=base,
patch_config_dict=patch_config_dict,
)
finalized = config.finalize_and_validate()
return finalized.to_dict(omit_none=True)
try:
finalized = config.finalize_and_validate()
return finalized.to_dict(omit_none=True)
except ValidationError as exc:
# we got a ValidationError - probably bad types in config()
raise SchemaConfigError(exc, node=config) from exc


class UnrenderedConfigGenerator(BaseContextConfigGenerator[Dict[str, Any]]):
Expand Down
4 changes: 3 additions & 1 deletion core/dbt/parser/schema_generic_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ def parse_generic_test(

# this is the ContextConfig that is used in render_update
config: ContextConfig = self.initial_config(fqn)

# Adding the builder's config to the ContextConfig
# is needed to ensure the config makes it to the pre_model hook which dbt-snowflake needs
config.add_config_call(builder.config)
# builder.args contains keyword args for the test macro,
# not configs which have been separated out in the builder.
# The keyword args are not completely rendered until compilation.
Expand Down
7 changes: 4 additions & 3 deletions tests/functional/configs/test_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pytest

from dbt.exceptions import SchemaConfigError
from dbt.tests.util import (
check_relations_equal,
run_dbt,
Expand Down Expand Up @@ -81,7 +82,7 @@ def test_tests_materialization_proj_config(self, project):
tests_dir = os.path.join(project.project_root, "tests")
write_file("select * from foo", tests_dir, "test.sql")

with pytest.raises(ValidationError):
with pytest.raises(SchemaConfigError):
run_dbt()


Expand All @@ -93,7 +94,7 @@ def test_seeds_materialization_proj_config(self, project):
seeds_dir = os.path.join(project.project_root, "seeds")
write_file("id1, id2\n1, 2", seeds_dir, "seed.csv")

with pytest.raises(ValidationError):
with pytest.raises(SchemaConfigError):
run_dbt()


Expand All @@ -107,7 +108,7 @@ def test_seeds_materialization_schema_config(self, project):
)
write_file("id1, id2\n1, 2", seeds_dir, "myseed.csv")

with pytest.raises(ValidationError):
with pytest.raises(SchemaConfigError):
run_dbt()


Expand Down
7 changes: 3 additions & 4 deletions tests/functional/configs/test_disabled_model.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import pytest

from dbt.exceptions import CompilationError, ParsingError
from dbt.exceptions import CompilationError, ParsingError, SchemaConfigError
from dbt.tests.util import get_manifest, run_dbt
from dbt_common.dataclass_schema import ValidationError
from tests.functional.configs.fixtures import (
my_model,
my_model_2,
Expand Down Expand Up @@ -394,8 +393,8 @@ def models(self):
"my_model.sql": my_model,
}

def test_invalis_config(self, project):
with pytest.raises(ValidationError) as exc:
def test_invalid_config(self, project):
with pytest.raises(SchemaConfigError) as exc:
run_dbt(["parse"])
exc_str = " ".join(str(exc.value).split()) # flatten all whitespace
expected_msg = "'True and False' is not of type 'boolean'"
Expand Down
57 changes: 42 additions & 15 deletions tests/functional/schema_tests/data_test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import pytest

from dbt.contracts.graph.manifest import Manifest
from dbt.contracts.graph.nodes import TestNode
from dbt.exceptions import CompilationError
from dbt.tests.util import get_manifest, run_dbt
from tests.functional.schema_tests.fixtures import (
Expand All @@ -10,14 +12,44 @@
same_key_error_yml,
seed_csv,
table_sql,
test_custom_color_from_config,
)


def _select_test_node(manifest: Manifest, pattern: re.Pattern[str]):
# Find the test_id dynamically
test_id = None
for node_id in manifest.nodes:
if pattern.match(node_id):
test_id = node_id
break

# Ensure the test_id was found
assert test_id is not None, "Test ID matching the pattern was not found in the manifest nodes"
return manifest.nodes[test_id]


def get_table_persistence(project, table_name):
sql = f"""
SELECT
relpersistence
FROM pg_class
WHERE relname like '%{table_name}%'
"""
result = project.run_sql(sql, fetch="one")
assert len(result) == 1
return result[0]


class BaseDataTestsConfig:
@pytest.fixture(scope="class")
def seeds(self):
return {"seed.csv": seed_csv}

@pytest.fixture(scope="class")
def macros(self):
return {"custom_color_from_config.sql": test_custom_color_from_config}

@pytest.fixture(scope="class")
def project_config_update(self):
return {
Expand All @@ -35,29 +67,24 @@ def models(self):
return {"table.sql": table_sql, "custom_config.yml": custom_config_yml}

def test_custom_config(self, project):
run_dbt(["parse"])
manifest = get_manifest(project.project_root)
run_dbt(["run"])
run_dbt(["test", "--log-level", "debug"], expect_pass=False)

manifest = get_manifest(project.project_root)
# Pattern to match the test_id without the specific suffix
pattern = re.compile(r"test\.test\.accepted_values_table_color__blue__red\.\d+")

# Find the test_id dynamically
test_id = None
for node_id in manifest.nodes:
if pattern.match(node_id):
test_id = node_id
break

# Ensure the test_id was found
assert (
test_id is not None
), "Test ID matching the pattern was not found in the manifest nodes"

test_node: TestNode = _select_test_node(manifest, pattern)
# Proceed with the assertions
test_node = manifest.nodes[test_id]
assert "custom_config_key" in test_node.config
assert test_node.config["custom_config_key"] == "some_value"

# pattern = re.compile(r"test\.test\.custom_color_from_config.*")
# test_node = _select_test_node(manifest, pattern)
persistence = get_table_persistence(project, "custom_color_from_config_table_color")

assert persistence == "u"


class TestMixedDataTestConfig(BaseDataTestsConfig):
@pytest.fixture(scope="class")
Expand Down
21 changes: 19 additions & 2 deletions tests/functional/schema_tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,12 @@
values: ['blue', 'red']
config:
custom_config_key: some_value
- custom_color_from_config:
severity: error
config:
test_color: orange
store_failures: true
unlogged: True
"""

mixed_config_yml = """
Expand All @@ -1296,9 +1302,13 @@
data_tests:
- accepted_values:
values: ['blue', 'red']
severity: warn
config:
custom_config_key: some_value
severity: warn
- custom_color_from_config:
severity: error
config:
test_color: blue
"""

same_key_error_yml = """
Expand Down Expand Up @@ -1327,9 +1337,16 @@
8,green,80
9,yellow,90
10,blue,100
"""
""".strip()

table_sql = """
-- content of the table.sql
select * from {{ ref('seed') }}
"""

test_custom_color_from_config = """
{% test custom_color_from_config(model, column_name) %}
select * from {{ model }}
where color = '{{ config.get('test_color') }}'
{% endtest %}
"""

0 comments on commit 6743e32

Please sign in to comment.