Skip to content

Commit

Permalink
setup initial tests, need to update for redshift
Browse files Browse the repository at this point in the history
  • Loading branch information
mikealfare committed Jul 11, 2023
1 parent 9f62fb0 commit 43678c7
Show file tree
Hide file tree
Showing 8 changed files with 511 additions and 0 deletions.
194 changes: 194 additions & 0 deletions tests/unit/conftest.py
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"
34 changes: 34 additions & 0 deletions tests/unit/materialization_tests/test_materialization.py
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 tests/unit/materialization_tests/test_materialization_factory.py
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
24 changes: 24 additions & 0 deletions tests/unit/relation_tests/model_tests/test_database.py
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")
25 changes: 25 additions & 0 deletions tests/unit/relation_tests/model_tests/test_index.py
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")
Loading

0 comments on commit 43678c7

Please sign in to comment.