Skip to content

Commit 2c2b94d

Browse files
committed
test: expect Recall schema version 4 and compare rewritten views over the previous columns
Derive the expected Recall schema version from RECALL_SCHEMA_VERSION, compare the rewritten ClickHouse views with the previous ones over the columns both have, and check the columns the invocations view adds separately.
1 parent 0cbb9a7 commit 2c2b94d

5 files changed

Lines changed: 103 additions & 16 deletions

File tree

‎tests/e2e/src/sqlbuild/cli/commands/main/clickhouse/_test_types.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ class ClickHouseRecallViewEquivalenceTestCase:
268268
replaced_views: tuple[str, ...]
269269
all_views: tuple[str, ...]
270270
expected_statuses: list[list[object]]
271+
expected_added_columns: tuple[tuple[tuple[object, ...], ...], ...]
271272

272273

273274
@dataclass(frozen=True)

‎tests/e2e/src/sqlbuild/cli/commands/main/clickhouse/helpers.py‎

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from sqlbuild.adapters.clickhouse.classes.clickhouse_adapter import ClickHouseAdapter
1616
from tests.e2e.src.sqlbuild.cli.commands.shared.helpers import (
17+
REPO_ROOT,
1718
prepare_inline_project,
1819
prepare_waffle_shop,
1920
run_sqb,
@@ -28,6 +29,22 @@
2829
)
2930

3031
CLICKHOUSE_IMAGE: str = "clickhouse/clickhouse-server:26.1"
32+
_RECALL_SCHEMA_CONSTANTS: Path = REPO_ROOT / "crates/sqlbuild-recall/src/schema/constants.rs"
33+
_RECALL_SCHEMA_VERSION_PATTERN: re.Pattern[str] = re.compile(
34+
r"pub const RECALL_SCHEMA_VERSION: i64 = (\d+);"
35+
)
36+
37+
38+
def _recall_schema_version() -> int:
39+
"""The Recall schema version this build writes, as `RECALL_SCHEMA_VERSION` declares it."""
40+
41+
(version,) = _RECALL_SCHEMA_VERSION_PATTERN.findall(
42+
_RECALL_SCHEMA_CONSTANTS.read_text(encoding="utf-8")
43+
)
44+
return int(version)
45+
46+
47+
RECALL_SCHEMA_VERSION: int = _recall_schema_version()
3148

3249

3350
def build_unique_schema_name(*, prefix: str) -> str:
@@ -915,16 +932,23 @@ def fetch_with_settings(
915932

916933

917934
def differing_rows(
918-
*, config: dict[str, object], left: str, right: str, settings: dict[str, object]
935+
*,
936+
config: dict[str, object],
937+
left: str,
938+
right: str,
939+
settings: dict[str, object],
940+
columns: tuple[str, ...] = (),
919941
) -> int:
920-
"""Rows of `left` missing from `right` plus rows of `right` missing from `left`."""
942+
"""Rows of `left` missing from `right` plus rows of `right` missing from `left`, over `columns`
943+
when given, else over every column."""
921944

945+
selected: str = ", ".join(f"`{column}`" for column in columns) or "*"
922946
rows: tuple[tuple[object, ...], ...] = fetch_with_settings(
923947
config=config,
924948
sql=(
925-
f"SELECT (SELECT count() FROM (SELECT * FROM {left} EXCEPT DISTINCT "
926-
f"SELECT * FROM {right})) + (SELECT count() FROM (SELECT * FROM {right} "
927-
f"EXCEPT DISTINCT SELECT * FROM {left}))"
949+
f"SELECT (SELECT count() FROM (SELECT {selected} FROM {left} EXCEPT DISTINCT "
950+
f"SELECT {selected} FROM {right})) + (SELECT count() FROM (SELECT {selected} "
951+
f"FROM {right} EXCEPT DISTINCT SELECT {selected} FROM {left}))"
928952
),
929953
settings=settings,
930954
)
@@ -940,6 +964,30 @@ def described(*, config: dict[str, object], relation: str) -> tuple[tuple[object
940964
)
941965

942966

967+
def column_names(*, config: dict[str, object], relation: str) -> tuple[str, ...]:
968+
"""Each column's name, in order."""
969+
970+
return tuple(str(name) for name, _ in described(config=config, relation=relation))
971+
972+
973+
def described_except(
974+
*, config: dict[str, object], relation: str, previous: str
975+
) -> tuple[tuple[tuple[object, ...], ...], tuple[tuple[object, ...], ...]]:
976+
"""`relation`'s columns and types that `previous` also has, and those it adds, in order."""
977+
978+
columns: dict[object, object] = {
979+
column[0]: column[1] for column in described(config=config, relation=relation)
980+
}
981+
kept: tuple[str, ...] = column_names(config=config, relation=previous)
982+
added: dict[object, object] = dict(columns)
983+
for name in kept:
984+
del added[name]
985+
return (
986+
tuple((name, columns[name]) for name in kept),
987+
tuple(added.items()),
988+
)
989+
990+
943991
def create_previous_views(
944992
*, config: dict[str, object], database: str, names: tuple[str, ...], prefix: str
945993
) -> None:

‎tests/e2e/src/sqlbuild/cli/commands/main/clickhouse/test_clickhouse_recall.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
)
3333
from tests.e2e.src.sqlbuild.cli.commands.main.clickhouse.helpers import (
3434
FIRST_RELEASE_EDITS,
35+
RECALL_SCHEMA_VERSION,
3536
age_recorded_invocations,
3637
age_stored_artifacts,
3738
apply_printed_ddl,
@@ -903,7 +904,7 @@ def test_given_a_large_store_when_filtering_a_view_then_the_filter_reaches_the_t
903904
description="views of an older version are replaced when its version row expired",
904905
stale_view="SELECT invocation_id, statement_id FROM {database}.recall_events",
905906
expected_statement_columns=((1,),),
906-
expected_version=((4,),),
907+
expected_version=((RECALL_SCHEMA_VERSION,),),
907908
),
908909
],
909910
ids=lambda case: case.description,
@@ -1039,12 +1040,12 @@ def test_given_a_newer_store_whose_version_row_expired_when_an_older_writer_buil
10391040
ClickHouseRecallVersionRefreshTestCase(
10401041
description="a version row past half the retention is recorded again",
10411042
row_age_days=20,
1042-
expected_rows=((2, 3, 1),),
1043+
expected_rows=((2, RECALL_SCHEMA_VERSION, 1),),
10431044
),
10441045
ClickHouseRecallVersionRefreshTestCase(
10451046
description="a recent version row is left as it is",
10461047
row_age_days=1,
1047-
expected_rows=((1, 3, 0),),
1048+
expected_rows=((1, RECALL_SCHEMA_VERSION, 0),),
10481049
),
10491050
],
10501051
ids=lambda case: case.description,

‎tests/e2e/src/sqlbuild/cli/commands/main/clickhouse/test_clickhouse_recall_setup.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
ClickHouseRecallStaleViewsTestCase,
1616
)
1717
from tests.e2e.src.sqlbuild.cli.commands.main.clickhouse.helpers import (
18+
RECALL_SCHEMA_VERSION,
1819
apply_printed_ddl,
1920
create_previous_views,
2021
drop_database,
@@ -197,15 +198,15 @@ def test_given_a_missing_database_when_the_writer_may_not_create_it_then_the_sta
197198
writer_privileges="ALL",
198199
expected_notices=0,
199200
expected_stale_views=((0,),),
200-
expected_version=((4,),),
201+
expected_version=((RECALL_SCHEMA_VERSION,),),
201202
),
202203
ClickHouseRecallStaleViewsTestCase(
203204
description="previous views recorded as current are replaced by an administrator",
204205
deleted_version_rows="0",
205206
writer_privileges="ALL",
206207
expected_notices=0,
207208
expected_stale_views=((0,),),
208-
expected_version=((4,),),
209+
expected_version=((RECALL_SCHEMA_VERSION,),),
209210
),
210211
ClickHouseRecallStaleViewsTestCase(
211212
description="previous views without a version row make a SELECT, INSERT writer warn",
@@ -374,7 +375,7 @@ def test_given_a_writer_that_may_create_only_the_database_when_building_then_bot
374375
dropped_column=("recall_invocations", "argv_digest"),
375376
expected_columns=((1,),),
376377
expected_stale_views=((0,),),
377-
expected_version=((4,),),
378+
expected_version=((RECALL_SCHEMA_VERSION,),),
378379
),
379380
],
380381
ids=lambda case: case.description,

