From a3c07ca0af395531b23b04c2ee9c59cd38ed7f0d Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Tue, 14 Sep 2021 12:01:50 +0200 Subject: [PATCH 1/5] Fix #3347 --- core/dbt/parser/sources.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/dbt/parser/sources.py b/core/dbt/parser/sources.py index 035e345f1cb..028bf6ae119 100644 --- a/core/dbt/parser/sources.py +++ b/core/dbt/parser/sources.py @@ -269,11 +269,6 @@ def parse_source_test( tags=tags, column_name=column_name ) - # we can't go through result.add_node - no file... instead! - if node.config.enabled: - self.manifest.add_node_nofile(node) - else: - self.manifest.add_disabled_nofile(node) return node def _generate_source_config(self, fqn: List[str], rendered: bool, project_name: str): From e0da922303dd144dd64853917e16d3c2b9fc7d4e Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Tue, 14 Sep 2021 09:28:26 +0200 Subject: [PATCH 2/5] Rename data->singular, schema->generic --- core/dbt/clients/jinja.py | 10 +++--- core/dbt/compilation.py | 4 +-- core/dbt/contracts/files.py | 2 +- core/dbt/contracts/graph/compiled.py | 28 +++++++-------- core/dbt/contracts/graph/parsed.py | 14 ++++---- core/dbt/graph/cli.py | 6 +++- core/dbt/graph/selector_methods.py | 21 ++++++------ .../accepted_values.sql | 0 .../not_null.sql | 0 .../relationships.sql | 0 .../unique.sql | 0 core/dbt/main.py | 2 ++ core/dbt/parser/__init__.py | 4 +-- ...t_builders.py => generic_test_builders.py} | 12 +++---- core/dbt/parser/manifest.py | 4 +-- core/dbt/parser/read_files.py | 2 +- core/dbt/parser/schemas.py | 34 +++++++++---------- .../parser/{data_test.py => singular_test.py} | 13 +++---- core/dbt/parser/sources.py | 6 ++-- core/dbt/task/test.py | 8 +++-- .../test_graph_selection.py | 4 +-- .../models-v2/custom-configs/schema.yml | 7 ++-- .../custom-configs/table.copy.with.dots.sql | 10 +----- .../custom-configs/table_copy_another_one.sql | 1 + .../test_schema_v2_tests.py | 2 +- .../test_docs_generate.py | 24 ++++++------- test/integration/047_dbt_ls_test/test_ls.py | 12 +++---- .../test_modified_state.py | 2 +- test/unit/test_contracts_graph_compiled.py | 16 ++++----- test/unit/test_contracts_graph_parsed.py | 16 ++++----- test/unit/test_graph_selector_methods.py | 13 ++++--- test/unit/test_parser.py | 26 +++++++------- 32 files changed, 157 insertions(+), 146 deletions(-) rename core/dbt/include/global_project/macros/{schema_tests => generic_tests}/accepted_values.sql (100%) rename core/dbt/include/global_project/macros/{schema_tests => generic_tests}/not_null.sql (100%) rename core/dbt/include/global_project/macros/{schema_tests => generic_tests}/relationships.sql (100%) rename core/dbt/include/global_project/macros/{schema_tests => generic_tests}/unique.sql (100%) rename core/dbt/parser/{schema_test_builders.py => generic_test_builders.py} (97%) rename core/dbt/parser/{data_test.py => singular_test.py} (57%) create mode 100644 test/integration/008_schema_tests_test/models-v2/custom-configs/table_copy_another_one.sql diff --git a/core/dbt/clients/jinja.py b/core/dbt/clients/jinja.py index 270ae948bc9..f6f0e8246fc 100644 --- a/core/dbt/clients/jinja.py +++ b/core/dbt/clients/jinja.py @@ -25,8 +25,8 @@ ) from dbt.clients._jinja_blocks import BlockIterator, BlockData, BlockTag -from dbt.contracts.graph.compiled import CompiledSchemaTestNode -from dbt.contracts.graph.parsed import ParsedSchemaTestNode +from dbt.contracts.graph.compiled import CompiledGenericTestNode +from dbt.contracts.graph.parsed import ParsedGenericTestNode from dbt.exceptions import ( InternalException, raise_compiler_error, CompilationException, invalid_materialization_argument, MacroReturn, JinjaRenderingException, @@ -627,12 +627,12 @@ def extract_toplevel_blocks( ) -SCHEMA_TEST_KWARGS_NAME = '_dbt_schema_test_kwargs' +GENERIC_TEST_KWARGS_NAME = '_dbt_generic_test_kwargs' def add_rendered_test_kwargs( context: Dict[str, Any], - node: Union[ParsedSchemaTestNode, CompiledSchemaTestNode], + node: Union[ParsedGenericTestNode, CompiledGenericTestNode], capture_macros: bool = False, ) -> None: """Render each of the test kwargs in the given context using the native @@ -662,4 +662,4 @@ def _convert_function( return value kwargs = deep_map(_convert_function, node.test_metadata.kwargs) - context[SCHEMA_TEST_KWARGS_NAME] = kwargs + context[GENERIC_TEST_KWARGS_NAME] = kwargs diff --git a/core/dbt/compilation.py b/core/dbt/compilation.py index 45da3521ab1..9b9b9781a28 100644 --- a/core/dbt/compilation.py +++ b/core/dbt/compilation.py @@ -13,7 +13,7 @@ from dbt.contracts.graph.manifest import Manifest, UniqueID from dbt.contracts.graph.compiled import ( COMPILED_TYPES, - CompiledSchemaTestNode, + CompiledGenericTestNode, GraphMemberNode, InjectedCTE, ManifestNode, @@ -181,7 +181,7 @@ def _create_node_context( node, self.config, manifest ) context.update(extra_context) - if isinstance(node, CompiledSchemaTestNode): + if isinstance(node, CompiledGenericTestNode): # for test nodes, add a special keyword args value to the context jinja.add_rendered_test_kwargs(context, node) diff --git a/core/dbt/contracts/files.py b/core/dbt/contracts/files.py index 8aa928f9b0e..1293fd9a54c 100644 --- a/core/dbt/contracts/files.py +++ b/core/dbt/contracts/files.py @@ -30,7 +30,7 @@ class ParseFileType(StrEnum): ParseFileType.Model: 'ModelParser', ParseFileType.Snapshot: 'SnapshotParser', ParseFileType.Analysis: 'AnalysisParser', - ParseFileType.Test: 'DataTestParser', + ParseFileType.Test: 'SingularTestParser', ParseFileType.Seed: 'SeedParser', ParseFileType.Documentation: 'DocumentationParser', ParseFileType.Schema: 'SchemaParser', diff --git a/core/dbt/contracts/graph/compiled.py b/core/dbt/contracts/graph/compiled.py index b0869bb4f47..fe30fb60338 100644 --- a/core/dbt/contracts/graph/compiled.py +++ b/core/dbt/contracts/graph/compiled.py @@ -2,13 +2,13 @@ HasTestMetadata, ParsedNode, ParsedAnalysisNode, - ParsedDataTestNode, + ParsedSingularTestNode, ParsedHookNode, ParsedModelNode, ParsedExposure, ParsedResource, ParsedRPCNode, - ParsedSchemaTestNode, + ParsedGenericTestNode, ParsedSeedNode, ParsedSnapshotNode, ParsedSourceDefinition, @@ -107,7 +107,7 @@ class CompiledSnapshotNode(CompiledNode): @dataclass -class CompiledDataTestNode(CompiledNode): +class CompiledSingularTestNode(CompiledNode): resource_type: NodeType = field(metadata={'restrict': [NodeType.Test]}) # Was not able to make mypy happy and keep the code working. We need to # refactor the various configs. @@ -115,8 +115,8 @@ class CompiledDataTestNode(CompiledNode): @dataclass -class CompiledSchemaTestNode(CompiledNode, HasTestMetadata): - # keep this in sync with ParsedSchemaTestNode! +class CompiledGenericTestNode(CompiledNode, HasTestMetadata): + # keep this in sync with ParsedGenericTestNode! resource_type: NodeType = field(metadata={'restrict': [NodeType.Test]}) column_name: Optional[str] = None # Was not able to make mypy happy and keep the code working. We need to @@ -134,7 +134,7 @@ def same_contents(self, other) -> bool: ) -CompiledTestNode = Union[CompiledDataTestNode, CompiledSchemaTestNode] +CompiledTestNode = Union[CompiledSingularTestNode, CompiledGenericTestNode] PARSED_TYPES: Dict[Type[CompiledNode], Type[ParsedResource]] = { @@ -144,8 +144,8 @@ def same_contents(self, other) -> bool: CompiledRPCNode: ParsedRPCNode, CompiledSeedNode: ParsedSeedNode, CompiledSnapshotNode: ParsedSnapshotNode, - CompiledDataTestNode: ParsedDataTestNode, - CompiledSchemaTestNode: ParsedSchemaTestNode, + CompiledSingularTestNode: ParsedSingularTestNode, + CompiledGenericTestNode: ParsedGenericTestNode, } @@ -156,8 +156,8 @@ def same_contents(self, other) -> bool: ParsedRPCNode: CompiledRPCNode, ParsedSeedNode: CompiledSeedNode, ParsedSnapshotNode: CompiledSnapshotNode, - ParsedDataTestNode: CompiledDataTestNode, - ParsedSchemaTestNode: CompiledSchemaTestNode, + ParsedSingularTestNode: CompiledSingularTestNode, + ParsedGenericTestNode: CompiledGenericTestNode, } @@ -185,22 +185,22 @@ def parsed_instance_for(compiled: CompiledNode) -> ParsedResource: NonSourceCompiledNode = Union[ CompiledAnalysisNode, - CompiledDataTestNode, + CompiledSingularTestNode, CompiledModelNode, CompiledHookNode, CompiledRPCNode, - CompiledSchemaTestNode, + CompiledGenericTestNode, CompiledSeedNode, CompiledSnapshotNode, ] NonSourceParsedNode = Union[ ParsedAnalysisNode, - ParsedDataTestNode, + ParsedSingularTestNode, ParsedHookNode, ParsedModelNode, ParsedRPCNode, - ParsedSchemaTestNode, + ParsedGenericTestNode, ParsedSeedNode, ParsedSnapshotNode, ] diff --git a/core/dbt/contracts/graph/parsed.py b/core/dbt/contracts/graph/parsed.py index a33cdeb6fcb..9390f4d776f 100644 --- a/core/dbt/contracts/graph/parsed.py +++ b/core/dbt/contracts/graph/parsed.py @@ -242,9 +242,9 @@ def _deserialize(cls, dct: Dict[str, int]): return ParsedRPCNode.from_dict(dct) elif resource_type == 'test': if 'test_metadata' in dct: - return ParsedSchemaTestNode.from_dict(dct) + return ParsedGenericTestNode.from_dict(dct) else: - return ParsedDataTestNode.from_dict(dct) + return ParsedSingularTestNode.from_dict(dct) elif resource_type == 'operation': return ParsedHookNode.from_dict(dct) elif resource_type == 'seed': @@ -412,7 +412,7 @@ class HasTestMetadata(dbtClassMixin): @dataclass -class ParsedDataTestNode(ParsedNode): +class ParsedSingularTestNode(ParsedNode): resource_type: NodeType = field(metadata={'restrict': [NodeType.Test]}) # Was not able to make mypy happy and keep the code working. We need to # refactor the various configs. @@ -420,8 +420,8 @@ class ParsedDataTestNode(ParsedNode): @dataclass -class ParsedSchemaTestNode(ParsedNode, HasTestMetadata): - # keep this in sync with CompiledSchemaTestNode! +class ParsedGenericTestNode(ParsedNode, HasTestMetadata): + # keep this in sync with CompiledGenericTestNode! resource_type: NodeType = field(metadata={'restrict': [NodeType.Test]}) column_name: Optional[str] = None # Was not able to make mypy happy and keep the code working. We need to @@ -773,11 +773,11 @@ def same_contents(self, old: Optional['ParsedExposure']) -> bool: ManifestNodes = Union[ ParsedAnalysisNode, - ParsedDataTestNode, + ParsedSingularTestNode, ParsedHookNode, ParsedModelNode, ParsedRPCNode, - ParsedSchemaTestNode, + ParsedGenericTestNode, ParsedSeedNode, ParsedSnapshotNode, ] diff --git a/core/dbt/graph/cli.py b/core/dbt/graph/cli.py index 4ab9e4ec6af..1fcd324616c 100644 --- a/core/dbt/graph/cli.py +++ b/core/dbt/graph/cli.py @@ -22,6 +22,9 @@ DEFAULT_INCLUDES: List[str] = ['fqn:*', 'source:*', 'exposure:*'] DEFAULT_EXCLUDES: List[str] = [] + +# here for backwards compatibility +# we have since renamed data --> singular, schema --> generic DATA_TEST_SELECTOR: str = 'test_type:data' SCHEMA_TEST_SELECTOR: str = 'test_type:schema' @@ -71,7 +74,8 @@ def parse_difference( excluded = parse_union_from_default(exclude, DEFAULT_EXCLUDES, greedy=True) return SelectionDifference(components=[included, excluded]) - +# serves to handle --schema and --data flags +# only supported for backwards compatibility def parse_test_selectors( data: bool, schema: bool, base: SelectionSpec ) -> SelectionSpec: diff --git a/core/dbt/graph/selector_methods.py b/core/dbt/graph/selector_methods.py index 5fa7e21628b..247c2f81dba 100644 --- a/core/dbt/graph/selector_methods.py +++ b/core/dbt/graph/selector_methods.py @@ -8,17 +8,17 @@ from .graph import UniqueId from dbt.contracts.graph.compiled import ( - CompiledDataTestNode, - CompiledSchemaTestNode, + CompiledSingularTestNode, + CompiledGenericTestNode, CompileResultNode, ManifestNode, ) from dbt.contracts.graph.manifest import Manifest, WritableManifest from dbt.contracts.graph.parsed import ( HasTestMetadata, - ParsedDataTestNode, + ParsedSingularTestNode, ParsedExposure, - ParsedSchemaTestNode, + ParsedGenericTestNode, ParsedSourceDefinition, ) from dbt.contracts.state import PreviousState @@ -361,14 +361,15 @@ def search( self, included_nodes: Set[UniqueId], selector: str ) -> Iterator[UniqueId]: search_types: Tuple[Type, ...] - if selector == 'schema': - search_types = (ParsedSchemaTestNode, CompiledSchemaTestNode) - elif selector == 'data': - search_types = (ParsedDataTestNode, CompiledDataTestNode) + # continue supporting 'schema' + 'data' for backwards compatibility + if selector in ('generic', 'schema'): + search_types = (ParsedGenericTestNode, CompiledGenericTestNode) + elif selector in ('singular', 'data'): + search_types = (ParsedSingularTestNode, CompiledSingularTestNode) else: raise RuntimeException( - f'Invalid test type selector {selector}: expected "data" or ' - '"schema"' + f'Invalid test type selector {selector}: expected "generic" or ' + '"singular"' ) for node, real_node in self.parsed_nodes(included_nodes): diff --git a/core/dbt/include/global_project/macros/schema_tests/accepted_values.sql b/core/dbt/include/global_project/macros/generic_tests/accepted_values.sql similarity index 100% rename from core/dbt/include/global_project/macros/schema_tests/accepted_values.sql rename to core/dbt/include/global_project/macros/generic_tests/accepted_values.sql diff --git a/core/dbt/include/global_project/macros/schema_tests/not_null.sql b/core/dbt/include/global_project/macros/generic_tests/not_null.sql similarity index 100% rename from core/dbt/include/global_project/macros/schema_tests/not_null.sql rename to core/dbt/include/global_project/macros/generic_tests/not_null.sql diff --git a/core/dbt/include/global_project/macros/schema_tests/relationships.sql b/core/dbt/include/global_project/macros/generic_tests/relationships.sql similarity index 100% rename from core/dbt/include/global_project/macros/schema_tests/relationships.sql rename to core/dbt/include/global_project/macros/generic_tests/relationships.sql diff --git a/core/dbt/include/global_project/macros/schema_tests/unique.sql b/core/dbt/include/global_project/macros/generic_tests/unique.sql similarity index 100% rename from core/dbt/include/global_project/macros/schema_tests/unique.sql rename to core/dbt/include/global_project/macros/generic_tests/unique.sql diff --git a/core/dbt/main.py b/core/dbt/main.py index 2de551532d5..a2129578ca7 100644 --- a/core/dbt/main.py +++ b/core/dbt/main.py @@ -724,6 +724,7 @@ def _build_test_subparser(subparsers, base_subparser): ''' ) sub.add_argument( + # here for backwards compatibility '--data', action='store_true', help=''' @@ -731,6 +732,7 @@ def _build_test_subparser(subparsers, base_subparser): ''' ) sub.add_argument( + # here for backwards compatibility '--schema', action='store_true', help=''' diff --git a/core/dbt/parser/__init__.py b/core/dbt/parser/__init__.py index b17d2925548..ee6098d6fdf 100644 --- a/core/dbt/parser/__init__.py +++ b/core/dbt/parser/__init__.py @@ -1,6 +1,6 @@ from .analysis import AnalysisParser # noqa from .base import Parser, ConfiguredParser # noqa -from .data_test import DataTestParser # noqa +from .singular_test import SingularTestParser # noqa from .docs import DocumentationParser # noqa from .hooks import HookParser # noqa from .macros import MacroParser # noqa @@ -10,6 +10,6 @@ from .snapshots import SnapshotParser # noqa from . import ( # noqa - analysis, base, data_test, docs, hooks, macros, models, schemas, + analysis, base, singular_test, docs, hooks, macros, models, schemas, snapshots ) diff --git a/core/dbt/parser/schema_test_builders.py b/core/dbt/parser/generic_test_builders.py similarity index 97% rename from core/dbt/parser/schema_test_builders.py rename to core/dbt/parser/generic_test_builders.py index 9546c179efe..b1b8df7537d 100644 --- a/core/dbt/parser/schema_test_builders.py +++ b/core/dbt/parser/generic_test_builders.py @@ -6,7 +6,7 @@ Generic, TypeVar, Dict, Any, Tuple, Optional, List, ) -from dbt.clients.jinja import get_rendered, SCHEMA_TEST_KWARGS_NAME +from dbt.clients.jinja import get_rendered, GENERIC_TEST_KWARGS_NAME from dbt.contracts.graph.parsed import UnpatchedSourceDefinition from dbt.contracts.graph.unparsed import ( TestDef, @@ -19,7 +19,7 @@ from dbt.parser.search import FileBlock -def get_nice_schema_test_name( +def get_nice_generic_test_name( test_type: str, test_name: str, args: Dict[str, Any] ) -> Tuple[str, str]: flat_args = [] @@ -153,7 +153,7 @@ def from_yaml_block( @dataclass -class SchemaTestBlock(TestBlock[Testable], Generic[Testable]): +class GenericTestBlock(TestBlock[Testable], Generic[Testable]): test: Dict[str, Any] column_name: Optional[str] tags: List[str] @@ -165,7 +165,7 @@ def from_test_block( test: Dict[str, Any], column_name: Optional[str], tags: List[str], - ) -> 'SchemaTestBlock': + ) -> 'GenericTestBlock': return cls( file=src.file, data=src.data, @@ -404,7 +404,7 @@ def get_test_name(self) -> Tuple[str, str]: raise self._bad_type() if self.namespace is not None: name = '{}_{}'.format(self.namespace, name) - return get_nice_schema_test_name(name, self.target.name, self.args) + return get_nice_generic_test_name(name, self.target.name, self.args) def construct_config(self) -> str: configs = ",".join([ @@ -428,7 +428,7 @@ def build_raw_sql(self) -> str: ).format( macro=self.macro_name(), config=self.construct_config(), - kwargs_name=SCHEMA_TEST_KWARGS_NAME, + kwargs_name=GENERIC_TEST_KWARGS_NAME, ) def build_model_str(self): diff --git a/core/dbt/parser/manifest.py b/core/dbt/parser/manifest.py index d8f23ba4ce3..780ecac0b31 100644 --- a/core/dbt/parser/manifest.py +++ b/core/dbt/parser/manifest.py @@ -47,7 +47,7 @@ ) from dbt.parser.base import Parser from dbt.parser.analysis import AnalysisParser -from dbt.parser.data_test import DataTestParser +from dbt.parser.singular_test import SingularTestParser from dbt.parser.docs import DocumentationParser from dbt.parser.hooks import HookParser from dbt.parser.macros import MacroParser @@ -292,7 +292,7 @@ def load(self): # Load the rest of the files except for schema yaml files parser_types: List[Type[Parser]] = [ - ModelParser, SnapshotParser, AnalysisParser, DataTestParser, + ModelParser, SnapshotParser, AnalysisParser, SingularTestParser, SeedParser, DocumentationParser, HookParser] for project in self.all_projects.values(): if project.project_name not in project_parser_files: diff --git a/core/dbt/parser/read_files.py b/core/dbt/parser/read_files.py index 68ba1011eab..3d5c4d8746e 100644 --- a/core/dbt/parser/read_files.py +++ b/core/dbt/parser/read_files.py @@ -136,7 +136,7 @@ def read_files(project, files, parser_files, saved_files): project, files, project.analysis_paths, '.sql', ParseFileType.Analysis, saved_files ) - project_files['DataTestParser'] = read_files_for_parser( + project_files['SingularTestParser'] = read_files_for_parser( project, files, project.test_paths, '.sql', ParseFileType.Test, saved_files ) diff --git a/core/dbt/parser/schemas.py b/core/dbt/parser/schemas.py index 4f1ad038d28..d721524b72f 100644 --- a/core/dbt/parser/schemas.py +++ b/core/dbt/parser/schemas.py @@ -26,7 +26,7 @@ from dbt.contracts.graph.parsed import ( ParsedNodePatch, ColumnInfo, - ParsedSchemaTestNode, + ParsedGenericTestNode, ParsedMacroPatch, UnpatchedSourceDefinition, ParsedExposure, @@ -54,8 +54,8 @@ from dbt.node_types import NodeType from dbt.parser.base import SimpleParser from dbt.parser.search import FileBlock -from dbt.parser.schema_test_builders import ( - TestBuilder, SchemaTestBlock, TargetBlock, YamlBlock, +from dbt.parser.generic_test_builders import ( + TestBuilder, GenericTestBlock, TargetBlock, YamlBlock, TestBlock, Testable ) from dbt.utils import ( @@ -163,7 +163,7 @@ def _trimmed(inp: str) -> str: return inp[:44] + '...' + inp[-3:] -class SchemaParser(SimpleParser[SchemaTestBlock, ParsedSchemaTestNode]): +class SchemaParser(SimpleParser[GenericTestBlock, ParsedGenericTestNode]): def __init__( self, project, manifest, root_project, ) -> None: @@ -201,10 +201,10 @@ def get_compiled_path(cls, block: FileBlock) -> str: def resource_type(self) -> NodeType: return NodeType.Test - def parse_from_dict(self, dct, validate=True) -> ParsedSchemaTestNode: + def parse_from_dict(self, dct, validate=True) -> ParsedGenericTestNode: if validate: - ParsedSchemaTestNode.validate(dct) - return ParsedSchemaTestNode.from_dict(dct) + ParsedGenericTestNode.validate(dct) + return ParsedGenericTestNode.from_dict(dct) def parse_column_tests( self, block: TestBlock, column: UnparsedColumn @@ -226,7 +226,7 @@ def create_test_node( raw_sql: str, test_metadata: Dict[str, Any], column_name: Optional[str], - ) -> ParsedSchemaTestNode: + ) -> ParsedGenericTestNode: HASH_LENGTH = 10 @@ -267,8 +267,8 @@ def get_hashable_md( 'checksum': FileHash.empty().to_dict(omit_none=True), } try: - ParsedSchemaTestNode.validate(dct) - return ParsedSchemaTestNode.from_dict(dct) + ParsedGenericTestNode.validate(dct) + return ParsedGenericTestNode.from_dict(dct) except ValidationError as exc: msg = validator_error_message(exc) # this is a bit silly, but build an UnparsedNode just for error @@ -288,7 +288,7 @@ def _parse_generic_test( test: Dict[str, Any], tags: List[str], column_name: Optional[str], - ) -> ParsedSchemaTestNode: + ) -> ParsedGenericTestNode: try: builder = TestBuilder( test=test, @@ -307,10 +307,10 @@ def _parse_generic_test( raise CompilationException(msg) from exc original_name = os.path.basename(target.original_file_path) compiled_path = get_pseudo_test_path( - builder.compiled_name, original_name, 'schema_test', + builder.compiled_name, original_name, 'test', ) fqn_path = get_pseudo_test_path( - builder.fqn_name, original_name, 'schema_test', + builder.fqn_name, original_name, 'test', ) # the fqn for tests actually happens in the test target's name, which # is not necessarily this package's name @@ -387,7 +387,7 @@ def render_test_update(self, node, config, builder): msg = validator_error_message(exc) raise CompilationException(msg, node=node) from exc - def parse_node(self, block: SchemaTestBlock) -> ParsedSchemaTestNode: + def parse_node(self, block: GenericTestBlock) -> ParsedGenericTestNode: """In schema parsing, we rewrite most of the part of parse_node that builds the initial node to be parsed, but rendering is basically the same @@ -401,7 +401,7 @@ def parse_node(self, block: SchemaTestBlock) -> ParsedSchemaTestNode: self.add_test_node(block, node) return node - def add_test_node(self, block: SchemaTestBlock, node: ParsedSchemaTestNode): + def add_test_node(self, block: GenericTestBlock, node: ParsedGenericTestNode): test_from = {"key": block.target.yaml_key, "name": block.target.name} if node.config.enabled: self.manifest.add_node(block.file, node, test_from) @@ -409,7 +409,7 @@ def add_test_node(self, block: SchemaTestBlock, node: ParsedSchemaTestNode): self.manifest.add_disabled(block.file, node, test_from) def render_with_context( - self, node: ParsedSchemaTestNode, config: ContextConfig, + self, node: ParsedGenericTestNode, config: ContextConfig, ) -> None: """Given the parsed node and a ContextConfig to use during parsing, collect all the refs that might be squirreled away in the test @@ -447,7 +447,7 @@ def parse_test( column_name = get_adapter(self.root_project).quote(column_name) column_tags = column.tags - block = SchemaTestBlock.from_test_block( + block = GenericTestBlock.from_test_block( src=target_block, test=test, column_name=column_name, diff --git a/core/dbt/parser/data_test.py b/core/dbt/parser/singular_test.py similarity index 57% rename from core/dbt/parser/data_test.py rename to core/dbt/parser/singular_test.py index 3f572b8be0e..d39e5ac7b6b 100644 --- a/core/dbt/parser/data_test.py +++ b/core/dbt/parser/singular_test.py @@ -1,21 +1,22 @@ -from dbt.contracts.graph.parsed import ParsedDataTestNode +from dbt.contracts.graph.parsed import ParsedSingularTestNode from dbt.node_types import NodeType from dbt.parser.base import SimpleSQLParser from dbt.parser.search import FileBlock from dbt.utils import get_pseudo_test_path -class DataTestParser(SimpleSQLParser[ParsedDataTestNode]): - def parse_from_dict(self, dct, validate=True) -> ParsedDataTestNode: +class SingularTestParser(SimpleSQLParser[ParsedSingularTestNode]): + def parse_from_dict(self, dct, validate=True) -> ParsedSingularTestNode: if validate: - ParsedDataTestNode.validate(dct) - return ParsedDataTestNode.from_dict(dct) + ParsedSingularTestNode.validate(dct) + return ParsedSingularTestNode.from_dict(dct) @property def resource_type(self) -> NodeType: return NodeType.Test def transform(self, node): + # here for backwards compatibility only if 'data' not in node.tags: node.tags.append('data') return node @@ -23,4 +24,4 @@ def transform(self, node): @classmethod def get_compiled_path(cls, block: FileBlock): return get_pseudo_test_path(block.name, block.path.relative_path, - 'data_test') + 'test') diff --git a/core/dbt/parser/sources.py b/core/dbt/parser/sources.py index 028bf6ae119..20b34dadf7a 100644 --- a/core/dbt/parser/sources.py +++ b/core/dbt/parser/sources.py @@ -15,7 +15,7 @@ from dbt.contracts.graph.parsed import ( UnpatchedSourceDefinition, ParsedSourceDefinition, - ParsedSchemaTestNode, + ParsedGenericTestNode, ) from dbt.contracts.graph.unparsed import ( UnparsedSourceDefinition, @@ -211,7 +211,7 @@ def get_schema_parser_for(self, package_name: str) -> 'SchemaParser': def get_source_tests( self, target: UnpatchedSourceDefinition - ) -> Iterable[ParsedSchemaTestNode]: + ) -> Iterable[ParsedGenericTestNode]: for test, column in target.get_tests(): yield self.parse_source_test( target=target, @@ -242,7 +242,7 @@ def parse_source_test( target: UnpatchedSourceDefinition, test: Dict[str, Any], column: Optional[UnparsedColumn], - ) -> ParsedSchemaTestNode: + ) -> ParsedGenericTestNode: column_name: Optional[str] if column is None: column_name = None diff --git a/core/dbt/task/test.py b/core/dbt/task/test.py index 28c29f343c9..58f1572bcd2 100644 --- a/core/dbt/task/test.py +++ b/core/dbt/task/test.py @@ -9,8 +9,8 @@ from .printer import print_start_line, print_test_result_line from dbt.contracts.graph.compiled import ( - CompiledDataTestNode, - CompiledSchemaTestNode, + CompiledSingularTestNode, + CompiledGenericTestNode, CompiledTestNode, ) from dbt.contracts.graph.manifest import Manifest @@ -54,7 +54,7 @@ def before_execute(self): def execute_test( self, - test: Union[CompiledDataTestNode, CompiledSchemaTestNode], + test: Union[CompiledSingularTestNode, CompiledGenericTestNode], manifest: Manifest ) -> TestResultData: context = generate_runtime_model( @@ -175,6 +175,8 @@ def safe_run_hooks( def get_selection_spec(self) -> SelectionSpec: base_spec = super().get_selection_spec() + # serves to handle --schema and --data flags + # only supported for backwards compatibility return parse_test_selectors( data=self.args.data, schema=self.args.schema, diff --git a/test/integration/007_graph_selection_tests/test_graph_selection.py b/test/integration/007_graph_selection_tests/test_graph_selection.py index 9cc771554ab..361aca694db 100644 --- a/test/integration/007_graph_selection_tests/test_graph_selection.py +++ b/test/integration/007_graph_selection_tests/test_graph_selection.py @@ -408,8 +408,8 @@ def test__postgres__exposure_parents(self): results = self.run_dbt(['ls', '--select', '1+exposure:user_exposure']) assert len(results) == 5 - assert sorted(results) == ['exposure:test.user_exposure', 'test.schema_test.unique_users_id', - 'test.schema_test.unique_users_rollup_gender', 'test.users', 'test.users_rollup'] + assert sorted(results) == ['exposure:test.user_exposure', 'test.test.unique_users_id', + 'test.test.unique_users_rollup_gender', 'test.users', 'test.users_rollup'] results = self.run_dbt(['run', '-m', '+exposure:user_exposure']) # users, users_rollup diff --git a/test/integration/008_schema_tests_test/models-v2/custom-configs/schema.yml b/test/integration/008_schema_tests_test/models-v2/custom-configs/schema.yml index 016a47ce45b..03f6514caa1 100644 --- a/test/integration/008_schema_tests_test/models-v2/custom-configs/schema.yml +++ b/test/integration/008_schema_tests_test/models-v2/custom-configs/schema.yml @@ -10,8 +10,6 @@ models: - warn_if - limit - fail_calc - - where: # test override + weird quoting - where: "\"favorite_color\" = 'red'" columns: - name: id tests: @@ -20,6 +18,11 @@ models: to: ref('table_copy') # itself field: id where: 1=1 + - name: table_copy_another_one + tests: + - where: # test override + weird quoting + config: + where: "\"favorite_color\" = 'red'" - name: "table.copy.with.dots" description: "A copy of the table with a gross name" # passes, see https://github.com/dbt-labs/dbt/issues/3857 diff --git a/test/integration/008_schema_tests_test/models-v2/custom-configs/table.copy.with.dots.sql b/test/integration/008_schema_tests_test/models-v2/custom-configs/table.copy.with.dots.sql index 3ab64fa0c7d..88ed00f1599 100644 --- a/test/integration/008_schema_tests_test/models-v2/custom-configs/table.copy.with.dots.sql +++ b/test/integration/008_schema_tests_test/models-v2/custom-configs/table.copy.with.dots.sql @@ -1,9 +1 @@ - -{{ - config( - materialized='table', - alias='table_copy_with_dots' - ) -}} - -select * from {{ this.schema }}.seed +select * from {{ ref('table_copy') }} diff --git a/test/integration/008_schema_tests_test/models-v2/custom-configs/table_copy_another_one.sql b/test/integration/008_schema_tests_test/models-v2/custom-configs/table_copy_another_one.sql new file mode 100644 index 00000000000..88ed00f1599 --- /dev/null +++ b/test/integration/008_schema_tests_test/models-v2/custom-configs/table_copy_another_one.sql @@ -0,0 +1 @@ +select * from {{ ref('table_copy') }} diff --git a/test/integration/008_schema_tests_test/test_schema_v2_tests.py b/test/integration/008_schema_tests_test/test_schema_v2_tests.py index e6bfc882e97..20c22367211 100644 --- a/test/integration/008_schema_tests_test/test_schema_v2_tests.py +++ b/test/integration/008_schema_tests_test/test_schema_v2_tests.py @@ -148,7 +148,7 @@ def test_postgres_config(self): this project will fail, configs are set to make test pass. """ results = self.run_dbt(['test'], expect_pass=False) - self.assertEqual(len(results), 7) + self.assertEqual(len(results), 8) for result in results: self.assertFalse(result.skipped) diff --git a/test/integration/029_docs_generate_tests/test_docs_generate.py b/test/integration/029_docs_generate_tests/test_docs_generate.py index 513adbf5c4f..aa9c7fb05cf 100644 --- a/test/integration/029_docs_generate_tests/test_docs_generate.py +++ b/test/integration/029_docs_generate_tests/test_docs_generate.py @@ -1335,7 +1335,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'test.test.not_null_model_id.d01cc630e6': { 'alias': 'not_null_model_id', - 'compiled_path': Normalized('target/compiled/test/models/schema.yml/schema_test/not_null_model_id.sql'), + 'compiled_path': Normalized('target/compiled/test/models/schema.yml/test/not_null_model_id.sql'), 'build_path': None, 'created_at': ANY, 'column_name': 'id', @@ -1348,13 +1348,13 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'deferred': False, 'description': '', - 'fqn': ['test', 'schema_test', 'not_null_model_id'], + 'fqn': ['test', 'test', 'not_null_model_id'], 'name': 'not_null_model_id', 'original_file_path': model_schema_yml_path, 'package_name': 'test', 'patch_path': None, - 'path': Normalized('schema_test/not_null_model_id.sql'), - 'raw_sql': "{{ test_not_null(**_dbt_schema_test_kwargs) }}", + 'path': Normalized('test/not_null_model_id.sql'), + 'raw_sql': "{{ test_not_null(**_dbt_generic_test_kwargs) }}", 'refs': [['model']], 'relation_name': None, 'resource_type': 'test', @@ -1426,7 +1426,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'test.test.test_nothing_model_.5d38568946': { 'alias': 'test_nothing_model_', - 'compiled_path': Normalized('target/compiled/test/models/schema.yml/schema_test/test_nothing_model_.sql'), + 'compiled_path': Normalized('target/compiled/test/models/schema.yml/test/test_nothing_model_.sql'), 'build_path': None, 'created_at': ANY, 'column_name': None, @@ -1439,13 +1439,13 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'deferred': False, 'description': '', - 'fqn': ['test', 'schema_test', 'test_nothing_model_'], + 'fqn': ['test', 'test', 'test_nothing_model_'], 'name': 'test_nothing_model_', 'original_file_path': model_schema_yml_path, 'package_name': 'test', 'patch_path': None, - 'path': normalize('schema_test/test_nothing_model_.sql'), - 'raw_sql': "{{ test.test_nothing(**_dbt_schema_test_kwargs) }}", + 'path': normalize('test/test_nothing_model_.sql'), + 'raw_sql': "{{ test.test_nothing(**_dbt_generic_test_kwargs) }}", 'refs': [['model']], 'relation_name': None, 'resource_type': 'test', @@ -1472,7 +1472,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'test.test.unique_model_id.67b76558ff': { 'alias': 'unique_model_id', - 'compiled_path': Normalized('target/compiled/test/models/schema.yml/schema_test/unique_model_id.sql'), + 'compiled_path': Normalized('target/compiled/test/models/schema.yml/test/unique_model_id.sql'), 'build_path': None, 'created_at': ANY, 'column_name': 'id', @@ -1485,13 +1485,13 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'deferred': False, 'description': '', - 'fqn': ['test', 'schema_test', 'unique_model_id'], + 'fqn': ['test', 'test', 'unique_model_id'], 'name': 'unique_model_id', 'original_file_path': model_schema_yml_path, 'package_name': 'test', 'patch_path': None, - 'path': normalize('schema_test/unique_model_id.sql'), - 'raw_sql': "{{ test_unique(**_dbt_schema_test_kwargs) }}", + 'path': normalize('test/unique_model_id.sql'), + 'raw_sql': "{{ test_unique(**_dbt_generic_test_kwargs) }}", 'refs': [['model']], 'relation_name': None, 'resource_type': 'test', diff --git a/test/integration/047_dbt_ls_test/test_ls.py b/test/integration/047_dbt_ls_test/test_ls.py index 90345e1e7ec..274e745a292 100644 --- a/test/integration/047_dbt_ls_test/test_ls.py +++ b/test/integration/047_dbt_ls_test/test_ls.py @@ -350,7 +350,7 @@ def expect_seed_output(self): def expect_test_output(self): expectations = { 'name': ('not_null_outer_id', 't', 'unique_outer_id'), - 'selector': ('test.schema_test.not_null_outer_id', 'test.data_test.t', 'test.schema_test.unique_outer_id'), + 'selector': ('test.test.not_null_outer_id', 'test.test.t', 'test.test.unique_outer_id'), 'json': ( { 'name': 'not_null_outer_id', @@ -447,9 +447,9 @@ def expect_all_output(self): 'test.outer', 'test.seed', 'source:test.my_source.my_table', - 'test.schema_test.not_null_outer_id', - 'test.schema_test.unique_outer_id', - 'test.data_test.t', + 'test.test.not_null_outer_id', + 'test.test.unique_outer_id', + 'test.test.t', } # analyses have their type inserted into their fqn like tests expected_all = expected_default | {'test.analysis.a'} @@ -467,12 +467,12 @@ def expect_all_output(self): def expect_select(self): results = self.run_dbt_ls(['--resource-type', 'test', '--select', 'outer']) - self.assertEqual(set(results), {'test.schema_test.not_null_outer_id', 'test.schema_test.unique_outer_id'}) + self.assertEqual(set(results), {'test.test.not_null_outer_id', 'test.test.unique_outer_id'}) self.run_dbt_ls(['--resource-type', 'test', '--select', 'inner'], expect_pass=True) results = self.run_dbt_ls(['--resource-type', 'test', '--select', '+inner']) - self.assertEqual(set(results), {'test.schema_test.not_null_outer_id', 'test.schema_test.unique_outer_id'}) + self.assertEqual(set(results), {'test.test.not_null_outer_id', 'test.test.unique_outer_id'}) results = self.run_dbt_ls(['--resource-type', 'model', '--select', 'outer+']) self.assertEqual(set(results), {'test.outer', 'test.sub.inner'}) diff --git a/test/integration/062_defer_state_test/test_modified_state.py b/test/integration/062_defer_state_test/test_modified_state.py index e83d33e649f..1a3b83a214d 100644 --- a/test/integration/062_defer_state_test/test_modified_state.py +++ b/test/integration/062_defer_state_test/test_modified_state.py @@ -72,7 +72,7 @@ def test_postgres_changed_seed_contents_state(self): results = self.run_dbt(['ls', '--select', 'state:modified+', '--state', './state']) assert len(results) == 7 - assert set(results) == {'test.seed', 'test.table_model', 'test.view_model', 'test.ephemeral_model', 'test.schema_test.not_null_view_model_id', 'test.schema_test.unique_view_model_id', 'exposure:test.my_exposure'} + assert set(results) == {'test.seed', 'test.table_model', 'test.view_model', 'test.ephemeral_model', 'test.test.not_null_view_model_id', 'test.test.unique_view_model_id', 'exposure:test.my_exposure'} shutil.rmtree('./state') self.copy_state() diff --git a/test/unit/test_contracts_graph_compiled.py b/test/unit/test_contracts_graph_compiled.py index 7974d37226e..cc970997901 100644 --- a/test/unit/test_contracts_graph_compiled.py +++ b/test/unit/test_contracts_graph_compiled.py @@ -3,7 +3,7 @@ from dbt.contracts.files import FileHash from dbt.contracts.graph.compiled import ( - CompiledModelNode, InjectedCTE, CompiledSchemaTestNode + CompiledModelNode, InjectedCTE, CompiledGenericTestNode ) from dbt.contracts.graph.parsed import ( DependsOn, NodeConfig, TestConfig, TestMetadata, ColumnInfo @@ -335,7 +335,7 @@ def minimal_schema_test_dict(): @pytest.fixture def basic_uncompiled_schema_test_node(): - return CompiledSchemaTestNode( + return CompiledGenericTestNode( package_name='test', root_path='/root/', path='/root/x/path.sql', @@ -367,7 +367,7 @@ def basic_uncompiled_schema_test_node(): @pytest.fixture def basic_compiled_schema_test_node(): - return CompiledSchemaTestNode( + return CompiledGenericTestNode( package_name='test', root_path='/root/', path='/root/x/path.sql', @@ -506,19 +506,19 @@ def test_basic_uncompiled_schema_test(basic_uncompiled_schema_test_node, basic_u node_dict = basic_uncompiled_schema_test_dict minimum = minimal_schema_test_dict - assert_symmetric(node, node_dict, CompiledSchemaTestNode) + assert_symmetric(node, node_dict, CompiledGenericTestNode) assert node.empty is False assert node.is_refable is False assert node.is_ephemeral is False - assert_from_dict(node, minimum, CompiledSchemaTestNode) + assert_from_dict(node, minimum, CompiledGenericTestNode) def test_basic_compiled_schema_test(basic_compiled_schema_test_node, basic_compiled_schema_test_dict): node = basic_compiled_schema_test_node node_dict = basic_compiled_schema_test_dict - assert_symmetric(node, node_dict, CompiledSchemaTestNode) + assert_symmetric(node, node_dict, CompiledGenericTestNode) assert node.empty is False assert node.is_refable is False assert node.is_ephemeral is False @@ -527,13 +527,13 @@ def test_basic_compiled_schema_test(basic_compiled_schema_test_node, basic_compi def test_invalid_extra_schema_test_fields(minimal_schema_test_dict): bad_extra = minimal_schema_test_dict bad_extra['extra'] = 'extra value' - assert_fails_validation(bad_extra, CompiledSchemaTestNode) + assert_fails_validation(bad_extra, CompiledGenericTestNode) def test_invalid_resource_type_schema_test(minimal_schema_test_dict): bad_type = minimal_schema_test_dict bad_type['resource_type'] = str(NodeType.Model) - assert_fails_validation(bad_type, CompiledSchemaTestNode) + assert_fails_validation(bad_type, CompiledGenericTestNode) unchanged_schema_tests = [ diff --git a/test/unit/test_contracts_graph_parsed.py b/test/unit/test_contracts_graph_parsed.py index a1095fb5fe0..65a4aa23586 100644 --- a/test/unit/test_contracts_graph_parsed.py +++ b/test/unit/test_contracts_graph_parsed.py @@ -16,7 +16,7 @@ ParsedModelNode, DependsOn, ColumnInfo, - ParsedSchemaTestNode, + ParsedGenericTestNode, ParsedSnapshotNode, IntermediateSnapshotNode, ParsedNodePatch, @@ -1000,7 +1000,7 @@ def basic_parsed_schema_test_dict(): @pytest.fixture def basic_parsed_schema_test_object(): - return ParsedSchemaTestNode( + return ParsedGenericTestNode( package_name='test', root_path='/root/', path='/root/x/path.sql', @@ -1089,7 +1089,7 @@ def complex_parsed_schema_test_object(): severity='WARN' ) cfg._extra.update({'extra_key': 'extra value'}) - return ParsedSchemaTestNode( + return ParsedGenericTestNode( package_name='test', root_path='/root/', path='/root/x/path.sql', @@ -1125,20 +1125,20 @@ def test_basic_schema_test_node(minimal_parsed_schema_test_dict, basic_parsed_sc node = basic_parsed_schema_test_object node_dict = basic_parsed_schema_test_dict minimum = minimal_parsed_schema_test_dict - assert_symmetric(node, node_dict, ParsedSchemaTestNode) + assert_symmetric(node, node_dict, ParsedGenericTestNode) assert node.empty is False assert node.is_ephemeral is False assert node.is_refable is False assert node.get_materialization() == 'test' - assert_from_dict(node, minimum, ParsedSchemaTestNode) + assert_from_dict(node, minimum, ParsedGenericTestNode) pickle.loads(pickle.dumps(node)) def test_complex_schema_test_node(complex_parsed_schema_test_dict, complex_parsed_schema_test_object): # this tests for the presence of _extra keys - node = complex_parsed_schema_test_object # ParsedSchemaTestNode + node = complex_parsed_schema_test_object # ParsedGenericTestNode assert(node.config._extra['extra_key']) node_dict = complex_parsed_schema_test_dict assert_symmetric(node, node_dict) @@ -1149,13 +1149,13 @@ def test_invalid_column_name_type(complex_parsed_schema_test_dict): # bad top-level field bad_column_name = complex_parsed_schema_test_dict bad_column_name['column_name'] = {} - assert_fails_validation(bad_column_name, ParsedSchemaTestNode) + assert_fails_validation(bad_column_name, ParsedGenericTestNode) def test_invalid_severity(complex_parsed_schema_test_dict): invalid_config_value = complex_parsed_schema_test_dict invalid_config_value['config']['severity'] = 'WERROR' - assert_fails_validation(invalid_config_value, ParsedSchemaTestNode) + assert_fails_validation(invalid_config_value, ParsedGenericTestNode) @pytest.fixture diff --git a/test/unit/test_graph_selector_methods.py b/test/unit/test_graph_selector_methods.py index c7c6426e877..6fe9a46f880 100644 --- a/test/unit/test_graph_selector_methods.py +++ b/test/unit/test_graph_selector_methods.py @@ -13,8 +13,8 @@ ParsedModelNode, ParsedExposure, ParsedSeedNode, - ParsedDataTestNode, - ParsedSchemaTestNode, + ParsedSingularTestNode, + ParsedGenericTestNode, ParsedSourceDefinition, TestConfig, TestMetadata, @@ -240,7 +240,7 @@ def make_schema_test(pkg, test_name, test_model, test_kwargs, path=None, refs=No source_values.append([source.source_name, source.name]) depends_on_nodes.append(source.unique_id) - return ParsedSchemaTestNode( + return ParsedGenericTestNode( raw_sql=raw_sql, test_metadata=TestMetadata( namespace=namespace, @@ -296,7 +296,7 @@ def make_data_test(pkg, name, sql, refs=None, sources=None, tags=None, path=None source_values.append([src.source_name, src.name]) depends_on_nodes.append(src.unique_id) - return ParsedDataTestNode( + return ParsedSingularTestNode( raw_sql=sql, database='dbt', schema='dbt_schema', @@ -712,6 +712,11 @@ def test_select_test_type(manifest): method = methods.get_method('test_type', []) assert isinstance(method, TestTypeSelectorMethod) assert method.arguments == [] + assert search_manifest_using_method(manifest, method, 'generic') == { + 'unique_table_model_id', 'not_null_table_model_id', 'unique_view_model_id', 'unique_ext_raw_ext_source_id'} + assert search_manifest_using_method(manifest, method, 'singular') == { + 'view_test_nothing'} + # test backwards compatibility assert search_manifest_using_method(manifest, method, 'schema') == { 'unique_table_model_id', 'not_null_table_model_id', 'unique_view_model_id', 'unique_ext_raw_ext_source_id'} assert search_manifest_using_method(manifest, method, 'data') == { diff --git a/test/unit/test_parser.py b/test/unit/test_parser.py index 2b8f6d9f35b..065a25f75ab 100644 --- a/test/unit/test_parser.py +++ b/test/unit/test_parser.py @@ -10,14 +10,14 @@ from dbt import tracking from dbt.exceptions import CompilationException from dbt.parser import ( - ModelParser, MacroParser, DataTestParser, SchemaParser, + ModelParser, MacroParser, SingularTestParser, SchemaParser, SnapshotParser, AnalysisParser ) from dbt.parser.schemas import ( TestablePatchParser, SourceParser, AnalysisPatchParser, MacroPatchParser ) from dbt.parser.search import FileBlock -from dbt.parser.schema_test_builders import YamlBlock +from dbt.parser.generic_test_builders import YamlBlock from dbt.parser.sources import SourcePatcher from dbt.node_types import NodeType @@ -28,7 +28,7 @@ ) from dbt.contracts.graph.parsed import ( ParsedModelNode, ParsedMacro, ParsedNodePatch, DependsOn, ColumnInfo, - ParsedDataTestNode, ParsedSnapshotNode, ParsedAnalysisNode, + ParsedSingularTestNode, ParsedSnapshotNode, ParsedAnalysisNode, UnpatchedSourceDefinition ) from dbt.contracts.graph.unparsed import Docs @@ -330,12 +330,12 @@ def test__parse_basic_source_tests(self): self.assertEqual(tests[0].tags, ['schema']) self.assertEqual(tests[0].sources, [['my_source', 'my_table']]) self.assertEqual(tests[0].column_name, 'color') - self.assertEqual(tests[0].fqn, ['snowplow', 'schema_test', tests[0].name]) + self.assertEqual(tests[0].fqn, ['snowplow', 'test', tests[0].name]) self.assertEqual(tests[1].config.severity, 'WARN') self.assertEqual(tests[1].tags, ['schema']) self.assertEqual(tests[1].sources, [['my_source', 'my_table']]) self.assertEqual(tests[1].column_name, 'color') - self.assertEqual(tests[1].fqn, ['snowplow', 'schema_test', tests[1].name]) + self.assertEqual(tests[1].fqn, ['snowplow', 'test', tests[1].name]) file_id = 'snowplow://' + normalize('models/test_one.yml') self.assertIn(file_id, self.parser.manifest.files) @@ -414,7 +414,7 @@ def test__parse_basic_model_tests(self): self.assertEqual(tests[0].column_name, 'color') self.assertEqual(tests[0].package_name, 'snowplow') self.assertTrue(tests[0].name.startswith('accepted_values_')) - self.assertEqual(tests[0].fqn, ['snowplow', 'schema_test', tests[0].name]) + self.assertEqual(tests[0].fqn, ['snowplow', 'test', tests[0].name]) self.assertEqual(tests[0].unique_id.split('.'), ['test', 'snowplow', tests[0].name, '9d4814efde']) self.assertEqual(tests[0].test_metadata.name, 'accepted_values') self.assertIsNone(tests[0].test_metadata.namespace) @@ -434,7 +434,7 @@ def test__parse_basic_model_tests(self): self.assertEqual(tests[1].refs, [['my_model']]) self.assertEqual(tests[1].column_name, 'color') self.assertEqual(tests[1].column_name, 'color') - self.assertEqual(tests[1].fqn, ['snowplow', 'schema_test', tests[1].name]) + self.assertEqual(tests[1].fqn, ['snowplow', 'test', tests[1].name]) self.assertTrue(tests[1].name.startswith('foreign_package_test_case_')) self.assertEqual(tests[1].package_name, 'snowplow') self.assertEqual(tests[1].unique_id.split('.'), ['test', 'snowplow', tests[1].name, '13958f62f7']) @@ -455,7 +455,7 @@ def test__parse_basic_model_tests(self): self.assertEqual(tests[2].column_name, 'color') self.assertEqual(tests[2].package_name, 'snowplow') self.assertTrue(tests[2].name.startswith('not_null_')) - self.assertEqual(tests[2].fqn, ['snowplow', 'schema_test', tests[2].name]) + self.assertEqual(tests[2].fqn, ['snowplow', 'test', tests[2].name]) self.assertEqual(tests[2].unique_id.split('.'), ['test', 'snowplow', tests[2].name, '2f61818750']) self.assertEqual(tests[2].test_metadata.name, 'not_null') self.assertIsNone(tests[2].test_metadata.namespace) @@ -805,10 +805,10 @@ def test_multiple_blocks(self): ) -class DataTestParserTest(BaseParserTest): +class SingularTestParserTest(BaseParserTest): def setUp(self): super().setUp() - self.parser = DataTestParser( + self.parser = SingularTestParser( project=self.snowplow_project_config, manifest=self.manifest, root_project=self.root_project_config, @@ -824,21 +824,21 @@ def test_basic(self): self.parser.parse_file(block) self.assert_has_manifest_lengths(self.parser.manifest, nodes=1) node = list(self.parser.manifest.nodes.values())[0] - expected = ParsedDataTestNode( + expected = ParsedSingularTestNode( alias='test_1', name='test_1', database='test', schema='dbt_test__audit', resource_type=NodeType.Test, unique_id='test.snowplow.test_1', - fqn=['snowplow', 'data_test', 'test_1'], + fqn=['snowplow', 'test', 'test_1'], package_name='snowplow', original_file_path=normalize('tests/test_1.sql'), root_path=get_abs_os_path('./dbt_modules/snowplow'), refs=[['blah']], config=TestConfig(severity='ERROR'), tags=['data'], - path=normalize('data_test/test_1.sql'), + path=normalize('test/test_1.sql'), raw_sql=raw_sql, checksum=block.file.checksum, unrendered_config={}, From b75ce76b10acc5bcd24a5881f1884a8fd712a280 Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Tue, 14 Sep 2021 09:33:07 +0200 Subject: [PATCH 3/5] Rm schema, data flag + tag behavior --- core/dbt/graph/__init__.py | 1 - core/dbt/graph/cli.py | 37 ----------- core/dbt/main.py | 16 ----- core/dbt/parser/schemas.py | 2 - core/dbt/parser/singular_test.py | 6 -- core/dbt/task/test.py | 12 ---- .../test_snapshot_check_cols.py | 2 +- .../009_data_tests_test/test_data_tests.py | 1 - .../test_docs_generate.py | 6 +- .../045_test_severity_tests/test_severity.py | 12 ++-- test/integration/047_dbt_ls_test/test_ls.py | 6 +- .../test_selection_expansion.py | 66 ++++++++----------- .../test_incremental_schema.py | 6 +- test/integration/base.py | 2 - test/unit/test_parser.py | 12 ++-- 15 files changed, 48 insertions(+), 139 deletions(-) diff --git a/core/dbt/graph/__init__.py b/core/dbt/graph/__init__.py index f815af4828b..67d979cc0fb 100644 --- a/core/dbt/graph/__init__.py +++ b/core/dbt/graph/__init__.py @@ -11,7 +11,6 @@ ) from .cli import ( # noqa: F401 parse_difference, - parse_test_selectors, parse_from_selectors_definition, ) from .queue import GraphQueue # noqa: F401 diff --git a/core/dbt/graph/cli.py b/core/dbt/graph/cli.py index 1fcd324616c..1e89fbb94f7 100644 --- a/core/dbt/graph/cli.py +++ b/core/dbt/graph/cli.py @@ -23,11 +23,6 @@ DEFAULT_INCLUDES: List[str] = ['fqn:*', 'source:*', 'exposure:*'] DEFAULT_EXCLUDES: List[str] = [] -# here for backwards compatibility -# we have since renamed data --> singular, schema --> generic -DATA_TEST_SELECTOR: str = 'test_type:data' -SCHEMA_TEST_SELECTOR: str = 'test_type:schema' - def parse_union( components: List[str], expect_exists: bool, greedy: bool = False @@ -74,38 +69,6 @@ def parse_difference( excluded = parse_union_from_default(exclude, DEFAULT_EXCLUDES, greedy=True) return SelectionDifference(components=[included, excluded]) -# serves to handle --schema and --data flags -# only supported for backwards compatibility -def parse_test_selectors( - data: bool, schema: bool, base: SelectionSpec -) -> SelectionSpec: - union_components = [] - - if data: - union_components.append( - SelectionCriteria.from_single_spec(DATA_TEST_SELECTOR) - ) - if schema: - union_components.append( - SelectionCriteria.from_single_spec(SCHEMA_TEST_SELECTOR) - ) - - intersect_with: SelectionSpec - if not union_components: - return base - elif len(union_components) == 1: - intersect_with = union_components[0] - else: # data and schema tests - intersect_with = SelectionUnion( - components=union_components, - expect_exists=True, - raw=[DATA_TEST_SELECTOR, SCHEMA_TEST_SELECTOR], - ) - - return SelectionIntersection( - components=[base, intersect_with], expect_exists=True - ) - RawDefinition = Union[str, Dict[str, Any]] diff --git a/core/dbt/main.py b/core/dbt/main.py index a2129578ca7..b78fb3b3a89 100644 --- a/core/dbt/main.py +++ b/core/dbt/main.py @@ -723,22 +723,6 @@ def _build_test_subparser(subparsers, base_subparser): Runs tests on data in deployed models. Run this after `dbt run` ''' ) - sub.add_argument( - # here for backwards compatibility - '--data', - action='store_true', - help=''' - Run data tests defined in "tests" directory. - ''' - ) - sub.add_argument( - # here for backwards compatibility - '--schema', - action='store_true', - help=''' - Run constraint validations from schema.yml files - ''' - ) sub.add_argument( '-x', '--fail-fast', diff --git a/core/dbt/parser/schemas.py b/core/dbt/parser/schemas.py index d721524b72f..9da1a576c44 100644 --- a/core/dbt/parser/schemas.py +++ b/core/dbt/parser/schemas.py @@ -325,8 +325,6 @@ def _parse_generic_test( 'kwargs': builder.args, } tags = sorted(set(itertools.chain(tags, builder.tags()))) - if 'schema' not in tags: - tags.append('schema') node = self.create_test_node( target=target, diff --git a/core/dbt/parser/singular_test.py b/core/dbt/parser/singular_test.py index d39e5ac7b6b..ab909524da7 100644 --- a/core/dbt/parser/singular_test.py +++ b/core/dbt/parser/singular_test.py @@ -15,12 +15,6 @@ def parse_from_dict(self, dct, validate=True) -> ParsedSingularTestNode: def resource_type(self) -> NodeType: return NodeType.Test - def transform(self, node): - # here for backwards compatibility only - if 'data' not in node.tags: - node.tags.append('data') - return node - @classmethod def get_compiled_path(cls, block: FileBlock): return get_pseudo_test_path(block.name, block.path.relative_path, diff --git a/core/dbt/task/test.py b/core/dbt/task/test.py index 58f1572bcd2..1cc61e991a3 100644 --- a/core/dbt/task/test.py +++ b/core/dbt/task/test.py @@ -23,8 +23,6 @@ ) from dbt.graph import ( ResourceTypeSelector, - SelectionSpec, - parse_test_selectors, ) from dbt.node_types import NodeType, RunHookType from dbt import flags @@ -173,16 +171,6 @@ def safe_run_hooks( # Don't execute on-run-* hooks for tests pass - def get_selection_spec(self) -> SelectionSpec: - base_spec = super().get_selection_spec() - # serves to handle --schema and --data flags - # only supported for backwards compatibility - return parse_test_selectors( - data=self.args.data, - schema=self.args.schema, - base=base_spec - ) - def get_node_selector(self) -> TestSelector: if self.manifest is None or self.graph is None: raise InternalException( diff --git a/test/integration/004_simple_snapshot_test/test_snapshot_check_cols.py b/test/integration/004_simple_snapshot_test/test_snapshot_check_cols.py index fc07ae0df96..3b49a119eb3 100644 --- a/test/integration/004_simple_snapshot_test/test_snapshot_check_cols.py +++ b/test/integration/004_simple_snapshot_test/test_snapshot_check_cols.py @@ -33,7 +33,7 @@ def test_snapshot_check_cols_cycle(self): self.assertEqual(len(results), 1) def assert_expected(self): - self.run_dbt(['test', '--data', '--vars', 'version: 3']) + self.run_dbt(['test', '--select', 'test_type:singular', '--vars', 'version: 3']) @use_profile('snowflake') def test__snowflake__simple_snapshot(self): diff --git a/test/integration/009_data_tests_test/test_data_tests.py b/test/integration/009_data_tests_test/test_data_tests.py index b2c2747e924..e09fde55d6b 100644 --- a/test/integration/009_data_tests_test/test_data_tests.py +++ b/test/integration/009_data_tests_test/test_data_tests.py @@ -25,7 +25,6 @@ def models(self): def run_data_validations(self): args = FakeArgs() - args.data = True test_task = TestTask(args, self.config) return test_task.run() diff --git a/test/integration/029_docs_generate_tests/test_docs_generate.py b/test/integration/029_docs_generate_tests/test_docs_generate.py index aa9c7fb05cf..35ebf83dadb 100644 --- a/test/integration/029_docs_generate_tests/test_docs_generate.py +++ b/test/integration/029_docs_generate_tests/test_docs_generate.py @@ -1361,7 +1361,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): 'root_path': self.test_root_realpath, 'schema': test_audit_schema, 'database': self.default_database, - 'tags': ['schema'], + 'tags': [], 'meta': {}, 'unique_id': 'test.test.not_null_model_id.d01cc630e6', 'docs': {'show': True}, @@ -1452,7 +1452,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): 'root_path': self.test_root_realpath, 'schema': test_audit_schema, 'database': self.default_database, - 'tags': ['schema'], + 'tags': [], 'meta': {}, 'unique_id': 'test.test.test_nothing_model_.5d38568946', 'docs': {'show': True}, @@ -1498,7 +1498,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): 'root_path': self.test_root_realpath, 'schema': test_audit_schema, 'database': self.default_database, - 'tags': ['schema'], + 'tags': [], 'meta': {}, 'unique_id': 'test.test.unique_model_id.67b76558ff', 'docs': {'show': True}, diff --git a/test/integration/045_test_severity_tests/test_severity.py b/test/integration/045_test_severity_tests/test_severity.py index b741349fbf5..aa31e01b118 100644 --- a/test/integration/045_test_severity_tests/test_severity.py +++ b/test/integration/045_test_severity_tests/test_severity.py @@ -31,7 +31,7 @@ def test_postgres_severity_warnings(self): self.run_dbt_with_vars(['seed'], 'false') self.run_dbt_with_vars(['run'], 'false') results = self.run_dbt_with_vars( - ['test', '--schema'], 'false') + ['test', '--select', 'test_type:generic'], 'false') self.assertEqual(len(results), 2) self.assertEqual(results[0].status, 'warn') self.assertEqual(results[0].failures, 2) @@ -43,7 +43,7 @@ def test_postgres_severity_rendered_errors(self): self.run_dbt_with_vars(['seed'], 'false') self.run_dbt_with_vars(['run'], 'false') results = self.run_dbt_with_vars( - ['test', '--schema'], 'true', expect_pass=False) + ['test', '--select', 'test_type:generic'], 'true', expect_pass=False) self.assertEqual(len(results), 2) self.assertEqual(results[0].status, 'fail') self.assertEqual(results[0].failures, 2) @@ -55,7 +55,7 @@ def test_postgres_severity_warnings_strict(self): self.run_dbt_with_vars(['seed'], 'false') self.run_dbt_with_vars(['run'], 'false') results = self.run_dbt_with_vars( - ['test', '--schema'], 'false', expect_pass=True) + ['test', '--select', 'test_type:generic'], 'false', expect_pass=True) self.assertEqual(len(results), 2) self.assertEqual(results[0].status, 'warn') self.assertEqual(results[0].failures, 2) @@ -67,7 +67,7 @@ def test_postgres_data_severity_warnings(self): self.run_dbt_with_vars(['seed'], 'false') self.run_dbt_with_vars(['run'], 'false') results = self.run_dbt_with_vars( - ['test', '--data'], 'false') + ['test', '--select', 'test_type:singular'], 'false') self.assertEqual(len(results), 1) self.assertEqual(results[0].status, 'warn') self.assertEqual(results[0].failures, 2) @@ -77,7 +77,7 @@ def test_postgres_data_severity_rendered_errors(self): self.run_dbt_with_vars(['seed'], 'false') self.run_dbt_with_vars(['run'], 'false') results = self.run_dbt_with_vars( - ['test', '--data'], 'true', expect_pass=False) + ['test', '--select', 'test_type:singular'], 'true', expect_pass=False) self.assertEqual(len(results), 1) self.assertEqual(results[0].status, 'fail') self.assertEqual(results[0].failures, 2) @@ -87,7 +87,7 @@ def test_postgres_data_severity_warnings_strict(self): self.run_dbt_with_vars(['seed'], 'false') self.run_dbt_with_vars(['run'], 'false') results = self.run_dbt_with_vars( - ['test', '--data'], 'false', expect_pass=True) + ['test', '--select', 'test_type:singular'], 'false', expect_pass=True) self.assertEqual(len(results), 1) self.assertTrue(results[0].status, 'fail') self.assertEqual(results[0].failures, 2) diff --git a/test/integration/047_dbt_ls_test/test_ls.py b/test/integration/047_dbt_ls_test/test_ls.py index 274e745a292..b424d383a8a 100644 --- a/test/integration/047_dbt_ls_test/test_ls.py +++ b/test/integration/047_dbt_ls_test/test_ls.py @@ -356,7 +356,7 @@ def expect_test_output(self): 'name': 'not_null_outer_id', 'package_name': 'test', 'depends_on': {'nodes': ['model.test.outer'], 'macros': ['macro.dbt.test_not_null']}, - 'tags': ['schema'], + 'tags': [], 'config': { 'enabled': True, 'materialized': 'test', @@ -382,7 +382,7 @@ def expect_test_output(self): 'name': 't', 'package_name': 'test', 'depends_on': {'nodes': [], 'macros': []}, - 'tags': ['data'], + 'tags': [], 'config': { 'enabled': True, 'materialized': 'test', @@ -408,7 +408,7 @@ def expect_test_output(self): 'name': 'unique_outer_id', 'package_name': 'test', 'depends_on': {'nodes': ['model.test.outer'], 'macros': ['macro.dbt.test_unique']}, - 'tags': ['schema'], + 'tags': [], 'config': { 'enabled': True, 'materialized': 'test', diff --git a/test/integration/066_test_selection_tests/test_selection_expansion.py b/test/integration/066_test_selection_tests/test_selection_expansion.py index 882505e43e3..74bfe7ff6bb 100644 --- a/test/integration/066_test_selection_tests/test_selection_expansion.py +++ b/test/integration/066_test_selection_tests/test_selection_expansion.py @@ -33,37 +33,31 @@ def list_tests_and_assert(self, include, exclude, expected_tests, greedy=False, list_args.append('--greedy') if selector_name: list_args.extend(('--selector', selector_name)) - + listed = self.run_dbt(list_args) assert len(listed) == len(expected_tests) - + test_names = [name.split('.')[2] for name in listed] assert sorted(test_names) == sorted(expected_tests) - def run_tests_and_assert( - self, include, exclude, expected_tests, schema=False, data=False, greedy=False, selector_name=None - ): + def run_tests_and_assert(self, include, exclude, expected_tests, greedy=False, selector_name=None): results = self.run_dbt(['run']) self.assertEqual(len(results), 2) - + test_args = ['test'] if include: test_args.extend(('--models', include)) if exclude: test_args.extend(('--exclude', exclude)) - if schema: - test_args.append('--schema') - if data: - test_args.append('--data') if greedy: test_args.append('--greedy') if selector_name: test_args.extend(('--selector', selector_name)) - + results = self.run_dbt(test_args) tests_run = [r.node.name for r in results] assert len(tests_run) == len(expected_tests) - + assert sorted(tests_run) == sorted(expected_tests) @use_profile('postgres') @@ -77,7 +71,7 @@ def test__postgres__all_tests_no_specifiers(self): 'source_unique_my_src_my_tbl_fun', 'unique_model_a_fun' ] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -86,7 +80,7 @@ def test__postgres__model_a_alone(self): select = 'model_a' exclude = None expected = ['just_a','unique_model_a_fun'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -98,7 +92,7 @@ def test__postgres__model_a_model_b(self): 'cf_a_b','just_a','unique_model_a_fun', 'relationships_model_a_fun__fun__ref_model_b_' ] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -111,10 +105,10 @@ def test__postgres__model_a_sources(self): 'source_unique_my_src_my_tbl_fun', 'relationships_model_a_fun__fun__source_my_src_my_tbl_' ] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) - + @use_profile('postgres') def test__postgres__exclude_model_b(self): select = None @@ -124,7 +118,7 @@ def test__postgres__exclude_model_b(self): 'relationships_model_a_fun__fun__source_my_src_my_tbl_', 'source_unique_my_src_my_tbl_fun','unique_model_a_fun' ] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -133,7 +127,7 @@ def test__postgres__model_a_exclude_specific_test(self): select = 'model_a' exclude = 'unique_model_a_fun' expected = ['just_a'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -147,56 +141,52 @@ def test__postgres__only_schema(self): 'source_unique_my_src_my_tbl_fun', 'unique_model_a_fun' ] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) - self.run_tests_and_assert(None, exclude, expected, schema=True) @use_profile('postgres') def test__postgres__model_a_only_data(self): select = 'model_a,test_type:schema' exclude = None expected = ['unique_model_a_fun'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) - self.run_tests_and_assert('model_a', exclude, expected, schema=True) @use_profile('postgres') def test__postgres__only_data(self): select = 'test_type:data' exclude = None expected = ['cf_a_b', 'cf_a_src', 'just_a'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) - self.run_tests_and_assert(None, exclude, expected, data=True) - + @use_profile('postgres') def test__postgres__model_a_only_data(self): select = 'model_a,test_type:data' exclude = None expected = ['just_a'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) - self.run_tests_and_assert('model_a', exclude, expected, data=True) @use_profile('postgres') def test__postgres__test_name_intersection(self): select = 'model_a,test_name:unique' exclude = None expected = ['unique_model_a_fun'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) - + @use_profile('postgres') def test__postgres__model_tag_test_name_intersection(self): select = 'tag:a_or_b,test_name:relationships' exclude = None expected = ['relationships_model_a_fun__fun__ref_model_b_'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -209,7 +199,7 @@ def test__postgres__select_column_level_tag(self): 'relationships_model_a_fun__fun__source_my_src_my_tbl_', 'unique_model_a_fun' ] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -218,7 +208,7 @@ def test__postgres__exclude_column_level_tag(self): select = None exclude = 'tag:column_level_tag' expected = ['cf_a_b','cf_a_src','just_a','source_unique_my_src_my_tbl_fun'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -227,7 +217,7 @@ def test__postgres__test_level_tag(self): select = 'tag:test_level_tag' exclude = None expected = ['relationships_model_a_fun__fun__ref_model_b_'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -236,7 +226,7 @@ def test__postgres__exclude_data_test_tag(self): select = 'model_a' exclude = 'tag:data_test_tag' expected = ['unique_model_a_fun'] - + self.list_tests_and_assert(select, exclude, expected) self.run_tests_and_assert(select, exclude, expected) @@ -251,7 +241,7 @@ def test__postgres__model_a_greedy(self): 'relationships_model_a_fun__fun__source_my_src_my_tbl_', 'unique_model_a_fun' ] - + self.list_tests_and_assert(select, exclude, expected, greedy) self.run_tests_and_assert(select, exclude, expected, greedy=greedy) @@ -265,7 +255,7 @@ def test__postgres__model_a_greedy_exclude_unique_tests(self): 'relationships_model_a_fun__fun__ref_model_b_', 'relationships_model_a_fun__fun__source_my_src_my_tbl_', ] - + self.list_tests_and_assert(select, exclude, expected, greedy) self.run_tests_and_assert(select, exclude, expected, greedy=greedy) @@ -294,7 +284,7 @@ def selectors_config(self): @use_profile('postgres') def test__postgres__selector_model_a_not_greedy(self): expected = ['just_a','unique_model_a_fun'] - + # when greedy is not specified, so implicitly False self.list_tests_and_assert(include=None, exclude=None, expected_tests=expected, selector_name='model_a_greedy_none') self.run_tests_and_assert(include=None, exclude=None, expected_tests=expected, selector_name='model_a_greedy_none') diff --git a/test/integration/070_incremental_schema_tests/test_incremental_schema.py b/test/integration/070_incremental_schema_tests/test_incremental_schema.py index 1331986d5b5..13d1a93dee5 100644 --- a/test/integration/070_incremental_schema_tests/test_incremental_schema.py +++ b/test/integration/070_incremental_schema_tests/test_incremental_schema.py @@ -32,7 +32,7 @@ def list_tests_and_assert(self, include, exclude, expected_tests): assert sorted(test_names) == sorted(expected_tests) def run_tests_and_assert( - self, include, exclude, expected_tests, compare_source, compare_target, schema = False, data = False + self, include, exclude, expected_tests, compare_source, compare_target ): run_args = ['run'] @@ -50,10 +50,6 @@ def run_tests_and_assert( test_args.extend(('--models', include)) if exclude: test_args.extend(('--exclude', exclude)) - if schema: - test_args.append('--schema') - if data: - test_args.append('--data') results = self.run_dbt(test_args) tests_run = [r.node.name for r in results] diff --git a/test/integration/base.py b/test/integration/base.py index c8ca3c5523c..bf18d33aaad 100644 --- a/test/integration/base.py +++ b/test/integration/base.py @@ -60,9 +60,7 @@ def __eq__(self, other): class FakeArgs: def __init__(self): self.threads = 1 - self.data = False self.defer = False - self.schema = True self.full_refresh = False self.models = None self.select = None diff --git a/test/unit/test_parser.py b/test/unit/test_parser.py index 065a25f75ab..d7bf515ba27 100644 --- a/test/unit/test_parser.py +++ b/test/unit/test_parser.py @@ -327,12 +327,12 @@ def test__parse_basic_source_tests(self): tests.sort(key=lambda n: n.unique_id) self.assertEqual(tests[0].config.severity, 'ERROR') - self.assertEqual(tests[0].tags, ['schema']) + self.assertEqual(tests[0].tags, []) self.assertEqual(tests[0].sources, [['my_source', 'my_table']]) self.assertEqual(tests[0].column_name, 'color') self.assertEqual(tests[0].fqn, ['snowplow', 'test', tests[0].name]) self.assertEqual(tests[1].config.severity, 'WARN') - self.assertEqual(tests[1].tags, ['schema']) + self.assertEqual(tests[1].tags, []) self.assertEqual(tests[1].sources, [['my_source', 'my_table']]) self.assertEqual(tests[1].column_name, 'color') self.assertEqual(tests[1].fqn, ['snowplow', 'test', tests[1].name]) @@ -409,7 +409,7 @@ def test__parse_basic_model_tests(self): continue tests.append(node) self.assertEqual(tests[0].config.severity, 'ERROR') - self.assertEqual(tests[0].tags, ['schema']) + self.assertEqual(tests[0].tags, []) self.assertEqual(tests[0].refs, [['my_model']]) self.assertEqual(tests[0].column_name, 'color') self.assertEqual(tests[0].package_name, 'snowplow') @@ -430,7 +430,7 @@ def test__parse_basic_model_tests(self): # foreign packages are a bit weird, they include the macro package # name in the test name self.assertEqual(tests[1].config.severity, 'ERROR') - self.assertEqual(tests[1].tags, ['schema']) + self.assertEqual(tests[1].tags, []) self.assertEqual(tests[1].refs, [['my_model']]) self.assertEqual(tests[1].column_name, 'color') self.assertEqual(tests[1].column_name, 'color') @@ -450,7 +450,7 @@ def test__parse_basic_model_tests(self): ) self.assertEqual(tests[2].config.severity, 'WARN') - self.assertEqual(tests[2].tags, ['schema']) + self.assertEqual(tests[2].tags, []) self.assertEqual(tests[2].refs, [['my_model']]) self.assertEqual(tests[2].column_name, 'color') self.assertEqual(tests[2].package_name, 'snowplow') @@ -837,7 +837,7 @@ def test_basic(self): root_path=get_abs_os_path('./dbt_modules/snowplow'), refs=[['blah']], config=TestConfig(severity='ERROR'), - tags=['data'], + tags=[], path=normalize('test/test_1.sql'), raw_sql=raw_sql, checksum=block.file.checksum, From 5336340b0611032a9b499ef544fca16f293d0d92 Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Sun, 26 Sep 2021 16:49:37 +0200 Subject: [PATCH 4/5] Update test FQNs, compiled paths --- core/dbt/parser/schemas.py | 18 +++++++++--------- core/dbt/parser/singular_test.py | 3 +-- core/dbt/utils.py | 4 ++-- .../test_graph_selection.py | 4 ++-- .../test_docs_generate.py | 18 +++++++++--------- test/integration/047_dbt_ls_test/test_ls.py | 18 +++++++++--------- .../test_modified_state.py | 2 +- .../test_selection_expansion.py | 2 +- .../test_incremental_schema.py | 6 +++--- test/unit/test_parser.py | 14 +++++++------- 10 files changed, 44 insertions(+), 45 deletions(-) diff --git a/core/dbt/parser/schemas.py b/core/dbt/parser/schemas.py index 9da1a576c44..c25464187b3 100644 --- a/core/dbt/parser/schemas.py +++ b/core/dbt/parser/schemas.py @@ -1,5 +1,6 @@ import itertools import os +import pathlib from abc import ABCMeta, abstractmethod from hashlib import md5 @@ -306,15 +307,14 @@ def _parse_generic_test( ) raise CompilationException(msg) from exc original_name = os.path.basename(target.original_file_path) - compiled_path = get_pseudo_test_path( - builder.compiled_name, original_name, 'test', - ) - fqn_path = get_pseudo_test_path( - builder.fqn_name, original_name, 'test', - ) - # the fqn for tests actually happens in the test target's name, which - # is not necessarily this package's name - fqn = self.get_fqn(fqn_path, builder.fqn_name) + compiled_path = get_pseudo_test_path(builder.compiled_name, original_name) + + # fqn is the relative path of the yaml file where this generic test is defined, + # minus the project-level directory and the file name itself + # TODO pass a consistent path object from both UnparsedNode and UnpatchedSourceDefinition + path = pathlib.Path(target.original_file_path) + relative_path = str(path.relative_to(*path.parts[:1])) + fqn = self.get_fqn(relative_path, builder.fqn_name) # this is the ContextConfig that is used in render_update config: ContextConfig = self.initial_config(fqn) diff --git a/core/dbt/parser/singular_test.py b/core/dbt/parser/singular_test.py index ab909524da7..22d203a8ebc 100644 --- a/core/dbt/parser/singular_test.py +++ b/core/dbt/parser/singular_test.py @@ -17,5 +17,4 @@ def resource_type(self) -> NodeType: @classmethod def get_compiled_path(cls, block: FileBlock): - return get_pseudo_test_path(block.name, block.path.relative_path, - 'test') + return get_pseudo_test_path(block.name, block.path.relative_path) diff --git a/core/dbt/utils.py b/core/dbt/utils.py index 2e2fe7eae4f..9d16aff2e50 100644 --- a/core/dbt/utils.py +++ b/core/dbt/utils.py @@ -232,11 +232,11 @@ def __init__(self, *args, **kwargs): self.__dict__ = self -def get_pseudo_test_path(node_name, source_path, test_type): +def get_pseudo_test_path(node_name, source_path): "schema tests all come from schema.yml files. fake a source sql file" source_path_parts = split_path(source_path) source_path_parts.pop() # ignore filename - suffix = [test_type, "{}.sql".format(node_name)] + suffix = ["{}.sql".format(node_name)] pseudo_path_parts = source_path_parts + suffix return os.path.join(*pseudo_path_parts) diff --git a/test/integration/007_graph_selection_tests/test_graph_selection.py b/test/integration/007_graph_selection_tests/test_graph_selection.py index 361aca694db..f0dd6188d40 100644 --- a/test/integration/007_graph_selection_tests/test_graph_selection.py +++ b/test/integration/007_graph_selection_tests/test_graph_selection.py @@ -408,8 +408,8 @@ def test__postgres__exposure_parents(self): results = self.run_dbt(['ls', '--select', '1+exposure:user_exposure']) assert len(results) == 5 - assert sorted(results) == ['exposure:test.user_exposure', 'test.test.unique_users_id', - 'test.test.unique_users_rollup_gender', 'test.users', 'test.users_rollup'] + assert sorted(results) == ['exposure:test.user_exposure', 'test.unique_users_id', + 'test.unique_users_rollup_gender', 'test.users', 'test.users_rollup'] results = self.run_dbt(['run', '-m', '+exposure:user_exposure']) # users, users_rollup diff --git a/test/integration/029_docs_generate_tests/test_docs_generate.py b/test/integration/029_docs_generate_tests/test_docs_generate.py index 35ebf83dadb..bcb82105aed 100644 --- a/test/integration/029_docs_generate_tests/test_docs_generate.py +++ b/test/integration/029_docs_generate_tests/test_docs_generate.py @@ -1335,7 +1335,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'test.test.not_null_model_id.d01cc630e6': { 'alias': 'not_null_model_id', - 'compiled_path': Normalized('target/compiled/test/models/schema.yml/test/not_null_model_id.sql'), + 'compiled_path': Normalized('target/compiled/test/models/schema.yml/not_null_model_id.sql'), 'build_path': None, 'created_at': ANY, 'column_name': 'id', @@ -1348,12 +1348,12 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'deferred': False, 'description': '', - 'fqn': ['test', 'test', 'not_null_model_id'], + 'fqn': ['test', 'not_null_model_id'], 'name': 'not_null_model_id', 'original_file_path': model_schema_yml_path, 'package_name': 'test', 'patch_path': None, - 'path': Normalized('test/not_null_model_id.sql'), + 'path': Normalized('not_null_model_id.sql'), 'raw_sql': "{{ test_not_null(**_dbt_generic_test_kwargs) }}", 'refs': [['model']], 'relation_name': None, @@ -1426,7 +1426,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'test.test.test_nothing_model_.5d38568946': { 'alias': 'test_nothing_model_', - 'compiled_path': Normalized('target/compiled/test/models/schema.yml/test/test_nothing_model_.sql'), + 'compiled_path': Normalized('target/compiled/test/models/schema.yml/test_nothing_model_.sql'), 'build_path': None, 'created_at': ANY, 'column_name': None, @@ -1439,12 +1439,12 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'deferred': False, 'description': '', - 'fqn': ['test', 'test', 'test_nothing_model_'], + 'fqn': ['test', 'test_nothing_model_'], 'name': 'test_nothing_model_', 'original_file_path': model_schema_yml_path, 'package_name': 'test', 'patch_path': None, - 'path': normalize('test/test_nothing_model_.sql'), + 'path': normalize('test_nothing_model_.sql'), 'raw_sql': "{{ test.test_nothing(**_dbt_generic_test_kwargs) }}", 'refs': [['model']], 'relation_name': None, @@ -1472,7 +1472,7 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'test.test.unique_model_id.67b76558ff': { 'alias': 'unique_model_id', - 'compiled_path': Normalized('target/compiled/test/models/schema.yml/test/unique_model_id.sql'), + 'compiled_path': Normalized('target/compiled/test/models/schema.yml/unique_model_id.sql'), 'build_path': None, 'created_at': ANY, 'column_name': 'id', @@ -1485,12 +1485,12 @@ def expected_seeded_manifest(self, model_database=None, quote_model=False): }, 'deferred': False, 'description': '', - 'fqn': ['test', 'test', 'unique_model_id'], + 'fqn': ['test', 'unique_model_id'], 'name': 'unique_model_id', 'original_file_path': model_schema_yml_path, 'package_name': 'test', 'patch_path': None, - 'path': normalize('test/unique_model_id.sql'), + 'path': normalize('unique_model_id.sql'), 'raw_sql': "{{ test_unique(**_dbt_generic_test_kwargs) }}", 'refs': [['model']], 'relation_name': None, diff --git a/test/integration/047_dbt_ls_test/test_ls.py b/test/integration/047_dbt_ls_test/test_ls.py index b424d383a8a..cf25dc403a5 100644 --- a/test/integration/047_dbt_ls_test/test_ls.py +++ b/test/integration/047_dbt_ls_test/test_ls.py @@ -350,7 +350,7 @@ def expect_seed_output(self): def expect_test_output(self): expectations = { 'name': ('not_null_outer_id', 't', 'unique_outer_id'), - 'selector': ('test.test.not_null_outer_id', 'test.test.t', 'test.test.unique_outer_id'), + 'selector': ('test.not_null_outer_id', 'test.t', 'test.unique_outer_id'), 'json': ( { 'name': 'not_null_outer_id', @@ -436,9 +436,9 @@ def expect_test_output(self): self.expect_given_output(['--resource-type', 'test'], expectations) def expect_all_output(self): - # tests have their type inserted into their fqn, after the package - # but models don't! they just have (package.name) - # sources are like models - (package.source_name.table_name) + # generic test FQNS include the resource + column they're defined on + # models are just package, subdirectory path, name + # sources are like models, ending in source_name.table_name expected_default = { 'test.ephemeral', 'test.incremental', @@ -447,9 +447,9 @@ def expect_all_output(self): 'test.outer', 'test.seed', 'source:test.my_source.my_table', - 'test.test.not_null_outer_id', - 'test.test.unique_outer_id', - 'test.test.t', + 'test.not_null_outer_id', + 'test.unique_outer_id', + 'test.t', } # analyses have their type inserted into their fqn like tests expected_all = expected_default | {'test.analysis.a'} @@ -467,12 +467,12 @@ def expect_all_output(self): def expect_select(self): results = self.run_dbt_ls(['--resource-type', 'test', '--select', 'outer']) - self.assertEqual(set(results), {'test.test.not_null_outer_id', 'test.test.unique_outer_id'}) + self.assertEqual(set(results), {'test.not_null_outer_id', 'test.unique_outer_id'}) self.run_dbt_ls(['--resource-type', 'test', '--select', 'inner'], expect_pass=True) results = self.run_dbt_ls(['--resource-type', 'test', '--select', '+inner']) - self.assertEqual(set(results), {'test.test.not_null_outer_id', 'test.test.unique_outer_id'}) + self.assertEqual(set(results), {'test.not_null_outer_id', 'test.unique_outer_id'}) results = self.run_dbt_ls(['--resource-type', 'model', '--select', 'outer+']) self.assertEqual(set(results), {'test.outer', 'test.sub.inner'}) diff --git a/test/integration/062_defer_state_test/test_modified_state.py b/test/integration/062_defer_state_test/test_modified_state.py index 1a3b83a214d..2a3c765a704 100644 --- a/test/integration/062_defer_state_test/test_modified_state.py +++ b/test/integration/062_defer_state_test/test_modified_state.py @@ -72,7 +72,7 @@ def test_postgres_changed_seed_contents_state(self): results = self.run_dbt(['ls', '--select', 'state:modified+', '--state', './state']) assert len(results) == 7 - assert set(results) == {'test.seed', 'test.table_model', 'test.view_model', 'test.ephemeral_model', 'test.test.not_null_view_model_id', 'test.test.unique_view_model_id', 'exposure:test.my_exposure'} + assert set(results) == {'test.seed', 'test.table_model', 'test.view_model', 'test.ephemeral_model', 'test.not_null_view_model_id', 'test.unique_view_model_id', 'exposure:test.my_exposure'} shutil.rmtree('./state') self.copy_state() diff --git a/test/integration/066_test_selection_tests/test_selection_expansion.py b/test/integration/066_test_selection_tests/test_selection_expansion.py index 74bfe7ff6bb..0ca37ceb14f 100644 --- a/test/integration/066_test_selection_tests/test_selection_expansion.py +++ b/test/integration/066_test_selection_tests/test_selection_expansion.py @@ -37,7 +37,7 @@ def list_tests_and_assert(self, include, exclude, expected_tests, greedy=False, listed = self.run_dbt(list_args) assert len(listed) == len(expected_tests) - test_names = [name.split('.')[2] for name in listed] + test_names = [name.split('.')[-1] for name in listed] assert sorted(test_names) == sorted(expected_tests) def run_tests_and_assert(self, include, exclude, expected_tests, greedy=False, selector_name=None): diff --git a/test/integration/070_incremental_schema_tests/test_incremental_schema.py b/test/integration/070_incremental_schema_tests/test_incremental_schema.py index 13d1a93dee5..d5b0ea4e0f7 100644 --- a/test/integration/070_incremental_schema_tests/test_incremental_schema.py +++ b/test/integration/070_incremental_schema_tests/test_incremental_schema.py @@ -1,10 +1,10 @@ from test.integration.base import DBTIntegrationTest, FakeArgs, use_profile -class TestSelectionExpansion(DBTIntegrationTest): +class TestIncrementalSchemaChange(DBTIntegrationTest): @property def schema(self): - return "test_incremental_schema_069" + return "test_incremental_schema_070" @property def models(self): @@ -28,7 +28,7 @@ def list_tests_and_assert(self, include, exclude, expected_tests): print(listed) assert len(listed) == len(expected_tests) - test_names = [name.split('.')[2] for name in listed] + test_names = [name.split('.')[-1] for name in listed] assert sorted(test_names) == sorted(expected_tests) def run_tests_and_assert( diff --git a/test/unit/test_parser.py b/test/unit/test_parser.py index d7bf515ba27..e0bc28e7d6c 100644 --- a/test/unit/test_parser.py +++ b/test/unit/test_parser.py @@ -330,12 +330,12 @@ def test__parse_basic_source_tests(self): self.assertEqual(tests[0].tags, []) self.assertEqual(tests[0].sources, [['my_source', 'my_table']]) self.assertEqual(tests[0].column_name, 'color') - self.assertEqual(tests[0].fqn, ['snowplow', 'test', tests[0].name]) + self.assertEqual(tests[0].fqn, ['snowplow', tests[0].name]) self.assertEqual(tests[1].config.severity, 'WARN') self.assertEqual(tests[1].tags, []) self.assertEqual(tests[1].sources, [['my_source', 'my_table']]) self.assertEqual(tests[1].column_name, 'color') - self.assertEqual(tests[1].fqn, ['snowplow', 'test', tests[1].name]) + self.assertEqual(tests[1].fqn, ['snowplow', tests[1].name]) file_id = 'snowplow://' + normalize('models/test_one.yml') self.assertIn(file_id, self.parser.manifest.files) @@ -414,7 +414,7 @@ def test__parse_basic_model_tests(self): self.assertEqual(tests[0].column_name, 'color') self.assertEqual(tests[0].package_name, 'snowplow') self.assertTrue(tests[0].name.startswith('accepted_values_')) - self.assertEqual(tests[0].fqn, ['snowplow', 'test', tests[0].name]) + self.assertEqual(tests[0].fqn, ['snowplow', tests[0].name]) self.assertEqual(tests[0].unique_id.split('.'), ['test', 'snowplow', tests[0].name, '9d4814efde']) self.assertEqual(tests[0].test_metadata.name, 'accepted_values') self.assertIsNone(tests[0].test_metadata.namespace) @@ -434,7 +434,7 @@ def test__parse_basic_model_tests(self): self.assertEqual(tests[1].refs, [['my_model']]) self.assertEqual(tests[1].column_name, 'color') self.assertEqual(tests[1].column_name, 'color') - self.assertEqual(tests[1].fqn, ['snowplow', 'test', tests[1].name]) + 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') self.assertEqual(tests[1].unique_id.split('.'), ['test', 'snowplow', tests[1].name, '13958f62f7']) @@ -455,7 +455,7 @@ def test__parse_basic_model_tests(self): self.assertEqual(tests[2].column_name, 'color') self.assertEqual(tests[2].package_name, 'snowplow') self.assertTrue(tests[2].name.startswith('not_null_')) - self.assertEqual(tests[2].fqn, ['snowplow', 'test', tests[2].name]) + self.assertEqual(tests[2].fqn, ['snowplow', tests[2].name]) self.assertEqual(tests[2].unique_id.split('.'), ['test', 'snowplow', tests[2].name, '2f61818750']) self.assertEqual(tests[2].test_metadata.name, 'not_null') self.assertIsNone(tests[2].test_metadata.namespace) @@ -831,14 +831,14 @@ def test_basic(self): schema='dbt_test__audit', resource_type=NodeType.Test, unique_id='test.snowplow.test_1', - fqn=['snowplow', 'test', 'test_1'], + fqn=['snowplow', 'test_1'], package_name='snowplow', original_file_path=normalize('tests/test_1.sql'), root_path=get_abs_os_path('./dbt_modules/snowplow'), refs=[['blah']], config=TestConfig(severity='ERROR'), tags=[], - path=normalize('test/test_1.sql'), + path=normalize('test_1.sql'), raw_sql=raw_sql, checksum=block.file.checksum, unrendered_config={}, From 7ff2f273997082cdeaf646dc7b458e5223203ec8 Mon Sep 17 00:00:00 2001 From: Jeremy Cohen Date: Wed, 22 Sep 2021 16:48:27 +0200 Subject: [PATCH 5/5] Add changelog entry --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8732f9f30b..a48c39058c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,15 @@ ## dbt 1.0.0 (Release TBD) +### Breaking changes + +- The two type of test definitions are now "singular" and "generic" (instead of "data" and "schema", respectively). The `test_type:` selection method accepts `test_type:singular` and `test_type:generic`. (It will also accept `test_type:schema` and `test_type:data` for backwards compatibility) ([#3234](https://github.com/dbt-labs/dbt/issues/3234), [#3880](https://github.com/dbt-labs/dbt/pull/3880)). **Not backwards compatible:** The `--data` and `--schema` flags to `dbt test` are no longer supported, and tests no longer have the tags `'data'` and `'schema'` automatically applied. + ### Features - Normalize global CLI arguments/flags ([#2990](https://github.com/dbt-labs/dbt/issues/2990), [#3839](https://github.com/dbt-labs/dbt/pull/3839)) +- Generic test FQNs have changed to include the relative path, resource, and column (if applicable) where they are defined. This makes it easier to configure them from the `tests` block in `dbt_project.yml` ([#3259](https://github.com/dbt-labs/dbt/pull/3259), [#3880](https://github.com/dbt-labs/dbt/pull/3880) ### Fixes +- Add generic tests defined on sources to the manifest once, not twice ([#3347](https://github.com/dbt-labs/dbt/issues/3347), [#3880](https://github.com/dbt-labs/dbt/pull/3880)) ### Under the hood