Skip to content

Commit dbb8034

Browse files
committed
test: add tests for data quality rule enhancements
1 parent 4d61f37 commit dbb8034

4 files changed

Lines changed: 156 additions & 5 deletions

File tree

pyatlan/generator/templates/methods/asset/data_quality_rule.jinja2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143

144144
asset_for_validation, target_table_asset = (
145145
DataQualityRule.Attributes._fetch_assets_for_row_scope_validation(
146-
client, asset, rule_conditions, row_scope_filtering_enabled
146+
client, asset, rule_conditions, row_scope_filtering_enabled or False
147147
)
148148
)
149149

pyatlan/generator/templates/methods/attribute/data_quality_rule.jinja2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
target_table_qualified_name = condition_value.get(
2424
"target_table"
2525
)
26-
except (json.JSONDecodeError, (KeyError, TypeError)):
26+
except (json.JSONDecodeError, KeyError, TypeError):
2727
pass
2828

2929
qualified_names_to_search = []

pyatlan/model/assets/core/data_quality_rule.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def column_level_rule_creator(
190190

191191
asset_for_validation, target_table_asset = (
192192
DataQualityRule.Attributes._fetch_assets_for_row_scope_validation(
193-
client, asset, rule_conditions, row_scope_filtering_enabled
193+
client, asset, rule_conditions, row_scope_filtering_enabled or False
194194
)
195195
)
196196

@@ -1135,7 +1135,7 @@ def _fetch_assets_for_row_scope_validation(
11351135
target_table_qualified_name = condition_value.get(
11361136
"target_table"
11371137
)
1138-
except (json.JSONDecodeError, (KeyError, TypeError)):
1138+
except (json.JSONDecodeError, KeyError, TypeError):
11391139
pass
11401140

11411141
qualified_names_to_search = []

tests/unit/model/data_quality_rule_test.py

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33

44
import pytest
55

6+
from pyatlan.client.asset import IndexSearchResults
67
from pyatlan.errors import ErrorCode, InvalidRequestError
78
from pyatlan.model.assets import Column, DataQualityRule, Table
89
from pyatlan.model.dq_rule_conditions import DQRuleConditionsBuilder
910
from pyatlan.model.enums import (
1011
DataQualityDimension,
1112
DataQualityRuleAlertPriority,
13+
DataQualityRuleCustomSQLReturnType,
1214
DataQualityRuleStatus,
1315
DataQualityRuleTemplateConfigRuleConditions,
1416
DataQualityRuleThresholdCompareOperator,
@@ -287,7 +289,6 @@ def test_column_level_rule_creator_with_missing_parameters_raise_value_error(
287289
)
288290

289291

290-
## Change below
291292
def test_table_level_rule_creator(mock_client):
292293
asset = Table.ref_by_qualified_name(qualified_name=DQ_TABLE_QUALIFIED_NAME)
293294

@@ -305,6 +306,23 @@ def test_table_level_rule_creator(mock_client):
305306
assert dq_rule.qualified_name.startswith(f"{DQ_TABLE_QUALIFIED_NAME}/rule/")
306307

307308

309+
def test_table_level_rule_creator_with_threshold_unit(mock_client):
310+
asset = Table.ref_by_qualified_name(qualified_name=DQ_TABLE_QUALIFIED_NAME)
311+
312+
dq_rule = DataQualityRule.table_level_rule_creator(
313+
client=mock_client,
314+
rule_type=DQ_RULE_TYPE_TABLE,
315+
asset=asset,
316+
threshold_compare_operator=DataQualityRuleThresholdCompareOperator.LESS_THAN_EQUAL,
317+
threshold_value=DQ_RULE_THRESHOLD_VALUE,
318+
alert_priority=DataQualityRuleAlertPriority.NORMAL,
319+
threshold_unit=DataQualityRuleThresholdUnit.ABSOLUTE,
320+
)
321+
322+
assert dq_rule.dq_rule_alert_priority == DataQualityRuleAlertPriority.NORMAL
323+
assert dq_rule.dq_rule_status == DataQualityRuleStatus.ACTIVE
324+
325+
308326
def test_custom_sql_creator(mock_client):
309327
asset = Table.ref_by_qualified_name(qualified_name=DQ_TABLE_QUALIFIED_NAME)
310328

@@ -347,6 +365,27 @@ def test_custom_sql_creator_with_optional_parameters(mock_client):
347365
assert dq_rule.user_description == DQ_RULE_DESCRIPTION
348366

349367

368+
def test_custom_sql_creator_with_custom_sql_return_type(mock_client):
369+
asset = Table.ref_by_qualified_name(qualified_name=DQ_TABLE_QUALIFIED_NAME)
370+
371+
dq_rule = DataQualityRule.custom_sql_creator(
372+
client=mock_client,
373+
rule_name=DQ_RULE_NAME,
374+
asset=asset,
375+
custom_sql=DQ_RULE_CUSTOM_SQL,
376+
threshold_compare_operator=DataQualityRuleThresholdCompareOperator.LESS_THAN_EQUAL,
377+
threshold_value=DQ_RULE_THRESHOLD_VALUE,
378+
alert_priority=DataQualityRuleAlertPriority.NORMAL,
379+
dimension=DataQualityDimension.COMPLETENESS,
380+
custom_sql_return_type=DataQualityRuleCustomSQLReturnType.ROW_COUNT,
381+
)
382+
383+
assert (
384+
dq_rule.dq_rule_custom_s_q_l_return_type
385+
== DataQualityRuleCustomSQLReturnType.ROW_COUNT
386+
)
387+
388+
350389
def test_column_level_rule_creator(mock_client):
351390
asset = Table.ref_by_qualified_name(qualified_name=DQ_TABLE_QUALIFIED_NAME)
352391
column = Column.ref_by_qualified_name(qualified_name=DQ_COLUMN_QUALIFIED_NAME)
@@ -391,6 +430,10 @@ def test_column_level_rule_creator_with_row_scope_filtering(mock_client):
391430
asset.asset_d_q_row_scope_filter_column_qualified_name = DQ_COLUMN_QUALIFIED_NAME
392431
column = Column.ref_by_qualified_name(qualified_name=DQ_COLUMN_QUALIFIED_NAME)
393432

433+
search_results = Mock(spec=IndexSearchResults)
434+
search_results.current_page.return_value = [asset]
435+
mock_client.asset.search.return_value = search_results
436+
394437
dq_rule = DataQualityRule.column_level_rule_creator(
395438
client=mock_client,
396439
rule_type=DQ_RULE_TYPE_COLUMN,
@@ -593,3 +636,111 @@ def test_validate_template_features_row_scope_filter_column_missing(mock_client)
593636
threshold_compare_operator=DataQualityRuleThresholdCompareOperator.EQUAL,
594637
asset=table_asset,
595638
)
639+
640+
641+
def test_fetch_assets_for_row_scope_validation_disabled(mock_client):
642+
asset = Table.ref_by_qualified_name(qualified_name=DQ_TABLE_QUALIFIED_NAME)
643+
644+
asset_for_validation, target_table_asset = (
645+
DataQualityRule.Attributes._fetch_assets_for_row_scope_validation(
646+
client=mock_client,
647+
base_asset=asset,
648+
rule_conditions=None,
649+
row_scope_filtering_enabled=False,
650+
)
651+
)
652+
653+
assert asset_for_validation == asset
654+
assert target_table_asset is None
655+
656+
657+
def test_fetch_assets_for_row_scope_validation_with_target_table(mock_client):
658+
asset = Table.ref_by_qualified_name(qualified_name=DQ_TABLE_QUALIFIED_NAME)
659+
asset.asset_d_q_row_scope_filter_column_qualified_name = DQ_COLUMN_QUALIFIED_NAME
660+
target_table = Table.ref_by_qualified_name(
661+
qualified_name="target/table/qualified_name"
662+
)
663+
target_table.asset_d_q_row_scope_filter_column_qualified_name = (
664+
DQ_COLUMN_QUALIFIED_NAME
665+
)
666+
667+
search_results = Mock(spec=IndexSearchResults)
668+
search_results.current_page.return_value = [asset, target_table]
669+
mock_client.asset.search.return_value = search_results
670+
671+
rule_conditions = (
672+
DQRuleConditionsBuilder()
673+
.add_condition(
674+
type=DataQualityRuleTemplateConfigRuleConditions.ROW_COUNT_RECON,
675+
target_table="target/table/qualified_name",
676+
)
677+
.build()
678+
)
679+
680+
asset_for_validation, target_table_asset = (
681+
DataQualityRule.Attributes._fetch_assets_for_row_scope_validation(
682+
client=mock_client,
683+
base_asset=asset,
684+
rule_conditions=rule_conditions,
685+
row_scope_filtering_enabled=True,
686+
)
687+
)
688+
689+
assert asset_for_validation == asset
690+
assert target_table_asset == target_table
691+
692+
693+
def test_dq_condition_in_list_reference():
694+
rule_conditions = (
695+
DQRuleConditionsBuilder()
696+
.add_condition(
697+
type=DataQualityRuleTemplateConfigRuleConditions.IN_LIST_REFERENCE,
698+
reference_table="reference/table/qualified_name",
699+
reference_column="reference/column/qualified_name",
700+
)
701+
.build()
702+
)
703+
704+
condition = json.loads(rule_conditions)["conditions"][0]
705+
assert condition["type"] == "IN_LIST_REFERENCE"
706+
assert condition["value"]["reference_table"] == "reference/table/qualified_name"
707+
assert condition["value"]["reference_column"] == "reference/column/qualified_name"
708+
709+
710+
def test_dq_condition_recon_with_target_table_and_column():
711+
rule_conditions = (
712+
DQRuleConditionsBuilder()
713+
.add_condition(
714+
type=DataQualityRuleTemplateConfigRuleConditions.AVERAGE_RECON,
715+
target_table="target/table/qualified_name",
716+
target_column="target/column/qualified_name",
717+
)
718+
.build()
719+
)
720+
721+
condition = json.loads(rule_conditions)["conditions"][0]
722+
assert condition["type"] == "AVERAGE_RECON"
723+
assert condition["value"]["target_table"] == "target/table/qualified_name"
724+
assert condition["value"]["target_column"] == "target/column/qualified_name"
725+
726+
727+
def test_dq_condition_missing_required_fields():
728+
with pytest.raises(ValueError, match="reference_table is required"):
729+
DQRuleConditionsBuilder().add_condition(
730+
type=DataQualityRuleTemplateConfigRuleConditions.IN_LIST_REFERENCE,
731+
reference_table=None,
732+
reference_column="reference/column/qualified_name",
733+
).build()
734+
735+
with pytest.raises(ValueError, match="target_table is required"):
736+
DQRuleConditionsBuilder().add_condition(
737+
type=DataQualityRuleTemplateConfigRuleConditions.ROW_COUNT_RECON,
738+
target_table=None,
739+
).build()
740+
741+
with pytest.raises(ValueError, match="target_column is required"):
742+
DQRuleConditionsBuilder().add_condition(
743+
type=DataQualityRuleTemplateConfigRuleConditions.AVERAGE_RECON,
744+
target_table="target/table/qualified_name",
745+
target_column=None,
746+
).build()

0 commit comments

Comments
 (0)