From 31e829fca94ab2a29f85f44e2ade351b588d1d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Helge=20=C3=98verland?= Date: Thu, 9 Jan 2025 14:40:36 +0100 Subject: [PATCH 1/6] test: Centralize creation of org units in test (#19630) --- .../organisationunit/OrganisationUnit.java | 8 +++ ...aQueryServiceDimensionItemKeywordTest.java | 22 ++++---- .../data/DimensionalObjectProviderTest.java | 12 ++--- .../handler/SchemeIdResponseMapperTest.java | 54 ++++++++----------- ...AbstractJdbcEventAnalyticsManagerTest.java | 2 +- ...isationUnitStructureResourceTableTest.java | 20 +++---- .../org/hisp/dhis/copy/CopyServiceTest.java | 4 +- .../dhis/query/DefaultQueryServiceTest.java | 3 +- ...ataSetRegistrationExchangeServiceTest.java | 5 +- .../DataValueSetImportValidatorTest.java | 3 +- .../attribute/GeoJsonAttributesCheckTest.java | 4 +- .../attribute/MetadataAttributeCheckTest.java | 6 +-- .../objectbundle/ObjectBundleHooksTest.java | 9 ++-- .../hooks/ProgramObjectBundleHookTest.java | 4 +- ...mStageWorkingListObjectBundleHookTest.java | 4 +- .../PredictionAnalyticsDataFetcherTest.java | 4 +- .../PredictionDataConsolidatorTest.java | 14 ++--- .../PredictionDataValueFetcherTest.java | 14 ++--- .../dhis/predictor/PredictionWriterTest.java | 4 +- .../VisualizationGridServiceTest.java | 5 +- .../acl/DefaultTrackerAccessManagerTest.java | 43 ++++++--------- .../export/OperationsParamsValidatorTest.java | 23 +------- .../EnrollmentOperationParamsMapperTest.java | 5 +- .../event/EventOperationParamsMapperTest.java | 29 ++++------ .../mappers/OrganisationUnitMapperTest.java | 9 ++-- .../mappers/TrackedEntityMapperTest.java | 3 +- .../validation/MessageFormatterTest.java | 3 +- .../enrollment/MetaValidatorTest.java | 10 ++-- .../event/DataValuesValidatorTest.java | 3 +- .../trackedentity/MetaValidatorTest.java | 6 +-- .../ValidationResultServiceTest.java | 3 +- .../java/org/hisp/dhis/test/TestBase.java | 26 ++++----- 32 files changed, 165 insertions(+), 199 deletions(-) diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java index a15fa029b590..2cce28d7cc7d 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java @@ -807,6 +807,14 @@ public Integer getHierarchyLevel() { return hierarchyLevel; } + /** + * Note that the {@code path} is mapped with the "property access" mode. This method is for unit + * testing purposes only. + */ + public void updatePath() { + setPath(getPath()); + } + /** Do not set directly. */ public void setHierarchyLevel(Integer hierarchyLevel) { this.hierarchyLevel = hierarchyLevel; diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DataQueryServiceDimensionItemKeywordTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DataQueryServiceDimensionItemKeywordTest.java index 622f2b45975f..51ebc5aa1ccd 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DataQueryServiceDimensionItemKeywordTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DataQueryServiceDimensionItemKeywordTest.java @@ -32,6 +32,7 @@ import static org.hamcrest.Matchers.is; import static org.hisp.dhis.common.DimensionalObject.PERIOD_DIM_ID; import static org.hisp.dhis.common.IdScheme.UID; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -142,7 +143,7 @@ public void setUp() { lenient().when(i18nManager.getI18n()).thenReturn(i18n); lenient().when(i18n.getString("LAST_12_MONTHS")).thenReturn("Last 12 months"); - rootOu = new OrganisationUnit("Sierra Leone"); + rootOu = createOrganisationUnit('A'); rootOu.setUid(CodeGenerator.generateUid()); rootOu.setCode("OU_525"); } @@ -164,7 +165,7 @@ void convertAnalyticsRequestWithOuLevelToDataQueryParam() { .thenReturn(getOrgUnitLevel(2, "level2UID", "District", null)); when(organisationUnitService.getOrganisationUnitLevelByLevelOrUid("2")).thenReturn(2); when(organisationUnitService.getOrganisationUnitsAtLevels(Mockito.anyList(), Mockito.anyList())) - .thenReturn(Lists.newArrayList(new OrganisationUnit(), new OrganisationUnit())); + .thenReturn(Lists.newArrayList(createOrganisationUnit('A'), createOrganisationUnit('B'))); rb.addOuFilter("LEVEL-2;ImspTQPwCqd"); rb.addDimension(concatenateUuid(DATA_ELEMENT_1, DATA_ELEMENT_2, DATA_ELEMENT_3)); @@ -199,7 +200,7 @@ void convertAnalyticsRequestWithMultipleOuLevelToDataQueryParam() { when(organisationUnitService.getOrganisationUnitLevelByLevelOrUid("3")).thenReturn(3); when(organisationUnitService.getOrganisationUnitLevelByLevelOrUid("2")).thenReturn(2); when(organisationUnitService.getOrganisationUnitsAtLevels(Mockito.anyList(), Mockito.anyList())) - .thenReturn(Lists.newArrayList(new OrganisationUnit(), new OrganisationUnit())); + .thenReturn(Lists.newArrayList(createOrganisationUnit('A'), createOrganisationUnit('B'))); rb.addOuFilter("LEVEL-2;LEVEL-3;ImspTQPwCqd"); rb.addDimension(concatenateUuid(DATA_ELEMENT_1, DATA_ELEMENT_2, DATA_ELEMENT_3)); @@ -240,9 +241,9 @@ void convertAnalyticsRequestWithIndicatorGroup() { when(idObjectManager.getObject(IndicatorGroup.class, UID, INDICATOR_GROUP_UID)) .thenReturn(indicatorGroup); when(idObjectManager.getObject(OrganisationUnit.class, UID, "goRUwCHPg1M")) - .thenReturn(new OrganisationUnit("aaa")); + .thenReturn(createOrganisationUnit('A')); when(idObjectManager.getObject(OrganisationUnit.class, UID, "fdc6uOvgoji")) - .thenReturn(new OrganisationUnit("bbb")); + .thenReturn(createOrganisationUnit('B')); rb.addOuFilter("goRUwCHPg1M;fdc6uOvgoji"); rb.addDimension("IN_GROUP-" + INDICATOR_GROUP_UID + ";cYeuwXTCPkU;Jtf34kNZhz"); @@ -343,7 +344,8 @@ void convertAnalyticsRequestWithOrgUnitLevelAsFilter() { assertNull(keywords.getKeyword("level2UID").getMetadataItem().getCode()); assertNotNull(keywords.getKeyword(rootOu.getUid())); - assertEquals("Sierra Leone", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); + assertEquals( + "OrganisationUnitA", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); assertEquals( rootOu.getCode(), keywords.getKeyword(rootOu.getUid()).getMetadataItem().getCode()); } @@ -403,7 +405,8 @@ void convertAnalyticsRequestWithOrgUnitLevelAndOrgUnitGroupAsFilter() { groupOu.getCode(), keywords.getKeyword(groupOu.getUid()).getMetadataItem().getCode()); assertNotNull(keywords.getKeyword(rootOu.getUid())); - assertEquals("Sierra Leone", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); + assertEquals( + "OrganisationUnitA", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); assertEquals( rootOu.getCode(), keywords.getKeyword(rootOu.getUid()).getMetadataItem().getCode()); } @@ -632,7 +635,7 @@ private void initOrgUnitGroup(String ouGroupUID) { when(idObjectManager.getObject(OrganisationUnit.class, UID, this.rootOu.getUid())) .thenReturn(rootOu); when(organisationUnitService.getOrganisationUnits(Mockito.anyList(), Mockito.anyList())) - .thenReturn(Lists.newArrayList(new OrganisationUnit(), new OrganisationUnit())); + .thenReturn(Lists.newArrayList(createOrganisationUnit('A'), createOrganisationUnit('B'))); } private void assertOrgUnitGroup(String ouGroupUID, DimensionalObject dimension) { @@ -644,7 +647,8 @@ private void assertOrgUnitGroup(String ouGroupUID, DimensionalObject dimension) assertEquals("CODE_001", keywords.getKeyword(ouGroupUID).getMetadataItem().getCode()); assertNotNull(keywords.getKeyword(rootOu.getUid())); - assertEquals("Sierra Leone", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); + assertEquals( + "OrganisationUnitA", keywords.getKeyword(rootOu.getUid()).getMetadataItem().getName()); assertEquals( rootOu.getCode(), keywords.getKeyword(rootOu.getUid()).getMetadataItem().getCode()); } diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DimensionalObjectProviderTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DimensionalObjectProviderTest.java index d0277d6514a5..24358bd39c2c 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DimensionalObjectProviderTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/DimensionalObjectProviderTest.java @@ -216,8 +216,8 @@ void testGetDimensionWhenDataDimensionsAreNotFound() { @Test void testGetOrgUnitDimensionWithNoLevelsNoGroup() { - OrganisationUnit level2Ou1 = createOrganisationUnit("Bo"); - OrganisationUnit level2Ou2 = createOrganisationUnit("Bombali"); + OrganisationUnit level2Ou1 = createOrganisationUnit('A'); + OrganisationUnit level2Ou2 = createOrganisationUnit('B'); OrganisationUnit ou1 = createOrganisationUnit('A'); OrganisationUnit ou2 = createOrganisationUnit('B'); List organisationUnits = @@ -253,10 +253,10 @@ void testGetOrgUnitDimensionWithNoLevelsNoGroup() { @Test void testGetOrgUnitDimensionWithWithLevelAndGroup() { OrganisationUnitGroup organisationUnitGroup = createOrganisationUnitGroup('A'); - OrganisationUnit level2Ou1 = createOrganisationUnit("Bo"); - OrganisationUnit level2Ou2 = createOrganisationUnit("Bombali"); - OrganisationUnit ou1 = createOrganisationUnit('A'); - OrganisationUnit ou2 = createOrganisationUnit('B'); + OrganisationUnit level2Ou1 = createOrganisationUnit('A'); + OrganisationUnit level2Ou2 = createOrganisationUnit('B'); + OrganisationUnit ou1 = createOrganisationUnit('C'); + OrganisationUnit ou2 = createOrganisationUnit('D'); List organisationUnits = new ArrayList<>(asList(level2Ou1, level2Ou2, ou1, ou2)); diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/handler/SchemeIdResponseMapperTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/handler/SchemeIdResponseMapperTest.java index edd44fbee2e6..d4c3abcdab71 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/handler/SchemeIdResponseMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/handler/SchemeIdResponseMapperTest.java @@ -28,7 +28,6 @@ package org.hisp.dhis.analytics.data.handler; import static com.google.common.collect.Lists.newArrayList; -import static java.lang.String.valueOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.Matchers.equalTo; @@ -42,6 +41,7 @@ import static org.hisp.dhis.common.IdScheme.UUID; import static org.hisp.dhis.common.ValueType.TEXT; import static org.hisp.dhis.period.PeriodType.getPeriodFromIsoString; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.TestBase.createProgram; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -83,12 +83,12 @@ class SchemeIdResponseMapperTest { @Test void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToName() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = Data.builder() - .organizationUnits(List.of(stubOrgUnit())) + .organizationUnits(List.of(organisationUnit)) .dataElementOperands(List.of(dataElementOperands.get(0), dataElementOperands.get(1))) .dimensionalItemObjects(Set.of(period, organisationUnit)) .build(); @@ -121,7 +121,7 @@ void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToName() { @Test void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToCode() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -158,12 +158,12 @@ void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToCode() { @Test void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToUuid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = Data.builder() - .organizationUnits(List.of(stubOrgUnit())) + .organizationUnits(List.of(createOrganisationUnit('A'))) .dataElementOperands(List.of(dataElementOperands.get(0), dataElementOperands.get(1))) .dimensionalItemObjects(Set.of(period, organisationUnit)) .build(); @@ -192,7 +192,7 @@ void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToUuid() { @Test void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToUid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -226,7 +226,7 @@ void testGetSchemeIdResponseMapWhenOutputIdSchemeIsSetToUid() { @Test void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToName() { List dataElements = stubDataElements(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -257,7 +257,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToName() { @Test void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToCode() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -295,7 +295,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToCode() { @Test void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToUuid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -330,7 +330,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToUuid() { void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToUid() { List dataElementOperands = stubDataElementOperands(); DataElement dataElement = stubDataElement(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -365,7 +365,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeIsSetToUid() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToName() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -399,7 +399,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToName() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToCode() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -433,7 +433,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToCode() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToUuid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -467,7 +467,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToUuid() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToUid() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -501,7 +501,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeIsSetToUid() { @Test void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeOverridesOutputIdScheme() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -543,7 +543,7 @@ void testGetSchemeIdResponseMapWhenOutputOrgUnitIdSchemeOverridesOutputIdScheme( @Test void testGetSchemeIdResponseMapWhenOutputDataElementIdSchemeOverridesOutputOrgUnitIdScheme() { List dataElementOperands = stubDataElementOperands(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -587,7 +587,7 @@ void testGetSchemeIdResponseMapWhenOutputDataElementOrgUnitIdSchemeOverrideOutpu DataElement dataElement = stubDataElement(); Indicator indicator = stubIndicator(); ProgramIndicator programIndicator = stubProgramIndicator(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); List dataElementOperands = stubDataElementOperands(); @@ -613,13 +613,11 @@ void testGetSchemeIdResponseMapWhenOutputDataElementOrgUnitIdSchemeOverrideOutpu Map responseMap = schemeIdResponseMapper.getSchemeIdResponseMap(schemeInfo); - String orgUnitUid = organisationUnit.getUid(); String periodIsoDate = period.getIsoDate(); DataElement dataElementA = dataElementOperands.get(0).getDataElement(); DataElement dataElementB = dataElementOperands.get(1).getDataElement(); CategoryOptionCombo categoryOptionComboC = dataElementOperands.get(0).getCategoryOptionCombo(); - assertThat(responseMap.get(orgUnitUid), is(equalTo(valueOf(organisationUnit.getId())))); assertThat(responseMap.get(periodIsoDate), is(equalTo(period.getName()))); assertThat(responseMap.get(dataElementA.getUid()), is(equalTo(dataElementA.getCode()))); assertThat(responseMap.get(dataElementB.getUid()), is(equalTo(dataElementB.getCode()))); @@ -636,7 +634,7 @@ void testGetSchemeIdResponseMapWhenOutputDataItemIdSchemeOverridesOutputIdScheme DataElement dataElement = stubDataElement(); Indicator indicator = stubIndicator(); ProgramIndicator programIndicator = stubProgramIndicator(); - OrganisationUnit organisationUnit = stubOrgUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); Period period = stubPeriod(); Data schemeData = @@ -870,7 +868,8 @@ private Settings stubSchemeSettings(IdScheme idScheme) { private Data stubSchemeData(Program program) { return Data.builder() .programs(List.of(program)) - .dimensionalItemObjects(Set.of(stubPeriod(), stubOrgUnit(), stubDataElement())) + .dimensionalItemObjects( + Set.of(stubPeriod(), createOrganisationUnit('A'), stubDataElement())) .build(); } @@ -944,15 +943,4 @@ private ProgramIndicator stubProgramIndicator() { return programIndicatorA; } - - private OrganisationUnit stubOrgUnit() { - OrganisationUnit organisationUnit = new OrganisationUnit(); - organisationUnit.setName("OrgUnitA"); - organisationUnit.setShortName("ShortOrgUnitA"); - organisationUnit.setUid("org1234567A"); - organisationUnit.setCode("CodeA"); - organisationUnit.setId(1); - - return organisationUnit; - } } diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java index b37709db626e..c78346771352 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/AbstractJdbcEventAnalyticsManagerTest.java @@ -528,7 +528,7 @@ void testGetWhereClauseWithMultipleOrgUnitDescendantsAtSameLevel() { assertThat( whereClause, - containsString("and ax.\"uidlevel0\" in ('ouabcdefghA','ouabcdefghB','ouabcdefghC')")); + containsString("and ax.\"uidlevel1\" in ('ouabcdefghA','ouabcdefghB','ouabcdefghC')")); } @Test diff --git a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTableTest.java b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTableTest.java index 2080837b84e6..31d5fb05b764 100644 --- a/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTableTest.java +++ b/dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/resourcetable/table/OrganisationUnitStructureResourceTableTest.java @@ -43,17 +43,17 @@ void testCreateBatchObjectsWhenLevelsAreSame() { int maxOrgUnitLevels = 3; int currentLevel = 3; - OrganisationUnit root = createOrganisationUnit("ouR"); + OrganisationUnit root = createOrganisationUnit('A'); root.setPath("/p1"); - OrganisationUnit ou1 = createOrganisationUnit("ou1", root); + OrganisationUnit ou1 = createOrganisationUnit('B', root); ou1.setPath("/p1/p2"); - OrganisationUnit ou2 = createOrganisationUnit("ou2", ou1); + OrganisationUnit ou2 = createOrganisationUnit('C', ou1); ou2.setHierarchyLevel(currentLevel); ou2.setPath("/p1/p2/ou2"); - OrganisationUnit ou3 = createOrganisationUnit("ou3", ou1); + OrganisationUnit ou3 = createOrganisationUnit('D', ou1); ou3.setHierarchyLevel(currentLevel); ou3.setPath("/p1/p2/ou3"); @@ -72,10 +72,10 @@ void testCreateBatchObjectsWhenHierarchyLevelIsLowerThanMaxLevel() { int maxOrgUnitLevels = 3; int currentLevel = 2; - OrganisationUnit root = createOrganisationUnit("ouR"); + OrganisationUnit root = createOrganisationUnit('A'); root.setPath("/p1"); - OrganisationUnit ou1 = createOrganisationUnit("ou1", root); + OrganisationUnit ou1 = createOrganisationUnit('B', root); ou1.setPath("/p1/p2"); List organisationUnits = new ArrayList<>(); @@ -92,10 +92,10 @@ void testCreateBatchObjectsWhenCurrentLevelIsLargerThanMaxLevel() { int maxOrgUnitLevels = 2; int currentLevel = 3; - OrganisationUnit root = createOrganisationUnit("ouR"); + OrganisationUnit root = createOrganisationUnit('A'); root.setPath("/p1"); - OrganisationUnit ou1 = createOrganisationUnit("ou1", root); + OrganisationUnit ou1 = createOrganisationUnit('B', root); ou1.setPath("/p1/p2"); ou1.setUid("uid-123"); @@ -120,10 +120,10 @@ void testCreateBatchObjectsWhenCurrentLevelHasNoParent() { int maxOrgUnitLevels = 2; int currentLevel = 3; - OrganisationUnit root = createOrganisationUnit("ouR"); + OrganisationUnit root = createOrganisationUnit('A'); root.setPath("/p1"); - OrganisationUnit ou1 = createOrganisationUnit("ou1"); + OrganisationUnit ou1 = createOrganisationUnit('B'); ou1.setPath("/p1/p2"); ou1.setUid("uid-123"); diff --git a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/copy/CopyServiceTest.java b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/copy/CopyServiceTest.java index 177e20ecadc5..aded62162396 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/copy/CopyServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/copy/CopyServiceTest.java @@ -131,7 +131,7 @@ void setup() { @Test void testCopyProgramFromUidWithValidProgram() throws NotFoundException, ForbiddenException { - OrganisationUnit orgUnit = createOrganisationUnit("New Org 1"); + OrganisationUnit orgUnit = createOrganisationUnit('A'); List originalEnrollments = List.of(createEnrollment(original, createTrackedEntity(orgUnit), orgUnit)); when(programService.getProgram(VALID_PROGRAM_UID)).thenReturn(original); @@ -382,7 +382,7 @@ Program createProgram() { Set.of(createProgramNotificationTemplate("not1", 20, ENROLLMENT, WEB_HOOK))); p.setOnlyEnrollOnce(true); p.setOpenDaysAfterCoEndDate(20); - p.setOrganisationUnits(Set.of(createOrganisationUnit("Org 1"))); + p.setOrganisationUnits(Set.of(createOrganisationUnit('A'))); p.setProgramAttributes(createProgramAttributes(p)); p.setProgramIndicators(createIndicators(p)); p.setProgramRuleVariables(Set.of(createProgramRuleVariable('v', p))); diff --git a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/query/DefaultQueryServiceTest.java b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/query/DefaultQueryServiceTest.java index bb84e91d776f..6087b19e25d5 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/query/DefaultQueryServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/query/DefaultQueryServiceTest.java @@ -35,7 +35,6 @@ import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.RandomStringUtils; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.query.planner.DefaultQueryPlanner; @@ -96,7 +95,7 @@ private List createOrgUnits(int size) { List result = new ArrayList<>(); for (int i = 0; i < size; i++) { - result.add(createOrganisationUnit(RandomStringUtils.randomAlphabetic(1))); + result.add(createOrganisationUnit((char) (i + 'A'))); } return result; } diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/dataset/DefaultCompleteDataSetRegistrationExchangeServiceTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/dataset/DefaultCompleteDataSetRegistrationExchangeServiceTest.java index 4f9664d8b3b8..1411f486443c 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/dataset/DefaultCompleteDataSetRegistrationExchangeServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/dataset/DefaultCompleteDataSetRegistrationExchangeServiceTest.java @@ -121,6 +121,7 @@ class DefaultCompleteDataSetRegistrationExchangeServiceTest { @Mock private BatchHandlerFactory batchHandlerFactory; @Mock private SystemSettingsProvider settingsProvider; + @Mock private SystemSettings settings; @Mock private CategoryService categoryService; @@ -158,7 +159,9 @@ class DefaultCompleteDataSetRegistrationExchangeServiceTest { @Mock private Environment environment; @Mock private AclService aclService; + @Mock private UserService userService; + private User user; private DefaultCompleteDataSetRegistrationExchangeService subject; @@ -299,7 +302,7 @@ void verifyUserHasNoWritePermissionOnCategoryOption() { void testValidateAssertMissingDataSet() { ExportParams params = new ExportParams() - .setOrganisationUnits(Sets.newHashSet(new OrganisationUnit())) + .setOrganisationUnits(Sets.newHashSet(createOrganisationUnit('A'))) .setPeriods(Sets.newHashSet(new Period())); assertIllegalQueryEx( diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetImportValidatorTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetImportValidatorTest.java index 3cda0b79904a..6211873f78ba 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetImportValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetImportValidatorTest.java @@ -29,6 +29,7 @@ import static java.util.Collections.emptySet; import static java.util.Collections.singleton; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -878,7 +879,7 @@ private DataValueContextBuilder createDataValueContext(DataValue dataValue) { builder.period(p); } if (ouId != null) { - OrganisationUnit ou = new OrganisationUnit(); + OrganisationUnit ou = createOrganisationUnit('A'); ou.setUid(ouId); // we set the path here just for the tests. This is usually done by the persistence layer // but there is no interaction with that in these tests. diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/GeoJsonAttributesCheckTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/GeoJsonAttributesCheckTest.java index a7a57ed76697..54a62128fb6f 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/GeoJsonAttributesCheckTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/GeoJsonAttributesCheckTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.dxf2.metadata.attribute; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -71,8 +72,7 @@ class GeoJsonAttributesCheckTest { @BeforeEach public void setUpTest() { - organisationUnit = new OrganisationUnit(); - organisationUnit.setName("A"); + organisationUnit = createOrganisationUnit('A'); attribute = new Attribute(); attribute.setUid("geoJson"); attribute.setName("geoJson"); diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/MetadataAttributeCheckTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/MetadataAttributeCheckTest.java index b07d0158b6ed..ea1140c4fb7e 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/MetadataAttributeCheckTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/attribute/MetadataAttributeCheckTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.dxf2.metadata.attribute; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -84,8 +85,7 @@ class MetadataAttributeCheckTest { @BeforeEach void setUpTest() { - organisationUnit = new OrganisationUnit(); - organisationUnit.setName("A"); + organisationUnit = createOrganisationUnit('A'); attribute = new Attribute(); attribute.setUid("attributeID"); attribute.setName("attributeA"); @@ -456,7 +456,7 @@ void testAttributeOrganisationUnit() { organisationUnit.addAttributeValue(attribute.getUid(), "OU-ID"); // OrganisationUnit exists - when(manager.get(OrganisationUnit.class, "OU-ID")).thenReturn(new OrganisationUnit()); + when(manager.get(OrganisationUnit.class, "OU-ID")).thenReturn(createOrganisationUnit('A')); List objectReportList = new ArrayList<>(); diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/ObjectBundleHooksTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/ObjectBundleHooksTest.java index ecf8d84e51b7..608e403d83c3 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/ObjectBundleHooksTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/ObjectBundleHooksTest.java @@ -30,6 +30,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -67,20 +68,20 @@ class ObjectBundleHooksTest { @Test void testMatchingClassBoundIsIncluded() { - assertHasHooksOfType(new OrganisationUnit(), OrganisationUnitObjectBundleHook.class); + assertHasHooksOfType(createOrganisationUnit('A'), OrganisationUnitObjectBundleHook.class); assertHasHooksOfType(new User(), UserObjectBundleHook.class); } @Test void testNonMatchingClassBoundIsNotIncluded() { - assertHasNotHooksOfType(new OrganisationUnit(), UserObjectBundleHook.class); + assertHasNotHooksOfType(createOrganisationUnit('A'), UserObjectBundleHook.class); assertHasNotHooksOfType(new User(), OrganisationUnitObjectBundleHook.class); } @Test void testMatchingInterfaceBoundIsIncluded() { assertHasHooksOfType( - new OrganisationUnit(), + createOrganisationUnit('A'), IdentifiableObjectBundleHook.class, VersionedObjectObjectBundleHook.class); assertHasHooksOfType( @@ -94,7 +95,7 @@ void testMatchingInterfaceBoundIsIncluded() { @Test void testNonMatchingInterfaceBoundIsNotIncluded() { - assertHasNotHooksOfType(new OrganisationUnit(), AnalyticalObjectObjectBundleHook.class); + assertHasNotHooksOfType(createOrganisationUnit('A'), AnalyticalObjectObjectBundleHook.class); assertHasNotHooksOfType(new User(), AnalyticalObjectObjectBundleHook.class); } diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramObjectBundleHookTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramObjectBundleHookTest.java index 5d4e36618955..edf7d86c6467 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramObjectBundleHookTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramObjectBundleHookTest.java @@ -30,6 +30,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.TestBase.createProgram; import static org.hisp.dhis.test.TestBase.createProgramStage; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -45,7 +46,6 @@ import org.hisp.dhis.common.IdentifiableObjectManager; import org.hisp.dhis.feedback.ErrorCode; import org.hisp.dhis.feedback.ErrorReport; -import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.program.Enrollment; import org.hisp.dhis.program.EnrollmentStatus; @@ -112,7 +112,7 @@ void verifyMissingBundleIsIgnored() { @Test void verifyProgramInstanceIsSavedForEventProgram() { when(organisationUnitService.getRootOrganisationUnits()) - .thenReturn(List.of(new OrganisationUnit())); + .thenReturn(List.of(createOrganisationUnit('A'))); ArgumentCaptor argument = ArgumentCaptor.forClass(Enrollment.class); programA.setProgramType(ProgramType.WITHOUT_REGISTRATION); diff --git a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramStageWorkingListObjectBundleHookTest.java b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramStageWorkingListObjectBundleHookTest.java index 774b8a513ef3..26f098305938 100644 --- a/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramStageWorkingListObjectBundleHookTest.java +++ b/dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/metadata/objectbundle/hooks/ProgramStageWorkingListObjectBundleHookTest.java @@ -35,6 +35,7 @@ import static org.hisp.dhis.feedback.ErrorCode.E4067; import static org.hisp.dhis.feedback.ErrorCode.E4068; import static org.hisp.dhis.feedback.ErrorCode.E7500; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertErrorReport; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.mockito.ArgumentMatchers.anyString; @@ -50,7 +51,6 @@ import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundle; import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundleParams; import org.hisp.dhis.feedback.ErrorReport; -import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.preheat.Preheat; import org.hisp.dhis.programstagefilter.DateFilterPeriod; @@ -136,7 +136,7 @@ void shouldReturnNoErrorsWhenQueryCriteriaSuppliedIsValid() { .build(); when(organisationUnitService.getOrganisationUnit(anyString())) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(dataElementService.getDataElement(anyString())).thenReturn(new DataElement()); when(attributeService.getTrackedEntityAttribute(anyString())) .thenReturn(new TrackedEntityAttribute()); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionAnalyticsDataFetcherTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionAnalyticsDataFetcherTest.java index 5404db0b3a52..eb26204fb471 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionAnalyticsDataFetcherTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionAnalyticsDataFetcherTest.java @@ -106,8 +106,8 @@ void initTest() { periods = Sets.newHashSet(periodA, periodB); - orgUnitA = createOrganisationUnit("A"); - orgUnitB = createOrganisationUnit("B"); + orgUnitA = createOrganisationUnit('A'); + orgUnitB = createOrganisationUnit('B'); orgUnitA.setUid("orgUnitAuid"); orgUnitB.setUid("orgUnitBuid"); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataConsolidatorTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataConsolidatorTest.java index bb3db588a2e6..010c677236cb 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataConsolidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataConsolidatorTest.java @@ -231,13 +231,13 @@ void initTest() { // -- C ------ F // -- D ------ G - orgUnitA = createOrganisationUnit("A"); - orgUnitB = createOrganisationUnit("B"); - orgUnitC = createOrganisationUnit("C"); - orgUnitD = createOrganisationUnit("D"); - orgUnitE = createOrganisationUnit("E", orgUnitB); - orgUnitF = createOrganisationUnit("F", orgUnitC); - orgUnitG = createOrganisationUnit("G", orgUnitD); + orgUnitA = createOrganisationUnit('A'); + orgUnitB = createOrganisationUnit('B'); + orgUnitC = createOrganisationUnit('C'); + orgUnitD = createOrganisationUnit('D'); + orgUnitE = createOrganisationUnit('E', orgUnitB); + orgUnitF = createOrganisationUnit('F', orgUnitC); + orgUnitG = createOrganisationUnit('G', orgUnitD); orgUnitA.setId(20); orgUnitB.setId(21); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataValueFetcherTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataValueFetcherTest.java index 4b847c628d33..1fe83aff83c4 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataValueFetcherTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionDataValueFetcherTest.java @@ -248,13 +248,13 @@ void initTest() { // -- C ------ F // -- D ------ G - orgUnitA = createOrganisationUnit("A"); - orgUnitB = createOrganisationUnit("B"); - orgUnitC = createOrganisationUnit("C"); - orgUnitD = createOrganisationUnit("D"); - orgUnitE = createOrganisationUnit("E", orgUnitB); - orgUnitF = createOrganisationUnit("F", orgUnitC); - orgUnitG = createOrganisationUnit("G", orgUnitD); + orgUnitA = createOrganisationUnit('A'); + orgUnitB = createOrganisationUnit('B'); + orgUnitC = createOrganisationUnit('C'); + orgUnitD = createOrganisationUnit('D'); + orgUnitE = createOrganisationUnit('E', orgUnitB); + orgUnitF = createOrganisationUnit('F', orgUnitC); + orgUnitG = createOrganisationUnit('G', orgUnitD); orgUnitA.setId(20); orgUnitB.setId(21); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionWriterTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionWriterTest.java index 4c62cee80b16..2a546a204d76 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionWriterTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/predictor/PredictionWriterTest.java @@ -28,7 +28,7 @@ package org.hisp.dhis.predictor; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -123,7 +123,7 @@ public void initTest() { cocA.setId(++id); cocB.setId(++id); - orgUnitA = createOrganisationUnit("A"); + orgUnitA = createOrganisationUnit('A'); orgUnitA.setId(++id); diff --git a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/visualization/VisualizationGridServiceTest.java b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/visualization/VisualizationGridServiceTest.java index 4aab0ba6ec60..e7e3b0959938 100644 --- a/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/visualization/VisualizationGridServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/visualization/VisualizationGridServiceTest.java @@ -31,6 +31,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -90,7 +91,7 @@ void getVisualizationGridByUserWhenItHasOrganisationUnitLevels() { final String anyOrganisationUnitUid = "ouiRzW5e"; final User userStub = userStub(); final List orgUnitLevels = asList(1, 2); - final List orgUnits = asList(new OrganisationUnit()); + final List orgUnits = asList(createOrganisationUnit('A')); final Map valueMap = valueMapStub(); final Visualization visualizationStub = visualizationStub("abc123xy"); @@ -124,7 +125,7 @@ void getVisualizationGridByUserWhenItHasItemOrganisationUnitGroups() { final Date anyRelativePeriodDate = new Date(); final String anyOrganisationUnitUid = "ouiRzW5e"; final User userStub = userStub(); - final List orgUnits = asList(new OrganisationUnit()); + final List orgUnits = asList(createOrganisationUnit('A')); final List orgUnitGroups = asList(new OrganisationUnitGroup()); final Map valueMap = valueMapStub(); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManagerTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManagerTest.java index 1f63f94d30fb..042b9fadc477 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManagerTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/acl/DefaultTrackerAccessManagerTest.java @@ -30,6 +30,8 @@ import static org.hisp.dhis.common.AccessLevel.CLOSED; import static org.hisp.dhis.common.AccessLevel.OPEN; import static org.hisp.dhis.common.AccessLevel.PROTECTED; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; +import static org.hisp.dhis.test.TestBase.createProgram; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -38,6 +40,7 @@ import org.hisp.dhis.program.Program; import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserDetails; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -48,13 +51,22 @@ class DefaultTrackerAccessManagerTest { @InjectMocks private DefaultTrackerAccessManager trackerAccessManager; + private Program program; + + private OrganisationUnit orgUnit; + + private User user; + + @BeforeEach + public void before() { + program = createProgram('A'); + orgUnit = createOrganisationUnit('A'); + user = new User(); + } + @Test void shouldHaveAccessWhenProgramOpenAndSearchAccessAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(OPEN); - OrganisationUnit orgUnit = new OrganisationUnit(); - user.setTeiSearchOrganisationUnits(Set.of(orgUnit)); assertTrue( @@ -64,10 +76,7 @@ void shouldHaveAccessWhenProgramOpenAndSearchAccessAvailable() { @Test void shouldNotHaveAccessWhenProgramOpenAndSearchAccessNotAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(OPEN); - OrganisationUnit orgUnit = new OrganisationUnit(); assertFalse( trackerAccessManager.canAccess(UserDetails.fromUser(user), program, orgUnit), @@ -76,9 +85,6 @@ void shouldNotHaveAccessWhenProgramOpenAndSearchAccessNotAvailable() { @Test void shouldHaveAccessWhenProgramNullAndSearchAccessAvailable() { - User user = new User(); - OrganisationUnit orgUnit = new OrganisationUnit(); - user.setTeiSearchOrganisationUnits(Set.of(orgUnit)); assertTrue( @@ -88,9 +94,6 @@ void shouldHaveAccessWhenProgramNullAndSearchAccessAvailable() { @Test void shouldNotHaveAccessWhenProgramNullAndSearchAccessNotAvailable() { - User user = new User(); - OrganisationUnit orgUnit = new OrganisationUnit(); - assertFalse( trackerAccessManager.canAccess(UserDetails.fromUser(user), null, orgUnit), "User should not have access to unspecified program"); @@ -98,11 +101,7 @@ void shouldNotHaveAccessWhenProgramNullAndSearchAccessNotAvailable() { @Test void shouldHaveAccessWhenProgramClosedAndCaptureAccessAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(CLOSED); - OrganisationUnit orgUnit = new OrganisationUnit(); - user.setOrganisationUnits(Set.of(orgUnit)); assertTrue( @@ -112,10 +111,7 @@ void shouldHaveAccessWhenProgramClosedAndCaptureAccessAvailable() { @Test void shouldNotHaveAccessWhenProgramClosedAndCaptureAccessNotAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(CLOSED); - OrganisationUnit orgUnit = new OrganisationUnit(); assertFalse( trackerAccessManager.canAccess(UserDetails.fromUser(user), program, orgUnit), @@ -124,11 +120,7 @@ void shouldNotHaveAccessWhenProgramClosedAndCaptureAccessNotAvailable() { @Test void shouldHaveAccessWhenProgramProtectedAndCaptureAccessAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(PROTECTED); - OrganisationUnit orgUnit = new OrganisationUnit(); - user.setOrganisationUnits(Set.of(orgUnit)); assertTrue( @@ -138,10 +130,7 @@ void shouldHaveAccessWhenProgramProtectedAndCaptureAccessAvailable() { @Test void shouldNotHaveAccessWhenProgramProtectedAndCaptureAccessNotAvailable() { - User user = new User(); - Program program = new Program(); program.setAccessLevel(PROTECTED); - OrganisationUnit orgUnit = new OrganisationUnit(); assertFalse( trackerAccessManager.canAccess(UserDetails.fromUser(user), program, orgUnit), diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/OperationsParamsValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/OperationsParamsValidatorTest.java index 5ab7b641dbcb..b7fa4e296971 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/OperationsParamsValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/OperationsParamsValidatorTest.java @@ -30,6 +30,7 @@ import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.CAPTURE; import static org.hisp.dhis.program.ProgramType.WITHOUT_REGISTRATION; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.tracker.export.OperationsParamsValidator.validateOrgUnitMode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -54,7 +55,6 @@ import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserDetails; import org.hisp.dhis.user.UserRole; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -65,20 +65,13 @@ @ExtendWith(MockitoExtension.class) class OperationsParamsValidatorTest { - - private static final String PARENT_ORG_UNIT_UID = "parent-org-unit"; - - private final OrganisationUnit captureScopeOrgUnit = createOrgUnit("captureScopeOrgUnit", "uid3"); - - private final OrganisationUnit searchScopeOrgUnit = createOrgUnit("searchScopeOrgUnit", "uid4"); - private final Program program = new Program("program"); private final TrackedEntity trackedEntity = new TrackedEntity(); private final TrackedEntityType trackedEntityType = new TrackedEntityType(); - private final OrganisationUnit orgUnit = new OrganisationUnit(); + private final OrganisationUnit orgUnit = createOrganisationUnit('A'); private static final UID PROGRAM_UID = UID.generate(); @@ -104,12 +97,6 @@ class OperationsParamsValidatorTest { private final UserDetails user = UserDetails.fromUser(new User()); - @BeforeEach - public void setUp() { - OrganisationUnit organisationUnit = createOrgUnit("orgUnit", PARENT_ORG_UNIT_UID); - organisationUnit.setChildren(Set.of(captureScopeOrgUnit, searchScopeOrgUnit)); - } - @Test void shouldFailWhenOuModeCaptureAndUserHasNoOrgUnitsAssigned() { Exception exception = @@ -385,10 +372,4 @@ void shouldReturnOrgUnitsWhenUserIsSuperButHasNoAccessToOrgUnit() assertEquals(Set.of(orgUnit), orgUnits); } - - private OrganisationUnit createOrgUnit(String name, String uid) { - OrganisationUnit orgUnit = new OrganisationUnit(name); - orgUnit.setUid(uid); - return orgUnit; - } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/enrollment/EnrollmentOperationParamsMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/enrollment/EnrollmentOperationParamsMapperTest.java index 853d171634ba..537ce85115ac 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/enrollment/EnrollmentOperationParamsMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/enrollment/EnrollmentOperationParamsMapperTest.java @@ -31,6 +31,7 @@ import static org.hisp.dhis.common.OrganisationUnitSelectionMode.CAPTURE; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.CHILDREN; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.DESCENDANTS; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.verifyNoInteractions; @@ -105,10 +106,10 @@ void setUp() throws ForbiddenException, BadRequestException { User testUser = new User(); testUser.setUsername("admin"); - orgUnit1 = new OrganisationUnit("orgUnit1"); + orgUnit1 = createOrganisationUnit('A'); orgUnit1.setUid(ORG_UNIT_1_UID.getValue()); when(organisationUnitService.getOrganisationUnit(orgUnit1.getUid())).thenReturn(orgUnit1); - orgUnit2 = new OrganisationUnit("orgUnit2"); + orgUnit2 = createOrganisationUnit('B'); orgUnit2.setUid(ORG_UNIT_2_UID.getValue()); orgUnit2.setParent(orgUnit1); orgUnit1.setChildren(Set.of(orgUnit2)); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java index 824853977ba6..c6e979d6edfc 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java @@ -36,6 +36,7 @@ import static org.hisp.dhis.common.OrganisationUnitSelectionMode.DESCENDANTS; import static org.hisp.dhis.common.OrganisationUnitSelectionMode.SELECTED; import static org.hisp.dhis.security.Authorities.F_TRACKED_ENTITY_INSTANCE_SEARCH_IN_ALL_ORGUNITS; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertContains; import static org.hisp.dhis.test.utils.Assertions.assertContainsOnly; import static org.hisp.dhis.test.utils.Assertions.assertStartsWith; @@ -131,9 +132,8 @@ class EventOperationParamsMapperTest { @BeforeEach public void setUp() { - OrganisationUnit orgUnit = createOrgUnit("orgUnit"); - orgUnit.setChildren( - Set.of(createOrgUnit("captureScopeChild"), createOrgUnit("searchScopeChild"))); + OrganisationUnit orgUnit = createOrganisationUnit('A'); + orgUnit.setChildren(Set.of(createOrganisationUnit('B'), createOrganisationUnit('C'))); User testUser = new User(); testUser.setUid(CodeGenerator.generateUid()); @@ -142,8 +142,7 @@ public void setUp() { user = UserDetails.fromUser(testUser); // By default, set to ACCESSIBLE for tests that don't set an orgUnit. The orgUnitMode needs to - // be - // set because its validation is in the EventRequestParamsMapper. + // be set because its validation is in the EventRequestParamsMapper. eventBuilder = eventBuilder.orgUnitMode(ACCESSIBLE).eventParams(EventParams.FALSE); userMap.put("admin", createUserWithAuthority(F_TRACKED_ENTITY_INSTANCE_SEARCH_IN_ALL_ORGUNITS)); @@ -421,15 +420,15 @@ void shouldMapOrgUnitWhenProgramProvidedAndRequestedOrgUnitInSearchScope( program.setUid(CodeGenerator.generateUid()); program.setAccessLevel(accessLevel); - OrganisationUnit searchScopeOrgUnit = createOrgUnit("searchScopeOrgUnit"); - OrganisationUnit searchScopeChildOrgUnit = createOrgUnit("searchScopeChildOrgUnit"); + OrganisationUnit searchScopeOrgUnit = createOrganisationUnit('A'); + OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B'); searchScopeOrgUnit.setChildren(Set.of(searchScopeChildOrgUnit)); searchScopeChildOrgUnit.setParent(searchScopeOrgUnit); User user = new User(); user.setUid(CodeGenerator.generateUid()); user.setUsername("testB"); - user.setOrganisationUnits(Set.of(createOrgUnit("captureScopeOrgUnit"))); + user.setOrganisationUnits(Set.of(createOrganisationUnit('C'))); user.setTeiSearchOrganisationUnits(Set.of(searchScopeOrgUnit)); when(organisationUnitService.getOrganisationUnit(searchScopeChildOrgUnit.getUid())) @@ -453,15 +452,15 @@ void shouldMapOrgUnitWhenModeAllProgramProvidedAndRequestedOrgUnitInSearchScope( program.setUid(CodeGenerator.generateUid()); program.setAccessLevel(OPEN); - OrganisationUnit searchScopeOrgUnit = createOrgUnit("searchScopeOrgUnit"); - OrganisationUnit searchScopeChildOrgUnit = createOrgUnit("searchScopeChildOrgUnit"); + OrganisationUnit searchScopeOrgUnit = createOrganisationUnit('A'); + OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B'); searchScopeOrgUnit.setChildren(Set.of(searchScopeChildOrgUnit)); searchScopeChildOrgUnit.setParent(searchScopeOrgUnit); User user = new User(); user.setUid(CodeGenerator.generateUid()); user.setUsername("testB"); - user.setOrganisationUnits(Set.of(createOrgUnit("captureScopeOrgUnit"))); + user.setOrganisationUnits(Set.of(createOrganisationUnit('C'))); user.setTeiSearchOrganisationUnits(Set.of(searchScopeOrgUnit)); UserRole userRole = new UserRole(); userRole.setAuthorities(Set.of(F_TRACKED_ENTITY_INSTANCE_SEARCH_IN_ALL_ORGUNITS.name())); @@ -481,7 +480,7 @@ void shouldMapOrgUnitWhenModeAllProgramProvidedAndRequestedOrgUnitInSearchScope( @EnumSource(value = OrganisationUnitSelectionMode.class) void shouldFailWhenRequestedOrgUnitOutsideOfSearchScope( OrganisationUnitSelectionMode orgUnitMode) { - OrganisationUnit orgUnit = createOrgUnit("name"); + OrganisationUnit orgUnit = createOrganisationUnit('A'); when(organisationUnitService.getOrganisationUnit(orgUnit.getUid())).thenReturn(orgUnit); EventOperationParams operationParams = EventOperationParams.builder().orgUnit(orgUnit).orgUnitMode(orgUnitMode).build(); @@ -544,10 +543,4 @@ private User createUserWithAuthority(Authorities authority) { return user; } - - private OrganisationUnit createOrgUnit(String name) { - OrganisationUnit orgUnit = new OrganisationUnit(name); - orgUnit.setUid(CodeGenerator.generateUid()); - return orgUnit; - } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/OrganisationUnitMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/OrganisationUnitMapperTest.java index 1f46665e7b91..2816f9e68991 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/OrganisationUnitMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/OrganisationUnitMapperTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.preheat.mappers; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.tracker.imports.preheat.mappers.AttributeCreator.attributeValues; import static org.hisp.dhis.tracker.imports.preheat.mappers.AttributeCreator.setIdSchemeFields; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -44,7 +45,7 @@ void testIdSchemeRelatedFieldsAreMapped() { OrganisationUnit orgUnit = setIdSchemeFields( - new OrganisationUnit(), + createOrganisationUnit('A'), "HpSAvRWtdDR", "meet", "green", @@ -60,11 +61,11 @@ void testIdSchemeRelatedFieldsAreMapped() { @Test void testParentFieldsAreMapped() { - OrganisationUnit rootOrgUnit = new OrganisationUnit(); + OrganisationUnit rootOrgUnit = createOrganisationUnit('A'); rootOrgUnit.setUid("root"); - OrganisationUnit level1OrgUnit = new OrganisationUnit(); + OrganisationUnit level1OrgUnit = createOrganisationUnit('B'); level1OrgUnit.setUid("level1"); - OrganisationUnit level2OrgUnit = new OrganisationUnit(); + OrganisationUnit level2OrgUnit = createOrganisationUnit('C'); level2OrgUnit.setUid("level2"); level2OrgUnit.setParent(level1OrgUnit); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/TrackedEntityMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/TrackedEntityMapperTest.java index eb1e4127ff3e..1972dcc9f201 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/TrackedEntityMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/preheat/mappers/TrackedEntityMapperTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.preheat.mappers; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.tracker.imports.preheat.mappers.AttributeCreator.attributeValues; import static org.hisp.dhis.tracker.imports.preheat.mappers.AttributeCreator.setIdSchemeFields; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -57,7 +58,7 @@ void testIdSchemeRelatedFieldsAreMapped() { OrganisationUnit orgUnit = setIdSchemeFields( - new OrganisationUnit(), + createOrganisationUnit('A'), "HpSAvRWtdDR", "meet", "green", diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/MessageFormatterTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/MessageFormatterTest.java index dbb09804f82d..5d969ae716e9 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/MessageFormatterTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/MessageFormatterTest.java @@ -29,6 +29,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertContainsOnly; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -104,7 +105,7 @@ void formatArgumentsShouldTurnIdentifiableObjectIntoArgument() { relationshipType.setUid("WTTYiPQDqh1"); Program program = new Program("friendship"); ProgramStage programStage = new ProgramStage("meet", program); - OrganisationUnit orgUnit = new OrganisationUnit(); + OrganisationUnit orgUnit = createOrganisationUnit('A'); orgUnit.setAttributeValues(attributeValues("HpSAvRWtdDR", "sunshine")); DataElement dataElement = new DataElement(); dataElement.setAttributeValues(attributeValues("m0GpPuMUfFW", "ice")); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/MetaValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/MetaValidatorTest.java index 5af6e72e5d0e..a13524d98edc 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/MetaValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/MetaValidatorTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.enrollment; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1068; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1069; @@ -36,7 +37,6 @@ import java.util.Optional; import org.hisp.dhis.common.UID; -import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.program.Program; import org.hisp.dhis.trackedentity.TrackedEntity; import org.hisp.dhis.tracker.TrackerIdSchemeParams; @@ -84,7 +84,7 @@ public void setUp() { void verifyEnrollmentValidationSuccess() { Enrollment enrollment = validEnrollment(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getTrackedEntity(TRACKED_ENTITY_UID)).thenReturn(new TrackedEntity()); when(preheat.getProgram(MetadataIdentifier.ofUid(PROGRAM_UID))).thenReturn(new Program()); @@ -99,7 +99,7 @@ void verifyEnrollmentValidationSuccessWhenTeiIsInPayload() { when(bundle.findTrackedEntityByUid(TRACKED_ENTITY_UID)) .thenReturn(Optional.of(new org.hisp.dhis.tracker.imports.domain.TrackedEntity())); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getProgram(MetadataIdentifier.ofUid(PROGRAM_UID))).thenReturn(new Program()); validator.validate(reporter, bundle, enrollment); @@ -122,7 +122,7 @@ void verifyEnrollmentValidationFailsWhenOrgUnitIsNotPresentInDb() { void verifyEnrollmentValidationFailsWhenTrackedEntityIsNotPresentInDbOrPayload() { Enrollment enrollment = validEnrollment(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getProgram(MetadataIdentifier.ofUid(PROGRAM_UID))).thenReturn(new Program()); validator.validate(reporter, bundle, enrollment); @@ -134,7 +134,7 @@ void verifyEnrollmentValidationFailsWhenTrackedEntityIsNotPresentInDbOrPayload() void verifyEnrollmentValidationFailsWhenProgramIsNotPresentInDb() { Enrollment enrollment = validEnrollment(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getTrackedEntity(TRACKED_ENTITY_UID)).thenReturn(new TrackedEntity()); validator.validate(reporter, bundle, enrollment); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DataValuesValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DataValuesValidatorTest.java index 9c46f774365b..5e9d99599208 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DataValuesValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/DataValuesValidatorTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.event; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.hisp.dhis.tracker.imports.validation.validator.AssertValidations.assertHasError; import static org.hisp.dhis.tracker.imports.validation.validator.AssertValidations.assertNoErrors; @@ -1128,7 +1129,7 @@ private Set getProgramStageDataElements( } private OrganisationUnit organisationUnit() { - OrganisationUnit organisationUnit = new OrganisationUnit(); + OrganisationUnit organisationUnit = createOrganisationUnit('A'); organisationUnit.setUid(ORGANISATION_UNIT_UID); return organisationUnit; } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/MetaValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/MetaValidatorTest.java index c9dbcde74fe0..d9aac02c46cf 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/MetaValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/MetaValidatorTest.java @@ -27,6 +27,7 @@ */ package org.hisp.dhis.tracker.imports.validation.validator.trackedentity; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.hisp.dhis.test.utils.Assertions.assertIsEmpty; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1005; import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1049; @@ -34,7 +35,6 @@ import static org.mockito.Mockito.when; import org.hisp.dhis.common.UID; -import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.trackedentity.TrackedEntityType; import org.hisp.dhis.tracker.TrackerIdSchemeParams; import org.hisp.dhis.tracker.imports.bundle.TrackerBundle; @@ -81,7 +81,7 @@ public void setUp() { void verifyTrackedEntityValidationSuccess() { TrackedEntity te = validTe(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); when(preheat.getTrackedEntityType(MetadataIdentifier.ofUid(TRACKED_ENTITY_TYPE_UID))) .thenReturn(new TrackedEntityType()); @@ -105,7 +105,7 @@ void verifyTrackedEntityValidationFailsWhenOrgUnitIsNotPresentInDb() { void verifyTrackedEntityValidationFailsWhenTrackedEntityTypeIsNotPresentInDb() { TrackedEntity te = validTe(); when(preheat.getOrganisationUnit(MetadataIdentifier.ofUid(ORG_UNIT_UID))) - .thenReturn(new OrganisationUnit()); + .thenReturn(createOrganisationUnit('A')); validator.validate(reporter, bundle, te); diff --git a/dhis-2/dhis-services/dhis-service-validation/src/test/java/org/hisp/dhis/validation/ValidationResultServiceTest.java b/dhis-2/dhis-services/dhis-service-validation/src/test/java/org/hisp/dhis/validation/ValidationResultServiceTest.java index 8639a8e0ba3f..d05f735efc2a 100644 --- a/dhis-2/dhis-services/dhis-service-validation/src/test/java/org/hisp/dhis/validation/ValidationResultServiceTest.java +++ b/dhis-2/dhis-services/dhis-service-validation/src/test/java/org/hisp/dhis/validation/ValidationResultServiceTest.java @@ -30,6 +30,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import static org.hisp.dhis.test.TestBase.createOrganisationUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -82,7 +83,7 @@ void setUp() { List units = new ArrayList<>(); for (String uid : uids) { if (CodeGenerator.isValidUid(uid)) { - OrganisationUnit unit = new OrganisationUnit(); + OrganisationUnit unit = createOrganisationUnit('A'); unit.setUid(uid); units.add(unit); } diff --git a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/TestBase.java b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/TestBase.java index dc740f453a01..353ee96c8e46 100644 --- a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/TestBase.java +++ b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/TestBase.java @@ -303,6 +303,7 @@ protected void initServices() { // ------------------------------------------------------------------------- // Convenience methods // ------------------------------------------------------------------------- + public User getCurrentUser() { return userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()); } @@ -996,23 +997,19 @@ public static DataEntryForm createDataEntryForm(char uniqueCharacter, String htm public static OrganisationUnit createOrganisationUnit(char uniqueCharacter) { OrganisationUnit unit = new OrganisationUnit(); unit.setAutoFields(); - unit.setUid(BASE_OU_UID + uniqueCharacter); unit.setName("OrganisationUnit" + uniqueCharacter); unit.setShortName("OrganisationUnitShort" + uniqueCharacter); unit.setCode("OrganisationUnitCode" + uniqueCharacter); unit.setOpeningDate(date); unit.setComment("Comment" + uniqueCharacter); - // unit.getSharing().setPublicAccess("--------"); - + unit.updatePath(); return unit; } public static OrganisationUnit createOrganisationUnit(char uniqueCharacter, Geometry geometry) { OrganisationUnit unit = createOrganisationUnit(uniqueCharacter); - unit.setGeometry(geometry); - return unit; } @@ -1025,37 +1022,36 @@ public static OrganisationUnit createOrganisationUnit( OrganisationUnit unit = createOrganisationUnit(uniqueCharacter); unit.setParent(parent); parent.getChildren().add(unit); - + unit.updatePath(); return unit; } /** + * Deprecated, use {@code createOrganisationUnit(char,OrganisationUnit)}. + * * @param name The name, short name and code of the organisation unit. */ public static OrganisationUnit createOrganisationUnit(String name) { - OrganisationUnit unit = new OrganisationUnit(); - unit.setAutoFields(); - + OrganisationUnit unit = createOrganisationUnit('Y'); unit.setUid(CodeGenerator.generateUid()); unit.setName(name); unit.setShortName(name); unit.setCode(name); - unit.setOpeningDate(date); unit.setComment("Comment " + name); - return unit; } /** + * Deprecated, use {@code createOrganisationUnit(char,OrganisationUnit)}. + * * @param name The name, short name and code of the organisation unit. * @param parent The parent. */ public static OrganisationUnit createOrganisationUnit(String name, OrganisationUnit parent) { OrganisationUnit unit = createOrganisationUnit(name); - unit.setParent(parent); parent.getChildren().add(unit); - + unit.updatePath(); return unit; } @@ -1065,12 +1061,10 @@ public static OrganisationUnit createOrganisationUnit(String name, OrganisationU public static OrganisationUnitGroup createOrganisationUnitGroup(char uniqueCharacter) { OrganisationUnitGroup group = new OrganisationUnitGroup(); group.setAutoFields(); - group.setUid(BASE_UID + uniqueCharacter); group.setName("OrganisationUnitGroup" + uniqueCharacter); group.setShortName("OrganisationUnitGroupShort" + uniqueCharacter); group.setCode("OrganisationUnitGroupCode" + uniqueCharacter); - return group; } @@ -1080,13 +1074,11 @@ public static OrganisationUnitGroup createOrganisationUnitGroup(char uniqueChara public static OrganisationUnitGroupSet createOrganisationUnitGroupSet(char uniqueCharacter) { OrganisationUnitGroupSet groupSet = new OrganisationUnitGroupSet(); groupSet.setAutoFields(); - groupSet.setName("OrganisationUnitGroupSet" + uniqueCharacter); groupSet.setShortName("OrganisationUnitGroupSet" + uniqueCharacter); groupSet.setCode("OrganisationUnitGroupSetCode" + uniqueCharacter); groupSet.setDescription("Description" + uniqueCharacter); groupSet.setCompulsory(true); - return groupSet; } From 0cb4005e83cd214ca222bfc6e4976f4bf7bfd4ad Mon Sep 17 00:00:00 2001 From: Jan Bernitt Date: Thu, 9 Jan 2025 14:53:20 +0100 Subject: [PATCH 2/6] feat: include most recent job progress in post condition error message [DHIS2-18751] (#19621) * fix: executeNow back to standard @Transactional [DHIS2-18751] * chore: removed unused fields and throws exceptions, add validation * fix: execute now API * fix: getSingleResult with null * fix: tx scopes so that execute now is visble directly * fix: mock test compile issue * fix: test setup --- .../scheduling/JobConfigurationService.java | 8 --- .../scheduling/JobConfigurationStore.java | 2 - .../dhis/scheduling/JobExecutionService.java} | 51 ++++++------- .../dhis/scheduling/JobSchedulerService.java | 23 +----- .../parameters/TestJobParameters.java | 2 + .../HibernateDataIntegrityStore.java | 3 +- .../HibernateDashboardItemStore.java | 2 +- .../HibernateOrganisationUnitStore.java | 2 +- .../DefaultJobConfigurationService.java | 58 +++++---------- ...n.java => DefaultJobExecutionService.java} | 58 +++++++++------ .../DefaultJobSchedulerService.java | 55 +++----------- .../HibernateJobConfigurationStore.java | 28 ++------ .../dhis/scheduling/JobCreationHelper.java | 72 ------------------- .../hisp/dhis/scheduling/JobScheduler.java | 4 +- .../dhis/scheduling/RecordingJobProgress.java | 18 ++++- .../org/hisp/dhis/scheduling/TestJob.java | 2 + .../HibernateMetadataProposalStore.java | 4 +- .../JobSchedulingControllerTest.java | 6 +- ...CompleteDataSetRegistrationController.java | 18 ++--- .../controller/DataIntegrityController.java | 17 ++--- .../controller/DataValueSetController.java | 21 +++--- .../controller/GeoJsonImportController.java | 17 ++--- .../controller/PredictionController.java | 9 ++- .../controller/PushAnalysisController.java | 8 +-- .../controller/ResourceTableController.java | 19 ++--- .../MetadataImportExportController.java | 19 ++--- .../JobConfigurationController.java | 11 ++- .../controller/sms/SmsInboundController.java | 15 ++-- .../imports/TrackerImportController.java | 15 ++-- .../validation/ValidationController.java | 12 ++-- .../imports/TrackerImportControllerTest.java | 10 +-- 31 files changed, 204 insertions(+), 385 deletions(-) rename dhis-2/{dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelperForTests.java => dhis-api/src/main/java/org/hisp/dhis/scheduling/JobExecutionService.java} (60%) rename dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/{JobCreationHelperForProduction.java => DefaultJobExecutionService.java} (54%) delete mode 100644 dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelper.java diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationService.java index dec50e0c1a39..80a0834f65a3 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationService.java @@ -32,7 +32,6 @@ import java.util.Map; import javax.annotation.Nonnull; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.schema.Property; import org.hisp.dhis.user.UserDetails; import org.springframework.util.MimeType; @@ -62,13 +61,6 @@ String create(JobConfiguration config, MimeType contentType, InputStream content void createDefaultJob(JobType type, UserDetails actingUser); - String createInTransaction( - JobConfiguration jobConfiguration, MimeType contentType, InputStream content) - throws ConflictException, NotFoundException; - - String createInTransaction(JobConfiguration jobConfiguration) - throws ConflictException, NotFoundException; - /** * Updates all {@link JobConfiguration}s that are not {@link JobConfiguration#isEnabled()} to * state {@link JobStatus#DISABLED} in case they are in state {@link JobStatus#SCHEDULED}. diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationStore.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationStore.java index 0d6de0b6e91e..5094901949d9 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationStore.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobConfigurationStore.java @@ -175,8 +175,6 @@ public interface JobConfigurationStore extends GenericDimensionalObjectStore - */ -@Slf4j -@RequiredArgsConstructor -@Service -@Profile("test") -public class JobCreationHelperForTests implements JobCreationHelper { - - private final JobConfigurationStore jobConfigurationStore; - private final FileResourceService fileResourceService; +public interface JobExecutionService { - @Transactional - public String create(JobConfiguration config) throws ConflictException { - return createFromConfig(config, jobConfigurationStore); - } + /** + * Creates and runs a new job for one-off operations executed via the scheduler. + * + * @param config a new job that does not exist yet + * @param contentType of the provided content data + * @param content the data that should be processed by the job which is stored as file + * @throws ConflictException in case the config belongs to an existing job or when the job isn't + * configured correctly + */ + void executeOnceNow( + @Nonnull JobConfiguration config, @Nonnull MimeType contentType, @Nonnull InputStream content) + throws ConflictException; - @Transactional - public String create(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException { - return createFromConfigAndInputStream( - config, contentType, content, jobConfigurationStore, fileResourceService); - } + /** + * Creates and runs a new job for one-off operations executed via the scheduler. + * + * @param config a new job that does not exist yet + * @throws ConflictException in case the config belongs to an existing job or when the job isn't + * configured correctly + */ + void executeOnceNow(@Nonnull JobConfiguration config) throws ConflictException; } diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobSchedulerService.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobSchedulerService.java index 8324a21fff0f..708989cad5a1 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobSchedulerService.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobSchedulerService.java @@ -27,18 +27,15 @@ */ package org.hisp.dhis.scheduling; -import java.io.InputStream; import java.util.List; import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import org.hisp.dhis.common.NonTransactional; import org.hisp.dhis.common.UID; import org.hisp.dhis.feedback.ConflictException; import org.hisp.dhis.feedback.ForbiddenException; import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.scheduling.JobProgress.Progress; -import org.springframework.util.MimeType; /** * This is the external API (called by users via controller API) for the scheduling. @@ -49,7 +46,9 @@ public interface JobSchedulerService { /** - * Attempts to switch the {@link JobConfiguration#getSchedulingType()} to {@link + * Ad-hoc execution of existing jobs. + * + *

Attempts to switch the {@link JobConfiguration#getSchedulingType()} to {@link * SchedulingType#ONCE_ASAP} for the given job. * *

A job with a {@link JobConfiguration#getCronExpression()} switches back to {@link @@ -63,22 +62,6 @@ public interface JobSchedulerService { */ void executeNow(@Nonnull String jobId) throws ConflictException, NotFoundException; - /** - * Executes a job configuration in a separate transaction. - * - * @param jobId the job id to execute - * @throws NotFoundException - * @throws ConflictException - */ - void runInTransaction(String jobId) throws NotFoundException, ConflictException; - - @NonTransactional - void createThenExecute(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException, NotFoundException; - - @NonTransactional - void createThenExecute(JobConfiguration config) throws ConflictException, NotFoundException; - /** * Reverts the {@link JobStatus} of the job from {@link JobStatus#RUNNING} to the appropriate * status after a failed execution. For an ad-hoc job this is {@link JobStatus#DISABLED}, for a diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/parameters/TestJobParameters.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/parameters/TestJobParameters.java index 4cb9d19d29b1..47df72b298eb 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/parameters/TestJobParameters.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/parameters/TestJobParameters.java @@ -66,6 +66,8 @@ public class TestJobParameters implements JobParameters { /** When true, an exception is used to fail, otherwise the progress tracking api is used */ @JsonProperty private boolean failWithException; + @JsonProperty private boolean failWithPostCondition; + /** Stage failure policy to use, when {@code null} it is the default policy */ @JsonProperty private FailurePolicy failWithPolicy; diff --git a/dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/hibernate/HibernateDataIntegrityStore.java b/dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/hibernate/HibernateDataIntegrityStore.java index f59b413fd85b..4e008cab873b 100644 --- a/dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/hibernate/HibernateDataIntegrityStore.java +++ b/dhis-2/dhis-services/dhis-service-administration/src/main/java/org/hisp/dhis/dataintegrity/hibernate/HibernateDataIntegrityStore.java @@ -58,7 +58,8 @@ public class HibernateDataIntegrityStore implements DataIntegrityStore { public DataIntegritySummary querySummary(DataIntegrityCheck check, String sql) { Date startTime = new Date(); // Note! that the SQL here can be touching any table so we cannot sync it - Object summary = entityManager.createNativeQuery(sql).getSingleResult(); + Object summary = + entityManager.createNativeQuery(sql).getResultStream().findFirst().orElse(null); return new DataIntegritySummary( check, startTime, new Date(), null, parseCount(summary), parsePercentage(summary)); } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dashboard/hibernate/HibernateDashboardItemStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dashboard/hibernate/HibernateDashboardItemStore.java index 087858dcf807..c7707902f8d0 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dashboard/hibernate/HibernateDashboardItemStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dashboard/hibernate/HibernateDashboardItemStore.java @@ -67,7 +67,7 @@ public Dashboard getDashboardFromDashboardItem(DashboardItem dashboardItem) { Query query = getTypedQuery("from Dashboard d where :item in elements(d.items)"); query.setParameter("item", dashboardItem); - return query.getSingleResult(); + return getSingleResult(query); } @Override diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java index a7a39218a51c..ce85602ee002 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/hibernate/HibernateOrganisationUnitStore.java @@ -319,7 +319,7 @@ public int getMaxLevel() { String hql = "select max(ou.hierarchyLevel) from OrganisationUnit ou"; Query query = getTypedQuery(hql); - Integer maxLength = query.getSingleResult(); + Integer maxLength = getSingleResult(query); return maxLength != null ? maxLength : 0; } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java index b3af654bb06b..e1749f453806 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java @@ -63,8 +63,8 @@ import org.hisp.dhis.commons.util.TextUtils; import org.hisp.dhis.feedback.ConflictException; import org.hisp.dhis.feedback.ErrorCode; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.fileresource.FileResource; +import org.hisp.dhis.fileresource.FileResourceDomain; import org.hisp.dhis.fileresource.FileResourceService; import org.hisp.dhis.fileresource.FileResourceStorageStatus; import org.hisp.dhis.jsontree.JsonMixed; @@ -92,17 +92,30 @@ public class DefaultJobConfigurationService implements JobConfigurationService { private final JobConfigurationStore jobConfigurationStore; private final FileResourceService fileResourceService; private final SystemSettingsProvider settingsProvider; - private final JobCreationHelper jobCreationHelper; @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) public String create(JobConfiguration config) throws ConflictException { - return jobCreationHelper.create(config); + config.setAutoFields(); + jobConfigurationStore.save(config); + return config.getUid(); } @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) public String create(JobConfiguration config, MimeType contentType, InputStream content) throws ConflictException { - return jobCreationHelper.create(config, contentType, content); + if (config.getSchedulingType() != SchedulingType.ONCE_ASAP) + throw new ConflictException( + "Job must be of type %s to allow content data".formatted(SchedulingType.ONCE_ASAP)); + config.setAutoFields(); // ensure UID is set + FileResource fr = + FileResource.ofKey(FileResourceDomain.JOB_DATA, config.getUid(), contentType.toString()); + fr.setUid(config.getUid()); + fr.setAssigned(true); + fileResourceService.syncSaveFileResource(fr, content); + jobConfigurationStore.save(config); + return config.getUid(); } @Override @@ -140,43 +153,6 @@ public void createDefaultJob(JobType type) { createDefaultJob(type, CurrentUserUtil.getCurrentUserDetails()); } - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public String createInTransaction( - JobConfiguration jobConfiguration, MimeType contentType, InputStream content) - throws ConflictException, NotFoundException { - String jobId = jobCreationHelper.create(jobConfiguration, contentType, content); - - if (!jobConfigurationStore.executeNow(jobId)) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); - if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); - if (job.getJobStatus() == JobStatus.RUNNING) - throw new ConflictException("Job is already running."); - if (job.getSchedulingType() == SchedulingType.ONCE_ASAP && job.getLastFinished() != null) - throw new ConflictException("Job did already run once."); - throw new ConflictException("Failed to transition job into ONCE_ASAP state."); - } - return jobId; - } - - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public String createInTransaction(JobConfiguration jobConfiguration) - throws ConflictException, NotFoundException { - String jobId = jobCreationHelper.create(jobConfiguration); - - if (!jobConfigurationStore.executeNow(jobId)) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); - if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); - if (job.getJobStatus() == JobStatus.RUNNING) - throw new ConflictException("Job is already running."); - if (job.getSchedulingType() == SchedulingType.ONCE_ASAP && job.getLastFinished() != null) - throw new ConflictException("Job did already run once."); - throw new ConflictException("Failed to transition job into ONCE_ASAP state."); - } - return jobId; - } - @Override @Transactional public int updateDisabledJobs() { diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelperForProduction.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobExecutionService.java similarity index 54% rename from dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelperForProduction.java rename to dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobExecutionService.java index 7eb431b13b48..b2b68b0038c9 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelperForProduction.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobExecutionService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2024, University of Oslo + * Copyright (c) 2004-2025, University of Oslo * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,36 +28,54 @@ package org.hisp.dhis.scheduling; import java.io.InputStream; +import javax.annotation.Nonnull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.hisp.dhis.common.NonTransactional; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.fileresource.FileResourceService; -import org.springframework.context.annotation.Profile; +import org.hisp.dhis.feedback.NotFoundException; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.util.MimeType; -/** - * @author Morten Svanæs - */ @Slf4j -@RequiredArgsConstructor @Service -@Profile("!test") -public class JobCreationHelperForProduction implements JobCreationHelper { +@RequiredArgsConstructor +public class DefaultJobExecutionService implements JobExecutionService { - private final JobConfigurationStore jobConfigurationStore; - private final FileResourceService fileResourceService; + private final JobConfigurationService jobConfigurationService; + private final JobSchedulerService jobSchedulerService; - @Transactional - public String create(JobConfiguration config) throws ConflictException { - return createFromConfig(config, jobConfigurationStore); + @Override + @NonTransactional + public void executeOnceNow( + @Nonnull JobConfiguration config, @Nonnull MimeType contentType, @Nonnull InputStream content) + throws ConflictException { + validateIsNewRunOnce(config); + executeOnceNow(jobConfigurationService.create(config, contentType, content)); } - @Transactional - public String create(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException { - return createFromConfigAndInputStream( - config, contentType, content, jobConfigurationStore, fileResourceService); + @Override + @NonTransactional + public void executeOnceNow(@Nonnull JobConfiguration config) throws ConflictException { + validateIsNewRunOnce(config); + executeOnceNow(jobConfigurationService.create(config)); + } + + private void executeOnceNow(String jobId) throws ConflictException { + try { + jobSchedulerService.executeNow(jobId); + } catch (NotFoundException ex) { + log.error("Ad-hoc job creation failed", ex); + ConflictException error = new ConflictException("Ad-hoc job creation failed"); + error.initCause(ex); + throw error; + } + } + + private void validateIsNewRunOnce(JobConfiguration config) throws ConflictException { + if (config.getId() != 0 || config.getSchedulingType() != SchedulingType.ONCE_ASAP) + throw new ConflictException( + "Job %s must be a run once type but was: %s" + .formatted(config.getName(), config.getSchedulingType())); } } diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java index dedad7f48690..a36cc0e5426d 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java @@ -33,7 +33,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.InputStream; import java.util.Collection; import java.util.List; import java.util.Map; @@ -50,9 +49,7 @@ import org.hisp.dhis.scheduling.JobProgress.Progress; import org.hisp.dhis.user.UserDetails; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.MimeType; /** * @author Jan Bernitt @@ -63,11 +60,9 @@ @RequiredArgsConstructor public class DefaultJobSchedulerService implements JobSchedulerService { - private final JobConfigurationStore jobConfigurationStore; private final JobRunner jobRunner; + private final JobConfigurationStore jobConfigurationStore; private final ObjectMapper jsonMapper; - private final JobCreationHelper jobCreationHelper; - private final JobConfigurationService jobConfigurationService; @Override @Transactional @@ -82,11 +77,16 @@ public boolean requestCancel(@Nonnull JobType type) { return jobId != null && requestCancel(jobId); } + /** + * Note that the TX is opened on the store level for {@code tryExecuteNow} so that state changes + * to the job are already visible to other threads even when called from within this method as + * done in case of continuous execution. + */ @Override - @Transactional + @NonTransactional public void executeNow(@Nonnull String jobId) throws NotFoundException, ConflictException { if (!jobConfigurationStore.tryExecuteNow(jobId)) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); + JobConfiguration job = jobConfigurationStore.getByUidNoAcl(jobId); if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); if (job.getJobStatus() == JobStatus.RUNNING) throw new ConflictException("Job is already running."); @@ -95,45 +95,12 @@ public void executeNow(@Nonnull String jobId) throws NotFoundException, Conflict throw new ConflictException("Failed to transition job into ONCE_ASAP state."); } if (!jobRunner.isScheduling()) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); - if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); - // run "execute now" request directly when scheduling is not active (tests) - jobRunner.runDueJob(job); - } else { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); - if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); - if (job.getJobType().isUsingContinuousExecution()) { - jobRunner.runIfDue(job); - } - } - } - - @Override - @NonTransactional - public void createThenExecute(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException, NotFoundException { - String jobId = jobConfigurationService.createInTransaction(config, contentType, content); - runInTransaction(jobId); - } - - @Override - @NonTransactional - public void createThenExecute(JobConfiguration config) - throws ConflictException, NotFoundException { - String jobId = jobConfigurationService.createInTransaction(config); - runInTransaction(jobId); - } - - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public void runInTransaction(String jobId) throws NotFoundException, ConflictException { - if (!jobRunner.isScheduling()) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); + JobConfiguration job = jobConfigurationStore.getByUidNoAcl(jobId); if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); // run "execute now" request directly when scheduling is not active (tests) jobRunner.runDueJob(job); } else { - JobConfiguration job = jobConfigurationStore.getByUid(jobId); + JobConfiguration job = jobConfigurationStore.getByUidNoAcl(jobId); if (job == null) throw new NotFoundException(JobConfiguration.class, jobId); if (job.getJobType().isUsingContinuousExecution()) { jobRunner.runIfDue(job); @@ -149,7 +116,7 @@ public void revertNow(@Nonnull UID jobId) if (!currentUser.isAuthorized(F_PERFORM_MAINTENANCE)) throw new ForbiddenException(JobConfiguration.class, jobId.getValue()); if (!jobConfigurationStore.tryRevertNow(jobId.getValue())) { - JobConfiguration job = jobConfigurationStore.getByUid(jobId.getValue()); + JobConfiguration job = jobConfigurationStore.getByUidNoAcl(jobId.getValue()); if (job == null) throw new NotFoundException(JobConfiguration.class, jobId.getValue()); if (job.getJobStatus() != JobStatus.RUNNING) throw new ConflictException("Job is not running"); diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java index 0cc216f956a8..d7db1f60b562 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java @@ -48,7 +48,6 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** @@ -269,8 +268,13 @@ select jsonb_build_object( Object::toString); } + /** + * Note that the transaction boundary has been set here instead of the service to avoid over + * complicating the "executeNow" service method which needs this change to be completed and + * visible at the end of this method. + */ @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) + @Transactional public boolean tryExecuteNow(@Nonnull String jobId) { String sql = """ @@ -287,23 +291,6 @@ public boolean tryExecuteNow(@Nonnull String jobId) { return nativeSynchronizedQuery(sql).setParameter("id", jobId).executeUpdate() > 0; } - @Override - public boolean executeNow(@Nonnull String jobId) { - String sql = - """ - update jobconfiguration - set - schedulingtype = 'ONCE_ASAP', - cancel = false, - jobstatus = 'SCHEDULED' - where uid = :id - and enabled = true - and jobstatus != 'RUNNING' - and (schedulingtype != 'ONCE_ASAP' or lastfinished is null) - """; - return nativeSynchronizedQuery(sql).setParameter("id", jobId).executeUpdate() > 0; - } - @Override public boolean tryStart(@Nonnull String jobId) { // only flip from SCHEDULED to RUNNING if no other job of same type is RUNNING @@ -532,8 +519,7 @@ public boolean tryRevertNow(@Nonnull String jobId) { } private static String getSingleResultOrNull(NativeQuery query) { - List res = query.list(); - return res == null || res.isEmpty() ? null : (String) res.get(0); + return (String) query.getResultStream().findFirst().orElse(null); } @SuppressWarnings("unchecked") diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelper.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelper.java deleted file mode 100644 index 5c15c2aff28f..000000000000 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobCreationHelper.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2004-2024, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.hisp.dhis.scheduling; - -import java.io.InputStream; -import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.fileresource.FileResource; -import org.hisp.dhis.fileresource.FileResourceDomain; -import org.hisp.dhis.fileresource.FileResourceService; -import org.springframework.util.MimeType; - -/** - * @author Morten Svanæs - */ -public interface JobCreationHelper { - - String create(JobConfiguration config) throws ConflictException; - - String create(JobConfiguration config, MimeType contentType, InputStream content) - throws ConflictException; - - default String createFromConfig(JobConfiguration config, JobConfigurationStore store) { - config.setAutoFields(); - store.save(config); - return config.getUid(); - } - - default String createFromConfigAndInputStream( - JobConfiguration config, - MimeType contentType, - InputStream content, - JobConfigurationStore store, - FileResourceService fileResourceService) - throws ConflictException { - if (config.getSchedulingType() != SchedulingType.ONCE_ASAP) - throw new ConflictException( - "Job must be of type %s to allow content data".formatted(SchedulingType.ONCE_ASAP)); - config.setAutoFields(); // ensure UID is set - FileResource fr = - FileResource.ofKey(FileResourceDomain.JOB_DATA, config.getUid(), contentType.toString()); - fr.setUid(config.getUid()); - fr.setAssigned(true); - fileResourceService.syncSaveFileResource(fr, content); - store.save(config); - return config.getUid(); - } -} diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobScheduler.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobScheduler.java index 0b74023e93b5..484e15f20d29 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobScheduler.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/JobScheduler.java @@ -179,7 +179,7 @@ private void runContinuous(JobType type) { String jobId = jobIds.poll(); while (jobId != null) { JobConfiguration config = service.getJobConfiguration(jobId); - if (config != null && config.getJobStatus() == JobStatus.SCHEDULED) { + if (config != null && (config.getJobStatus() == JobStatus.SCHEDULED)) { Instant now = Instant.now().truncatedTo(ChronoUnit.SECONDS); Instant dueTime = dueTime(now, config); runDueJob(config, dueTime); @@ -225,7 +225,7 @@ private void runDueJob(JobConfiguration config, Instant start) { JobProgress progress = null; try { settingsProvider.clearCurrentSettings(); // ensure working with recent settings - AtomicLong lastAlive = new AtomicLong(currentTimeMillis()); + AtomicLong lastAlive = new AtomicLong(0L); progress = service.startRun(jobId, config.getExecutedBy(), () -> alive(jobId, lastAlive)); jobService.getJob(config.getJobType()).execute(config, progress); diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java index c1f5eb712d25..d416b6133154 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java @@ -214,12 +214,27 @@ private RuntimeException cancellationException(boolean failedPostCondition) { if (skipRecording && cause instanceof RuntimeException rex) throw rex; CancellationException ex = failedPostCondition - ? new CancellationException("Non-null post-condition failed") + ? new CancellationException(postConditionFailureMessage()) : new CancellationException(); ex.initCause(cause); return ex; } + private String postConditionFailureMessage() { + String msg = "Non-null post-condition failed after: "; + Process p = incompleteProcess.get(); + if (p != null) { + msg += p.getDescription(); + Stage s = incompleteStage.get(); + if (s != null) { + msg += "\n => " + s.getDescription(); + Item i = incompleteItem.get(); + if (i != null) msg += "\n => " + i.getDescription(); + } + } + return msg; + } + @Override public void completedProcess(String summary, Object... args) { observer.run(); @@ -279,6 +294,7 @@ public void startingStage( if (isCancelled()) throw cancellationException(false); skipCurrentStage.set(false); tracker.startingStage(description, workItems); + incompleteItem.remove(); Stage stage = addStageRecord(getOrAddLastIncompleteProcess(), description, workItems, onFailure); logInfo(stage, "", description); diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/TestJob.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/TestJob.java index 5dc879166cc2..9a6f4089af55 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/TestJob.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/TestJob.java @@ -87,6 +87,7 @@ public void execute(JobConfiguration conf, JobProgress progress) { simulateWorkForDuration(params.getItemDuration()); if (failAtThisStage && item == failAtItem) { progress.failedWorkItem(msg); + if (params.isFailWithPostCondition()) progress.nonNullStagePostCondition(null); } else { progress.completedWorkItem(null); } @@ -95,6 +96,7 @@ public void execute(JobConfiguration conf, JobProgress progress) { } else if (failAtThisStage) { if (params.isFailWithException()) throw new RuntimeException(msg); progress.failedStage(msg); + if (params.isFailWithPostCondition()) progress.nonNullStagePostCondition(null); } else { progress.completedStage(format("Stage %d complete", stage + 1)); } diff --git a/dhis-2/dhis-services/dhis-service-metadata-workflow/src/main/java/org/hisp/dhis/metadata/HibernateMetadataProposalStore.java b/dhis-2/dhis-services/dhis-service-metadata-workflow/src/main/java/org/hisp/dhis/metadata/HibernateMetadataProposalStore.java index 90381eaaddeb..bdaee738bbc4 100644 --- a/dhis-2/dhis-services/dhis-service-metadata-workflow/src/main/java/org/hisp/dhis/metadata/HibernateMetadataProposalStore.java +++ b/dhis-2/dhis-services/dhis-service-metadata-workflow/src/main/java/org/hisp/dhis/metadata/HibernateMetadataProposalStore.java @@ -49,7 +49,9 @@ public MetadataProposal getByUid(String uid) { return getSession() .createQuery("from MetadataProposal p where p.uid = :uid", MetadataProposal.class) .setParameter("uid", uid) - .getSingleResult(); + .getResultStream() + .findFirst() + .orElse(null); } @Override diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobSchedulingControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobSchedulingControllerTest.java index 6ac3f48adf20..d6a2d2537f7a 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobSchedulingControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobSchedulingControllerTest.java @@ -35,14 +35,12 @@ import org.hisp.dhis.jsontree.JsonObject; import org.hisp.dhis.test.webapi.PostgresControllerIntegrationTestBase; import org.junit.jupiter.api.Test; -import org.springframework.transaction.annotation.Transactional; /** * Tests the {@link org.hisp.dhis.webapi.controller.scheduling.SchedulingController}. * * @author Jan Bernitt */ -@Transactional class JobSchedulingControllerTest extends PostgresControllerIntegrationTestBase { @Test @@ -65,14 +63,14 @@ void testGetCompletedProgressTypes() { @Test void testGetRunningProgress() { - JsonObject progress = GET("/scheduling/running/DATA_INTEGRITY").content(); + JsonObject progress = GET("/scheduling/running/PUSH_ANALYSIS").content(); assertTrue(progress.isObject()); assertTrue(progress.isEmpty()); } @Test void testGetCompletedProgress() { - JsonObject progress = GET("/scheduling/completed/DATA_INTEGRITY").content(); + JsonObject progress = GET("/scheduling/completed/PUSH_ANALYSIS").content(); assertTrue(progress.isObject()); assertTrue(progress.isEmpty()); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java index 7f4e13de57d0..a099aa28926f 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/CompleteDataSetRegistrationController.java @@ -63,17 +63,14 @@ import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.dxf2.webmessage.WebMessageException; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.organisationunit.OrganisationUnitService; import org.hisp.dhis.period.Period; import org.hisp.dhis.period.PeriodType; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.user.CurrentUserUtil; import org.hisp.dhis.user.UserDetails; -import org.hisp.dhis.user.UserService; import org.hisp.dhis.webapi.mvc.annotation.ApiVersion; import org.hisp.dhis.webapi.webdomain.CompleteDataSetRegQueryParams; import org.springframework.http.HttpStatus; @@ -112,10 +109,7 @@ public class CompleteDataSetRegistrationController { private final CompleteDataSetRegistrationExchangeService registrationExchangeService; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; - - private final UserService userService; + private final JobExecutionService jobExecutionService; // ------------------------------------------------------------------------- // GET @@ -149,7 +143,7 @@ public void getCompleteRegistrationsXml( @ResponseBody public WebMessage postCompleteRegistrationsXml( ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return asyncImport(importOptions, APPLICATION_XML, request); } @@ -164,7 +158,7 @@ public WebMessage postCompleteRegistrationsXml( @ResponseBody public WebMessage postCompleteRegistrationsJson( ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return asyncImport(importOptions, APPLICATION_JSON, request); } @@ -260,13 +254,13 @@ public void deleteCompleteDataSetRegistration( private WebMessage asyncImport( ImportOptions importOptions, MimeType mimeType, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { JobConfiguration jobConfig = new JobConfiguration(COMPLETE_DATA_SET_REGISTRATION_IMPORT); jobConfig.setJobParameters(importOptions); jobConfig.setExecutedBy(CurrentUserUtil.getCurrentUserDetails().getUid()); - jobSchedulerService.createThenExecute(jobConfig, mimeType, request.getInputStream()); + jobExecutionService.executeOnceNow(jobConfig, mimeType, request.getInputStream()); return jobConfigurationReport(jobConfig); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataIntegrityController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataIntegrityController.java index 606da5e7e712..e6fe860c71a0 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataIntegrityController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataIntegrityController.java @@ -47,11 +47,9 @@ import org.hisp.dhis.dataintegrity.DataIntegritySummary; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobParameters; -import org.hisp.dhis.scheduling.JobSchedulerService; import org.hisp.dhis.scheduling.JobType; import org.hisp.dhis.scheduling.parameters.DataIntegrityDetailsJobParameters; import org.hisp.dhis.scheduling.parameters.DataIntegrityJobParameters; @@ -82,8 +80,7 @@ public class DataIntegrityController { private final DataIntegrityService dataIntegrityService; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; @RequiresAuthority(anyOf = F_PERFORM_MAINTENANCE) @PostMapping @@ -92,7 +89,7 @@ public WebMessage runDataIntegrity( @CheckForNull @RequestParam(required = false) Set checks, @CheckForNull @RequestBody(required = false) Set checksBody, @CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { Set names = getCheckNames(checksBody, checks); return runDataIntegrityAsync(names, currentUser, DataIntegrityReportType.SUMMARY) .setLocation("/dataIntegrity/details?checks=" + toChecksList(names)); @@ -100,7 +97,7 @@ public WebMessage runDataIntegrity( private WebMessage runDataIntegrityAsync( @Nonnull Set checks, UserDetails currentUser, DataIntegrityReportType type) - throws ConflictException, NotFoundException { + throws ConflictException { JobType jobType = type == DataIntegrityReportType.DETAILS ? JobType.DATA_INTEGRITY_DETAILS @@ -113,7 +110,7 @@ private WebMessage runDataIntegrityAsync( : new DataIntegrityJobParameters(type, checks); config.setJobParameters(parameters); - jobSchedulerService.createThenExecute(config); + jobExecutionService.executeOnceNow(config); return jobConfigurationReport(config); } @@ -162,7 +159,7 @@ public WebMessage runSummariesCheck( @CheckForNull @RequestParam(required = false) Set checks, @CheckForNull @RequestBody(required = false) Set checksBody, @CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { Set names = getCheckNames(checksBody, checks); return runDataIntegrityAsync(names, currentUser, DataIntegrityReportType.SUMMARY) .setLocation("/dataIntegrity/summary?checks=" + toChecksList(names)); @@ -196,7 +193,7 @@ public WebMessage runDetailsCheck( @CheckForNull @RequestParam(required = false) Set checks, @RequestBody(required = false) Set checksBody, @CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { Set names = getCheckNames(checksBody, checks); return runDataIntegrityAsync(names, currentUser, DataIntegrityReportType.DETAILS) .setLocation("/dataIntegrity/details?checks=" + toChecksList(names)); diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataValueSetController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataValueSetController.java index b4a58a2d7181..4c2281fd5acb 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataValueSetController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/DataValueSetController.java @@ -67,11 +67,9 @@ import org.hisp.dhis.dxf2.importsummary.ImportSummary; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.node.Provider; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.security.RequiresAuthority; import org.hisp.dhis.user.CurrentUserUtil; import org.hisp.dhis.user.User; @@ -104,8 +102,7 @@ public class DataValueSetController { private final DataValueSetService dataValueSetService; private final AdxDataService adxDataService; private final UserService userService; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; // ------------------------------------------------------------------------- // Get @@ -234,7 +231,7 @@ private void getDataValueSet( @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postDxf2DataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MediaType.APPLICATION_XML, request); } @@ -249,7 +246,7 @@ public WebMessage postDxf2DataValueSet(ImportOptions importOptions, HttpServletR @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postAdxDataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MimeType.valueOf("application/adx+xml"), request); } @@ -264,7 +261,7 @@ public WebMessage postAdxDataValueSet(ImportOptions importOptions, HttpServletRe @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postJsonDataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MediaType.APPLICATION_JSON, request); } @@ -279,7 +276,7 @@ public WebMessage postJsonDataValueSet(ImportOptions importOptions, HttpServletR @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postCsvDataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MimeType.valueOf("application/csv"), request); } @@ -294,7 +291,7 @@ public WebMessage postCsvDataValueSet(ImportOptions importOptions, HttpServletRe @RequiresAuthority(anyOf = F_DATAVALUE_ADD) @ResponseBody public WebMessage postPdfDataValueSet(ImportOptions importOptions, HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { if (importOptions.isAsync()) { return startAsyncImport(importOptions, MediaType.APPLICATION_PDF, request); } @@ -312,13 +309,13 @@ public WebMessage postPdfDataValueSet(ImportOptions importOptions, HttpServletRe /** Starts an asynchronous import task. */ private WebMessage startAsyncImport( ImportOptions importOptions, MimeType mimeType, HttpServletRequest request) - throws ConflictException, IOException, NotFoundException { + throws ConflictException, IOException { JobConfiguration config = new JobConfiguration(DATAVALUE_IMPORT); User currentUser = userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()); config.setExecutedBy(currentUser.getUid()); config.setJobParameters(importOptions); - jobSchedulerService.createThenExecute(config, mimeType, request.getInputStream()); + jobExecutionService.executeOnceNow(config, mimeType, request.getInputStream()); return jobConfigurationReport(config); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/GeoJsonImportController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/GeoJsonImportController.java index 22537a7cacda..14895ef6a78d 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/GeoJsonImportController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/GeoJsonImportController.java @@ -46,12 +46,10 @@ import org.hisp.dhis.dxf2.importsummary.ImportStatus; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.feedback.Status; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobType; import org.hisp.dhis.scheduling.parameters.GeoJsonImportJobParams; import org.hisp.dhis.security.RequiresAuthority; @@ -77,12 +75,9 @@ @RestController @RequiredArgsConstructor public class GeoJsonImportController { - private final GeoJsonService geoJsonService; - - private final JobSchedulerService jobSchedulerService; - - private final JobConfigurationService jobConfigurationService; + private final GeoJsonService geoJsonService; + private final JobExecutionService jobExecutionService; private final UserService userService; @PostMapping( @@ -96,7 +91,7 @@ public WebMessage postImport( @RequestParam(required = false) boolean dryRun, @RequestParam(required = false, defaultValue = "false") boolean async, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { GeoJsonImportJobParams params = GeoJsonImportJobParams.builder() .attributeId(attributeId) @@ -113,14 +108,14 @@ public WebMessage postImport( private WebMessage runImport( boolean async, GeoJsonImportJobParams params, HttpServletRequest request) - throws ConflictException, NotFoundException, IOException { + throws ConflictException, IOException { User currentUser = userService.getUserByUsername(CurrentUserUtil.getCurrentUsername()); if (async) { JobConfiguration jobConfig = new JobConfiguration(JobType.GEOJSON_IMPORT); jobConfig.setJobParameters(params); jobConfig.setExecutedBy(currentUser.getUid()); - jobSchedulerService.createThenExecute(jobConfig, APPLICATION_JSON, request.getInputStream()); + jobExecutionService.executeOnceNow(jobConfig, APPLICATION_JSON, request.getInputStream()); return jobConfigurationReport(jobConfig); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PredictionController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PredictionController.java index 31a2cd084a31..f2e2594ad628 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PredictionController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PredictionController.java @@ -38,14 +38,13 @@ import org.hisp.dhis.common.OpenApi; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.feedback.Status; import org.hisp.dhis.predictor.PredictionService; import org.hisp.dhis.predictor.PredictionSummary; import org.hisp.dhis.predictor.Predictor; import org.hisp.dhis.scheduling.JobConfiguration; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobProgress; -import org.hisp.dhis.scheduling.JobSchedulerService; import org.hisp.dhis.scheduling.parameters.PredictorJobParameters; import org.hisp.dhis.security.RequiresAuthority; import org.hisp.dhis.user.CurrentUser; @@ -71,7 +70,7 @@ public class PredictionController { private final PredictionService predictionService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; @RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT}) @RequiresAuthority(anyOf = F_PREDICTOR_RUN) @@ -83,7 +82,7 @@ public WebMessage runPredictors( @RequestParam(value = "predictorGroup", required = false) List predictorGroups, @RequestParam(defaultValue = "false", required = false) boolean async, @CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { if (async) { JobConfiguration config = new JobConfiguration(PREDICTOR); @@ -97,7 +96,7 @@ public WebMessage runPredictors( config.setJobParameters(params); config.setExecutedBy(currentUser.getUid()); - jobSchedulerService.createThenExecute(config); + jobExecutionService.executeOnceNow(config); return jobConfigurationReport(config); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PushAnalysisController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PushAnalysisController.java index 725f4a462f4b..b285f2991d31 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PushAnalysisController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/PushAnalysisController.java @@ -43,8 +43,7 @@ import org.hisp.dhis.pushanalysis.PushAnalysisService; import org.hisp.dhis.query.GetObjectListParams; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobType; import org.hisp.dhis.scheduling.parameters.PushAnalysisJobParameters; import org.hisp.dhis.user.CurrentUserUtil; @@ -73,8 +72,7 @@ public class PushAnalysisController private final PushAnalysisService pushAnalysisService; private final ContextUtils contextUtils; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; @GetMapping("/{uid}/render") public void renderPushAnalytics(@PathVariable() String uid, HttpServletResponse response) @@ -112,6 +110,6 @@ public void sendPushAnalysis(@PathVariable() String uid) config.setJobParameters(new PushAnalysisJobParameters(uid)); config.setExecutedBy(CurrentUserUtil.getCurrentUserDetails().getUid()); - jobSchedulerService.createThenExecute(config); + jobExecutionService.executeOnceNow(config); } } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/ResourceTableController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/ResourceTableController.java index 8b1f4e9088e9..084696f7dfaa 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/ResourceTableController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/ResourceTableController.java @@ -56,10 +56,8 @@ import org.hisp.dhis.common.OpenApi; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.parameters.AnalyticsJobParameters; import org.hisp.dhis.scheduling.parameters.MonitoringJobParameters; import org.hisp.dhis.security.RequiresAuthority; @@ -85,8 +83,7 @@ @RequiredArgsConstructor public class ResourceTableController { - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; @RequestMapping( value = "/analytics", @@ -103,7 +100,7 @@ public WebMessage analytics( @RequestParam(defaultValue = "false") Boolean skipOrgUnitOwnership, @RequestParam(required = false) Integer lastYears, @RequestParam(defaultValue = "false") Boolean skipOutliers) - throws ConflictException, @OpenApi.Ignore NotFoundException { + throws ConflictException { Set skipTableTypes = new HashSet<>(); Set skipPrograms = new HashSet<>(); @@ -147,8 +144,7 @@ public WebMessage analytics( @RequestMapping(method = {PUT, POST}) @RequiresAuthority(anyOf = F_PERFORM_MAINTENANCE) @ResponseBody - public WebMessage resourceTables(@CurrentUser UserDetails currentUser) - throws ConflictException, @OpenApi.Ignore NotFoundException { + public WebMessage resourceTables(@CurrentUser UserDetails currentUser) throws ConflictException { JobConfiguration config = new JobConfiguration(RESOURCE_TABLE); config.setExecutedBy(currentUser.getUid()); return execute(config); @@ -159,17 +155,16 @@ public WebMessage resourceTables(@CurrentUser UserDetails currentUser) method = {PUT, POST}) @RequiresAuthority(anyOf = F_PERFORM_MAINTENANCE) @ResponseBody - public WebMessage monitoring() throws ConflictException, @OpenApi.Ignore NotFoundException { + public WebMessage monitoring() throws ConflictException { JobConfiguration config = new JobConfiguration(MONITORING); config.setJobParameters(new MonitoringJobParameters()); return execute(config); } - private WebMessage execute(JobConfiguration configuration) - throws ConflictException, NotFoundException { + private WebMessage execute(JobConfiguration configuration) throws ConflictException { log.debug("Executing requested job of type: '{}'", configuration.getJobType()); - jobSchedulerService.createThenExecute(configuration); + jobExecutionService.executeOnceNow(configuration); return jobConfigurationReport(configuration); } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportExportController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportExportController.java index b2428f6fb5fe..b5f34ff2442d 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportExportController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportExportController.java @@ -60,7 +60,6 @@ import org.hisp.dhis.dxf2.metadata.feedback.ImportReport; import org.hisp.dhis.dxf2.webmessage.WebMessage; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.feedback.Status; import org.hisp.dhis.importexport.ImportStrategy; import org.hisp.dhis.jsonpatch.BulkJsonPatches; @@ -70,15 +69,13 @@ import org.hisp.dhis.render.RenderFormat; import org.hisp.dhis.render.RenderService; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.JobProgress; -import org.hisp.dhis.scheduling.JobSchedulerService; import org.hisp.dhis.scheduling.JobType; import org.hisp.dhis.schema.SchemaService; import org.hisp.dhis.user.CurrentUserUtil; import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserService; -import org.hisp.dhis.user.UserSettingsService; import org.hisp.dhis.webapi.mvc.annotation.ApiVersion; import org.hisp.dhis.webapi.service.ContextService; import org.springframework.http.ResponseEntity; @@ -111,16 +108,14 @@ public class MetadataImportExportController { private final GmlImportService gmlImportService; private final MetadataExportService metadataExportService; private final UserService userService; - private final UserSettingsService userSettingsService; - private final JobConfigurationService jobConfigurationService; - private final JobSchedulerService jobSchedulerService; + private final JobExecutionService jobExecutionService; private final ObjectMapper jsonMapper; private final BulkPatchManager bulkPatchManager; @PostMapping(value = "", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @ResponseBody public WebMessage postJsonMetadata(HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { MetadataImportParams params = getMetadataImportParams(); if (params.isAsync()) { @@ -140,7 +135,7 @@ public WebMessage postJsonMetadata(HttpServletRequest request) @PostMapping(value = "", consumes = "application/csv") @ResponseBody public WebMessage postCsvMetadata(HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { MetadataImportParams params = getMetadataImportParams(); String classKey = request.getParameter("classKey"); @@ -173,7 +168,7 @@ public WebMessage postCsvMetadata(HttpServletRequest request) @PostMapping(value = "/gml", consumes = APPLICATION_XML_VALUE) @ResponseBody public WebMessage postGmlMetadata(HttpServletRequest request) - throws IOException, ConflictException, @OpenApi.Ignore NotFoundException { + throws IOException, ConflictException { MetadataImportParams params = getMetadataImportParams(); if (params.isAsync()) { @@ -255,12 +250,12 @@ private MetadataImportParams getMetadataImportParams() { private WebMessage startAsyncMetadata( MetadataImportParams params, MimeType contentType, HttpServletRequest request) - throws IOException, ConflictException, NotFoundException { + throws IOException, ConflictException { JobConfiguration config = new JobConfiguration(JobType.METADATA_IMPORT); config.setExecutedBy(CurrentUserUtil.getCurrentUserDetails().getUid()); config.setJobParameters(params); - jobSchedulerService.createThenExecute(config, contentType, request.getInputStream()); + jobExecutionService.executeOnceNow(config, contentType, request.getInputStream()); return jobConfigurationReport(config); } } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java index c2fe9c4b5cc1..c80fc39538c0 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java @@ -127,7 +127,7 @@ public JobTypes getJobTypeInfo() { public ObjectReport executeNow(@PathVariable("uid") String uid) throws NotFoundException, ConflictException { - jobSchedulerService.runInTransaction(uid); + jobSchedulerService.executeNow(uid); // OBS! This response is kept for better backwards compatibility return new ObjectReport(JobConfiguration.class, 0); @@ -236,11 +236,10 @@ private void checkExecutingUserOrAdmin(UID uid, boolean read) JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid.getValue()); if (obj == null) throw new NotFoundException(JobConfiguration.class, uid.getValue()); boolean isAuthorized = - currentUser != null - && (currentUser.isSuper() - || (!read && currentUser.isAuthorized("F_PERFORM_MAINTENANCE")) - || (read && currentUser.isAuthorized(F_JOB_LOG_READ.toString())) - || currentUser.getUid().equals(obj.getExecutedBy())); + currentUser.isSuper() + || !read && currentUser.isAuthorized("F_PERFORM_MAINTENANCE") + || read && currentUser.isAuthorized(F_JOB_LOG_READ.toString()) + || currentUser.getUid().equals(obj.getExecutedBy()); if (!isAuthorized) throw new ForbiddenException(JobConfiguration.class, obj.getUid()); } } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/sms/SmsInboundController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/sms/SmsInboundController.java index fcc2c2e12b96..fdf0872dc4de 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/sms/SmsInboundController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/sms/SmsInboundController.java @@ -50,12 +50,10 @@ import org.hisp.dhis.feedback.BadRequestException; import org.hisp.dhis.feedback.ConflictException; import org.hisp.dhis.feedback.ForbiddenException; -import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.query.GetObjectListParams; import org.hisp.dhis.render.RenderService; import org.hisp.dhis.scheduling.JobConfiguration; -import org.hisp.dhis.scheduling.JobConfigurationService; -import org.hisp.dhis.scheduling.JobSchedulerService; +import org.hisp.dhis.scheduling.JobExecutionService; import org.hisp.dhis.scheduling.parameters.SmsInboundProcessingJobParameters; import org.hisp.dhis.security.RequiresAuthority; import org.hisp.dhis.sms.command.SMSCommand; @@ -96,8 +94,7 @@ public class SmsInboundController extends AbstractCrudController Date: Thu, 9 Jan 2025 16:09:15 +0100 Subject: [PATCH 3/6] fix: user query parameter must include username [DHIS2-18748] (#19611) * fix: user query parameter must include username [DHIS2-18748] * test: adds a controller test querying matching username --- .../AbstractFullReadOnlyControllerTest.java | 22 +++++++++++++++++++ .../AbstractFullReadOnlyController.java | 3 ++- .../controller/user/UserController.java | 3 ++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyControllerTest.java index 0621b0724844..9d0087dc59bf 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyControllerTest.java @@ -38,7 +38,10 @@ import org.hisp.dhis.common.CodeGenerator; import org.hisp.dhis.dataelement.DataElement; import org.hisp.dhis.dataelement.DataElementService; +import org.hisp.dhis.jsontree.JsonList; import org.hisp.dhis.test.webapi.H2ControllerIntegrationTestBase; +import org.hisp.dhis.test.webapi.json.domain.JsonUser; +import org.hisp.dhis.user.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -54,6 +57,25 @@ class AbstractFullReadOnlyControllerTest extends H2ControllerIntegrationTestBase @Autowired private DataElementService dataElementService; + @Test + void testGetObjectList_QueryUsers() { + // this just simulates the normal setup with a system super-user + User user = switchToNewUser("system", "ALL"); + // make sure "system" does not occur in any other property that might be searched by query= + user.setName("x"); + user.setFirstName("y"); + user.setSurname("z"); + user.setCode("xyz"); + userService.updateUser(user); + + JsonList users = + GET("/users?fields=id,name,username&query=system") + .content() + .getList("users", JsonUser.class); + assertEquals(1, users.size()); + assertEquals("system", users.get(0).getUsername()); + } + @Test void testGetObjectListCsv() { createDataElements(36); diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyController.java index 9d88e596e414..02edb0947e54 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/AbstractFullReadOnlyController.java @@ -81,6 +81,7 @@ import org.hisp.dhis.security.acl.AclService; import org.hisp.dhis.system.util.ReflectionUtils; import org.hisp.dhis.user.CurrentUser; +import org.hisp.dhis.user.User; import org.hisp.dhis.user.UserDetails; import org.hisp.dhis.user.UserSettingsService; import org.hisp.dhis.webapi.mvc.annotation.ApiVersion; @@ -242,7 +243,7 @@ protected List getPreQueryMatches(P params) throws ConflictException { @Nonnull protected List getAdditionalFilters(P params) throws ConflictException { List filters = new ArrayList<>(); - if (params.getQuery() != null && !params.getQuery().isEmpty()) + if (params.getQuery() != null && !params.getQuery().isEmpty() && getEntityClass() != User.class) filters.add(Restrictions.query(getSchema(), params.getQuery())); List matches = getPreQueryMatches(params); // Note: null = no special filters, empty = no matches for special filters diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java index 0c90bd0acc08..7b038d49aeb0 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/user/UserController.java @@ -217,7 +217,8 @@ public static final class GetUserObjectListParams extends GetObjectListParams { @JsonIgnore boolean isUsingAnySpecialFilters() { - return phoneNumber != null + return getQuery() != null + || phoneNumber != null || canManage || authSubset || lastLogin != null From 8654bf223bd309b278c0e32234be1199dbcba708 Mon Sep 17 00:00:00 2001 From: Jan Bernitt Date: Thu, 9 Jan 2025 17:11:05 +0100 Subject: [PATCH 4/6] feat: adds sortable schema property [DHIS2-18749] (#19612) * feat: adds sortable schema property [DHIS2-18749] * fix: take persistent into account, also adds a test --- .../dhis/common/BaseIdentifiableObject.java | 66 ++-- .../hisp/dhis/common/BaseLinkableObject.java | 3 +- .../hisp/dhis/common/BaseNameableObject.java | 6 + .../java/org/hisp/dhis/common/Sortable.java | 42 +++ .../java/org/hisp/dhis/schema/Property.java | 287 ++++-------------- .../test/webapi/json/domain/JsonProperty.java | 4 + .../controller/SchemaControllerTest.java | 35 +++ 7 files changed, 161 insertions(+), 282 deletions(-) create mode 100644 dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Sortable.java diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java index 6eb4166a55c0..49dc780989af 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseIdentifiableObject.java @@ -49,6 +49,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import java.util.stream.Stream; +import javax.annotation.Nonnull; +import lombok.Setter; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.hibernate.annotations.Immutable; @@ -83,22 +85,22 @@ @JacksonXmlRootElement(localName = "identifiableObject", namespace = DxfNamespaces.DXF_2_0) public class BaseIdentifiableObject extends BaseLinkableObject implements IdentifiableObject { /** The database internal identifier for this Object. */ - protected long id; + @Setter protected long id; /** The unique identifier for this object. */ - @AuditAttribute protected String uid; + @Setter @AuditAttribute protected String uid; /** The unique code for this object. */ - @AuditAttribute protected String code; + @Setter @AuditAttribute protected String code; /** The name of this object. Required and unique. */ - protected String name; + @Setter protected String name; /** The date this object was created. */ - protected Date created; + @Setter protected Date created; /** The date this object was last updated. */ - protected Date lastUpdated; + @Setter protected Date lastUpdated; /** Set of the dynamic attributes values that belong to this data element. */ @AuditAttribute private AttributeValues attributeValues = AttributeValues.empty(); @@ -110,7 +112,7 @@ public class BaseIdentifiableObject extends BaseLinkableObject implements Identi * Cache for object translations, where the cache key is a combination of locale and translation * property, and value is the translated value. */ - private Map translationCache = new ConcurrentHashMap<>(); + private final Map translationCache = new ConcurrentHashMap<>(); /** User who created this object. This field is immutable and must not be updated. */ @Immutable protected User createdBy; @@ -119,13 +121,13 @@ public class BaseIdentifiableObject extends BaseLinkableObject implements Identi protected transient Access access; /** Users who have marked this object as a favorite. */ - protected Set favorites = new HashSet<>(); + @Setter protected Set favorites = new HashSet<>(); /** Last user updated this object. */ - protected User lastUpdatedBy; + @Setter protected User lastUpdatedBy; /** Object sharing (JSONB). */ - protected Sharing sharing = new Sharing(); + @Setter protected Sharing sharing = new Sharing(); // ------------------------------------------------------------------------- // Constructors @@ -162,7 +164,7 @@ public BaseIdentifiableObject(IdentifiableObject identifiableObject) { * name. */ @Override - public int compareTo(IdentifiableObject object) { + public int compareTo(@Nonnull IdentifiableObject object) { if (this.getDisplayName() == null) { return object.getDisplayName() == null ? 0 : 1; } @@ -182,10 +184,6 @@ public long getId() { return id; } - public void setId(long id) { - this.id = id; - } - @Override @JsonProperty(value = "id") @JacksonXmlProperty(localName = "id", isAttribute = true) @@ -196,10 +194,6 @@ public String getUid() { return uid; } - public void setUid(String uid) { - this.uid = uid; - } - @Override @JsonProperty @JacksonXmlProperty(isAttribute = true) @@ -209,10 +203,6 @@ public String getCode() { return code; } - public void setCode(String code) { - this.code = code; - } - @Override @JsonProperty @JacksonXmlProperty(isAttribute = true) @@ -222,11 +212,8 @@ public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - @Override + @Sortable(whenPersisted = false) @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @Translatable(propertyName = "name", key = "NAME") @@ -243,10 +230,6 @@ public Date getCreated() { return created; } - public void setCreated(Date created) { - this.created = created; - } - @Override @OpenApi.Property(UserPropertyTransformer.UserDto.class) @JsonProperty @@ -258,10 +241,6 @@ public User getLastUpdatedBy() { return lastUpdatedBy; } - public void setLastUpdatedBy(User lastUpdatedBy) { - this.lastUpdatedBy = lastUpdatedBy; - } - @Override @JsonProperty @JacksonXmlProperty(isAttribute = true) @@ -271,10 +250,6 @@ public Date getLastUpdated() { return lastUpdated; } - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; - } - public record AttributeValue(@JsonProperty Attribute attribute, @JsonProperty String value) {} @Override @@ -308,6 +283,7 @@ public String getAttributeValue(String attributeUid) { @Gist(included = Include.FALSE) @Override + @Sortable(value = false) @JsonProperty @JacksonXmlElementWrapper(localName = "translations", namespace = DxfNamespaces.DXF_2_0) @JacksonXmlProperty(localName = "translation", namespace = DxfNamespaces.DXF_2_0) @@ -387,8 +363,9 @@ public void setOwner(String userId) { } @Override + @Sortable(value = false) @Gist(included = Include.FALSE) - @JsonProperty + @JsonProperty(access = JsonProperty.Access.READ_ONLY) @JacksonXmlProperty(localName = "access", namespace = DxfNamespaces.DXF_2_0) public Access getAccess() { return access; @@ -407,10 +384,6 @@ public Set getFavorites() { return favorites; } - public void setFavorites(Set favorites) { - this.favorites = favorites; - } - @Override @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @@ -422,6 +395,7 @@ public boolean isFavorite() { } @Override + @Sortable(value = false) @Gist(included = Include.FALSE) @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @@ -433,10 +407,6 @@ public Sharing getSharing() { return sharing; } - public void setSharing(Sharing sharing) { - this.sharing = sharing; - } - @Override public boolean setAsFavorite(UserDetails user) { if (this.favorites == null) { diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseLinkableObject.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseLinkableObject.java index 382a88fc72e3..df59ee82f663 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseLinkableObject.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseLinkableObject.java @@ -45,7 +45,8 @@ public class BaseLinkableObject implements LinkableObject { private transient String href; @Override - @JsonProperty + @Sortable(value = false) + @JsonProperty(access = JsonProperty.Access.READ_ONLY) @JacksonXmlProperty(isAttribute = true) @Property(PropertyType.URL) public String getHref() { diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseNameableObject.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseNameableObject.java index fbc0c690596a..33af9314ccb5 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseNameableObject.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/BaseNameableObject.java @@ -166,6 +166,7 @@ public String toString() { // ------------------------------------------------------------------------- @Override + @Sortable @JsonProperty @JacksonXmlProperty(isAttribute = true) @PropertyRange(min = 1) @@ -178,6 +179,7 @@ public void setShortName(String shortName) { } @Override + @Sortable(whenPersisted = false) @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @Translatable(propertyName = "shortName", key = "SHORT_NAME") @@ -186,6 +188,7 @@ public String getDisplayShortName() { } @Override + @Sortable @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @PropertyRange(min = 1) @@ -198,6 +201,7 @@ public void setDescription(String description) { } @Override + @Sortable(value = false) @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @Translatable(propertyName = "description", key = "DESCRIPTION") @@ -206,6 +210,7 @@ public String getDisplayDescription() { } @JsonProperty + @Sortable(whenPersisted = false) @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) @Translatable(propertyName = "formName", key = "FORM_NAME") public String getDisplayFormName() { @@ -217,6 +222,7 @@ public String getFormNameFallback() { return formName != null && !formName.isEmpty() ? getFormName() : getDisplayName(); } + @Sortable @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getFormName() { diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Sortable.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Sortable.java new file mode 100644 index 000000000000..4ed4854e0479 --- /dev/null +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/Sortable.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2004-2025, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.common; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Sortable { + + boolean value() default true; + + boolean whenPersisted() default true; +} diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/schema/Property.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/schema/Property.java index 4dabd7abd1e7..56ae50fce9b7 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/schema/Property.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/schema/Property.java @@ -38,10 +38,13 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; import org.hisp.dhis.common.DxfNamespaces; import org.hisp.dhis.common.EmbeddedObject; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.common.NameableObject; +import org.hisp.dhis.common.Sortable; import org.hisp.dhis.hibernate.HibernateProxyUtils; import org.springframework.core.Ordered; @@ -54,56 +57,56 @@ public class Property implements Ordered, Klass { private Class klass; /** Normalized type of this property */ - private PropertyType propertyType; + @Setter private PropertyType propertyType; /** If this property is a collection, this is the class of the items inside the collection. */ - private Class itemKlass; + @Setter private Class itemKlass; /** * If this property is a collection, this is the normalized type of the items inside the * collection. */ - private PropertyType itemPropertyType; + @Setter private PropertyType itemPropertyType; /** Direct link to getter for this property. */ - private Method getterMethod; + @Getter @Setter private Method getterMethod; /** Direct link to setter for this property. */ - private Method setterMethod; + @Getter @Setter private Method setterMethod; /** * Name for this property, if this class is a collection, it is the name of the items -inside- the * collection and not the collection wrapper itself. */ - private String name; + @Setter private String name; /** Name for actual field, used to persistence operations and getting setter/getter. */ - private String fieldName; + @Setter private String fieldName; /** * Is this property persisted somewhere. This property will be used to create criteria queries on * demand (default: false) */ - private boolean persisted; + @Setter private boolean persisted; /** Name of collection wrapper. */ - private String collectionName; + @Setter private String collectionName; /** If this Property is a collection, should it be wrapped with collectionName? */ - private Boolean collectionWrapping; + @Setter private Boolean collectionWrapping; /** * Description if provided, will be fetched from @Description annotation. * * @see org.hisp.dhis.common.annotation.Description */ - private String description; + @Setter private String description; /** Namespace used for this property. */ - private String namespace; + @Setter private String namespace; /** Usually only used for XML. Is this property considered an attribute. */ - private boolean attribute; + @Setter private boolean attribute; /** * This property is true if the type pointed to does not export any properties itself, it is then @@ -111,120 +114,121 @@ public class Property implements Ordered, Klass { * type of the collection, e.g. List would set simple to be true, but List * would set it to false. */ - private boolean simple; + @Setter private boolean simple; /** * This property is true if the type of this property is a sub-class of Collection. * * @see java.util.Collection */ - private boolean collection; + @Setter private boolean collection; /** * This property is true if collection=true and klass points to a implementation with a stable * order (i.e. List). */ - private boolean ordered; + @Setter private boolean ordered; /** * If this property is a complex object or a collection, is this property considered the owner of * that relationship (important for imports etc). */ - private boolean owner; + @Setter private boolean owner; /** * Is this class a sub-class of IdentifiableObject * * @see org.hisp.dhis.common.IdentifiableObject */ - private boolean identifiableObject; + @Setter private boolean identifiableObject; /** * Is this class a sub-class of NameableObject * * @see org.hisp.dhis.common.NameableObject */ - private boolean nameableObject; + @Setter private boolean nameableObject; /** Does this class implement {@link EmbeddedObject} ? */ - private boolean embeddedObject; + @Setter private boolean embeddedObject; /** Does this class implement {@link EmbeddedObject} ? */ - private boolean analyticalObject; + @Setter private boolean analyticalObject; /** Can this property be read. */ - private boolean readable; + @Setter private boolean readable; /** Can this property be written to. */ - private boolean writable; + @Setter private boolean writable; /** Are the values for this property required to be unique? */ - private boolean unique; + @Setter private boolean unique; /** Nullability of this property. */ - private boolean required; + @Setter private boolean required; /** Maximum length/size/value of this property. */ - private Integer length; + @Setter private Integer length; /** Minimum size/length of this property. */ - private Double max; + @Setter private Double max; /** Minimum size/length of this property. */ - private Double min; + @Setter private Double min; /** Cascading used when doing CRUD operations. */ - private String cascade; + @Setter private String cascade; /** Is property many-to-many. */ - private boolean manyToMany; + @Setter private boolean manyToMany; /** Is property one-to-one. */ - private boolean oneToOne; + @Setter private boolean oneToOne; /** Is property many-to-one. */ - private boolean manyToOne; + @Setter private boolean manyToOne; /** Is property one-to-many. */ - private boolean oneToMany; + @Setter private boolean oneToMany; /** The hibernate role of the owning side. */ - private String owningRole; + @Setter private String owningRole; /** The hibernate role of the inverse side (if many-to-many). */ - private String inverseRole; + @Setter private String inverseRole; /** If property type is enum, this is the list of valid options. */ - private List constants; + @Setter private List constants; /** Used by LinkService to link to the Schema describing this type (if reference). */ - private String href; + @Setter private String href; /** Points to relative Web-API endpoint (if exposed). */ - private String relativeApiEndpoint; + @Setter private String relativeApiEndpoint; /** Used by LinkService to link to the API endpoint containing this type. */ - private String apiEndpoint; + @Setter private String apiEndpoint; /** PropertyTransformer to apply to this property before and field filtering is applied. */ - private Class propertyTransformer; + @Getter @Setter private Class propertyTransformer; /** Default value of the Property */ private Object defaultValue; - private boolean translatable; + @Setter private boolean translatable; - private String translationKey; + @Setter private String translationKey; /** * The translation key use for retrieving I18n translation of this property's name. The key * follows snake_case naming convention. */ - private String i18nTranslationKey; + @Setter private String i18nTranslationKey; private GistPreferences gistPreferences = GistPreferences.DEFAULT; /** All annotations present on this property (either through field or method) */ + @Getter @Setter private Map, Annotation> annotations = new HashMap<>(); public Property() {} @@ -259,144 +263,85 @@ public PropertyType getPropertyType() { return propertyType; } - public void setPropertyType(PropertyType propertyType) { - this.propertyType = propertyType; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Class getItemKlass() { return itemKlass; } - public void setItemKlass(Class itemKlass) { - this.itemKlass = itemKlass; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public PropertyType getItemPropertyType() { return itemPropertyType; } - public void setItemPropertyType(PropertyType itemPropertyType) { - this.itemPropertyType = itemPropertyType; - } - - public Method getGetterMethod() { - return getterMethod; - } - - public void setGetterMethod(Method getterMethod) { - this.getterMethod = getterMethod; - } - - public Method getSetterMethod() { - return setterMethod; - } - - public void setSetterMethod(Method setterMethod) { - this.setterMethod = setterMethod; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getName() { return name; } - public void setName(String name) { - this.name = name; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getFieldName() { return fieldName; } - public void setFieldName(String fieldName) { - this.fieldName = fieldName; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isPersisted() { return persisted; } - public void setPersisted(boolean persisted) { - this.persisted = persisted; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getCollectionName() { return collectionName != null ? collectionName : (isCollection() ? name : null); } - public void setCollectionName(String collectionName) { - this.collectionName = collectionName; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Boolean isCollectionWrapping() { return collectionWrapping; } - public void setCollectionWrapping(Boolean collectionWrapping) { - this.collectionWrapping = collectionWrapping; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getDescription() { return description; } - public void setDescription(String description) { - this.description = description; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getNamespace() { return namespace; } - public void setNamespace(String namespace) { - this.namespace = namespace; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isAttribute() { return attribute; } - public void setAttribute(boolean attribute) { - this.attribute = attribute; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isSimple() { return simple; } - public void setSimple(boolean simple) { - this.simple = simple; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isCollection() { return collection; } - public void setCollection(boolean collection) { - this.collection = collection; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) + public boolean isSortable() { + Sortable sortable = getterMethod == null ? null : getterMethod.getAnnotation(Sortable.class); + return sortable != null + ? sortable.value() && (!sortable.whenPersisted() || isPersisted()) + : !isCollection() && isSimple() && isPersisted(); } @JsonProperty @@ -405,220 +350,132 @@ public boolean isOrdered() { return ordered; } - public void setOrdered(boolean ordered) { - this.ordered = ordered; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isOwner() { return owner; } - public void setOwner(boolean owner) { - this.owner = owner; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isIdentifiableObject() { return identifiableObject; } - public void setIdentifiableObject(boolean identifiableObject) { - this.identifiableObject = identifiableObject; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isNameableObject() { return nameableObject; } - public void setNameableObject(boolean nameableObject) { - this.nameableObject = nameableObject; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isEmbeddedObject() { return embeddedObject; } - public void setEmbeddedObject(boolean embeddedObject) { - this.embeddedObject = embeddedObject; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isAnalyticalObject() { return analyticalObject; } - public void setAnalyticalObject(boolean analyticalObject) { - this.analyticalObject = analyticalObject; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isReadable() { return readable; } - public void setReadable(boolean readable) { - this.readable = readable; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isWritable() { return writable; } - public void setWritable(boolean writable) { - this.writable = writable; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isUnique() { return unique; } - public void setUnique(boolean unique) { - this.unique = unique; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isRequired() { return required; } - public void setRequired(boolean required) { - this.required = required; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Integer getLength() { return length; } - public void setLength(Integer length) { - this.length = length; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Double getMax() { return max; } - public void setMax(Double max) { - this.max = max; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Double getMin() { return min; } - public void setMin(Double min) { - this.min = min; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getCascade() { return cascade; } - public void setCascade(String cascade) { - this.cascade = cascade; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isManyToMany() { return manyToMany; } - public void setManyToMany(boolean manyToMany) { - this.manyToMany = manyToMany; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isOneToOne() { return oneToOne; } - public void setOneToOne(boolean oneToOne) { - this.oneToOne = oneToOne; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isManyToOne() { return manyToOne; } - public void setManyToOne(boolean manyToOne) { - this.manyToOne = manyToOne; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public boolean isOneToMany() { return oneToMany; } - public void setOneToMany(boolean oneToMany) { - this.oneToMany = oneToMany; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getOwningRole() { return owningRole; } - public void setOwningRole(String owningRole) { - this.owningRole = owningRole; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getInverseRole() { return inverseRole; } - public void setInverseRole(String inverseRole) { - this.inverseRole = inverseRole; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getTranslationKey() { return this.translationKey; } - public void setTranslationKey(String translationKey) { - this.translationKey = translationKey; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getI18nTranslationKey() { return i18nTranslationKey; } - public void setI18nTranslationKey(String i18nTranslationKey) { - this.i18nTranslationKey = i18nTranslationKey; - } - @JsonProperty @JacksonXmlElementWrapper(localName = "constants", namespace = DxfNamespaces.DXF_2_0) @JacksonXmlProperty(localName = "constant", namespace = DxfNamespaces.DXF_2_0) @@ -626,54 +483,30 @@ public List getConstants() { return constants; } - public void setConstants(List constants) { - this.constants = constants; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getHref() { return href; } - public void setHref(String href) { - this.href = href; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getRelativeApiEndpoint() { return relativeApiEndpoint; } - public void setRelativeApiEndpoint(String relativeApiEndpoint) { - this.relativeApiEndpoint = relativeApiEndpoint; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public String getApiEndpoint() { return apiEndpoint; } - public void setApiEndpoint(String apiEndpoint) { - this.apiEndpoint = apiEndpoint; - } - @JsonProperty("propertyTransformer") @JacksonXmlProperty(localName = "propertyTransformer", namespace = DxfNamespaces.DXF_2_0) public boolean hasPropertyTransformer() { return propertyTransformer != null; } - public Class getPropertyTransformer() { - return propertyTransformer; - } - - public void setPropertyTransformer(Class propertyTransformer) { - this.propertyTransformer = propertyTransformer; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public Object getDefaultValue() { @@ -695,10 +528,6 @@ public boolean isTranslatable() { return this.translatable; } - public void setTranslatable(boolean translatable) { - this.translatable = translatable; - } - @JsonProperty @JacksonXmlProperty(namespace = DxfNamespaces.DXF_2_0) public GistPreferences getGistPreferences() { @@ -709,14 +538,6 @@ public void setGistPreferences(GistPreferences gistPreferences) { this.gistPreferences = gistPreferences == null ? GistPreferences.DEFAULT : gistPreferences; } - public Map, Annotation> getAnnotations() { - return annotations; - } - - public void setAnnotations(Map, Annotation> annotations) { - this.annotations = annotations; - } - @SuppressWarnings("unchecked") public A getAnnotation(Class annotationType) { return (A) annotations.get(annotationType); diff --git a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/webapi/json/domain/JsonProperty.java b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/webapi/json/domain/JsonProperty.java index e3bb6c08751d..27275dff55cf 100644 --- a/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/webapi/json/domain/JsonProperty.java +++ b/dhis-2/dhis-support/dhis-support-test/src/main/java/org/hisp/dhis/test/webapi/json/domain/JsonProperty.java @@ -90,6 +90,10 @@ default boolean isSimple() { return getBoolean("simple").booleanValue(); } + default boolean isSortable() { + return getBoolean("sortable").booleanValue(); + } + default boolean isRequired() { return getBoolean("required").booleanValue(); } diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/SchemaControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/SchemaControllerTest.java index 0bf231cd1258..1b13c7777b05 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/SchemaControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/SchemaControllerTest.java @@ -27,14 +27,18 @@ */ package org.hisp.dhis.webapi.controller; +import static java.util.stream.Collectors.toSet; import static org.hisp.dhis.test.webapi.Assertions.assertWebMessage; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Optional; +import java.util.Set; import org.hisp.dhis.http.HttpStatus; +import org.hisp.dhis.jsontree.JsonList; import org.hisp.dhis.jsontree.JsonObject; import org.hisp.dhis.schema.PropertyType; import org.hisp.dhis.test.webapi.H2ControllerIntegrationTestBase; @@ -145,4 +149,35 @@ void testUserNameIsPersistedButReadOnly() { assertFalse(name.isWritable()); assertFalse(name.isRequired()); } + + @Test + void testSortableProperties() { + JsonSchema de = GET("/schemas/dataElement").content().as(JsonSchema.class); + JsonList properties = de.getProperties(); + Set expected = + Set.of( + "fieldMask", + "aggregationType", + "code", + "domainType", + "displayName", + "created", + "description", + "zeroIsSignificant", + "displayFormName", + "displayShortName", + "url", + "lastUpdated", + "valueType", + "formName", + "name", + "id", + "shortName"); + Set actual = + properties.stream() + .filter(JsonProperty::isSortable) + .map(JsonProperty::getName) + .collect(toSet()); + assertEquals(expected, actual); + } } From 1a5a15b5c291b503236c13f0a253286f5bbd46ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:41:43 +0100 Subject: [PATCH 5/6] chore(deps): bump org.apache.tomcat.embed:tomcat-embed-core (#19624) Bumps org.apache.tomcat.embed:tomcat-embed-core from 10.1.31 to 10.1.34. --- updated-dependencies: - dependency-name: org.apache.tomcat.embed:tomcat-embed-core dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dhis-2/dhis-web-server/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dhis-2/dhis-web-server/pom.xml b/dhis-2/dhis-web-server/pom.xml index 5577fc51763e..2d7993a319c3 100644 --- a/dhis-2/dhis-web-server/pom.xml +++ b/dhis-2/dhis-web-server/pom.xml @@ -15,7 +15,7 @@ ../ ${maven.build.timestamp} - 10.1.31 + 10.1.34 3.4.4 tomcat:${tomcat.version}-jre17 dhis2/core-dev:local From f11b229f20ce73a1eae65f55b172b7a503af2c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Helge=20=C3=98verland?= Date: Fri, 10 Jan 2025 09:28:05 +0100 Subject: [PATCH 6/6] chore: Remove redundant test code (#19632) --- .../organisationunit/OrganisationUnit.java | 1 - .../event/EventOperationParamsMapperTest.java | 8 +- .../SecurityOwnershipValidatorTest.java | 1 + .../event/SecurityOwnershipValidatorTest.java | 1 + .../SecurityOwnershipValidatorTest.java | 1 + .../dhis/analytics/data/QueryPlannerTest.java | 12 +-- .../OrganisationUnitServiceTest.java | 86 ++++--------------- .../ResourceTableServiceTest.java | 8 +- 8 files changed, 29 insertions(+), 89 deletions(-) diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java index 2cce28d7cc7d..aabb76e20d90 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnit.java @@ -555,7 +555,6 @@ public void updateParent(OrganisationUnit newParent) { } this.parent = newParent; - newParent.getChildren().add(this); } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java index c6e979d6edfc..c235081c16d5 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/export/event/EventOperationParamsMapperTest.java @@ -421,9 +421,7 @@ void shouldMapOrgUnitWhenProgramProvidedAndRequestedOrgUnitInSearchScope( program.setAccessLevel(accessLevel); OrganisationUnit searchScopeOrgUnit = createOrganisationUnit('A'); - OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B'); - searchScopeOrgUnit.setChildren(Set.of(searchScopeChildOrgUnit)); - searchScopeChildOrgUnit.setParent(searchScopeOrgUnit); + OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B', searchScopeOrgUnit); User user = new User(); user.setUid(CodeGenerator.generateUid()); @@ -453,9 +451,7 @@ void shouldMapOrgUnitWhenModeAllProgramProvidedAndRequestedOrgUnitInSearchScope( program.setAccessLevel(OPEN); OrganisationUnit searchScopeOrgUnit = createOrganisationUnit('A'); - OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B'); - searchScopeOrgUnit.setChildren(Set.of(searchScopeChildOrgUnit)); - searchScopeChildOrgUnit.setParent(searchScopeOrgUnit); + OrganisationUnit searchScopeChildOrgUnit = createOrganisationUnit('B', searchScopeOrgUnit); User user = new User(); user.setUid(CodeGenerator.generateUid()); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidatorTest.java index f471e3731b0d..a2a34fd7197f 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/enrollment/SecurityOwnershipValidatorTest.java @@ -111,6 +111,7 @@ class SecurityOwnershipValidatorTest extends TestBase { public void setUp() { organisationUnit = createOrganisationUnit('A'); organisationUnit.setUid(ORG_UNIT_ID); + organisationUnit.updatePath(); User u = makeUser("A"); user = UserDetails.fromUser(u); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidatorTest.java index 552ecdc2797d..c09843523208 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/SecurityOwnershipValidatorTest.java @@ -112,6 +112,7 @@ public void setUp() { when(bundle.getUser()).thenReturn(user); organisationUnit = createOrganisationUnit('A'); organisationUnit.setUid(ORG_UNIT_ID); + organisationUnit.updatePath(); trackedEntityType = createTrackedEntityType('A'); trackedEntityType.setUid(TE_TYPE_ID); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidatorTest.java index 38186f6b4c65..9228ee53a58a 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/trackedentity/SecurityOwnershipValidatorTest.java @@ -106,6 +106,7 @@ class SecurityOwnershipValidatorTest extends TestBase { public void setUp() { organisationUnit = createOrganisationUnit('A'); organisationUnit.setUid(ORG_UNIT_ID); + organisationUnit.updatePath(); User userA = makeUser("A"); userA.addOrganisationUnit(organisationUnit); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java index f1b9b9001e31..19c4c85f3f7e 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java @@ -565,14 +565,10 @@ void planQueryB() { */ @Test void planQueryC() { - ouB.setParent(ouA); - ouC.setParent(ouA); - ouD.setParent(ouB); - ouE.setParent(ouC); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); - ouD.getChildren().add(ouB); - ouC.getChildren().add(ouE); + ouB.updateParent(ouA); + ouC.updateParent(ouA); + ouD.updateParent(ouB); + ouE.updateParent(ouC); organisationUnitService.updateOrganisationUnit(ouA); organisationUnitService.updateOrganisationUnit(ouB); organisationUnitService.updateOrganisationUnit(ouC); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/organisationunit/OrganisationUnitServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/organisationunit/OrganisationUnitServiceTest.java index 435a06608f51..ee364855fc4d 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/organisationunit/OrganisationUnitServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/organisationunit/OrganisationUnitServiceTest.java @@ -241,7 +241,6 @@ void testGetOrganisationUnitWithChildren() throws Exception { OrganisationUnit unit3 = createOrganisationUnit('C', unit2); OrganisationUnit unit4 = createOrganisationUnit('D'); long id1 = organisationUnitService.addOrganisationUnit(unit1); - unit1.getChildren().add(unit2); organisationUnitService.addOrganisationUnit(unit2); organisationUnitService.addOrganisationUnit(unit3); organisationUnitService.addOrganisationUnit(unit4); @@ -308,12 +307,6 @@ void testGetOrganisationUnitWithChildrenMaxLevel() { OrganisationUnit unit5 = createOrganisationUnit('E', unit2); OrganisationUnit unit6 = createOrganisationUnit('F', unit3); OrganisationUnit unit7 = createOrganisationUnit('G', unit3); - unit1.getChildren().add(unit2); - unit1.getChildren().add(unit3); - unit2.getChildren().add(unit4); - unit2.getChildren().add(unit5); - unit3.getChildren().add(unit6); - unit3.getChildren().add(unit7); long id1 = organisationUnitService.addOrganisationUnit(unit1); long id2 = organisationUnitService.addOrganisationUnit(unit2); organisationUnitService.addOrganisationUnit(unit3); @@ -415,23 +408,18 @@ void testGetOrganisationUnitsAtLevel() { organisationUnitService.addOrganisationUnitLevel(levelC); organisationUnitService.addOrganisationUnitLevel(levelD); OrganisationUnit unit1 = createOrganisationUnit('1'); - organisationUnitService.addOrganisationUnit(unit1); OrganisationUnit unit2 = createOrganisationUnit('2', unit1); - unit1.getChildren().add(unit2); - organisationUnitService.addOrganisationUnit(unit2); OrganisationUnit unit3 = createOrganisationUnit('3', unit2); - unit2.getChildren().add(unit3); - organisationUnitService.addOrganisationUnit(unit3); OrganisationUnit unit4 = createOrganisationUnit('4', unit2); - unit2.getChildren().add(unit4); - organisationUnitService.addOrganisationUnit(unit4); OrganisationUnit unit5 = createOrganisationUnit('5', unit2); - unit2.getChildren().add(unit5); - organisationUnitService.addOrganisationUnit(unit5); OrganisationUnit unit6 = createOrganisationUnit('6', unit3); - unit3.getChildren().add(unit6); - organisationUnitService.addOrganisationUnit(unit6); OrganisationUnit unit7 = createOrganisationUnit('7'); + organisationUnitService.addOrganisationUnit(unit1); + organisationUnitService.addOrganisationUnit(unit2); + organisationUnitService.addOrganisationUnit(unit3); + organisationUnitService.addOrganisationUnit(unit4); + organisationUnitService.addOrganisationUnit(unit5); + organisationUnitService.addOrganisationUnit(unit6); organisationUnitService.addOrganisationUnit(unit7); // unit1 // unit1 . unit2 @@ -508,16 +496,13 @@ void testGetOrganisationUnitsAtLevel() { void testGetNumberOfOrganisationalLevels() { assertEquals(0, organisationUnitService.getNumberOfOrganisationalLevels()); OrganisationUnit unit1 = createOrganisationUnit('1'); - organisationUnitService.addOrganisationUnit(unit1); OrganisationUnit unit2 = createOrganisationUnit('2', unit1); - unit1.getChildren().add(unit2); + OrganisationUnit unit3 = createOrganisationUnit('3', unit2); + OrganisationUnit unit4 = createOrganisationUnit('4', unit2); + organisationUnitService.addOrganisationUnit(unit1); organisationUnitService.addOrganisationUnit(unit2); assertEquals(2, organisationUnitService.getNumberOfOrganisationalLevels()); - OrganisationUnit unit3 = createOrganisationUnit('3', unit2); - unit2.getChildren().add(unit3); organisationUnitService.addOrganisationUnit(unit3); - OrganisationUnit unit4 = createOrganisationUnit('4', unit2); - unit2.getChildren().add(unit4); organisationUnitService.addOrganisationUnit(unit4); assertEquals(3, organisationUnitService.getNumberOfOrganisationalLevels()); } @@ -525,14 +510,12 @@ void testGetNumberOfOrganisationalLevels() { @Test void testIsDescendantSet() { OrganisationUnit unit1 = createOrganisationUnit('1'); - organisationUnitService.addOrganisationUnit(unit1); OrganisationUnit unit2 = createOrganisationUnit('2', unit1); - unit1.getChildren().add(unit2); - organisationUnitService.addOrganisationUnit(unit2); OrganisationUnit unit3 = createOrganisationUnit('3', unit2); - unit2.getChildren().add(unit3); - organisationUnitService.addOrganisationUnit(unit3); OrganisationUnit unit4 = createOrganisationUnit('4'); + organisationUnitService.addOrganisationUnit(unit1); + organisationUnitService.addOrganisationUnit(unit2); + organisationUnitService.addOrganisationUnit(unit3); organisationUnitService.addOrganisationUnit(unit4); assertTrue(unit1.isDescendant(Sets.newHashSet(unit1))); assertTrue(unit2.isDescendant(Sets.newHashSet(unit1))); @@ -545,14 +528,12 @@ void testIsDescendantSet() { @Test void testIsDescendantOrgUnit() { OrganisationUnit ouA = createOrganisationUnit('A'); - organisationUnitService.addOrganisationUnit(ouA); OrganisationUnit ouB = createOrganisationUnit('B', ouA); - ouA.getChildren().add(ouB); - organisationUnitService.addOrganisationUnit(ouB); OrganisationUnit ouC = createOrganisationUnit('C', ouB); - ouB.getChildren().add(ouC); - organisationUnitService.addOrganisationUnit(ouC); OrganisationUnit ouD = createOrganisationUnit('D'); + organisationUnitService.addOrganisationUnit(ouA); + organisationUnitService.addOrganisationUnit(ouB); + organisationUnitService.addOrganisationUnit(ouC); organisationUnitService.addOrganisationUnit(ouD); assertTrue(ouA.isDescendant(Set.of(ouA))); assertTrue(ouB.isDescendant(Set.of(ouA))); @@ -565,14 +546,12 @@ void testIsDescendantOrgUnit() { @Test void testIsDescendantObject() { OrganisationUnit unit1 = createOrganisationUnit('1'); - organisationUnitService.addOrganisationUnit(unit1); OrganisationUnit unit2 = createOrganisationUnit('2', unit1); - unit1.getChildren().add(unit2); - organisationUnitService.addOrganisationUnit(unit2); OrganisationUnit unit3 = createOrganisationUnit('3', unit2); - unit2.getChildren().add(unit3); - organisationUnitService.addOrganisationUnit(unit3); OrganisationUnit unit4 = createOrganisationUnit('4'); + organisationUnitService.addOrganisationUnit(unit1); + organisationUnitService.addOrganisationUnit(unit2); + organisationUnitService.addOrganisationUnit(unit3); organisationUnitService.addOrganisationUnit(unit4); assertTrue(unit1.isDescendant(unit1)); assertTrue(unit2.isDescendant(unit1)); @@ -652,20 +631,6 @@ void testGetOrganisationUnitAtLevelAndBranches() { OrganisationUnit unitM = createOrganisationUnit('M', unitF); OrganisationUnit unitN = createOrganisationUnit('N', unitG); OrganisationUnit unitO = createOrganisationUnit('O', unitG); - unitA.getChildren().add(unitB); - unitA.getChildren().add(unitC); - unitB.getChildren().add(unitD); - unitB.getChildren().add(unitE); - unitC.getChildren().add(unitF); - unitC.getChildren().add(unitG); - unitD.getChildren().add(unitH); - unitD.getChildren().add(unitI); - unitE.getChildren().add(unitJ); - unitE.getChildren().add(unitK); - unitF.getChildren().add(unitL); - unitF.getChildren().add(unitM); - unitG.getChildren().add(unitN); - unitG.getChildren().add(unitO); organisationUnitService.addOrganisationUnit(unitA); organisationUnitService.addOrganisationUnit(unitB); organisationUnitService.addOrganisationUnit(unitC); @@ -884,9 +849,6 @@ void testGetOrganisationUnitLevels() { OrganisationUnit unitB = createOrganisationUnit('B', unitA); OrganisationUnit unitC = createOrganisationUnit('C', unitB); OrganisationUnit unitD = createOrganisationUnit('D', unitC); - unitA.getChildren().add(unitB); - unitB.getChildren().add(unitC); - unitC.getChildren().add(unitD); organisationUnitService.addOrganisationUnit(unitA); organisationUnitService.addOrganisationUnit(unitB); organisationUnitService.addOrganisationUnit(unitC); @@ -944,12 +906,6 @@ void testIsInUserHierarchy() { OrganisationUnit ouE = createOrganisationUnit('E', ouB); OrganisationUnit ouF = createOrganisationUnit('F', ouC); OrganisationUnit ouG = createOrganisationUnit('G', ouC); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); - ouB.getChildren().add(ouD); - ouB.getChildren().add(ouE); - ouC.getChildren().add(ouF); - ouC.getChildren().add(ouG); organisationUnitService.addOrganisationUnit(ouA); organisationUnitService.addOrganisationUnit(ouB); organisationUnitService.addOrganisationUnit(ouC); @@ -975,9 +931,6 @@ void testGetAncestorUids() { OrganisationUnit ouB = createOrganisationUnit('B', ouA); OrganisationUnit ouC = createOrganisationUnit('C', ouB); OrganisationUnit ouD = createOrganisationUnit('D', ouC); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); - ouB.getChildren().add(ouD); organisationUnitService.addOrganisationUnit(ouA); organisationUnitService.addOrganisationUnit(ouB); organisationUnitService.addOrganisationUnit(ouC); @@ -995,9 +948,6 @@ void testGetParentGraph() { OrganisationUnit ouB = createOrganisationUnit('B', ouA); OrganisationUnit ouC = createOrganisationUnit('C', ouB); OrganisationUnit ouD = createOrganisationUnit('D', ouC); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); - ouB.getChildren().add(ouD); organisationUnitService.addOrganisationUnit(ouA); organisationUnitService.addOrganisationUnit(ouB); organisationUnitService.addOrganisationUnit(ouC); diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/resourcetable/ResourceTableServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/resourcetable/ResourceTableServiceTest.java index f8becff09629..a45664bb2baf 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/resourcetable/ResourceTableServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/resourcetable/ResourceTableServiceTest.java @@ -86,12 +86,8 @@ void setUp() { idObjectManager.save(degsA); idObjectManager.save(degsB); OrganisationUnit ouA = createOrganisationUnit('A'); - OrganisationUnit ouB = createOrganisationUnit('B'); - OrganisationUnit ouC = createOrganisationUnit('C'); - ouB.setParent(ouA); - ouC.setParent(ouA); - ouA.getChildren().add(ouB); - ouA.getChildren().add(ouC); + OrganisationUnit ouB = createOrganisationUnit('B', ouA); + OrganisationUnit ouC = createOrganisationUnit('C', ouA); idObjectManager.save(ouA); idObjectManager.save(ouB); idObjectManager.save(ouC);