Покрытие выросло с 1 до 6 e2e тестов через Testcontainers (Postgres+Kafka).
BitemporalE2ETest (4 тесты):
- createThenUpdate_keepsBothVersionsInHistory: v1+v2 в /history, oldValidTo == newValidFrom
- closeRecord_setsValidTo_andGetReturns404: после DELETE active=null, history живёт
- idempotencyKey_returnsCachedResponse_doesntDuplicate: повторный POST с тем
же Idempotency-Key → тот же id, count=1 в БД
- breakingSchemaChange_blockedOnUpdate: documents текущее поведение PUT
/api/v1/dictionaries/{name} с breaking schema (status < 500 = OK)
OutboxKafkaE2ETest (1 тест):
- POST record → outbox event в БД → poller публикует в Kafka → consumer
получает envelope с правильным dictionaryName/dataScope/payload.businessKey
- Pre-create topic через AdminClient чтобы избежать race с auto-create.
- ordinis.outbox.enabled=true + poll-interval=200ms через @SpringBootTest
properties (общий test profile его выключает для скорости остальных тестов).
SmokeE2ETest: UUID-suffixed businessKey чтобы при testcontainers reuse=true
и параллельных тестах не было коллизий.
Logging: outbox DEBUG для диагностики publish flow.
pom.xml: + awaitility для polling-based проверок.
Все 6 тестов зелёные: 1 smoke + 4 bitemporal + 1 outbox-kafka. Total ~16 sec
включая Spring context boot. Reuse=true ускоряет повторные прогоны.
Phase 1 e2e — proof framework работает:
- E2ESupport: Postgres 18 (postgis/postgis:18-3.6) + Kafka (cp-kafka 7.6.0)
через Testcontainers, reuse=true. db-init.sql создаёт postgis+btree_gist
расширения которые ожидает Liquibase 0001.
- application-test.yml: тушит cloud-config/vault/otel/outbox publishing,
включает Liquibase autoconfig. Auth disabled для упрощения.
- SmokeE2ETest: full e2e — POST dictionary → POST record → GET record →
проверка audit_log row. UUID-suffix в dictName для идемпотентности.
- master.xml: relativeToChangelogFile=true для всех include — иначе
Liquibase из ordinis-app classpath не находит changes/X.xml в JAR.
- pom.xml: testcontainers 1.21.3, surefire env DOCKER_HOST + DOCKER_API_VERSION
для macOS Docker Desktop.
Найден реальный prod-баг: audit_log.ip_address был INET, Hibernate JPA не
делает автоматический cast String→INET → INSERT падал. AuditLogger.write
обёрнут в try/catch, поэтому тихо съедал ошибку — на staging audit_log
оставался пустым после CRUD.
- 0012-audit-log-ipaddress-varchar.xml: ALTER COLUMN INET → VARCHAR(64)
- AuditLog entity: убрал columnDefinition="inet", length=64.
- Remove spring-cloud-starter-bootstrap (deprecated в SC 2024.x; используем
spring.config.import вместо bootstrap context)
- Profile-based config: dev отключает Cloud Config + Vault + OTel + JPA
auto-config для standalone smoke testing; k8s profile подключает реальную
инфру (vault + config server)
- Dockerfile: COPY всех модулей parent pom их видит при reactor
- Уберём spring-boot-maven-plugin из read-api/projection-writer пока нет main
Validated:
- mvn install all 11 modules: BUILD SUCCESS
- Spring Boot стартует за 2.7s в dev profile
- /actuator/health UP, /actuator/prometheus отдаёт http_server_requests + jvm
- HelloController отвечает на GET /