Skip to content

Commit 0b73fd6

Browse files
committed
test(athena): refactor build_with_subquery SQL assertions to heredoc style
Introduce _strip_line_ws/_assert_sql_equal helpers so expected SQL can be written as readable heredocs that ignore Jinja's incidental indentation. Convert all existing and new assertions to this style and drop the now-unused _normalize helper.
1 parent 4bd8917 commit 0b73fd6

1 file changed

Lines changed: 82 additions & 54 deletions

File tree

dbt-athena/tests/unit/test_build_with_subquery.py

Lines changed: 82 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,29 @@ def __init__(self, name):
4343
self.data_type = "varchar"
4444

4545

46-
def _normalize(sql):
47-
return " ".join(sql.strip().split())
46+
def _strip_line_ws(sql):
47+
"""Strip leading and trailing whitespace from each line. SQL semantics
48+
don't depend on indentation outside of string literals, so this lets the
49+
expected heredocs ignore Jinja's incidental indentation while still
50+
asserting line structure (newlines, ordering, content) exactly."""
51+
return "\n".join(line.strip() for line in sql.splitlines())
52+
53+
54+
def _assert_sql_equal(actual, expected):
55+
"""Compare SQL line-by-line, ignoring per-line leading/trailing whitespace."""
56+
assert _strip_line_ws(actual) == _strip_line_ws(expected)
57+
58+
59+
_EXPECTED_MERGE_TAIL = """\
60+
on (target.id = src.id
61+
62+
)
63+
64+
when matched
65+
then update set"msg" = src."msg","color" = src."color"
66+
when not matched
67+
then insert ("id", "msg", "color")
68+
values (src."id", src."msg", src."color")"""
4869

4970

