From 1014a6d490d95181de9376d708abe7eb0c3e6b44 Mon Sep 17 00:00:00 2001 From: Kshitij Aranke Date: Tue, 23 Apr 2024 17:09:48 +0200 Subject: [PATCH] Fix #9715: Simplify error message if test severity isn't 'warn' or 'error' (#10015) --- .../unreleased/Fixes-20240423-120112.yaml | 6 ++++ core/dbt/artifacts/resources/v1/config.py | 8 +++++ tests/unit/test_parser.py | 32 ++++++++++++++++--- 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 .changes/unreleased/Fixes-20240423-120112.yaml diff --git a/.changes/unreleased/Fixes-20240423-120112.yaml b/.changes/unreleased/Fixes-20240423-120112.yaml new file mode 100644 index 00000000000..59e763451dc --- /dev/null +++ b/.changes/unreleased/Fixes-20240423-120112.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Simplify error message if test severity isn't 'warn' or 'error' +time: 2024-04-23T12:01:12.374904+02:00 +custom: + Author: aranke + Issue: "9715" diff --git a/core/dbt/artifacts/resources/v1/config.py b/core/dbt/artifacts/resources/v1/config.py index 7a3ef63c334..28b9879584c 100644 --- a/core/dbt/artifacts/resources/v1/config.py +++ b/core/dbt/artifacts/resources/v1/config.py @@ -1,3 +1,5 @@ +import re + from dbt_common.dataclass_schema import dbtClassMixin, ValidationError from typing import Optional, List, Any, Dict, Union from typing_extensions import Annotated @@ -250,6 +252,12 @@ def same_contents(cls, unrendered: Dict[str, Any], other: Dict[str, Any]) -> boo @classmethod def validate(cls, data): + if data.get("severity") and not re.match(SEVERITY_PATTERN, data.get("severity")): + raise ValidationError( + f"Severity must be either 'warn' or 'error'. Got '{data.get('severity')}'" + ) + super().validate(data) + if data.get("materialized") and data.get("materialized") != "test": raise ValidationError("A test must have a materialized value of 'test'") diff --git a/tests/unit/test_parser.py b/tests/unit/test_parser.py index e1eb643eb49..420354f585e 100644 --- a/tests/unit/test_parser.py +++ b/tests/unit/test_parser.py @@ -1,5 +1,6 @@ import os import unittest +from argparse import Namespace from copy import deepcopy from unittest import mock @@ -8,12 +9,12 @@ import dbt.flags import dbt.parser from dbt import tracking +from dbt.artifacts.resources import ModelConfig from dbt.artifacts.resources import RefArgs from dbt.context.context_config import ContextConfig from dbt.contracts.files import SourceFile, FileHash, FilePath, SchemaSourceFile from dbt.contracts.graph.manifest import Manifest from dbt.contracts.graph.model_config import NodeConfig, TestConfig, SnapshotConfig -from dbt.artifacts.resources import ModelConfig from dbt.contracts.graph.nodes import ( ModelNode, Macro, @@ -23,7 +24,8 @@ AnalysisNode, UnpatchedSourceDefinition, ) -from dbt.exceptions import CompilationError, ParsingError +from dbt.exceptions import CompilationError, ParsingError, SchemaConfigError +from dbt.flags import set_from_args from dbt.node_types import NodeType from dbt.parser import ( ModelParser, @@ -53,8 +55,6 @@ from dbt.parser.search import FileBlock from dbt.parser.sources import SourcePatcher from .utils import config_from_parts_or_dicts, normalize, generate_name_macros, MockNode -from dbt.flags import set_from_args -from argparse import Namespace set_from_args(Namespace(WARN_ERROR=False), None) @@ -273,6 +273,22 @@ def assertEqualNodes(node_one, node_two): arg: 100 """ +SINGLE_TABLE_MODEL_TESTS_WRONG_SEVERITY = """ +models: + - name: my_model + description: A description of my model + columns: + - name: color + description: The color value + data_tests: + - not_null: + severity: WARNING + - accepted_values: + values: ['red', 'blue', 'green'] + - foreign_package.test_case: + arg: 100 +""" + MULTIPLE_TABLE_VERSIONED_MODEL_TESTS = """ models: @@ -577,6 +593,14 @@ def test__read_basic_model_tests(self): self.assertEqual(len(list(self.parser.manifest.sources)), 0) self.assertEqual(len(list(self.parser.manifest.nodes)), 4) + def test__read_basic_model_tests_wrong_severity(self): + block = self.yaml_block_for(SINGLE_TABLE_MODEL_TESTS_WRONG_SEVERITY, "test_one.yml") + dct = yaml_from_file(block.file) + with self.assertRaisesRegex( + SchemaConfigError, "Severity must be either 'warn' or 'error'. Got 'WARNING'" + ): + self.parser.parse_file(block, dct) + def test__parse_basic_model_tests(self): block = self.file_block_for(SINGLE_TABLE_MODEL_TESTS, "test_one.yml") self.parser.manifest.files[block.file.file_id] = block.file