-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
setup initial tests, need to update for redshift
- Loading branch information
1 parent
9f62fb0
commit 43678c7
Showing
8 changed files
with
511 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
from dataclasses import dataclass | ||
|
||
import agate | ||
import pytest | ||
|
||
from dbt.adapters.materialization.factory import MaterializationFactory | ||
from dbt.adapters.materialization.models import ( | ||
MaterializationType, | ||
MaterializedViewMaterialization, | ||
) | ||
from dbt.adapters.relation.factory import RelationFactory | ||
from dbt.contracts.files import FileHash | ||
from dbt.contracts.graph.model_config import OnConfigurationChangeOption | ||
from dbt.contracts.graph.nodes import DependsOn, ModelNode, NodeConfig | ||
from dbt.contracts.relation import RelationType | ||
from dbt.node_types import NodeType | ||
|
||
from dbt.adapters.redshift.relation import models | ||
|
||
|
||
@pytest.fixture | ||
def relation_factory(): | ||
return RelationFactory( | ||
relation_models={ | ||
RelationType.MaterializedView: models.RedshiftMaterializedViewRelation, | ||
}, | ||
relation_changesets={ | ||
RelationType.MaterializedView: models.RedshiftMaterializedViewRelationChangeset, | ||
}, | ||
relation_can_be_renamed={RelationType.MaterializedView}, | ||
render_policy=models.RedshiftRenderPolicy, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def materialization_factory(relation_factory): | ||
return MaterializationFactory( | ||
relation_factory=relation_factory, | ||
materialization_map={ | ||
MaterializationType.MaterializedView: MaterializedViewMaterialization | ||
}, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def materialized_view_stub(relation_factory): | ||
return relation_factory.make_stub( | ||
name="my_materialized_view", | ||
schema_name="my_schema", | ||
database_name="my_database", | ||
relation_type=RelationType.MaterializedView, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def view_stub(relation_factory): | ||
return relation_factory.make_stub( | ||
name="my_view", | ||
schema_name="my_schema", | ||
database_name="my_database", | ||
relation_type=RelationType.View, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def materialized_view_describe_relation_results(): | ||
# TODO separate query and add in sort/dist info | ||
materialized_view_agate = agate.Table.from_object( | ||
[ | ||
{ | ||
"name": "my_materialized_view", | ||
"schema_name": "my_schema", | ||
"database_name": "my_database", | ||
"query": "select 42 from meaning_of_life", | ||
} | ||
] | ||
) | ||
return {"materialized_view": materialized_view_agate} | ||
|
||
|
||
@pytest.fixture | ||
def materialized_view_model_node(): | ||
return ModelNode( | ||
alias="my_materialized_view", | ||
name="my_materialized_view", | ||
database="my_database", | ||
schema="my_schema", | ||
resource_type=NodeType.Model, | ||
unique_id="model.root.my_materialized_view", | ||
fqn=["root", "my_materialized_view"], | ||
package_name="root", | ||
original_file_path="my_materialized_view.sql", | ||
refs=[], | ||
sources=[], | ||
depends_on=DependsOn(), | ||
config=NodeConfig.from_dict( | ||
{ | ||
"enabled": True, | ||
"materialized": "materialized_view", | ||
"persist_docs": {}, | ||
"post-hook": [], | ||
"pre-hook": [], | ||
"vars": {}, | ||
"quoting": {}, | ||
"column_types": {}, | ||
"tags": [], | ||
# TODO replace this with sort/dist info | ||
"indexes": [ | ||
{"columns": ["id", "value"], "type": "hash"}, | ||
{"columns": ["id"], "unique": True}, | ||
], | ||
} | ||
), | ||
tags=[], | ||
path="my_materialized_view.sql", | ||
language="sql", | ||
raw_code="select 42 from meaning_of_life", | ||
compiled_code="select 42 from meaning_of_life", | ||
description="", | ||
columns={}, | ||
checksum=FileHash.from_contents(""), | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def materialized_view_relation(relation_factory, materialized_view_describe_relation_results): | ||
return relation_factory.make_from_describe_relation_results( | ||
materialized_view_describe_relation_results, RelationType.MaterializedView | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def materialized_view_runtime_config(materialized_view_model_node): | ||
""" | ||
This is not actually a `RuntimeConfigObject`. It's an object that has attribution that looks like | ||
a boiled down version of a RuntimeConfigObject. | ||
TODO: replace this with an actual `RuntimeConfigObject` | ||
""" | ||
|
||
@dataclass() | ||
class RuntimeConfigObject: | ||
model: ModelNode | ||
full_refresh: bool | ||
grants: dict | ||
on_configuration_change: OnConfigurationChangeOption | ||
|
||
def get(self, attribute: str, default=None): | ||
return getattr(self, attribute, default) | ||
|
||
return RuntimeConfigObject( | ||
model=materialized_view_model_node, | ||
full_refresh=False, | ||
grants={}, | ||
on_configuration_change=OnConfigurationChangeOption.Continue, | ||
) | ||
|
||
|
||
""" | ||
Make sure the fixtures at least work, more thorough testing is done elsewhere | ||
""" | ||
|
||
|
||
def test_relation_factory(relation_factory): | ||
assert ( | ||
relation_factory._get_parser(RelationType.MaterializedView) | ||
== models.RedshiftMaterializedViewRelation | ||
) | ||
|
||
|
||
def test_materialization_factory(materialization_factory): | ||
redshift_parser = materialization_factory.relation_factory._get_parser( | ||
RelationType.MaterializedView | ||
) | ||
assert redshift_parser == models.RedshiftMaterializedViewRelation | ||
|
||
|
||
def test_materialized_view_stub(materialized_view_stub): | ||
assert materialized_view_stub.name == "my_materialized_view" | ||
|
||
|
||
def test_materialized_view_model_node(materialized_view_model_node): | ||
assert materialized_view_model_node.name == "my_materialized_view" | ||
|
||
|
||
def test_materialized_view_runtime_config(materialized_view_runtime_config): | ||
assert materialized_view_runtime_config.get("full_refresh", False) is False | ||
assert materialized_view_runtime_config.get("on_configuration_change", "apply") == "continue" | ||
assert materialized_view_runtime_config.model.name == "my_materialized_view" | ||
|
||
|
||
def test_materialized_view_relation(materialized_view_relation): | ||
assert materialized_view_relation.type == RelationType.MaterializedView | ||
assert materialized_view_relation.name == "my_materialized_view" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from dataclasses import replace | ||
|
||
from dbt.adapters.materialization.models import ( | ||
MaterializedViewMaterialization, | ||
MaterializationBuildStrategy, | ||
) | ||
|
||
|
||
def test_materialized_view_create(materialized_view_runtime_config, relation_factory): | ||
materialization = MaterializedViewMaterialization.from_runtime_config( | ||
materialized_view_runtime_config, relation_factory | ||
) | ||
assert materialization.build_strategy == MaterializationBuildStrategy.Create | ||
assert materialization.should_revoke_grants is False | ||
|
||
|
||
def test_materialized_view_replace(materialized_view_runtime_config, relation_factory, view_stub): | ||
materialization = MaterializedViewMaterialization.from_runtime_config( | ||
materialized_view_runtime_config, relation_factory, view_stub | ||
) | ||
assert materialization.build_strategy == MaterializationBuildStrategy.Replace | ||
assert materialization.should_revoke_grants is True | ||
|
||
|
||
def test_materialized_view_alter( | ||
materialized_view_runtime_config, relation_factory, materialized_view_relation | ||
): | ||
altered_materialized_view = replace(materialized_view_relation, indexes={}) | ||
|
||
materialization = MaterializedViewMaterialization.from_runtime_config( | ||
materialized_view_runtime_config, relation_factory, altered_materialized_view | ||
) | ||
assert materialization.build_strategy == MaterializationBuildStrategy.Alter | ||
assert materialization.should_revoke_grants is True |
36 changes: 36 additions & 0 deletions
36
tests/unit/materialization_tests/test_materialization_factory.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from dbt.adapters.materialization.models import MaterializationType | ||
from dbt.contracts.relation import RelationType | ||
|
||
from dbt.adapters.redshift.relation import models as relation_models | ||
|
||
|
||
def test_make_from_runtime_config(materialization_factory, materialized_view_runtime_config): | ||
materialization = materialization_factory.make_from_runtime_config( | ||
runtime_config=materialized_view_runtime_config, | ||
materialization_type=MaterializationType.MaterializedView, | ||
existing_relation_stub=None, | ||
) | ||
assert materialization.type == MaterializationType.MaterializedView | ||
|
||
materialized_view = materialization.target_relation | ||
assert materialized_view.type == RelationType.MaterializedView | ||
|
||
assert materialized_view.name == "my_materialized_view" | ||
assert materialized_view.schema_name == "my_schema" | ||
assert materialized_view.database_name == "my_database" | ||
assert materialized_view.query == "select 42 from meaning_of_life" | ||
|
||
index_1 = relation_models.RedshiftIndexRelation( | ||
column_names=frozenset({"id", "value"}), | ||
method=relation_models.RedshiftIndexMethod.hash, | ||
unique=False, | ||
render=relation_models.RedshiftRenderPolicy, | ||
) | ||
index_2 = relation_models.RedshiftIndexRelation( | ||
column_names=frozenset({"id"}), | ||
method=relation_models.RedshiftIndexMethod.btree, | ||
unique=True, | ||
render=relation_models.RedshiftRenderPolicy, | ||
) | ||
assert index_1 in materialized_view.indexes | ||
assert index_2 in materialized_view.indexes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from typing import Type | ||
|
||
import pytest | ||
from dbt.exceptions import DbtRuntimeError | ||
|
||
from dbt.adapters.redshift.relation.models import RedshiftDatabaseRelation | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"config_dict,exception", | ||
[ | ||
({"name": "my_database"}, None), | ||
({"name": ""}, DbtRuntimeError), | ||
({"wrong_name": "my_database"}, DbtRuntimeError), | ||
({}, DbtRuntimeError), | ||
], | ||
) | ||
def test_make_database(config_dict: dict, exception: Type[Exception]): | ||
if exception: | ||
with pytest.raises(exception): | ||
RedshiftDatabaseRelation.from_dict(config_dict) | ||
else: | ||
my_database = RedshiftDatabaseRelation.from_dict(config_dict) | ||
assert my_database.name == config_dict.get("name") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from typing import Type | ||
|
||
import pytest | ||
from dbt.exceptions import DbtRuntimeError | ||
|
||
from dbt.adapters.redshift.relation.models import RedshiftIndexRelation | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"config_dict,exception", | ||
[ | ||
({"column_names": frozenset({"id", "value"}), "method": "hash", "unique": False}, None), | ||
({"column_names": frozenset("id"), "method": "btree", "unique": True}, None), | ||
({}, DbtRuntimeError), | ||
({"method": "btree", "unique": True}, DbtRuntimeError), | ||
], | ||
) | ||
# TODO replace this with sort/dist stuff | ||
def test_create_index(config_dict: dict, exception: Type[Exception]): | ||
if exception: | ||
with pytest.raises(exception): | ||
RedshiftIndexRelation.from_dict(config_dict) | ||
else: | ||
my_index = RedshiftIndexRelation.from_dict(config_dict) | ||
assert my_index.column_names == config_dict.get("column_names") |
Oops, something went wrong.