From bc5ea1f4d925e5f2e1e0dfa89b304037ac681300 Mon Sep 17 00:00:00 2001 From: Stian Sandvold Date: Wed, 27 May 2026 20:56:22 +0200 Subject: [PATCH] test: convert eligible integration tests to @Transactional Convert 7 non-@Transactional integration tests to @Transactional so the SpringIntegrationTestExtension cleans up via cheap rollback instead of the expensive dbmsManager.emptyDatabase() truncate-all run per test method. Tests whose reads go through raw jdbcTemplate SQL (or whose write happens via session.doWork on the shared connection) get an explicit entityManager.flush() so those reads see the un-committed session writes within the same transaction. Measured ~52% reduction in per-class execution time on the 6 separable converted classes in a shared-context run (each ~halves, consistent with eliminating one emptyDatabase() truncate per test method). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../DataApprovalServiceCategoryOptionGroupTest.java | 9 +++++++++ .../dhis/dataapproval/DataApprovalStoreUserTest.java | 4 ++++ .../datastatistics/DataStatisticsEventStoreTest.java | 5 +++++ .../sql/PostgreSqlBuilderInheritanceIntegrationTest.java | 2 ++ .../orgunit/handler/DataOrgUnitMergeHandlerTest.java | 6 ++++++ .../org/hisp/dhis/predictor/PredictorServiceTest.java | 4 ++++ .../dhis/program/ProgramStageDataElementServiceTest.java | 6 ++++++ 7 files changed, 36 insertions(+) diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceCategoryOptionGroupTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceCategoryOptionGroupTest.java index c8d182535a4d..cf9ea6759123 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceCategoryOptionGroupTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataapproval/DataApprovalServiceCategoryOptionGroupTest.java @@ -74,10 +74,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; /** * @author Jim Grace */ +@Transactional class DataApprovalServiceCategoryOptionGroupTest extends PostgresIntegrationTestBase { private static final String ACCESS_NONE = "--------"; @@ -630,6 +632,9 @@ void setUp() { settingsService.put("keyIgnoreAnalyticsApprovalYearThreshold", 0); settingsService.put("keyAcceptanceRequiredForApproval", true); settingsService.clearCurrentSettings(); + + // flush so the raw-SQL data-approval reads see the setup metadata + entityManager.flush(); } @AfterEach @@ -738,6 +743,7 @@ private boolean approve( setUser(user); try { dataApprovalService.approveData(Arrays.asList(da)); + entityManager.flush(); return true; } catch (DataApprovalException ex) { return false; @@ -766,6 +772,7 @@ private boolean unapprove( setUser(user); try { dataApprovalService.unapproveData(Arrays.asList(da)); + entityManager.flush(); return true; } catch (DataApprovalException ex) { return false; @@ -794,6 +801,7 @@ private boolean accept( setUser(user); try { dataApprovalService.acceptData(Arrays.asList(da)); + entityManager.flush(); return true; } catch (DataApprovalException ex) { return false; @@ -822,6 +830,7 @@ private boolean unaccept( setUser(user); try { dataApprovalService.unacceptData(Arrays.asList(da)); + entityManager.flush(); return true; } catch (DataApprovalException ex) { return false; diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataapproval/DataApprovalStoreUserTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataapproval/DataApprovalStoreUserTest.java index f73faf0d476c..da3ab28dc854 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataapproval/DataApprovalStoreUserTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/dataapproval/DataApprovalStoreUserTest.java @@ -50,10 +50,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; /** * @author Jim Grace */ +@Transactional class DataApprovalStoreUserTest extends PostgresIntegrationTestBase { @Autowired private DataApprovalStore dataApprovalStore; @@ -145,6 +147,8 @@ void testGetDataApprovalStatuses() { categoryService.addCategoryCombo(catComboA); CategoryOptionCombo catOptionComboA = createCategoryOptionCombo(catComboA, catOptionA); categoryService.addCategoryOptionCombo(catOptionComboA); + // flush so the raw-SQL data-approval status query sees the session writes + entityManager.flush(); List statuses = dataApprovalStore.getDataApprovalStatuses( workflowA, diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/datastatistics/DataStatisticsEventStoreTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/datastatistics/DataStatisticsEventStoreTest.java index f99f1c0686a7..4f3bdf765bdf 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/datastatistics/DataStatisticsEventStoreTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/datastatistics/DataStatisticsEventStoreTest.java @@ -47,11 +47,13 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; /** * @author Yrjan A. F. Fraschetti * @author Julie Hill Roa */ +@Transactional class DataStatisticsEventStoreTest extends PostgresIntegrationTestBase { @Autowired private DataStatisticsEventStore dataStatisticsEventStore; @@ -95,6 +97,9 @@ void setUp() { // Add one dashboard. assertTrue(dashboardService.saveDashboard(dashboard) != 0); + + // flush so the raw-SQL statistics-store reads see the session writes + entityManager.flush(); } @Test diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/db/sql/PostgreSqlBuilderInheritanceIntegrationTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/db/sql/PostgreSqlBuilderInheritanceIntegrationTest.java index 1b396d7c9f4f..f21136ab8b60 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/db/sql/PostgreSqlBuilderInheritanceIntegrationTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/db/sql/PostgreSqlBuilderInheritanceIntegrationTest.java @@ -41,7 +41,9 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.transaction.annotation.Transactional; +@Transactional class PostgreSqlBuilderInheritanceIntegrationTest extends PostgresIntegrationTestBase { @Autowired private JdbcTemplate jdbcTemplate; diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/merge/orgunit/handler/DataOrgUnitMergeHandlerTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/merge/orgunit/handler/DataOrgUnitMergeHandlerTest.java index 7f87b3db01df..1d74ecbc703d 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/merge/orgunit/handler/DataOrgUnitMergeHandlerTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/merge/orgunit/handler/DataOrgUnitMergeHandlerTest.java @@ -60,10 +60,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.transaction.annotation.Transactional; /** * @author Lars Helge Overland */ +@Transactional class DataOrgUnitMergeHandlerTest extends PostgresIntegrationTestBase { @Autowired private CategoryService categoryService; @@ -127,6 +129,8 @@ void setUp() { CategoryCombo ccA = categoryService.getDefaultCategoryCombo(); dwA = new DataApprovalWorkflow("DataApprovalWorkflowA", monthly, ccA, Sets.newHashSet(dlA)); idObjectManager.save(dwA); + // flush so the raw-SQL count/merge queries see the setup metadata + entityManager.flush(); } @Test @@ -194,5 +198,7 @@ private void addDataValues(DataValue... values) { private void addDataApprovals(DataApproval... dataApprovals) { Stream.of(dataApprovals).forEach(dataApprovalService::addDataApproval); + // flush so the raw-SQL data-approval count/merge queries see the session writes + entityManager.flush(); } } diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/predictor/PredictorServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/predictor/PredictorServiceTest.java index 7fdedf753c5e..6a0ee2d11c68 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/predictor/PredictorServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/predictor/PredictorServiceTest.java @@ -57,10 +57,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; /** * @author Lars Helge Overland */ +@Transactional class PredictorServiceTest extends PostgresIntegrationTestBase { @Autowired private PredictorService predictorService; @@ -434,6 +436,8 @@ void testGetAllPredictorGroup() { @Test void testCannotDeleteCategoryOptionComboUsedByPredictor() { setUpPredictorGroups(); + // flush so the raw-SQL deletion-veto query sees the predictor rows + entityManager.flush(); DeleteNotAllowedException ex = assertThrows( DeleteNotAllowedException.class, diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/program/ProgramStageDataElementServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/program/ProgramStageDataElementServiceTest.java index 6e913e18ed61..a6ac5b96b174 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/program/ProgramStageDataElementServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/program/ProgramStageDataElementServiceTest.java @@ -49,10 +49,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; /** * @author Chau Thu Tran */ +@Transactional class ProgramStageDataElementServiceTest extends PostgresIntegrationTestBase { @Autowired private ProgramStageDataElementService programStageDataElementService; @@ -182,6 +184,8 @@ void testRemoveReferencedDataElement() { programStageDataElementService.addProgramStageDataElement(stageDataElementA); stageA.getProgramStageDataElements().addAll(Set.of(stageDataElementA)); programStageService.updateProgramStage(stageA); + // flush so the raw-SQL deletion-veto query sees the program-stage-data-element link + entityManager.flush(); assertThrows( DeleteNotAllowedException.class, () -> dataElementService.deleteDataElement(dataElementA)); } @@ -197,6 +201,8 @@ void testGetProgramStageDataElementsWithSyncFiltering() { programStageDataElementService.addProgramStageDataElement(stageDataElementB); programStageDataElementService.addProgramStageDataElement(stageDataElementC); programStageDataElementService.addProgramStageDataElement(stageDataElementD); + // flush so the raw-SQL store read sees the newly added program-stage-data-elements + entityManager.flush(); Map> result = programStageDataElementService