DatabaseAuditTestConfiguration.java
package io.github.databaseaudits.spring.boot;
import javax.sql.DataSource;
import org.hibernate.cfg.JdbcSettings;
import org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import io.github.databaseaudits.capture.SqlCapturingStatementInspector;
import io.github.databaseaudits.spring.boot.assertion.DatabaseAuditAssertions;
import jakarta.persistence.EntityManagerFactory;
/**
* Wires the database-audit suite for a module's integration-test context. The
* core module is dependency-injection-framework-neutral (its classes carry no
* Spring annotations), so this configuration builds a {@link DatabaseAuditSuite}
* from the context's primary {@link DataSource} and {@link EntityManagerFactory}
* and, through an {@link AuditAssertionRegistrar}, registers its
* {@code *AuditAssertion}s — and the {@link DatabaseAuditAssertions} facade — as
* beans. It also registers the suite's {@link SqlCapturingStatementInspector} as
* Hibernate's {@code StatementInspector}, so the runtime audits see every
* statement the repositories run.
*
* <p>
* A single {@code @Import(DatabaseAuditTestConfiguration.class)} on your
* test-infrastructure base class is enough — no separate component-scan setup
* required. (Assumes a JPA + Liquibase + DataSource context, which the DB
* integration tests already boot.) The platform is auto-detected from the
* {@link DataSource}; the PostgreSQL-only requirements of the plan-based audits
* (including the {@code preferQueryMode=simple} connection property) are
* described on {@link DatabaseAuditSuite}.
*
* <p>
* This is the default, single-datasource entry point: it audits <em>one</em>
* datasource, resolving the {@link DataSource}/{@link EntityManagerFactory}
* <em>by type</em> — Spring's autowiring selects the single, {@code @Primary}, or
* conventionally-named ({@code dataSource}/{@code entityManagerFactory}) candidate.
* Several peer datasources it cannot disambiguate make importing this configuration
* fail fast with Spring's "expected single matching bean but found 2". To audit a
* <em>specific</em> datasource <em>by name</em> instead (typically a non-primary one
* among peers), use the archetype-generated {@code DatabaseAudit<Name>TestConfiguration}
* — a {@code @Qualifier}-based mirror of this class — rather than this one. That does
* not make this class obsolete: it stays the entry point for auditing any single or
* {@code @Primary} datasource. See the integration usage docs.
*/
@TestConfiguration(proxyBeanMethods = false)
public class DatabaseAuditTestConfiguration {
/**
* Creates the configuration; the audit beans are registered by the
* {@code @Bean} methods and the {@link AuditAssertionRegistrar}.
*/
public DatabaseAuditTestConfiguration() {
}
/**
* The SQL capturer the runtime audits read. Marked {@code @Primary} so this
* configuration's by-type injections of it still resolve when an application
* adds a second capturer for another datasource's suite.
*
* @return the shared SQL capturer.
*/
@Bean
@Primary
SqlCapturingStatementInspector sqlCapturingStatementInspector() {
return new SqlCapturingStatementInspector();
}
@Bean
HibernatePropertiesCustomizer sqlCaptureHibernatePropertiesCustomizer(
final SqlCapturingStatementInspector sqlCapturer) {
// Register the Spring bean itself, so the inspector and the injected
// audits share one capture instance.
return properties -> properties.put(JdbcSettings.STATEMENT_INSPECTOR,
sqlCapturer);
}
/**
* The audit suite for the context's primary datasource. On PostgreSQL the
* injected {@link DataSource} must connect with {@code preferQueryMode=simple}
* — see {@link DatabaseAuditSuite}. Marked {@code @Primary} so this
* configuration's by-type injections of the suite still resolve when an
* application registers another {@link DatabaseAuditSuite} for a second
* datasource.
*
* @param dataSource
* the primary datasource to audit.
* @param entityManagerFactory
* the primary entity-manager factory whose
* mappings the JPA audit validates against the
* schema.
* @param sqlCapturer
* the shared SQL capturer the runtime audits
* read.
* @return the wired audit suite.
*/
@Bean
@Primary
DatabaseAuditSuite databaseAuditSuite(final DataSource dataSource,
final EntityManagerFactory entityManagerFactory,
final SqlCapturingStatementInspector sqlCapturer) {
return new DatabaseAuditSuite(dataSource, entityManagerFactory,
sqlCapturer);
}
/**
* Registers every {@code *AuditAssertion} the suite wires — and the
* {@link DatabaseAuditAssertions} facade — as a bean under its concrete type,
* replacing one hand-written {@code @Bean} method per audit. Registered as
* {@code primary} with no name prefix, so these beans are the default an
* unqualified by-type injection resolves to and keep the conventional bean
* names an application may already reference. Consumers {@code @Autowired}
* the assertion bean they need and call {@code assertClean(...)}.
*
* @param suite
* the primary datasource's audit suite.
* @return the registrar that publishes the suite's assertions as beans.
*/
@Bean
AuditAssertionRegistrar auditAssertionRegistrar(
final DatabaseAuditSuite suite) {
return new AuditAssertionRegistrar(suite, "", true);
}
}