Commit e9eb6a4d authored by Deniro StopCovid's avatar Deniro StopCovid

Merge branch 'feat-update-management-status-atRisk' into 'develop'

Feat update management status at risk

See merge request !97
parents 2991e593 f4bf37ec
package fr.gouv.stopc.robert.server.batch.listener;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import fr.gouv.stopc.robert.server.batch.service.ItemIdMappingService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@AllArgsConstructor
public class PopulateIdMappingListener implements StepExecutionListener {
private ItemIdMappingService itemIdMappingService;
@Override
public void beforeStep(StepExecution stepExecution) {
log.info("START : Reset the itemIdMapping collection.");
itemIdMappingService.deleteAll();
log.info("END : Reset the itemIdMapping collection.");
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
return stepExecution.getExitStatus();
}
}
package fr.gouv.stopc.robert.server.batch.processor;
import org.springframework.batch.item.ItemProcessor;
import fr.gouv.stopc.robert.server.batch.utils.PropertyLoader;
import fr.gouv.stopc.robertserver.database.model.Registration;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@AllArgsConstructor
public class UpdateRegistrationFlagsProcessor implements ItemProcessor<Registration, Registration> {
private PropertyLoader propertyLoader;
@Override
public Registration process(Registration registration) throws Exception {
if(registration.isAtRisk() && registration.isNotified()) {
if(registration.getLastStatusRequestEpoch() - registration.getLatestRiskEpoch() >= this.propertyLoader.getAtRiskNotificationEpochGap()) {
registration.setAtRisk(false);
return registration;
}
}
return null;
}
}
......@@ -34,4 +34,7 @@ public class PropertyLoader {
@Value("${robert.scoring.batch-mode}")
private String batchMode;
@Value("${robert.at-risk.notification.epoch.minimum-gap}")
private Integer atRiskNotificationEpochGap;
}
......@@ -73,6 +73,7 @@ public final class ScoringUtils {
registration.setLatestRiskEpoch(newLatestRiskEpoch);
log.info("Updating latest risk epoch {}", newLatestRiskEpoch);
registration.setAtRisk(true);
registration.setNotified(false);
isRegistrationAtRisk = true;
}
......
package fr.gouv.stopc.robert.server.batch.writer;
import fr.gouv.stopc.robert.server.batch.configuration.ContactsProcessingConfiguration;
import fr.gouv.stopc.robert.server.batch.utils.ItemProcessingCounterUtils;
import fr.gouv.stopc.robertserver.database.model.Registration;
import fr.gouv.stopc.robertserver.database.service.IRegistrationService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.item.ItemWriter;
import org.springframework.util.CollectionUtils;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import fr.gouv.stopc.robert.server.batch.utils.ItemProcessingCounterUtils;
import fr.gouv.stopc.robertserver.database.model.Registration;
import fr.gouv.stopc.robertserver.database.service.IRegistrationService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@AllArgsConstructor
......
......@@ -41,3 +41,6 @@ robert.protocol.hello-message-timestamp-tolerance=${ROBERT_PROTOCOL_HELLO_TOLERA
robert.server.country-code=${ROBERT_SERVER_COUNTRY_CODE:0x21}
robert.protocol.contagious-period=${ROBERT_PROTOCOL_CONTAGIOUS_PERIOD:14}
# Number of epcoh gap, an at-rish app should be still notified
robert.at-risk.notification.epoch.minimum-gap=${ROBERT_AT_RISK_EPOCH_MINIMUM_GAP:192}
......@@ -16,3 +16,6 @@ robert.scoring.batch-mode=${ROBERT_SCORING_BATCH_MODE:SCORE_CONTACTS_AND_COMPUTE
robert.protocol.hello-message-timestamp-tolerance=${ROBERT_PROTOCOL_HELLO_TOLERANCE:180}
robert.server.country-code=${ROBERT_SERVER_COUNTRY_CODE:0x21}
# Number of epcoh gap, an at-rish app should be still notified
robert.at-risk.notification.epoch.minimum-gap=${ROBERT_AT_RISK_EPOCH_MINIMUM_GAP:192}
......@@ -194,7 +194,7 @@ public class RegistrationProcessorTest {
}
@Test
public void testNotifiedRemainsTrueIfRiskDetectedSucceeds() {
public void testNotifiedBecomesFalseIfRiskDetectedSucceeds() {
Double[] expositionsForFirstEpoch = new Double[] { 10.0, 2.0, 1.0, 4.3 };
Double[] expositionsForSecondEpoch = new Double[] { };
ArrayList<EpochExposition> expositions = new ArrayList<>();
......@@ -207,7 +207,7 @@ public class RegistrationProcessorTest {
.expositionScores(Arrays.asList(expositionsForSecondEpoch))
.build());
testNotifiedNotModified(true, expositions, true);
testNotifiedNotModified(true, false, expositions, true);
}
@Test
......@@ -224,7 +224,7 @@ public class RegistrationProcessorTest {
.expositionScores(Arrays.asList(expositionsForSecondEpoch))
.build());
testNotifiedNotModified(false, expositions, true);
testNotifiedNotModified(false, false, expositions, true);
}
@Test
......@@ -241,7 +241,7 @@ public class RegistrationProcessorTest {
.expositionScores(Arrays.asList(expositionsForSecondEpoch))
.build());
testNotifiedNotModified(true, expositions, false);
testNotifiedNotModified(true, true, expositions, false);
}
@Test
......@@ -258,10 +258,10 @@ public class RegistrationProcessorTest {
.expositionScores(Arrays.asList(expositionsForSecondEpoch))
.build());
testNotifiedNotModified(false, expositions, false);
testNotifiedNotModified(false, false, expositions, false);
}
private void testNotifiedNotModified(boolean initialValue, List<EpochExposition> expositions, boolean riskDetected) {
private void testNotifiedNotModified(boolean initialValue, boolean expectedValue, List<EpochExposition> expositions, boolean riskDetected) {
this.registration = this.registrationService.createRegistration(ProcessorTestUtils.generateIdA());
assertTrue(this.registration.isPresent());
this.registration.get().setNotified(initialValue);
......@@ -279,6 +279,6 @@ public class RegistrationProcessorTest {
expositions.get(0).getExpositionScores().toArray()));
assertTrue(Arrays.equals(reg.get().getExposedEpochs().get(1).getExpositionScores().toArray(),
expositions.get(1).getExpositionScores().toArray()));
assertEquals(initialValue, reg.get().isNotified());
assertEquals(expectedValue, reg.get().isNotified());
}
}
package test.fr.gouv.stopc.robertserver.batch.processor;
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 static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import fr.gouv.stopc.robert.server.batch.processor.UpdateRegistrationFlagsProcessor;
import fr.gouv.stopc.robert.server.batch.utils.PropertyLoader;
import fr.gouv.stopc.robertserver.database.model.Registration;
@ExtendWith(SpringExtension.class)
@TestPropertySource("classpath:application.properties")
public class UpdateRegistrationFlagsProcessorTest {
private static final String SHOULD_NOT_FAIL = "It should not fail";
@Mock
private PropertyLoader propertyLoader;
@Value("${robert.at-risk.notification.epoch.minimum-gap}")
private Integer atRiskNotificationEpochGap;
private UpdateRegistrationFlagsProcessor processor;
@BeforeEach
public void beforeEach() {
this.processor = new UpdateRegistrationFlagsProcessor(this.propertyLoader);
when(this.propertyLoader.getAtRiskNotificationEpochGap()).thenReturn(this.atRiskNotificationEpochGap);
}
@Test
public void testRegistrationShouldNotBeUpdatedWhenNotAtRiskAndNotNotified() {
try {
// Given
Registration registration = Registration.builder()
.atRisk(false)
.isNotified(false)
.build();
// When
Registration processedRegistration = this.processor.process(registration);
// Then
assertNull(processedRegistration);
} catch (Exception e) {
fail(SHOULD_NOT_FAIL);
}
}
@Test
public void testRegistrationShouldNotBeUpdatedWhenNotAtRiskAndNotified() {
try {
// Given
Registration registration = Registration.builder()
.atRisk(false)
.isNotified(true)
.build();
// When
Registration processedRegistration = this.processor.process(registration);
// Then
assertNull(processedRegistration);
} catch (Exception e) {
fail(SHOULD_NOT_FAIL);
}
}
@Test
public void testRegistrationShouldNotBeUpdatedWhenAtRiskAndNotNotified() {
try {
// Given
Registration registration = Registration.builder()
.atRisk(true)
.isNotified(false)
.build();
// When
Registration processedRegistration = this.processor.process(registration);
// Then
assertNull(processedRegistration);
} catch (Exception e) {
fail(SHOULD_NOT_FAIL);
}
}
@Test
public void testRegistrationShouldNotBeUpdatedWhenAtRiskAndNotifiedButEpochMinimunIsNotReached() {
try {
// Given
Registration registration = Registration.builder()
.atRisk(true)
.isNotified(true)
.lastStatusRequestEpoch(5000)
.latestRiskEpoch(4912)
.build();
// When
Registration processedRegistration = this.processor.process(registration);
// Then
assertNull(processedRegistration);
} catch (Exception e) {
fail(SHOULD_NOT_FAIL);
}
}
@Test
public void testRegistrationShouldNotBeUpdatedWhenAtRiskAndNotifiedButEpochMinimunIsReached() {
try {
// Given
Registration registration = Registration.builder()
.atRisk(true)
.isNotified(true)
.lastStatusRequestEpoch(5000)
.latestRiskEpoch(4808)
.build();
// When
Registration processedRegistration = this.processor.process(registration);
// Then
assertNotNull(processedRegistration);
assertFalse(processedRegistration.isAtRisk());
assertTrue(processedRegistration.isNotified());
} catch (Exception e) {
fail(SHOULD_NOT_FAIL);
}
}
@Test
public void testRegistrationShouldNotBeUpdatedWhenAtRiskAndNotifiedButEpochMinimunIsExceeded() {
try {
// Given
Registration registration = Registration.builder()
.atRisk(true)
.isNotified(true)
.lastStatusRequestEpoch(5000)
.latestRiskEpoch(4500)
.build();
// When
Registration processedRegistration = this.processor.process(registration);
// Then
assertNotNull(processedRegistration);
assertFalse(processedRegistration.isAtRisk());
assertTrue(processedRegistration.isNotified());
} catch (Exception e) {
fail(SHOULD_NOT_FAIL);
}
}
}
......@@ -34,4 +34,7 @@ robert.server.time-start=20200601
robert.protocol.contagious-period=14
robert.protocol.hello-message-timestamp-tolerance=180
# Number of epcoh gap, an at-rish app should be still notified
robert.at-risk.notification.epoch.minimum-gap=${ROBERT_AT_RISK_EPOCH_MINIMUM_GAP:192}
spring.cloud.consul.config.watch.enabled=false
......@@ -180,8 +180,8 @@ public class StatusControllerImpl implements IStatusController {
// Step #3: Set UserNotified to true if at risk
// If was never notified and batch flagged a risk, notify
// and remember last exposed epoch as new starting point for subsequent risk notifications
// The status atRisk will be reinitialized by the batch
if (atRisk) {
record.setAtRisk(false);
record.setNotified(true);
}
......@@ -190,6 +190,7 @@ public class StatusControllerImpl implements IStatusController {
.atRisk(atRisk)
.config(getClientConfig())
.tuples(Base64.encode(tuples))
.riskEpoch(record.getLatestRiskEpoch())
.build();
// Save changes to the record
......
......@@ -2,15 +2,14 @@ package fr.gouv.stopc.robertserver.ws.dto;
import java.util.List;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Singular;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@AllArgsConstructor
@NoArgsConstructor
@Data
......@@ -28,4 +27,6 @@ public class StatusResponseDto {
private long lastExposureTimeframe;
private String message;
private int riskEpoch;
}
......@@ -56,6 +56,7 @@ robert.server.request-time-delta-tolerance=${ROBERT_SERVER_REQUEST_TIME_DELTA_TO
robert.server.status-request-minimum-epoch-gap=${ROBERT_SERVER_ESR_MINI_EPOCH_GAP:2}
robert.server.captcha-challenge-timestamp-tolerance=${ROBERT_SERVER_CAPTCHA_CHALLENGE_TIMESTAMP_TOLERANCE:15}
robert.server.time-start=${ROBERT_SERVER_TIMESTART:20200601}
robert.epoch-bundle-duration-in-days=4
push.server.host=${PUSH_SERVER_HOST:localhost}
push.server.port=${PUSH_SERVER_PORT:9096}
......
......@@ -640,6 +640,7 @@ public class StatusControllerWsRestTest {
.permanentIdentifier(idA)
.atRisk(true)
.isNotified(false)
.latestRiskEpoch(currentEpoch - 10)
.lastStatusRequestEpoch(currentEpoch - 3).build();
byte[][] reqContent = createEBIDTimeMACFor(idA, kA, currentEpoch);
......@@ -674,6 +675,7 @@ public class StatusControllerWsRestTest {
assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response.getBody().isAtRisk());
assertNotNull(response.getBody().getTuples());
assertEquals(response.getBody().getRiskEpoch(), reg.getLatestRiskEpoch());
assertTrue(reg.isNotified());
assertTrue(currentEpoch - 3 < reg.getLastStatusRequestEpoch());
verify(this.registrationService, times(2)).findById(idA);
......@@ -867,8 +869,9 @@ public class StatusControllerWsRestTest {
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(currentEpoch, reg.getLastStatusRequestEpoch());
assertEquals(true, response.getBody().isAtRisk());
assertEquals(currentEpoch - 8 , response.getBody().getRiskEpoch());
assertNotNull(response.getBody().getTuples());
assertEquals(false, reg.isAtRisk());
assertEquals(true, reg.isAtRisk());
assertEquals(true, reg.isNotified());
verify(this.registrationService, times(2)).findById(idA);
verify(this.registrationService, times(2)).saveRegistration(reg);
......@@ -1048,7 +1051,7 @@ public class StatusControllerWsRestTest {
assertEquals(currentEpoch, reg.getLastStatusRequestEpoch());
assertEquals(true, response.getBody().isAtRisk());
assertNotNull(response.getBody().getTuples());
assertEquals(false, reg.isAtRisk());
assertEquals(true, reg.isAtRisk());
assertEquals(true, reg.isNotified());
verify(this.registrationService, times(2)).findById(idA);
verify(this.registrationService, times(2)).saveRegistration(reg);
......@@ -1109,7 +1112,7 @@ public class StatusControllerWsRestTest {
assertEquals(currentEpoch, reg.getLastStatusRequestEpoch());
assertEquals(true, response.getBody().isAtRisk());
assertNotNull(response.getBody().getTuples());
assertEquals(false, reg.isAtRisk());
assertEquals(true, reg.isAtRisk());
assertEquals(true, reg.isNotified());
verify(this.registrationService, times(2)).findById(idA);
verify(this.registrationService, times(2)).saveRegistration(reg);
......@@ -1185,7 +1188,7 @@ public class StatusControllerWsRestTest {
assertEquals(currentEpoch, reg.getLastStatusRequestEpoch());
assertEquals(true, response.getBody().isAtRisk());
assertNotNull(response.getBody().getTuples());
assertEquals(false, reg.isAtRisk());
assertEquals(true, reg.isAtRisk());
assertEquals(true, reg.isNotified());
assertTrue(reg.getLastTimestampDrift() == Math.abs(timestampDelta) + 1 || reg.getLastTimestampDrift() == Math.abs(timestampDelta));
verify(this.registrationService, times(2)).findById(idA);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment