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
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("""
SELECT typname FROM pg_type
WHERE typname IN ('severity_enum','condition_kind_enum','alert_state_enum',
SELECT t.typname FROM pg_type t
JOIN pg_namespace n ON n.oid = t.typnamespace
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);
assertThat(enums).containsExactlyInAnyOrder(
"severity_enum", "condition_kind_enum", "alert_state_enum",
@@ -86,6 +90,7 @@ class SchemaBootstrapIT extends AbstractPostgresIT {
SELECT column_name FROM information_schema.columns
WHERE table_name = 'alert_instances'
AND column_name IN ('read_at','deleted_at')
AND table_schema = current_schema()
""", String.class);
assertThat(cols).containsExactlyInAnyOrder("read_at", "deleted_at");
}
@@ -96,13 +101,16 @@ class SchemaBootstrapIT extends AbstractPostgresIT {
SELECT COUNT(*)::int FROM pg_indexes
WHERE indexname = 'alert_instances_open_rule_uq'
AND tablename = 'alert_instances'
AND schemaname = current_schema()
""", Integer.class);
assertThat(count).isEqualTo(1);
Boolean isUnique = jdbcTemplate.queryForObject("""
SELECT indisunique FROM pg_index
JOIN pg_class ON pg_class.oid = pg_index.indexrelid
WHERE pg_class.relname = 'alert_instances_open_rule_uq'
JOIN pg_class c ON c.oid = pg_index.indexrelid
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'alert_instances_open_rule_uq'
AND n.nspname = current_schema()
""", Boolean.class);
assertThat(isUnique).isTrue();
}

View File

@@ -34,6 +34,10 @@ class OutboundConnectionAdminControllerIT extends AbstractPostgresIT {
@org.junit.jupiter.api.AfterEach
void cleanupRows() {
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')");
}

View File

@@ -16,10 +16,13 @@ class V4DeploymentCreatedByMigrationIT extends AbstractPostgresIT {
@Test
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(
"SELECT column_name, data_type, is_nullable " +
"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.get(0)).containsEntry("data_type", "text");
@@ -30,7 +33,8 @@ class V4DeploymentCreatedByMigrationIT extends AbstractPostgresIT {
void created_by_index_exists() {
Integer count = jdbc.queryForObject(
"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
);
assertThat(count).isEqualTo(1);
@@ -45,7 +49,8 @@ class V4DeploymentCreatedByMigrationIT extends AbstractPostgresIT {
"WHERE tc.table_name = 'deployments' " +
" AND tc.constraint_type = 'FOREIGN KEY' " +
" 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
);
assertThat(count).isGreaterThanOrEqualTo(1);