Skip to content
This repository was archived by the owner on Sep 2, 2025. It is now read-only.
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add tests for constraints
  • Loading branch information
b-per authored and jtcohen6 committed Feb 1, 2023
commit 2687b7730f720543f699f3404d1168f761e1001b
136 changes: 136 additions & 0 deletions tests/functional/constraints/test_constraints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import pytest
from dbt.tests.util import run_dbt, run_dbt_and_capture

models__constraints_column_types_sql = """
select
1000 as int_column,
99.99 as float_column,
true as bool_column,
'2022-01-01'::date as date_column
"""

models__constraints_incorrect_column_types_sql = """
select
1000 as int_column,
99.99 as float_column,
true as bool_column,
'2022-01-01'::date as date_column
"""

models__constraints_not_null_sql = """
select
1000 as int_column,
99.99 as float_column,
true as bool_column,
'2022-01-01'::date as date_column

union all

select
NULL as int_column,
99.99 as float_column,
true as bool_column,
'2022-01-01'::date as date_column
"""

models__models_config_yml = """
version: 2
models:
- name: constraints_column_types
description: "Model to test column data type constraints"
config:
constraints_enabled: true
columns:
- name: int_column
description: "Test for int type"
data_type: int
constraints:
- unique
- not null
check: "int_column > 0"
- name: float_column
description: "Test for int type"
data_type: float
check: "float_column > 0"
- name: bool_column
description: "Test for int type"
data_type: boolean
- name: date_column
description: "Test for int type"
data_type: date

- name: constraints_incorrect_column_types
description: "Model to test failing column data type constraints"
config:
constraints_enabled: true
columns:
- name: int_column
description: "Test for int type"
data_type: boolean
- name: float_column
description: "Test for int type"
data_type: date
- name: bool_column
description: "Test for int type"
data_type: int
- name: date_column
description: "Test for int type"
data_type: date

- name: constraints_not_null
description: "Model to test failing materialization when a column is NULL"
config:
constraints_enabled: true
columns:
- name: int_column
description: "Test for int type with some constraints"
data_type: int
constraints:
- unique
- not null
- name: float_column
description: "Test for int type"
data_type: float
- name: bool_column
description: "Test for int type"
data_type: boolean
- name: date_column
description: "Test for int type"
data_type: date
"""


class TestMaterializedWithConstraints:
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we really want the DDL test? I feel like any other change to create_table_as() would then require updating the tests for something unrelated.

I actually wanted to avoid a test checking the DDL.

Copy link
Contributor

Choose a reason for hiding this comment

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

Based on an internal slack thread, you don't need the DDL test, but the rollback test remains to be needed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I can create a rollback test. Because this PR leverages Snowflake's ability to set constraints as part of the CTAS statement I think that this use case is already covered by the existing CTAS tests but it is not too difficult for me to add another one here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks looks great!

@pytest.fixture(scope="class")
def models(self):
return {
"constraints_column_types.sql": models__constraints_column_types_sql,
"constraints_incorrect_column_types.sql": models__constraints_incorrect_column_types_sql,
"constraints_not_null.sql": models__constraints_not_null_sql,
"models_config.yml": models__models_config_yml,
}

@pytest.fixture(scope="class")
def project_config_update(self, prefix):
return {
"config-version": 2,
"models": {
"materialized": "table",
},
}

def test_materialized_with_constraints(self, project):
_, stdout = run_dbt_and_capture(["run", "--select", "constraints_column_types"])
found_check_config_str = "We noticed you have `check` configs"
number_times_print_found_check_config = stdout.count(found_check_config_str)
assert number_times_print_found_check_config == 1

def test_failing_materialized_with_constraints(self, project):
result = run_dbt(
["run", "--select", "constraints_incorrect_column_types"], expect_pass=False
)
assert "incompatible types" in result.results[0].message

def test_failing_not_null_constraint(self, project):
result = run_dbt(["run", "--select", "constraints_not_null"], expect_pass=False)
assert "NULL result in a non-nullable column" in result.results[0].message