5071
class MockAdapter:
@@ -162,11 +183,16 @@ def _render_iceberg_merge(source_sql=None, query_result="OK"):
162183
class TestIncrementalInsertWithSubquery:
163184
def test_insert_uses_subquery(self):
164185
adapter, _ = _render_incremental_insert(source_sql="SELECT id, msg, color FROM src")
165-
assert _normalize(adapter.last_sql) == (
166-
'insert into db.schema.tbl ("id", "msg", "color")'
167-
" ( select"
168-
' "id", "msg", "color"'
169-
" from ( SELECT id, msg, color FROM src ) _dbt_sbq );"
186+
_assert_sql_equal(
187+
adapter.last_sql,
188+
"""\
189+
insert into db.schema.tbl ("id", "msg", "color")
190+
(
191+
select "id", "msg", "color"
192+
from (
193+
SELECT id, msg, color FROM src
194+
) _dbt_sbq
195+
);""",
170196
)
171197

172198
def test_insert_subquery_isolates_trailing_line_comment(self):
@@ -175,23 +201,28 @@ def test_insert_subquery_isolates_trailing_line_comment(self):
175201
in whitespace/newline handling is caught."""
176202
source_sql = "SELECT id, msg, color FROM src -- trailing comment"
177203
adapter, _ = _render_incremental_insert(source_sql=source_sql)
178-
assert adapter.last_sql == (
179-
'insert into db.schema.tbl ("id", "msg", "color")\n'
180-
" (\n"
181-
' select "id", "msg", "color"\n'
182-
" from (\n"
183-
" SELECT id, msg, color FROM src -- trailing comment\n"
184-
" ) _dbt_sbq\n"
185-
" );"
204+
_assert_sql_equal(
205+
adapter.last_sql,
206+
"""\
207+
insert into db.schema.tbl ("id", "msg", "color")
208+
(
209+
select "id", "msg", "color"
210+
from (
211+
SELECT id, msg, color FROM src -- trailing comment
212+
) _dbt_sbq
213+
);""",
186214
)
187215

188216
def test_insert_without_subquery_uses_tmp_relation(self):
189217
adapter, _ = _render_incremental_insert()
190-
assert _normalize(adapter.last_sql) == (
191-
'insert into db.schema.tbl ("id", "msg", "color")'
192-
" ( select"
193-
' "id", "msg", "color"'
194-
" from db.schema.tbl__dbt_tmp );"
218+
_assert_sql_equal(
219+
adapter.last_sql,
220+
"""\
221+
insert into db.schema.tbl ("id", "msg", "color")
222+
(
223+
select "id", "msg", "color"
224+
from db.schema.tbl__dbt_tmp
225+
);""",
195226
)
196227

197228
def test_subquery_too_many_partitions_raises_error(self):
@@ -210,21 +241,18 @@ def test_without_subquery_too_many_partitions_falls_back_to_batch(self):
210241

211242
# --- iceberg_merge ---
212243

213-
_EXPECTED_MERGE_CLAUSES = (
214-
" on (target.id = src.id )"
215-
" when matched"
216-
' then update set"msg" = src."msg","color" = src."color"'
217-
' when not matched then insert ("id", "msg", "color")'
218-
' values (src."id", src."msg", src."color")'
219-
)
220-
221244

222245
class TestIcebergMergeWithSubquery:
223246
def test_merge_uses_subquery(self):
224247
adapter, _ = _render_iceberg_merge(source_sql="SELECT id, msg, color FROM src")
225-
assert _normalize(adapter.last_sql) == (
226-
"merge into db.schema.tbl as target"
227-
" using ( SELECT id, msg, color FROM src ) as src" + _EXPECTED_MERGE_CLAUSES
248+
_assert_sql_equal(
249+
adapter.last_sql,
250+
"""\
251+
merge into db.schema.tbl as target using (
252+
SELECT id, msg, color FROM src
253+
) as src
254+
"""
255+
+ _EXPECTED_MERGE_TAIL,
228256
)
229257

230258
def test_merge_subquery_isolates_trailing_line_comment(self):
@@ -233,26 +261,22 @@ def test_merge_subquery_isolates_trailing_line_comment(self):
233261
in whitespace/newline handling is caught."""
234262
source_sql = "SELECT id, msg, color FROM src -- trailing comment"
235263
adapter, _ = _render_iceberg_merge(source_sql=source_sql)
236-
assert adapter.last_sql == (
237-
"merge into db.schema.tbl as target using (\n"
238-
" SELECT id, msg, color FROM src -- trailing comment\n"
239-
" ) as src\n"
240-
" on (target.id = src.id\n"
241-
" \n"
242-
" )\n"
243-
" \n"
244-
" when matched \n"
245-
' then update set"msg" = src."msg","color" = src."color"\n'
246-
" when not matched \n"
247-
' then insert ("id", "msg", "color")\n'
248-
' values (src."id", src."msg", src."color")'
264+
_assert_sql_equal(
265+
adapter.last_sql,
266+
"""\
267+
merge into db.schema.tbl as target using (
268+
SELECT id, msg, color FROM src -- trailing comment
269+
) as src
270+
"""
271+
+ _EXPECTED_MERGE_TAIL,
249272
)
250273

251274
def test_merge_without_subquery_uses_tmp_relation(self):
252275
adapter, _ = _render_iceberg_merge()
253-
assert _normalize(adapter.last_sql) == (
254-
"merge into db.schema.tbl as target"
255-
" using db.schema.tbl__dbt_tmp as src" + _EXPECTED_MERGE_CLAUSES
276+
_assert_sql_equal(
277+
adapter.last_sql,
278+
"merge into db.schema.tbl as target using db.schema.tbl__dbt_tmp as src\n"
279+
+ _EXPECTED_MERGE_TAIL,
256280
)
257281

258282
def test_subquery_too_many_partitions_raises_error(self):
@@ -292,19 +316,23 @@ class TestEmptySqlSubqueryWrapping:
292316
def test_empty_sql_wraps_compiled_code(self):
293317
renderings = _render_empty_sql("SELECT 1 AS id")
294318
assert renderings, "no empty_sql fragments rendered"
319+
expected = """\
320+
SELECT * FROM (
321+
SELECT 1 AS id
322+
) _dbt_sbq WITH NO DATA"""
295323
for rendered in renderings:
296-
assert rendered == "SELECT * FROM (\nSELECT 1 AS id\n) _dbt_sbq WITH NO DATA"
324+
_assert_sql_equal(rendered, expected)
297325

298326
def test_empty_sql_isolates_trailing_line_comment(self):
299327
"""The closing paren of empty_sql must land on a fresh line so a
300328
trailing -- line comment in compiled_code cannot comment it out."""
301329
compiled_code = "SELECT 1 AS id\n-- trailing comment"
302330
renderings = _render_empty_sql(compiled_code)
303331
assert renderings, "no empty_sql fragments rendered"
332+
expected = """\
333+
SELECT * FROM (
334+
SELECT 1 AS id
335+
-- trailing comment
336+
) _dbt_sbq WITH NO DATA"""
304337
for rendered in renderings:
305-
assert rendered == (
306-
"SELECT * FROM (\n"
307-
"SELECT 1 AS id\n"
308-
"-- trailing comment\n"
309-
") _dbt_sbq WITH NO DATA"
310-
)
338+
_assert_sql_equal(rendered, expected)

0 commit comments

Comments
 (0)