Skip to content

Commit 9a245dc

Browse files
committed
Experiment with adding functional tests
1 parent 7adb22f commit 9a245dc

8 files changed

+350
-1
lines changed

run_functional_test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ if [[ ! -f $VENV ]]; then
1010
fi
1111

1212
. $VENV
13-
python3 -m pytest tests/functional --profile $1
13+
python3 -m pytest tests/functional -n4 --profile $1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import os
2+
import pytest
3+
from dbt.tests.util import run_dbt, check_relations_equal, get_relation_columns
4+
5+
class BaseDataTypeMacro:
6+
@pytest.fixture(scope="class")
7+
def packages(self):
8+
return {"packages": [{"local": os.getcwd()}]}
9+
10+
def is_legacy(self):
11+
return False
12+
13+
def test_check_types_assert_match(self, project):
14+
run_dbt(['deps'])
15+
run_dbt(['build'])
16+
17+
# check contents equal
18+
check_relations_equal(project.adapter, ["expected", "actual"])
19+
20+
# check types equal
21+
expected_cols = get_relation_columns(project.adapter, "expected")
22+
actual_cols = get_relation_columns(project.adapter, "actual")
23+
print(f"Expected: {expected_cols}")
24+
print(f"Actual: {actual_cols}")
25+
26+
27+
if not self.is_legacy():
28+
assert expected_cols == actual_cols, f"Type difference detected: {expected_cols} vs. {actual_cols}"
29+
# we need to be a little more lenient when mapping between 'legacy' and 'new' types that are equivalent
30+
# e.g. 'character varying' and 'text'
31+
elif expected_cols == actual_cols:
32+
# cool, no need for jank
33+
pass
34+
else:
35+
# this is pretty janky
36+
for i in range(0, len(expected_cols)):
37+
expected = project.adapter.Column(*expected_cols[i])
38+
actual = project.adapter.Column(*actual_cols[i])
39+
print(f"Subtle type difference detected: {expected.data_type} vs. {actual.data_type}")
40+
if any((
41+
expected.is_string() and actual.is_string(),
42+
expected.is_float() and actual.is_float(),
43+
expected.is_integer() and actual.is_integer(),
44+
expected.is_numeric() and actual.is_numeric(),
45+
)):
46+
pytest.xfail()
47+
else:
48+
pytest.fail()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import os
2+
import pytest
3+
from tests.functional.data_type.base_data_type_macro import BaseDataTypeMacro
4+
5+
models__expected_sql = """
6+
select 9223372036854775800 as bigint_col
7+
""".lstrip()
8+
9+
models__actual_sql = """
10+
select cast('9223372036854775800' as {{ dbt_utils.type_bigint() }}) as bigint_col
11+
"""
12+
13+
# previous dbt_utils code, replaced in this PR
14+
macros__legacy_sql = """
15+
{% macro default__type_bigint() %}
16+
bigint
17+
{% endmacro %}
18+
19+
{% macro bigquery__type_bigint() %}
20+
int64
21+
{% endmacro %}
22+
"""
23+
24+
25+
class TestTypeBigInt(BaseDataTypeMacro):
26+
@pytest.fixture(scope="class")
27+
def models(self):
28+
return {
29+
"expected.sql": models__expected_sql,
30+
"actual.sql": models__actual_sql
31+
}
32+
33+
34+
class TestTypeBigIntLegacy(TestTypeBigInt):
35+
@pytest.fixture(scope="class")
36+
def macros(self):
37+
return {
38+
"legacy.sql": macros__legacy_sql
39+
}
40+
41+
def is_legacy(self):
42+
return True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import os
2+
import pytest
3+
from tests.functional.data_type.base_data_type_macro import BaseDataTypeMacro
4+
5+
seeds__expected_csv = """float_col
6+
1.2345
7+
""".lstrip()
8+
9+
models__actual_sql = """
10+
select cast('1.2345' as {{ dbt_utils.type_float() }}) as float_col
11+
"""
12+
13+
# previous dbt_utils code, replaced in this PR
14+
macros__legacy_sql = """
15+
{% macro default__type_float() %}
16+
float
17+
{% endmacro %}
18+
19+
{% macro bigquery__type_float() %}
20+
float64
21+
{% endmacro %}
22+
"""
23+
24+
25+
class TestTypeFloat(BaseDataTypeMacro):
26+
@pytest.fixture(scope="class")
27+
def seeds(self):
28+
return {
29+
"expected.csv": seeds__expected_csv
30+
}
31+
32+
@pytest.fixture(scope="class")
33+
def models(self):
34+
return {
35+
"actual.sql": models__actual_sql
36+
}
37+
38+
39+
class TestTypeFloatLegacy(TestTypeFloat):
40+
@pytest.fixture(scope="class")
41+
def macros(self):
42+
return {
43+
"legacy.sql": macros__legacy_sql
44+
}
45+
46+
def is_legacy(self):
47+
return True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import os
2+
import pytest
3+
from tests.functional.data_type.base_data_type_macro import BaseDataTypeMacro
4+
5+
seeds__expected_csv = """int_col
6+
12345678
7+
""".lstrip()
8+
9+
models__actual_sql = """
10+
select cast('12345678' as {{ dbt_utils.type_int() }}) as int_col
11+
"""
12+
13+
# previous dbt_utils code, replaced in this PR
14+
macros__legacy_sql = """
15+
{% macro default__type_int() %}
16+
int
17+
{% endmacro %}
18+
19+
{% macro bigquery__type_int() %}
20+
int64
21+
{% endmacro %}
22+
"""
23+
24+
25+
class TestTypeFloat(BaseDataTypeMacro):
26+
@pytest.fixture(scope="class")
27+
def seeds(self):
28+
return {
29+
"expected.csv": seeds__expected_csv
30+
}
31+
32+
@pytest.fixture(scope="class")
33+
def models(self):
34+
return {
35+
"actual.sql": models__actual_sql
36+
}
37+
38+
39+
class TestTypeFloatLegacy(TestTypeFloat):
40+
@pytest.fixture(scope="class")
41+
def macros(self):
42+
return {
43+
"legacy.sql": macros__legacy_sql
44+
}
45+
46+
def is_legacy(self):
47+
return True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import os
2+
import pytest
3+
from tests.functional.data_type.base_data_type_macro import BaseDataTypeMacro
4+
5+
seeds__expected_csv = """numeric_col
6+
1.2345
7+
""".lstrip()
8+
9+
# need to explicitly cast this to avoid it being a double/float
10+
seeds__expected_yml = """
11+
version: 2
12+
seeds:
13+
- name: expected
14+
config:
15+
column_types:
16+
numeric_col: numeric(5,4)
17+
"""
18+
19+
models__actual_sql = """
20+
select cast('1.2345' as {{ dbt_utils.type_numeric() }}) as numeric_col
21+
"""
22+
23+
# previous dbt_utils code, replaced in this PR
24+
macros__legacy_sql = """
25+
{% macro default__type_numeric() %}
26+
numeric(28, 6)
27+
{% endmacro %}
28+
29+
{% macro bigquery__type_numeric() %}
30+
numeric
31+
{% endmacro %}
32+
"""
33+
34+
35+
class TestTypeNumeric(BaseDataTypeMacro):
36+
@pytest.fixture(scope="class")
37+
def seeds(self):
38+
return {
39+
"expected.csv": seeds__expected_csv,
40+
"expected.yml": seeds__expected_yml
41+
}
42+
43+
@pytest.fixture(scope="class")
44+
def models(self):
45+
return {
46+
"actual.sql": models__actual_sql
47+
}
48+
49+
50+
class TestTypeNumericLegacy(TestTypeNumeric):
51+
@pytest.fixture(scope="class")
52+
def macros(self):
53+
return {
54+
"legacy.sql": macros__legacy_sql
55+
}
56+
57+
def is_legacy(self):
58+
return True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import os
2+
import pytest
3+
from tests.functional.data_type.base_data_type_macro import BaseDataTypeMacro
4+
5+
seeds__expected_csv = """string_col
6+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
7+
""".lstrip()
8+
9+
models__actual_sql = """
10+
select cast('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' as {{ dbt_utils.type_string() }}) as string_col
11+
"""
12+
13+
# previous dbt_utils code, replaced in this PR
14+
macros__legacy_sql = """
15+
{% macro default__type_string() %}
16+
string
17+
{% endmacro %}
18+
19+
{%- macro redshift__type_string() -%}
20+
varchar
21+
{%- endmacro -%}
22+
23+
{% macro postgres__type_string() %}
24+
varchar
25+
{% endmacro %}
26+
27+
{% macro snowflake__type_string() %}
28+
varchar
29+
{% endmacro %}
30+
"""
31+
32+
33+
class TestTypeString(BaseDataTypeMacro):
34+
@pytest.fixture(scope="class")
35+
def seeds(self):
36+
return {
37+
"expected.csv": seeds__expected_csv
38+
}
39+
40+
@pytest.fixture(scope="class")
41+
def models(self):
42+
return {
43+
"actual.sql": models__actual_sql
44+
}
45+
46+
47+
class TestTypeStringLegacy(TestTypeString):
48+
@pytest.fixture(scope="class")
49+
def macros(self):
50+
return {
51+
"legacy.sql": macros__legacy_sql
52+
}
53+
54+
def is_legacy(self):
55+
return True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import os
2+
import pytest
3+
from tests.functional.data_type.base_data_type_macro import BaseDataTypeMacro
4+
5+
seeds__expected_csv = """timestamp_col
6+
2021-01-01 01:01:01
7+
""".lstrip()
8+
9+
models__actual_sql = """
10+
select cast('2021-01-01 01:01:01' as {{ dbt_utils.type_timestamp() }}) as timestamp_col
11+
"""
12+
13+
# previous dbt_utils code, replaced in this PR
14+
macros__legacy_sql = """
15+
{% macro default__type_timestamp() %}
16+
timestamp
17+
{% endmacro %}
18+
19+
{% macro postgres__type_timestamp() %}
20+
timestamp without time zone
21+
{% endmacro %}
22+
23+
{% macro snowflake__type_timestamp() %}
24+
timestamp_ntz
25+
{% endmacro %}
26+
"""
27+
28+
29+
class TestTypeTimestamp(BaseDataTypeMacro):
30+
@pytest.fixture(scope="class")
31+
def seeds(self):
32+
return {
33+
"expected.csv": seeds__expected_csv
34+
}
35+
36+
@pytest.fixture(scope="class")
37+
def models(self):
38+
return {
39+
"actual.sql": models__actual_sql
40+
}
41+
42+
43+
class TestTypeTimestampLegacy(TestTypeTimestamp):
44+
@pytest.fixture(scope="class")
45+
def macros(self):
46+
return {
47+
"legacy.sql": macros__legacy_sql
48+
}
49+
50+
def is_legacy(self):
51+
return True
52+

0 commit comments

Comments
 (0)