-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DTSAM-317 Update processing of REFRESH_JOB env var (#1923)
* DTSAM-263 Update processing of REFRESH_JOB env var [DTSAM-263](https://tools.hmcts.net/jira/browse/DTSAM-263) [AM-2902](https://tools.hmcts.net/jira/browse/AM-2902) Import some elements of AM-2902: * Update the processing of the REFRESH_JOB env variable on start up to allow it to generate multiple refresh jobs at a time. * DTSAM-317 Update processing of REFRESH_JOB env var [DTSAM-263](https://tools.hmcts.net/jira/browse/DTSAM-263) [DTSAM-317](https://tools.hmcts.net/jira/browse/DTSAM-317) Prevent unexpected update of job config during startup. --------- Co-authored-by: mikebrownccd <104495891+mikebrownccd@users.noreply.github.com>
- Loading branch information
1 parent
1d282f6
commit 4f676b7
Showing
7 changed files
with
804 additions
and
31 deletions.
There are no files selected for viewing
193 changes: 193 additions & 0 deletions
193
...ov/hmcts/reform/orgrolemapping/domain/service/RefreshJobConfigServiceIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package uk.gov.hmcts.reform.orgrolemapping.domain.service; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.test.context.jdbc.Sql; | ||
import uk.gov.hmcts.reform.orgrolemapping.controller.BaseTestIntegration; | ||
import uk.gov.hmcts.reform.orgrolemapping.controller.advice.exception.UnprocessableEntityException; | ||
import uk.gov.hmcts.reform.orgrolemapping.data.RefreshJobEntity; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
@SuppressWarnings("UnnecessaryLocalVariable") | ||
class RefreshJobConfigServiceIntegrationTest extends BaseTestIntegration { | ||
|
||
private static final String JOB_CONFIG_1 = "LEGAL_OPERATIONS-PUBLICLAW-NEW-0"; | ||
private static final String JOB_CONFIG_2 = "JUDICIAL-CIVIL-ABORTED-4"; | ||
private static final String JOB_CONFIG_BAD = "BAD_JOB-INCORRECT_FORMAT-NOT_ENOUGH_PARTS"; | ||
|
||
private static final Long NEXT_JOB_ID = 5L; // NB: this is next sequence number in `sql/insert_refresh_jobs.sql` | ||
|
||
@Autowired | ||
private PersistenceService persistenceService; | ||
|
||
@Autowired | ||
private RefreshJobConfigService sut; | ||
|
||
@Test | ||
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:sql/insert_refresh_jobs.sql"}) | ||
void testProcessJobDetail_singleJob_noJobId() { | ||
|
||
// GIVEN | ||
String jobDetail = JOB_CONFIG_1; | ||
|
||
// WHEN | ||
sut.processJobDetail(jobDetail, false); | ||
|
||
// THEN | ||
var jobOutput = persistenceService.fetchRefreshJobById(NEXT_JOB_ID); | ||
assertTrue(jobOutput.isPresent()); | ||
assertJobEqualsJobConfig1(jobOutput.get()); | ||
} | ||
|
||
@Test | ||
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:sql/insert_refresh_jobs.sql"}) | ||
void testProcessJobDetail_singleJob_withJobId_new() { | ||
|
||
// GIVEN | ||
String jobDetail = createJobConfigWithId(JOB_CONFIG_1, NEXT_JOB_ID); | ||
|
||
// WHEN | ||
sut.processJobDetail(jobDetail, false); | ||
|
||
// THEN | ||
var jobOutput = persistenceService.fetchRefreshJobById(NEXT_JOB_ID); | ||
assertTrue(jobOutput.isPresent()); | ||
assertEquals(NEXT_JOB_ID, jobOutput.get().getJobId()); | ||
assertJobEqualsJobConfig1(jobOutput.get()); | ||
} | ||
|
||
@Test | ||
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:sql/insert_refresh_jobs.sql"}) | ||
void testProcessJobDetail_singleJob_withJobId_new_mismatched() { | ||
|
||
// GIVEN | ||
String jobDetail = createJobConfigWithId(JOB_CONFIG_1, NEXT_JOB_ID + 1); | ||
|
||
// WHEN / THEN | ||
UnprocessableEntityException exception = assertThrows(UnprocessableEntityException.class, () -> | ||
sut.processJobDetail(jobDetail, false) | ||
); | ||
|
||
// THEN | ||
assertTrue(exception.getMessage().startsWith(RefreshJobConfigService.ERROR_REJECTED_JOB_ID_MISMATCH)); | ||
// verify new job config entry not created | ||
assertTrue(persistenceService.fetchRefreshJobById(NEXT_JOB_ID).isEmpty()); // i.e. mismatched removed | ||
assertTrue(persistenceService.fetchRefreshJobById(NEXT_JOB_ID + 1).isEmpty()); // requested not created | ||
} | ||
|
||
@Test | ||
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:sql/insert_refresh_jobs.sql"}) | ||
void testProcessJobDetail_multipleJobs_withJobId_updateAllowed() { | ||
|
||
// GIVEN | ||
String jobDetail = createMultipleJobDetailsList( | ||
createJobConfigWithId(JOB_CONFIG_1, 1L), // this is an update 1 < NEXT_JOB_ID | ||
createJobConfigWithId(JOB_CONFIG_2, 2L) // this is an update 2 < NEXT_JOB_ID | ||
); | ||
|
||
// WHEN | ||
sut.processJobDetail(jobDetail, true); // NB: allows update | ||
|
||
// THEN | ||
// verify updated job is saved OK | ||
var jobOutput1 = persistenceService.fetchRefreshJobById(1L); | ||
assertTrue(jobOutput1.isPresent()); | ||
assertEquals(1L, jobOutput1.get().getJobId()); | ||
assertJobEqualsJobConfig1(jobOutput1.get()); | ||
|
||
// verify updated job is saved OK | ||
var jobOutput2 = persistenceService.fetchRefreshJobById(2L); | ||
assertTrue(jobOutput2.isPresent()); | ||
assertEquals(2L, jobOutput2.get().getJobId()); | ||
assertJobEqualsJobConfig2(jobOutput2.get()); | ||
} | ||
|
||
@Test | ||
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:sql/insert_refresh_jobs.sql"}) | ||
void testProcessJobDetail_multipleJobs_withJobId_noUpdateAllowed_includingSkipped() { | ||
|
||
// GIVEN | ||
String jobDetail = createMultipleJobDetailsList( | ||
createJobConfigWithId(JOB_CONFIG_1, 4L), // this update will be skipped | ||
createJobConfigWithId(JOB_CONFIG_2, NEXT_JOB_ID) // this new job will be saved | ||
); | ||
|
||
// WHEN | ||
sut.processJobDetail(jobDetail, false); | ||
|
||
// THEN | ||
// verify update not applied | ||
var jobOutput1 = persistenceService.fetchRefreshJobById(4L); | ||
assertTrue(jobOutput1.isPresent()); | ||
assertJobEqualsJob4Unchanged(jobOutput1.get()); | ||
|
||
// verify new job is saved OK | ||
var jobOutput2 = persistenceService.fetchRefreshJobById(NEXT_JOB_ID); | ||
assertTrue(jobOutput2.isPresent()); | ||
assertEquals(NEXT_JOB_ID, jobOutput2.get().getJobId()); | ||
assertJobEqualsJobConfig2(jobOutput2.get()); | ||
} | ||
|
||
@Test | ||
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = {"classpath:sql/insert_refresh_jobs.sql"}) | ||
void testProcessJobDetail_multipleJobs_badJob_noSaveOrUpdate() { | ||
|
||
// GIVEN | ||
String jobDetail = createMultipleJobDetailsList( | ||
createJobConfigWithId(JOB_CONFIG_1, 4L), // this is an update | ||
createJobConfigWithId(JOB_CONFIG_2, NEXT_JOB_ID), // this is a new job | ||
JOB_CONFIG_BAD | ||
); | ||
|
||
// WHEN / THEN | ||
assertThrows(UnprocessableEntityException.class, () -> | ||
sut.processJobDetail(jobDetail, true) // NB: allows update | ||
); | ||
|
||
// THEN | ||
// verify update has been rolled back | ||
var jobOutput1 = persistenceService.fetchRefreshJobById(4L); | ||
assertTrue(jobOutput1.isPresent()); | ||
assertJobEqualsJob4Unchanged(jobOutput1.get()); | ||
|
||
// verify new job has been rolled back | ||
assertTrue(persistenceService.fetchRefreshJobById(NEXT_JOB_ID).isEmpty()); | ||
} | ||
|
||
private void assertJobEqualsJobConfig1(RefreshJobEntity job) { | ||
// assert entries match: JOB_CONFIG_1 | ||
assertEquals("LEGAL_OPERATIONS", job.getRoleCategory()); | ||
assertEquals("PUBLICLAW", job.getJurisdiction()); | ||
assertEquals("NEW", job.getStatus()); | ||
assertEquals(0, job.getLinkedJobId()); | ||
} | ||
|
||
private void assertJobEqualsJobConfig2(RefreshJobEntity job) { | ||
// assert entries match: JOB_CONFIG_2 | ||
assertEquals("JUDICIAL", job.getRoleCategory()); | ||
assertEquals("CIVIL", job.getJurisdiction()); | ||
assertEquals("ABORTED", job.getStatus()); | ||
assertEquals(4, job.getLinkedJobId()); | ||
} | ||
|
||
private void assertJobEqualsJob4Unchanged(RefreshJobEntity job) { | ||
// verify update not applied: i.e. must match jobId=4 in `sql/insert_refresh_jobs.sql` | ||
assertEquals(4L, job.getJobId()); | ||
assertEquals("LEGAL_OPERATIONS", job.getRoleCategory()); | ||
assertEquals("IA", job.getJurisdiction()); | ||
assertEquals("COMPLETED", job.getStatus()); | ||
assertEquals(2, job.getLinkedJobId()); | ||
} | ||
|
||
private String createJobConfigWithId(String jobConfig, Long jobId) { | ||
return jobConfig + RefreshJobConfigService.REFRESH_JOBS_CONFIG_SPLITTER + jobId; | ||
} | ||
|
||
private String createMultipleJobDetailsList(String... jobConfigs) { | ||
return String.join(RefreshJobConfigService.REFRESH_JOBS_DETAILS_SPLITTER, jobConfigs); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
DELETE FROM refresh_jobs; | ||
|
||
INSERT INTO public.refresh_jobs (job_id, role_category, jurisdiction, status, user_ids, linked_job_id, created) | ||
VALUES(1, 'LEGAL_OPERATIONS', 'IA', 'NEW', NULL, 0, NULL); | ||
INSERT INTO public.refresh_jobs (job_id, role_category, jurisdiction, status, user_ids, linked_job_id, created) | ||
VALUES(2, 'LEGAL_OPERATIONS', 'IA', 'ABORTED', '{"7c12a4bc-450e-4290-8063-b387a5d5e0b7"}', NULL, NULL); | ||
INSERT INTO public.refresh_jobs (job_id, role_category, jurisdiction, status, user_ids, linked_job_id, created) | ||
VALUES(3, 'LEGAL_OPERATIONS', 'IA', 'NEW', NULL, 2, NULL); | ||
INSERT INTO public.refresh_jobs (job_id, role_category, jurisdiction, status, user_ids, linked_job_id, created) | ||
VALUES(4, 'LEGAL_OPERATIONS', 'IA', 'COMPLETED', NULL, 2, NULL); | ||
|
||
ALTER SEQUENCE JOB_ID_SEQ RESTART WITH 5; |
53 changes: 22 additions & 31 deletions
53
src/main/java/uk/gov/hmcts/reform/orgrolemapping/config/JobConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,58 @@ | ||
package uk.gov.hmcts.reform.orgrolemapping.config; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.apache.commons.lang.BooleanUtils; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.CommandLineRunner; | ||
import org.springframework.stereotype.Component; | ||
import uk.gov.hmcts.reform.orgrolemapping.data.RefreshJobEntity; | ||
import uk.gov.hmcts.reform.orgrolemapping.data.RefreshJobsRepository; | ||
import uk.gov.hmcts.reform.orgrolemapping.controller.advice.exception.UnprocessableEntityException; | ||
import uk.gov.hmcts.reform.orgrolemapping.domain.service.RefreshJobConfigService; | ||
import uk.gov.hmcts.reform.orgrolemapping.launchdarkly.FeatureConditionEvaluator; | ||
|
||
import java.time.ZonedDateTime; | ||
import java.util.Optional; | ||
|
||
@Component | ||
@Slf4j | ||
public class JobConfiguration implements CommandLineRunner { | ||
|
||
private final RefreshJobsRepository refreshJobsRepository; | ||
static final String ERROR_ABORTED_JOB_IMPORT = "Aborted the job configuration import: {}"; | ||
|
||
private final RefreshJobConfigService refreshJobConfigService; | ||
|
||
private final FeatureConditionEvaluator featureConditionEvaluator; | ||
|
||
private final String jobDetail; | ||
private final boolean jobDetailAllowUpdate; | ||
|
||
|
||
@Autowired | ||
public JobConfiguration(RefreshJobsRepository refreshJobsRepository, | ||
public JobConfiguration(RefreshJobConfigService refreshJobConfigService, | ||
@Value("${refresh.job.update}") String jobDetail, | ||
@Value("${refresh.Job.updateOverride}") Boolean jobDetailAllowUpdate, | ||
FeatureConditionEvaluator featureConditionEvaluator | ||
) { | ||
this.refreshJobsRepository = refreshJobsRepository; | ||
this.refreshJobConfigService = refreshJobConfigService; | ||
this.featureConditionEvaluator = featureConditionEvaluator; | ||
this.jobDetail = jobDetail; | ||
this.jobDetailAllowUpdate = BooleanUtils.isTrue(jobDetailAllowUpdate); | ||
} | ||
|
||
@Override | ||
public void run(String... args) { | ||
if (StringUtils.isNotEmpty(jobDetail) && featureConditionEvaluator | ||
.isFlagEnabled("am_org_role_mapping_service", "orm-refresh-job-enable")) { | ||
String[] jobAttributes = jobDetail.split("-"); | ||
log.info("Job {} inserting into refresh table", jobDetail); | ||
if (jobAttributes.length < 4) { | ||
return; | ||
} | ||
RefreshJobEntity refreshJobEntity = RefreshJobEntity.builder().build(); | ||
if (jobAttributes.length > 4) { | ||
Optional<RefreshJobEntity> refreshJob = refreshJobsRepository.findById(Long.valueOf(jobAttributes[4])); | ||
refreshJobEntity = refreshJob.orElse(refreshJobEntity); | ||
} | ||
|
||
refreshJobEntity.setRoleCategory(jobAttributes[0]); | ||
refreshJobEntity.setJurisdiction(jobAttributes[1]); | ||
refreshJobEntity.setStatus(jobAttributes[2]); | ||
refreshJobEntity.setLinkedJobId(Long.valueOf(jobAttributes[3])); | ||
refreshJobEntity.setCreated(ZonedDateTime.now()); | ||
|
||
persistJobDetail(refreshJobEntity); | ||
if (StringUtils.isNotEmpty(jobDetail)) { | ||
if (featureConditionEvaluator.isFlagEnabled("am_org_role_mapping_service", "orm-refresh-job-enable")) { | ||
try { | ||
this.refreshJobConfigService.processJobDetail(this.jobDetail, this.jobDetailAllowUpdate); | ||
} catch (UnprocessableEntityException ex) { | ||
log.error(ERROR_ABORTED_JOB_IMPORT, ex.getMessage(), ex); | ||
} | ||
} else { | ||
log.warn("LD flag 'orm-refresh-job-enable' is not enabled"); | ||
} | ||
} else { | ||
log.warn("LD flag 'orm-refresh-job-enable' is not enabled"); | ||
log.info("No Job Configuration to create"); | ||
} | ||
} | ||
|
||
private void persistJobDetail(RefreshJobEntity refreshJobEntity) { | ||
refreshJobsRepository.save(refreshJobEntity); | ||
} | ||
} |
Oops, something went wrong.