fix(lineage): 3 e2e CI failures — Liquibase XSD + JSONB ?-op + size cap
Phase 4 e2e suite (skipped в local mvn verify, гонится только на CI с testcontainers) поймал 3 issues. Все исправлены, e2e теперь 20/20 PASS локально (Postgres testcontainer): - AuthE2ETest 6/6 - AutoDeriveGeometryE2ETest 6/6 - BitemporalE2ETest 4/4 - OutboxKafkaE2ETest 1/1 - SmokeE2ETest 1/1 - WebhookE2ETest 2/2 Fix #1 — Liquibase XSD ordering (0016 changeset): - <comment> должен идти ПОСЛЕ <preConditions>. Liquibase XSD строгий: preConditions → comment → operations. - "Invalid content was found starting with element preConditions" на startup → ApplicationContext fail → весь webserver не поднимается. Fix #2 — JSONB ?-operator vs JDBC parameter substitution (0016): - Postgres JDBC PreparedStatement обрабатывает любой `?` как $N placeholder. SQL "prop.value ? 'x-references'" → "prop.value $1 'x-references'" → "syntax error at or near $1". Same для regex с $ anchor. - Replaced `?` operator на эквивалент `-> 'key' IS NOT NULL`, drop-or-replace regex anchors на `LIKE '%.%'` (split_part guards malformed values gracefully). - Comment в migration документирует ловушку для будущих changesets. Fix #3 — service size cap mismatch (LineageIndexService): - CascadeCloseService.evaluatePlan вызывает findRecordDependents с size=CASCADE_MAX_PER_REQUEST=500. Но findRecordDependents enforced size 1..200 → IllegalArgumentException → 400 на DELETE record path. - Bumped service cap до 500. Controller отдельно держит public cap=200 (UI не нуждается в больше). - Test updated: expects "size 1..500". Lessons learned: - Local pre-push discipline должна включать `mvn -P e2e` для миграций. Не запустил, потому что: e2e требует Docker, медленнее, не было в routine. Now corrected — будущие migration changes будут идти через e2e check. - Liquibase JDBC рабочий принцип: SQL прогоняется через PreparedStatement → любой `?` или `$N` ловится. Documenting в migration comment. Verify: - mvn -pl ordinis-app -am -P e2e test: BUILD SUCCESS, 20/20 PASS (28s). - mvn test: 106 unit tests + 20 e2e — все green.
This commit is contained in:
+12
-4
@@ -29,7 +29,6 @@
|
||||
pure JSONB indexing (jsonb_each + ?-marker) — не ожидаем больше.
|
||||
-->
|
||||
<changeSet id="0016-record-dependents-index-create" author="ordinis">
|
||||
<comment>MV record_dependents_index: precomputed reverse FK</comment>
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<sqlCheck expectedResult="1">
|
||||
@@ -37,6 +36,7 @@
|
||||
</sqlCheck>
|
||||
</not>
|
||||
</preConditions>
|
||||
<comment>MV record_dependents_index: precomputed reverse FK</comment>
|
||||
<sql splitStatements="false"><![CDATA[
|
||||
CREATE MATERIALIZED VIEW record_dependents_index AS
|
||||
SELECT
|
||||
@@ -58,9 +58,17 @@
|
||||
FROM dictionary_records r
|
||||
JOIN dictionary_definitions src_def ON src_def.id = r.dictionary_id
|
||||
JOIN LATERAL jsonb_each(src_def.schema_json -> 'properties') AS prop(key, value) ON true
|
||||
WHERE prop.value ? 'x-references'
|
||||
AND prop.value->>'x-references' ~ '^[a-zA-Z_][a-zA-Z0-9_]*\.[a-zA-Z_][a-zA-Z0-9_]*$'
|
||||
AND r.data ? prop.key
|
||||
-- Note: избегаем JSONB ?-operator — Liquibase прогоняет SQL через
|
||||
-- PreparedStatement, который любой ? интерпретирует как $N
|
||||
-- placeholder → "syntax error at $1". Заменяем на эквиваленты:
|
||||
-- prop.value ? 'x-references' → prop.value -> 'x-references' IS NOT NULL
|
||||
-- r.data ? prop.key → r.data -> prop.key IS NOT NULL
|
||||
-- Регекс с $ anchor по той же причине заменён на LIKE — split_part'ы
|
||||
-- ниже сами справятся с malformed (вернут empty strings, никогда не
|
||||
-- match-ятся с real records).
|
||||
WHERE prop.value -> 'x-references' IS NOT NULL
|
||||
AND prop.value->>'x-references' LIKE '%.%'
|
||||
AND r.data -> prop.key IS NOT NULL
|
||||
AND jsonb_typeof(r.data -> prop.key) = 'string'
|
||||
WITH NO DATA;
|
||||
]]></sql>
|
||||
|
||||
+5
-2
@@ -209,8 +209,11 @@ public class LineageIndexService {
|
||||
int page,
|
||||
int size) {
|
||||
if (page < 0) throw new IllegalArgumentException("page must be >= 0");
|
||||
if (size < 1 || size > 200) {
|
||||
throw new IllegalArgumentException("size must be 1..200, got " + size);
|
||||
// Service-level cap = 500 (CascadeCloseService запрашивает up to
|
||||
// CASCADE_MAX_PER_REQUEST). Controller separately enforces 200 cap для
|
||||
// public endpoint — UI не нуждается в больше.
|
||||
if (size < 1 || size > 500) {
|
||||
throw new IllegalArgumentException("size must be 1..500, got " + size);
|
||||
}
|
||||
|
||||
Optional<DictionaryDefinition> targetOpt = definitionRepository.findByName(targetDictName);
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ class LineageIndexServiceTest {
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("size");
|
||||
assertThatThrownBy(() -> service.findRecordDependents(
|
||||
"d", "k", Set.of(DataScope.PUBLIC), 0, 201))
|
||||
"d", "k", Set.of(DataScope.PUBLIC), 0, 501))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("size");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user