‎tests/e2e/src/sqlbuild/cli/commands/main/clickhouse/test_clickhouse_recall_views.py‎

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
ClickHouseRecallViewEquivalenceTestCase,
1818
)
1919
from tests.e2e.src.sqlbuild.cli.commands.main.clickhouse.helpers import (
20+
RECALL_SCHEMA_VERSION,
2021
RECALL_VIEWS,
22+
column_names,
2123
create_previous_views,
2224
described,
25+
described_except,
2326
differing_rows,
2427
duplicate_recall_rows,
2528
execute_clickhouse_sql,
@@ -206,6 +209,19 @@ def test_given_a_reader_when_querying_then_pinned_settings_apply_unless_it_may_n
206209
["failed"],
207210
["running"],
208211
],
212+
expected_added_columns=(
213+
(
214+
("origin", "Nullable(String)"),
215+
("command_mode", "Nullable(String)"),
216+
("integration", "Nullable(String)"),
217+
("integration_job", "Nullable(String)"),
218+
("integration_run_id", "Nullable(String)"),
219+
("integration_retry", "Nullable(Int64)"),
220+
),
221+
(),
222+
(),
223+
(),
224+
),
209225
),
210226
],
211227
ids=lambda case: case.description,
@@ -230,22 +246,40 @@ def test_given_representative_invocations_when_views_are_rewritten_then_rows_and
230246
statuses: list[list[object]] = recall_rows(
231247
project_dir, "SELECT status FROM invocations ORDER BY status"
232248
)
249+
previous_columns: list[tuple[str, ...]] = [
250+
column_names(
251+
config=clickhouse_e2e_config, relation=f"{recall_database}.previous_{view}"
252+
)
253+
for view in test_case.replaced_views
254+
]
233255
against_previous: list[int] = [
234256
differing_rows(
235257
config=clickhouse_e2e_config,
236258
left=f"{recall_database}.{view}",
237259
right=f"{recall_database}.previous_{view}",
238260
settings={"join_use_nulls": 1},
261+
columns=columns,
262+
)
263+
for view, columns in zip(test_case.replaced_views, previous_columns, strict=True)
264+
]
265+
compared: list[tuple[tuple[tuple[object, ...], ...], tuple[tuple[object, ...], ...]]] = [
266+
described_except(
267+
config=clickhouse_e2e_config,
268+
relation=f"{recall_database}.{view}",
269+
previous=f"{recall_database}.previous_{view}",
239270
)
240271
for view in test_case.replaced_views
241272
]
242273
types: list[bool] = [
243-
described(config=clickhouse_e2e_config, relation=f"{recall_database}.{view}")
274+
kept
244275
== described(
245276
config=clickhouse_e2e_config, relation=f"{recall_database}.previous_{view}"
246277
)
247-
for view in test_case.replaced_views
278+
for view, (kept, _) in zip(test_case.replaced_views, compared, strict=True)
248279
]
280+
added: tuple[tuple[tuple[object, ...], ...], ...] = tuple(
281+
added_columns for _, added_columns in compared
282+
)
249283
finally:
250284
os.killpg(running.pid, signal.SIGKILL)
251285
_ = running.wait(timeout=30)
@@ -277,8 +311,9 @@ def test_given_representative_invocations_when_views_are_rewritten_then_rows_and
277311
left=f"{recall_database}.{view}",
278312
right=f"{recall_database}.previous_{view}",
279313
settings={"join_use_nulls": 1},
314+
columns=columns,
280315
)
281-
for view in test_case.replaced_views
316+
for view, columns in zip(test_case.replaced_views, previous_columns, strict=True)
282317
]
283318
counts_with_duplicates: list[bool] = [
284319
fetch_clickhouse_rows(
@@ -293,6 +328,7 @@ def test_given_representative_invocations_when_views_are_rewritten_then_rows_and
293328
assert statuses == test_case.expected_statuses
294329
assert against_previous == [0 for _ in test_case.replaced_views]
295330
assert types == [True for _ in test_case.replaced_views]
331+
assert added == test_case.expected_added_columns
296332
assert without_join_nulls == [0 for _ in test_case.all_views]
297333
assert with_duplicates == [0 for _ in test_case.all_views]
298334
assert previous_with_duplicates == [0 for _ in test_case.replaced_views]
@@ -354,9 +390,9 @@ def test_given_one_invocation_lookup_when_planned_then_each_table_is_read_once_b
354390
expected_ddl_fragments=(
355391
"CREATE OR REPLACE VIEW `{database}`.`invocations`",
356392
"CREATE OR REPLACE VIEW `{database}`.`statements`",
357-
"SELECT 'schema', 'schema_version', '4'",
393+
f"SELECT 'schema', 'schema_version', '{RECALL_SCHEMA_VERSION}'",
358394
),
359-
expected_version=((4,),),
395+
expected_version=((RECALL_SCHEMA_VERSION,),),
360396
),
361397
],
362398
ids=lambda case: case.description,

0 commit comments

Comments
 (0)