test(deploy): scope schema ITs to current_schema + clear deployments FK in teardown
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m59s
CI / docker (push) Successful in 1m5s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 38s

Surface from the Task 0 testcontainers.reuse enable: when the same Postgres
container is reused across `mvn verify` runs, Flyway migrates both `public`
and `tenant_default` schemas (the app.yml default URL uses
?currentSchema=tenant_default; AbstractPostgresIT overrides to public).
Schema-introspection assertions saw duplicate rows/indexes/enums.

Plus: OutboundConnectionAdminControllerIT's AfterEach couldn't delete its
test users because sibling deployment ITs (Task 4) left deployments.created_by
references — FK blocks the DELETE. Clear referencing deployments first.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-23 14:06:56 +02:00
parent d192f6b57c
commit e36c82c4db
3 changed files with 25 additions and 8 deletions

View File

@@ -52,10 +52,14 @@ class SchemaBootstrapIT extends AbstractPostgresIT {
@Test @Test
void alerting_enums_exist() { void alerting_enums_exist() {
// Scope to current schema's namespace — Testcontainers reuse can otherwise
// expose enums from a previous run's tenant_default schema alongside public.
var enums = jdbcTemplate.queryForList(""" var enums = jdbcTemplate.queryForList("""
SELECT typname FROM pg_type SELECT t.typname FROM pg_type t
WHERE typname IN ('severity_enum','condition_kind_enum','alert_state_enum', JOIN pg_namespace n ON n.oid = t.typnamespace
'target_kind_enum','notification_status_enum') WHERE t.typname IN ('severity_enum','condition_kind_enum','alert_state_enum',
'target_kind_enum','notification_status_enum')
AND n.nspname = current_schema()
""", String.class); """, String.class);
assertThat(enums).containsExactlyInAnyOrder( assertThat(enums).containsExactlyInAnyOrder(
"severity_enum", "condition_kind_enum", "alert_state_enum", "severity_enum", "condition_kind_enum", "alert_state_enum",
@@ -86,6 +90,7 @@ class SchemaBootstrapIT extends AbstractPostgresIT {
SELECT column_name FROM information_schema.columns SELECT column_name FROM information_schema.columns
WHERE table_name = 'alert_instances' WHERE table_name = 'alert_instances'
AND column_name IN ('read_at','deleted_at') AND column_name IN ('read_at','deleted_at')
AND table_schema = current_schema()
""", String.class); """, String.class);
assertThat(cols).containsExactlyInAnyOrder("read_at", "deleted_at"); assertThat(cols).containsExactlyInAnyOrder("read_at", "deleted_at");
} }
@@ -96,13 +101,16 @@ class SchemaBootstrapIT extends AbstractPostgresIT {
SELECT COUNT(*)::int FROM pg_indexes SELECT COUNT(*)::int FROM pg_indexes
WHERE indexname = 'alert_instances_open_rule_uq' WHERE indexname = 'alert_instances_open_rule_uq'
AND tablename = 'alert_instances' AND tablename = 'alert_instances'
AND schemaname = current_schema()
""", Integer.class); """, Integer.class);
assertThat(count).isEqualTo(1); assertThat(count).isEqualTo(1);
Boolean isUnique = jdbcTemplate.queryForObject(""" Boolean isUnique = jdbcTemplate.queryForObject("""
SELECT indisunique FROM pg_index SELECT indisunique FROM pg_index
JOIN pg_class ON pg_class.oid = pg_index.indexrelid JOIN pg_class c ON c.oid = pg_index.indexrelid
WHERE pg_class.relname = 'alert_instances_open_rule_uq' JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'alert_instances_open_rule_uq'
AND n.nspname = current_schema()
""", Boolean.class); """, Boolean.class);
assertThat(isUnique).isTrue(); assertThat(isUnique).isTrue();
} }

View File

@@ -34,6 +34,10 @@ class OutboundConnectionAdminControllerIT extends AbstractPostgresIT {
@org.junit.jupiter.api.AfterEach @org.junit.jupiter.api.AfterEach
void cleanupRows() { void cleanupRows() {
jdbcTemplate.update("DELETE FROM outbound_connections WHERE tenant_id = 'default'"); jdbcTemplate.update("DELETE FROM outbound_connections WHERE tenant_id = 'default'");
// Clear deployments.created_by for our test users — sibling ITs
// (DeploymentControllerIT etc.) may have left rows that FK-block user deletion.
jdbcTemplate.update(
"DELETE FROM deployments WHERE created_by IN ('test-admin','test-operator','test-viewer')");
jdbcTemplate.update("DELETE FROM users WHERE user_id IN ('test-admin','test-operator','test-viewer')"); jdbcTemplate.update("DELETE FROM users WHERE user_id IN ('test-admin','test-operator','test-viewer')");
} }

View File

@@ -16,10 +16,13 @@ class V4DeploymentCreatedByMigrationIT extends AbstractPostgresIT {
@Test @Test
void created_by_column_exists_with_correct_type_and_nullable() { void created_by_column_exists_with_correct_type_and_nullable() {
// Scope to current schema — Testcontainers reuse can otherwise leave
// a previous run's tenant_default schema visible alongside public.
List<Map<String, Object>> cols = jdbc.queryForList( List<Map<String, Object>> cols = jdbc.queryForList(
"SELECT column_name, data_type, is_nullable " + "SELECT column_name, data_type, is_nullable " +
"FROM information_schema.columns " + "FROM information_schema.columns " +
"WHERE table_name = 'deployments' AND column_name = 'created_by'" "WHERE table_name = 'deployments' AND column_name = 'created_by' " +
" AND table_schema = current_schema()"
); );
assertThat(cols).hasSize(1); assertThat(cols).hasSize(1);
assertThat(cols.get(0)).containsEntry("data_type", "text"); assertThat(cols.get(0)).containsEntry("data_type", "text");
@@ -30,7 +33,8 @@ class V4DeploymentCreatedByMigrationIT extends AbstractPostgresIT {
void created_by_index_exists() { void created_by_index_exists() {
Integer count = jdbc.queryForObject( Integer count = jdbc.queryForObject(
"SELECT count(*)::int FROM pg_indexes " + "SELECT count(*)::int FROM pg_indexes " +
"WHERE tablename = 'deployments' AND indexname = 'idx_deployments_created_by'", "WHERE tablename = 'deployments' AND indexname = 'idx_deployments_created_by' " +
" AND schemaname = current_schema()",
Integer.class Integer.class
); );
assertThat(count).isEqualTo(1); assertThat(count).isEqualTo(1);
@@ -45,7 +49,8 @@ class V4DeploymentCreatedByMigrationIT extends AbstractPostgresIT {
"WHERE tc.table_name = 'deployments' " + "WHERE tc.table_name = 'deployments' " +
" AND tc.constraint_type = 'FOREIGN KEY' " + " AND tc.constraint_type = 'FOREIGN KEY' " +
" AND ccu.table_name = 'users' " + " AND ccu.table_name = 'users' " +
" AND ccu.column_name = 'user_id'", " AND ccu.column_name = 'user_id' " +
" AND tc.table_schema = current_schema()",
Integer.class Integer.class
); );
assertThat(count).isGreaterThanOrEqualTo(1); assertThat(count).isGreaterThanOrEqualTo(1);