package uk.ac.ox.zoo.seeg.abraid.mp.common.service.workflow; import org.geotools.coverage.grid.GridCoverage2D; import org.joda.time.DateTime; import org.junit.Before; import org.junit.Test; import uk.ac.ox.zoo.seeg.abraid.mp.common.domain.*; import uk.ac.ox.zoo.seeg.abraid.mp.common.service.core.ModelRunService; import uk.ac.ox.zoo.seeg.abraid.mp.common.service.workflow.support.DistanceFromDiseaseExtentHelper; import uk.ac.ox.zoo.seeg.abraid.mp.common.service.workflow.support.EnvironmentalSuitabilityHelper; import uk.ac.ox.zoo.seeg.abraid.mp.common.service.workflow.support.MachineWeightingPredictor; import java.util.Arrays; import java.util.List; import static com.googlecode.catchexception.CatchException.catchException; import static com.googlecode.catchexception.CatchException.caughtException; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.same; import static org.mockito.Mockito.*; /** * Integration tests for the DiseaseOccurrenceValidationService class. * * Copyright (c) 2014 University of Oxford */ public class DiseaseOccurrenceValidationServiceTest { private DiseaseOccurrenceValidationService service; private EnvironmentalSuitabilityHelper esHelper; private DistanceFromDiseaseExtentHelper dfdeHelper; private MachineWeightingPredictor mwPredictor; private ModelRunService modelRunService; @Before public void setUp() { esHelper = mock(EnvironmentalSuitabilityHelper.class); dfdeHelper = mock(DistanceFromDiseaseExtentHelper.class); mwPredictor = mock(MachineWeightingPredictor.class); modelRunService = mock(ModelRunService.class); service = new DiseaseOccurrenceValidationServiceImpl(esHelper, dfdeHelper, mwPredictor, modelRunService); } @Test public void addValidationParametersWithChecksDiscardsOccurrenceIfOccurrenceLocationIsNull() { DiseaseOccurrence occurrence = new DiseaseOccurrence(); setIsGoldStandardProvenance(occurrence, false); service.addValidationParametersWithChecks(occurrence); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.DISCARDED_FAILED_QC); } private void setIsGoldStandardProvenance(DiseaseOccurrence occurrence, boolean isGoldStandard) { String provenanceName = isGoldStandard ? ProvenanceNames.MANUAL_GOLD_STANDARD : ProvenanceNames.MANUAL; Provenance provenance = new Provenance(provenanceName); Feed feed = new Feed("Test feed", provenance); Alert alert = new Alert(); alert.setFeed(feed); occurrence.setAlert(alert); } @Test public void addValidationParametersWithChecksDiscardsOccurrenceIfOccurrenceLocationHasNotPassedQCWhenAutomaticModelRunsAreEnabled() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrence(1, true, false); occurrence.getLocation().setHasPassedQc(false); setIsGoldStandardProvenance(occurrence, false); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.DISCARDED_FAILED_QC); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksDiscardsOccurrenceIfOccurrenceLocationHasNotPassedQCWhenAutomaticModelRunsAreDisabled() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrence(1, false, false); occurrence.getLocation().setHasPassedQc(false); setIsGoldStandardProvenance(occurrence, false); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.DISCARDED_FAILED_QC); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSetsValidationParametersWhenAutomaticModelRunsAreEnabled() { // Arrange int diseaseGroupId = 30; double environmentalSuitability = 0.42; double distanceFromDiseaseExtent = 500; DiseaseOccurrence occurrence = createDiseaseOccurrence(diseaseGroupId, true, false); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(environmentalSuitability); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(distanceFromDiseaseExtent); when(mwPredictor.findMachineWeighting(occurrence)).thenReturn(null); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(environmentalSuitability); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(distanceFromDiseaseExtent); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); // At present mwPredictor is only set up to return a null weighting, which means occurrence must go to validator assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSetsStatusToReadyWhenAutomaticModelRunsAreDisabledAndNoBatching() { // Arrange int diseaseGroupId = 30; DiseaseOccurrence occurrence = createDiseaseOccurrence(diseaseGroupId, false, false); setIsGoldStandardProvenance(occurrence, false); when(modelRunService.hasBatchingEverCompleted(diseaseGroupId)).thenReturn(false); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertDefaultParameters(occurrence, DiseaseOccurrenceStatus.READY); } @Test public void addValidationParametersWithChecksSetsStatusToAwaitingBatchingWhenAutomaticModelRunsAreDisabledAndBatching() { // Arrange int diseaseGroupId = 30; DiseaseOccurrence occurrence = createDiseaseOccurrence(diseaseGroupId, false, false); setIsGoldStandardProvenance(occurrence, false); when(modelRunService.hasBatchingEverCompleted(diseaseGroupId)).thenReturn(true); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertDefaultParameters(occurrence, DiseaseOccurrenceStatus.AWAITING_BATCHING); } private void assertDefaultParameters(DiseaseOccurrence occurrence, DiseaseOccurrenceStatus status) { assertThat(occurrence.getEnvironmentalSuitability()).isNull(); assertThat(occurrence.getDistanceFromDiseaseExtent()).isNull(); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(status); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); } @Test public void addValidationParametersWithChecksSetsStatusToReadyForLargeCountryPointWhenAutomaticModelRunsAreEnabled() { // Arrange int diseaseGroupId = 30; double environmentalSuitability = 0.42; double distanceFromDiseaseExtent = 500; DiseaseOccurrence occurrence = createDiseaseOccurrence(diseaseGroupId, true, false); setIsGoldStandardProvenance(occurrence, false); occurrence.getLocation().setPrecision(LocationPrecision.COUNTRY); occurrence.getLocation().setIsModelEligible(false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(environmentalSuitability); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(distanceFromDiseaseExtent); when(mwPredictor.findMachineWeighting(occurrence)).thenReturn(null); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertParameterValues(occurrence, environmentalSuitability, distanceFromDiseaseExtent, DiseaseOccurrenceStatus.READY); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorIfESIsNullAndDistanceFromExtentIsNull() { // Arrange int diseaseGroupId = 30; DiseaseOccurrence occurrence = createDiseaseOccurrence(diseaseGroupId, true, false); occurrence.getLocation().setHasPassedQc(true); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(null); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(null); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertDefaultParameters(occurrence, DiseaseOccurrenceStatus.IN_REVIEW); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorIfOutsideDiseaseExtentAndESIsNull() { // Arrange int diseaseGroupId = 30; DiseaseOccurrence occurrence = createDiseaseOccurrence(diseaseGroupId, true, false); occurrence.getLocation().setHasPassedQc(true); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(null); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(1.0); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isNull(); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(1.0); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorIfAboveMaxESAndDistanceFromExtentIsNull() { // Arrange int diseaseGroupId = 30; DiseaseOccurrence occurrence = createDiseaseOccurrence(diseaseGroupId, true, false); occurrence.getLocation().setHasPassedQc(true); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(0.5); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(null); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(0.5); assertThat(occurrence.getDistanceFromDiseaseExtent()).isNull(); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSetsAllValidationParameters() { // Arrange int diseaseGroupId = 30; double environmentalSuitability = 0.42; double distanceFromDiseaseExtent = 500; GridCoverage2D suitabilityRaster = mock(GridCoverage2D.class); GridCoverage2D[] adminRasters = new GridCoverage2D[] {mock(GridCoverage2D.class)}; DiseaseOccurrence occurrence = createDiseaseOccurrence(diseaseGroupId, true, false); occurrence.getLocation().setPrecision(LocationPrecision.ADMIN1); occurrence.getLocation().setHasPassedQc(true); setIsGoldStandardProvenance(occurrence, false); when(esHelper.getLatestMeanPredictionRaster(occurrence.getDiseaseGroup())).thenReturn(suitabilityRaster); when(esHelper.getSingleAdminRaster(LocationPrecision.ADMIN1)).thenReturn(adminRasters); when(esHelper.findEnvironmentalSuitability(same(occurrence), same(suitabilityRaster), same(adminRasters))).thenReturn(environmentalSuitability); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(distanceFromDiseaseExtent); when(mwPredictor.findMachineWeighting(occurrence)).thenReturn(null); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(environmentalSuitability); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(distanceFromDiseaseExtent); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); // At present mwPredictor is only set up to return a null weighting, which means occurrence must go to validator assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSetsGoldStandardParametersWhenAutomaticModelRunsAreDisabled() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrence(1, false, false); occurrence.getLocation().setHasPassedQc(true); setIsGoldStandardProvenance(occurrence, true); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isNull(); assertThat(occurrence.getDistanceFromDiseaseExtent()).isNull(); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.READY); assertThat(occurrence.getFinalWeighting()).isEqualTo(1.0); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isEqualTo(1.0); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSetsGoldStandardParametersWhenAutomaticModelRunsAreEnabled() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrence(1, true, false); occurrence.getLocation().setHasPassedQc(true); setIsGoldStandardProvenance(occurrence, true); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isNull(); assertThat(occurrence.getDistanceFromDiseaseExtent()).isNull(); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.READY); assertThat(occurrence.getFinalWeighting()).isEqualTo(1.0); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isEqualTo(1.0); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorWithoutMLIfBelowMaxES() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrenceWithoutMachineLearning(); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(0.39); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(-300.0); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(0.39); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(-300.0); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorWithoutMLIfOutsideDiseaseExtent() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrenceWithoutMachineLearning(); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(0.6); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(1.0); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(0.6); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(1.0); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorWithoutMLIfESIsNullAndDistanceFromExtentIsNull() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrenceWithoutMachineLearning(); occurrence.getLocation().setHasPassedQc(true); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(null); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(null); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isNull(); assertThat(occurrence.getDistanceFromDiseaseExtent()).isNull(); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorWithoutMLIfOutsideDiseaseExtentAndESIsNull() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrenceWithoutMachineLearning(); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(null); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(1.0); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isNull(); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(1.0); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorWithoutMLIfOutsideDiseaseExtentAndMaxESIsNull() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrenceWithoutMachineLearning(); occurrence.getDiseaseGroup().setMaxEnvironmentalSuitabilityWithoutML(null); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(0.6); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(1.0); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(0.6); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(1.0); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksDoesNotSendToValidatorWithoutMLIfWithinTolerances() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrenceWithoutMachineLearning(); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(0.41); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(-1000.0); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(0.41); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(-1000.0); assertThat(occurrence.getMachineWeighting()).isEqualTo(1); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.READY); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersWithChecksSendsToValidatorWithoutMLIfAboveMaxESAndDistanceFromExtentIsNull() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrenceWithoutMachineLearning(); setIsGoldStandardProvenance(occurrence, false); when(esHelper.findEnvironmentalSuitability(occurrence, null, null)).thenReturn(0.5); when(dfdeHelper.findDistanceFromDiseaseExtent(occurrence)).thenReturn(null); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(0.5); assertThat(occurrence.getDistanceFromDiseaseExtent()).isNull(); assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.IN_REVIEW); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); verify(modelRunService, never()).hasBatchingEverCompleted(anyInt()); } @Test public void addValidationParametersSetsAllValidationParametersOnUsingRasterRegardlessOfOccurrenceValidityExceptGoldStandard() { // Arrange int diseaseGroupId = 30; double environmentalSuitability1 = 0.42; double environmentalSuitability2 = 0.52; double environmentalSuitability3 = 0.62; double distanceFromDiseaseExtent1 = 500; double distanceFromDiseaseExtent2 = 800; double distanceFromDiseaseExtent3 = 900; GridCoverage2D suitabilityRaster = mock(GridCoverage2D.class); GridCoverage2D[] adminRasters = new GridCoverage2D[] {mock(GridCoverage2D.class)}; DiseaseOccurrence occurrence1 = createDiseaseOccurrence(diseaseGroupId, false, false); DiseaseOccurrence occurrence2 = createDiseaseOccurrence(diseaseGroupId, true, false); DiseaseOccurrence occurrence3 = createDiseaseOccurrence(diseaseGroupId, true, true); DiseaseGroup diseaseGroup = occurrence1.getDiseaseGroup(); occurrence2.setDiseaseGroup(diseaseGroup); occurrence1.getLocation().setHasPassedQc(false); List<DiseaseOccurrence> occurrences = Arrays.asList(occurrence1, occurrence2); when(esHelper.getLatestMeanPredictionRaster(diseaseGroup)).thenReturn(suitabilityRaster); when(esHelper.getAdminRasters()).thenReturn(adminRasters); when(esHelper.findEnvironmentalSuitability(same(occurrence1), same(suitabilityRaster), same(adminRasters))).thenReturn(environmentalSuitability1); when(esHelper.findEnvironmentalSuitability(same(occurrence2), same(suitabilityRaster), same(adminRasters))).thenReturn(environmentalSuitability2); when(esHelper.findEnvironmentalSuitability(same(occurrence3), same(suitabilityRaster), same(adminRasters))).thenReturn(environmentalSuitability3); when(dfdeHelper.findDistanceFromDiseaseExtent(same(occurrence1))).thenReturn(distanceFromDiseaseExtent1); when(dfdeHelper.findDistanceFromDiseaseExtent(same(occurrence2))).thenReturn(distanceFromDiseaseExtent2); when(dfdeHelper.findDistanceFromDiseaseExtent(same(occurrence3))).thenReturn(distanceFromDiseaseExtent3); when(mwPredictor.findMachineWeighting(same(occurrence1))).thenReturn(null); when(mwPredictor.findMachineWeighting(same(occurrence2))).thenReturn(null); when(mwPredictor.findMachineWeighting(same(occurrence3))).thenReturn(null); // Act service.addValidationParameters(occurrences); // Assert assertParameterValues(occurrence1, environmentalSuitability1, distanceFromDiseaseExtent1, DiseaseOccurrenceStatus.IN_REVIEW); assertParameterValues(occurrence2, environmentalSuitability2, distanceFromDiseaseExtent2, DiseaseOccurrenceStatus.IN_REVIEW); assertDefaultParameters(occurrence3, DiseaseOccurrenceStatus.READY); } private void assertParameterValues(DiseaseOccurrence occurrence, double environmentalSuitability, double distanceFromDiseaseExtent, DiseaseOccurrenceStatus status) { assertThat(occurrence.getEnvironmentalSuitability()).isEqualTo(environmentalSuitability); assertThat(occurrence.getDistanceFromDiseaseExtent()).isEqualTo(distanceFromDiseaseExtent); assertThat(occurrence.getFinalWeighting()).isNull(); assertThat(occurrence.getFinalWeightingExcludingSpatial()).isNull(); // At present mwPredictor is only set up to return a null weighting, which means occurrence must go to validator assertThat(occurrence.getMachineWeighting()).isNull(); assertThat(occurrence.getStatus()).isEqualTo(status); } @Test public void addValidationParametersOnlyAddsModelEligibleOccurrencesToValidator() { // Arrange double environmentalSuitability = 0.42; double distanceFromDiseaseExtent = 500; GridCoverage2D suitabilityRaster = mock(GridCoverage2D.class); GridCoverage2D[] adminRasters = new GridCoverage2D[] {mock(GridCoverage2D.class)}; DiseaseGroup diseaseGroup = createDiseaseGroup(); DiseaseOccurrence admin1Occurrence = createAdmin1Occurrence(1, diseaseGroup); DiseaseOccurrence countryOccurrence = createCountryOccurrence(2, diseaseGroup, true); DiseaseOccurrence largeCountryOccurrence = createCountryOccurrence(3, diseaseGroup, false); List<DiseaseOccurrence> occurrences = Arrays.asList(admin1Occurrence, countryOccurrence, largeCountryOccurrence); when(esHelper.getLatestMeanPredictionRaster(diseaseGroup)).thenReturn(suitabilityRaster); when(esHelper.getAdminRasters()).thenReturn(adminRasters); when(esHelper.findEnvironmentalSuitability(same(admin1Occurrence), same(suitabilityRaster), same(adminRasters))).thenReturn(environmentalSuitability); when(esHelper.findEnvironmentalSuitability(same(countryOccurrence), same(suitabilityRaster), same(adminRasters))).thenReturn(environmentalSuitability); when(esHelper.findEnvironmentalSuitability(same(largeCountryOccurrence), same(suitabilityRaster), same(adminRasters))).thenReturn(environmentalSuitability); when(dfdeHelper.findDistanceFromDiseaseExtent(same(admin1Occurrence))).thenReturn(distanceFromDiseaseExtent); when(dfdeHelper.findDistanceFromDiseaseExtent(same(countryOccurrence))).thenReturn(distanceFromDiseaseExtent); when(dfdeHelper.findDistanceFromDiseaseExtent(same(largeCountryOccurrence))).thenReturn(distanceFromDiseaseExtent); when(mwPredictor.findMachineWeighting(same(admin1Occurrence))).thenReturn(null); when(mwPredictor.findMachineWeighting(same(countryOccurrence))).thenReturn(null); when(mwPredictor.findMachineWeighting(same(largeCountryOccurrence))).thenReturn(null); // Act service.addValidationParameters(occurrences); // Assert assertParameterValues(admin1Occurrence, environmentalSuitability, distanceFromDiseaseExtent, DiseaseOccurrenceStatus.IN_REVIEW); assertParameterValues(countryOccurrence, environmentalSuitability, distanceFromDiseaseExtent, DiseaseOccurrenceStatus.IN_REVIEW); assertParameterValues(largeCountryOccurrence, environmentalSuitability, distanceFromDiseaseExtent, DiseaseOccurrenceStatus.READY); } @Test public void addValidationParametersThrowsExceptionIfOccurrencesHaveDifferentDiseaseGroups() { // Arrange DiseaseOccurrence occurrence1 = createDiseaseOccurrence(1, true, false); DiseaseOccurrence occurrence2 = createDiseaseOccurrence(1, true, false); DiseaseOccurrence occurrence3 = createDiseaseOccurrence(2, true, false); List<DiseaseOccurrence> occurrences = Arrays.asList(occurrence1, occurrence2, occurrence3); // Act catchException(service).addValidationParameters(occurrences); // Assert assertThat(caughtException()).isInstanceOf(RuntimeException.class); } @Test public void addValidationParametersWithChecksSendsToValidatorForNonAutomaticDisease() { // Arrange int diseaseGroupId = 30; GridCoverage2D suitabilityRaster = mock(GridCoverage2D.class); GridCoverage2D[] adminRasters = new GridCoverage2D[] {mock(GridCoverage2D.class)}; DiseaseOccurrence occurrence1 = createDiseaseOccurrence(diseaseGroupId, false, false); DiseaseOccurrence occurrence2 = createDiseaseOccurrence(diseaseGroupId, false, false); DiseaseOccurrence occurrence3 = createDiseaseOccurrence(diseaseGroupId, false, true); // GOLD DiseaseGroup diseaseGroup = occurrence1.getDiseaseGroup(); List<DiseaseOccurrence> occurrences = Arrays.asList(occurrence1, occurrence2); when(esHelper.getLatestMeanPredictionRaster(diseaseGroup)).thenReturn(suitabilityRaster); when(esHelper.getAdminRasters()).thenReturn(adminRasters); when(esHelper.findEnvironmentalSuitability(any(DiseaseOccurrence.class), same(suitabilityRaster), same(adminRasters))).thenReturn(0.62); when(dfdeHelper.findDistanceFromDiseaseExtent(any(DiseaseOccurrence.class))).thenReturn(900.0); when(mwPredictor.findMachineWeighting(any(DiseaseOccurrence.class))).thenReturn(1.0); // Act service.addValidationParameters(occurrences); // Assert assertParameterValues(occurrence1, 0.62, 900.0, DiseaseOccurrenceStatus.IN_REVIEW); assertParameterValues(occurrence2, 0.62, 900.0, DiseaseOccurrenceStatus.IN_REVIEW); assertDefaultParameters(occurrence3, DiseaseOccurrenceStatus.READY); verify(mwPredictor, never()).findMachineWeighting(any(DiseaseOccurrence.class)); } @Test public void addValidationParametersWithChecksHandlesBiasOccurrencesMinimally() { // Arrange DiseaseOccurrence occurrence = createDiseaseOccurrence(1, false, false); occurrence.setBiasDisease(createDiseaseGroup()); occurrence.getLocation().setHasPassedQc(true); // Act service.addValidationParametersWithChecks(occurrence); // Assert assertThat(occurrence.getStatus()).isEqualTo(DiseaseOccurrenceStatus.BIAS); assertThat(occurrence.getValidationWeighting()).isNull(); } private DiseaseGroup createDiseaseGroup() { DiseaseGroup diseaseGroup = new DiseaseGroup(1); diseaseGroup.setAutomaticModelRunsStartDate(DateTime.now()); diseaseGroup.setGlobal(false); diseaseGroup.setUseMachineLearning(true); return diseaseGroup; } private DiseaseOccurrence createAdmin1Occurrence(int id, DiseaseGroup diseaseGroup) { Location location = new Location(); location.setHasPassedQc(true); location.setPrecision(LocationPrecision.ADMIN1); location.setIsModelEligible(true); DiseaseOccurrence diseaseOccurrence = new DiseaseOccurrence(id, diseaseGroup, location, new Alert(), null, null, null); setIsGoldStandardProvenance(diseaseOccurrence, false); return diseaseOccurrence; } private DiseaseOccurrence createCountryOccurrence(int id, DiseaseGroup diseaseGroup, boolean modelEligible) { Location location = new Location(); location.setHasPassedQc(true); location.setPrecision(LocationPrecision.COUNTRY); location.setIsModelEligible(modelEligible); DiseaseOccurrence diseaseOccurrence = new DiseaseOccurrence(id, diseaseGroup, location, new Alert(), null, null, null); setIsGoldStandardProvenance(diseaseOccurrence, false); return diseaseOccurrence; } private DiseaseOccurrence createDiseaseOccurrence(int diseaseGroupId, boolean isAutomaticModelRunsEnabled, boolean isGoldStandard) { DiseaseGroup diseaseGroup = new DiseaseGroup(diseaseGroupId); DateTime automaticModelRunsStartDate = isAutomaticModelRunsEnabled ? DateTime.now() : null; diseaseGroup.setAutomaticModelRunsStartDate(automaticModelRunsStartDate); diseaseGroup.setGlobal(false); diseaseGroup.setUseMachineLearning(true); Location location = new Location(); location.setHasPassedQc(true); location.setIsModelEligible(true); DiseaseOccurrence diseaseOccurrence = new DiseaseOccurrence(1, diseaseGroup, location, new Alert(), null, null, null); setIsGoldStandardProvenance(diseaseOccurrence, isGoldStandard); diseaseOccurrence.setStatus(DiseaseOccurrenceStatus.READY); return diseaseOccurrence; } private DiseaseOccurrence createDiseaseOccurrenceWithoutMachineLearning() { DiseaseOccurrence occurrence = createDiseaseOccurrence(1, true, false); occurrence.getLocation().setHasPassedQc(true); occurrence.getDiseaseGroup().setUseMachineLearning(false); occurrence.getDiseaseGroup().setMaxEnvironmentalSuitabilityWithoutML(0.4); return occurrence; } }