Commit 7dd91ad8 authored by calocedre TAC's avatar calocedre TAC
Browse files

Added hot reload for ws rest configurations

parent b2666b35
package fr.gouv.clea.ws.configuration;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
@Data
@NoArgsConstructor
@Validated
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "clea.conf")
@Slf4j
public class CleaWsProperties {
@Min(value = 1800)
private long exposureTimeUnitInSeconds;
@Positive
private long duplicateScanThresholdInSeconds;
@Min(value = 10)
@Max(value = 30)
private int retentionDurationInDays;
@NotNull
private boolean authorizationCheckActive;
@NotNull
@NotEmpty
@NotBlank
@ToString.Exclude
private String robertJwtPublicKey;
@PostConstruct
public void logConfigurationLoaded() {
log.info("Loaded Clea Ws configuration: {}", this);
}
}
......@@ -3,9 +3,7 @@ package fr.gouv.clea.ws.configuration;
import fr.inria.clea.lsp.LocationSpecificPartDecoder;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
......@@ -14,7 +12,6 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import javax.annotation.PostConstruct;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
......@@ -22,25 +19,18 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
@EnableWebSecurity
@Slf4j
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final boolean checkAuthorization;
private final String encodedRobertJwtPublicKey;
private final CleaWsProperties cleaWsProperties;
private final HandlerExceptionResolver handlerExceptionResolver;
private PublicKey robertJwtPublicKey;
@Autowired
public SecurityConfiguration(
@Value("${clea.conf.security.report.checkAuthorization}") boolean checkAuthorization,
@Value("${clea.conf.security.report.robertJwtPublicKey}") String encodedRobertJwtPublicKey,
CleaWsProperties cleaWsProperties,
HandlerExceptionResolver handlerExceptionResolver
) {
this.checkAuthorization = checkAuthorization;
this.encodedRobertJwtPublicKey = encodedRobertJwtPublicKey;
this.cleaWsProperties = cleaWsProperties;
this.handlerExceptionResolver = handlerExceptionResolver;
}
......@@ -49,12 +39,11 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
return new LocationSpecificPartDecoder();
}
@PostConstruct
private void initPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] encoded = Decoders.BASE64.decode(this.encodedRobertJwtPublicKey);
private PublicKey initPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] encoded = Decoders.BASE64.decode(this.cleaWsProperties.getRobertJwtPublicKey());
KeyFactory keyFactory = KeyFactory.getInstance(SignatureAlgorithm.RS256.getFamilyName());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
this.robertJwtPublicKey = keyFactory.generatePublic(keySpec);
return keyFactory.generatePublic(keySpec);
}
@Override
......@@ -63,7 +52,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.authorizeRequests()
.antMatchers("/api/clea/**").permitAll()
.and()
.addFilterAfter(new JwtValidationFilter(checkAuthorization, robertJwtPublicKey, handlerExceptionResolver), BasicAuthenticationFilter.class)
.addFilterAfter(new JwtValidationFilter(this.cleaWsProperties.isAuthorizationCheckActive(), this.initPublicKey(), handlerExceptionResolver), BasicAuthenticationFilter.class)
.httpBasic().disable()
.csrf().disable()
.cors();
......
package fr.gouv.clea.ws.service.impl;
import fr.gouv.clea.ws.configuration.CleaWsProperties;
import fr.gouv.clea.ws.model.DecodedVisit;
import fr.gouv.clea.ws.service.IDecodedVisitProducerService;
import fr.gouv.clea.ws.service.IReportService;
......@@ -12,7 +13,6 @@ import fr.inria.clea.lsp.exception.CleaEncodingException;
import fr.inria.clea.lsp.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.time.Duration;
......@@ -20,35 +20,29 @@ import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Comparator;
import java.util.stream.Collectors;
@Service
@Slf4j
public class ReportService implements IReportService {
private final int retentionDurationInDays;
private final long duplicateScanThresholdInSeconds;
private final CleaWsProperties cleaWsProperties;
private final LocationSpecificPartDecoder decoder;
private final IDecodedVisitProducerService processService;
private final long exposureTimeUnit;
@Autowired
public ReportService(
@Value("${clea.conf.retentionDurationInDays}") int retentionDuration,
@Value("${clea.conf.duplicateScanThresholdInSeconds}") long duplicateScanThreshold,
@Value("${clea.conf.exposureTimeUnitInSeconds}") long exposureTimeUnit,
LocationSpecificPartDecoder decoder,
IDecodedVisitProducerService processService) {
this.retentionDurationInDays = retentionDuration;
this.duplicateScanThresholdInSeconds = duplicateScanThreshold;
this.exposureTimeUnit = exposureTimeUnit;
CleaWsProperties cleaWsProperties,
LocationSpecificPartDecoder decoder,
IDecodedVisitProducerService processService
) {
this.cleaWsProperties = cleaWsProperties;
this.decoder = decoder;
this.processService = processService;
}
......@@ -56,7 +50,7 @@ public class ReportService implements IReportService {
@Override
public List<DecodedVisit> report(ReportRequest reportRequestVo) {
final Instant now = Instant.now();
final VisitsInSameUnitCounter closeScanTimeVisits = new VisitsInSameUnitCounter(exposureTimeUnit);
final VisitsInSameUnitCounter closeScanTimeVisits = new VisitsInSameUnitCounter(cleaWsProperties.getExposureTimeUnitInSeconds());
long validatedPivotDate = this.validatePivotDate(reportRequestVo.getPivotDateAsNtpTimestamp(), now);
List<Visit> reportVisits = reportRequestVo.getVisits();
List<DecodedVisit> verified = reportVisits.stream()
......@@ -92,7 +86,7 @@ public class ReportService implements IReportService {
}
private boolean isOutdated(Visit visit, Instant now) {
boolean outdated = ChronoUnit.DAYS.between(TimeUtils.instantFromTimestamp(visit.getQrCodeScanTimeAsNtpTimestamp()), now) > retentionDurationInDays;
boolean outdated = ChronoUnit.DAYS.between(TimeUtils.instantFromTimestamp(visit.getQrCodeScanTimeAsNtpTimestamp()), now) > cleaWsProperties.getRetentionDurationInDays();
if (outdated) {
log.warn("report: {} rejected: Outdated", MessageFormatter.truncateQrCode(visit.getQrCode()));
}
......@@ -117,7 +111,7 @@ public class ReportService implements IReportService {
}
long secondsBetweenScans = Duration.between(one.getQrCodeScanTime(), other.getQrCodeScanTime()).abs().toSeconds();
if (secondsBetweenScans <= duplicateScanThresholdInSeconds) {
if (secondsBetweenScans <= cleaWsProperties.getDuplicateScanThresholdInSeconds()) {
log.warn("report: {} {} rejected: Duplicate", MessageFormatter.truncateUUID(one.getStringLocationTemporaryPublicId()), one.getQrCodeScanTime());
return true;
}
......@@ -137,7 +131,7 @@ public class ReportService implements IReportService {
private long validatePivotDate(long pivotDate, Instant now) {
Instant pivotDateAsInstant = TimeUtils.instantFromTimestamp(pivotDate);
Instant nowWithoutMilis = now.truncatedTo(ChronoUnit.SECONDS);
Instant retentionDateLimit = nowWithoutMilis.minus(retentionDurationInDays, ChronoUnit.DAYS);
Instant retentionDateLimit = nowWithoutMilis.minus(cleaWsProperties.getRetentionDurationInDays(), ChronoUnit.DAYS);
if (pivotDateAsInstant.isAfter(now) || pivotDateAsInstant.isBefore(retentionDateLimit)) {
long retentionDateLimitAsNtp = TimeUtils.ntpTimestampFromInstant(retentionDateLimit);
log.warn("pivotDate: {} not between retentionLimitDate: {} and now: {}", pivotDateAsInstant, retentionDateLimit, now);
......
......@@ -3,10 +3,8 @@ clea:
exposureTimeUnitInSeconds: 1800
duplicateScanThresholdInSeconds: 10800
retentionDurationInDays: 14
security:
report:
checkAuthorization: false
robertJwtPublicKey: TODO
authorizationCheckActive: false
robertJwtPublicKey: TODO
controller:
path:
......
......@@ -103,7 +103,7 @@ class JwtValidationFilterTest {
assertThat(response.getStatus()).isEqualTo(200);
}
protected String newJwtToken(Instant now, Instant expiration) {
private String newJwtToken(Instant now, Instant expiration) {
return Jwts.builder()
.setHeaderParam("type", "JWT")
.setIssuedAt(Date.from(now))
......
......@@ -42,7 +42,7 @@ import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {"clea.conf.security.report.checkAuthorization=true"})
@TestPropertySource(properties = {"clea.conf.authorizationCheckActive=true"})
class CleaControllerAuthEnabledTest {
/*
......
......@@ -19,7 +19,6 @@ import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.test.EmbeddedKafkaBroker;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.kafka.test.utils.KafkaTestUtils;
import org.springframework.test.annotation.DirtiesContext;
import java.time.Instant;
import java.util.Collections;
......@@ -33,7 +32,6 @@ import java.util.stream.StreamSupport;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@DirtiesContext
@EmbeddedKafka(partitions = 1, brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"})
class DecodedVisitProducerServiceTest {
......@@ -126,7 +124,7 @@ class DecodedVisitProducerServiceTest {
assertThat(visit3.isBackward()).isEqualTo(isBackward3);
}
protected Instant newRandomInstant() {
private Instant newRandomInstant() {
return Instant.ofEpochSecond(RandomUtils.nextLong(0, Instant.now().getEpochSecond()));
}
......
......@@ -9,20 +9,20 @@ import fr.gouv.clea.ws.service.IReportService;
import fr.gouv.clea.ws.vo.ReportRequest;
import fr.gouv.clea.ws.vo.Visit;
import fr.inria.clea.lsp.CleaEciesEncoder;
import fr.inria.clea.lsp.EncryptedLocationSpecificPart;
import fr.inria.clea.lsp.LocationSpecificPart;
import fr.inria.clea.lsp.LocationSpecificPartDecoder;
import fr.inria.clea.lsp.LocationSpecificPartEncoder;
import fr.inria.clea.lsp.exception.CleaEncodingException;
import fr.inria.clea.lsp.utils.TimeUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
......@@ -32,22 +32,21 @@ import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
@SpringBootTest
class ReportServiceTest {
private final int retentionDuration = 14;
private final long duplicateScanThresholdInSeconds = 10800L;
private final long exposureTimeUnit = 1800L;
private final LocationSpecificPartDecoder decoder = new LocationSpecificPartDecoder();
private final IDecodedVisitProducerService processService = mock(IDecodedVisitProducerService.class);
private final IReportService reportService = new ReportService(retentionDuration, duplicateScanThresholdInSeconds, exposureTimeUnit, decoder, processService);
@MockBean
private IDecodedVisitProducerService processService;
@Autowired
private IReportService reportService;
private Instant now;
@BeforeEach
void init() {
now = Instant.now();
assertThat(decoder).isNotNull();
assertThat(processService).isNotNull();
assertThat(reportService).isNotNull();
doNothing().when(processService).produce(anyList());
......@@ -55,7 +54,7 @@ class ReportServiceTest {
@Test
@DisplayName("test successful report with no rejection")
void report() throws CleaEncodingException {
void report() {
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
UUID uuid3 = UUID.randomUUID();
......@@ -75,7 +74,7 @@ class ReportServiceTest {
@Test
@DisplayName("test report with non valid qr codes")
void testWithNonValidReports() throws CleaEncodingException {
void testWithNonValidReports() {
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
UUID uuid3 = UUID.randomUUID();
......@@ -96,7 +95,7 @@ class ReportServiceTest {
@Test
@DisplayName("test report with outdated scans")
void testWithOutdatedReports() throws CleaEncodingException {
void testWithOutdatedReports() {
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
UUID uuid3 = UUID.randomUUID();
......@@ -120,7 +119,7 @@ class ReportServiceTest {
@Test
@DisplayName("test report with future scans")
void testWithFutureReports() throws CleaEncodingException {
void testWithFutureReports() {
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
List<Visit> visits = List.of(
......@@ -137,7 +136,7 @@ class ReportServiceTest {
@Test
@DisplayName("test report with duplicated qr codes")
void testWithDuplicates() throws CleaEncodingException {
void testWithDuplicates() {
UUID uuidA = UUID.fromString("60f5ebf7-d2af-4451-a575-7d1a2de7a9fd");
UUID uuidA2 = UUID.fromString("60f5ebf7-d2af-4451-a575-7d1a2de7a9fd");
UUID uuidB = UUID.fromString("de4c7b16-d5a2-45fa-a4f4-50fbf1e3880b");
......@@ -155,7 +154,7 @@ class ReportServiceTest {
newVisit(uuidC, TimeUtils.ntpTimestampFromInstant(now)), // pass
newVisit(uuidC2, TimeUtils.ntpTimestampFromInstant(now)), /* don't pass */
newVisit(uuidC2, TimeUtils.ntpTimestampFromInstant(now)) /* don't pass */
);
);
List<DecodedVisit> processed = reportService.report(new ReportRequest(visits, 0L));
......@@ -167,7 +166,7 @@ class ReportServiceTest {
@Test
@DisplayName("if pivot date is in future, set it to retentionDate and check that all visits are forward")
void testWithPivotDateInFuture() throws CleaEncodingException {
void testWithPivotDateInFuture() {
long pivotDateInFutureAsNtp = TimeUtils.ntpTimestampFromInstant(now.plus(1, ChronoUnit.MINUTES));
UUID uuid1 = UUID.randomUUID();
......@@ -188,7 +187,7 @@ class ReportServiceTest {
@Test
@DisplayName("if pivot date is before retentionDate, set it to retentionDate and check that all visits are forward")
void testWithPivotDateTooOld() throws CleaEncodingException {
void testWithPivotDateTooOld() {
long pivotDateTooOldAsNtp = TimeUtils.ntpTimestampFromInstant(now.minus(15, ChronoUnit.DAYS));
UUID uuid1 = UUID.randomUUID();
......@@ -209,7 +208,7 @@ class ReportServiceTest {
@Test
@DisplayName("if pivot date is before or equal qrScanTime, visits should be marked as forward")
void testForward() throws CleaEncodingException {
void testForward() {
long pivotDate = TimeUtils.ntpTimestampFromInstant(now.minus(1, ChronoUnit.DAYS));
long qrScan = TimeUtils.ntpTimestampFromInstant(now);
UUID uuid1 = UUID.randomUUID();
......@@ -228,7 +227,7 @@ class ReportServiceTest {
@Test
@DisplayName("if pivot date is strictly after qrScanTime, visits should be marked as backward")
void testBackward() throws CleaEncodingException {
void testBackward() {
long pivotDate = TimeUtils.ntpTimestampFromInstant(now);
long qrScan = TimeUtils.ntpTimestampFromInstant(now.minus(1, ChronoUnit.DAYS));
UUID uuid = UUID.randomUUID();
......@@ -240,13 +239,7 @@ class ReportServiceTest {
assertThat(processed.get(0).isBackward()).isTrue();
}
private EncryptedLocationSpecificPart createEncryptedLocationSpecificPart(UUID locationTemporaryPublicId) {
return EncryptedLocationSpecificPart.builder()
.locationTemporaryPublicId(locationTemporaryPublicId)
.build();
}
private Visit newVisit(UUID uuid, Long qrCodeScanTime) throws CleaEncodingException {
private Visit newVisit(UUID uuid, Long qrCodeScanTime) {
LocationSpecificPart lsp = LocationSpecificPart.builder()
.locationTemporaryPublicId(uuid)
.build();
......@@ -272,7 +265,7 @@ class ReportServiceTest {
}
@Test
void test_that_duplicate_visits_increment_rejected_visits_count() throws CleaEncodingException {
void test_that_duplicate_visits_increment_rejected_visits_count() {
UUID uuidA = UUID.randomUUID();
UUID uuidB = UUID.randomUUID();
UUID uuidC = UUID.randomUUID();
......@@ -293,7 +286,7 @@ class ReportServiceTest {
}
@Test
void test_that_backward_visit_increments_backward_visits_count() throws CleaEncodingException {
void test_that_backward_visit_increments_backward_visits_count() {
long pivotDate = TimeUtils.ntpTimestampFromInstant(now);
long qrScan = TimeUtils.ntpTimestampFromInstant(now.minus(1, ChronoUnit.DAYS));
UUID uuid = UUID.randomUUID();
......@@ -306,7 +299,7 @@ class ReportServiceTest {
}
@Test
void test_that_forward_visit_increments_forward_visits_count() throws CleaEncodingException {
void test_that_forward_visit_increments_forward_visits_count() {
long pivotDate = TimeUtils.ntpTimestampFromInstant(now.minus(1, ChronoUnit.DAYS));
long qrScan = TimeUtils.ntpTimestampFromInstant(now);
UUID uuid1 = UUID.randomUUID();
......@@ -323,7 +316,7 @@ class ReportServiceTest {
}
@Test
void test_that_outdated_visits_increments_rejected_visits_count() throws CleaEncodingException {
void test_that_outdated_visits_increments_rejected_visits_count() {
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
UUID uuid3 = UUID.randomUUID();
......@@ -343,7 +336,7 @@ class ReportServiceTest {
}
@Test
void test_that_future_visits_increments_rejected_visits_count() throws CleaEncodingException {
void test_that_future_visits_increments_rejected_visits_count() {
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
List<Visit> visits = List.of(
......
package fr.gouv.clea.ws.service.impl;
import fr.gouv.clea.ws.model.DecodedVisit;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mockito;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class VisitsInSameCounterTest {
@Mock
private DecodedVisit decodedVisit;
private static final Duration exposureTimeUnit = Duration.ofSeconds(1800);
private static final Duration exposureTimeUnitInSeconds = Duration.ofSeconds(1800);
private final DecodedVisit decodedVisit = Mockito.mock(DecodedVisit.class);
@Test
void incrementIfScannedInSameTimeUnitThanLastScanTime_increments_counter_when_difference_between_scan_time_is_lower_than_exposureTimeUnit() {
final VisitsInSameUnitCounter counter = new VisitsInSameUnitCounter(exposureTimeUnit.getSeconds());
final VisitsInSameUnitCounter counter = new VisitsInSameUnitCounter(exposureTimeUnitInSeconds.getSeconds());
final int initialCount = 0;
counter.setCount(initialCount);
final Instant lastScanTime = Instant.now().minus(exposureTimeUnit.minus(1, ChronoUnit.SECONDS));
final Instant lastScanTime = Instant.now().minus(exposureTimeUnitInSeconds.minus(1, ChronoUnit.SECONDS));
// 1s after
final Instant currentVisitScanTime = Instant.now();
counter.setLastScanTime(lastScanTime);
......@@ -38,28 +33,28 @@ class VisitsInSameCounterTest {
counter.incrementIfScannedInSameTimeUnitThanLastScanTime(decodedVisit);
Assertions.assertThat(counter.getCount()).isEqualTo(initialCount + 1);
assertThat(counter.getCount()).isEqualTo(initialCount + 1);
}
@Test
void incrementIfScannedInSameTimeUnitThanLastScanTime_does_not_increment_counter_when_difference_between_scan_time_is_greater_than_exposureTimeUnit() {
final VisitsInSameUnitCounter counter = new VisitsInSameUnitCounter(exposureTimeUnit.getSeconds());
final VisitsInSameUnitCounter counter = new VisitsInSameUnitCounter(exposureTimeUnitInSeconds.getSeconds());
final int initialCount = 0;
counter.setCount(initialCount);
final Instant lastScanTime = Instant.now().minus(exposureTimeUnit.plus(1, ChronoUnit.SECONDS));
final Instant lastScanTime = Instant.now().minus(exposureTimeUnitInSeconds.plus(1, ChronoUnit.SECONDS));
final Instant currentVisitScanTime = Instant.now();
counter.setLastScanTime(lastScanTime);
when(decodedVisit.getQrCodeScanTime()).thenReturn(currentVisitScanTime);
counter.incrementIfScannedInSameTimeUnitThanLastScanTime(decodedVisit);
Assertions.assertThat(counter.getCount()).isEqualTo(initialCount);
assertThat(counter.getCount()).isEqualTo(initialCount);
}
@Test
void incrementIfScannedInSameTimeUnitThanLastScanTime_does_not_increment_counter_when_no_lastScanTime_has_already_been_registered() {
final VisitsInSameUnitCounter counter = new VisitsInSameUnitCounter(exposureTimeUnit.getSeconds());
final VisitsInSameUnitCounter counter = new VisitsInSameUnitCounter(exposureTimeUnitInSeconds.getSeconds());
final int initialCount = 0;
counter.setCount(initialCount);
......@@ -68,7 +63,7 @@ class VisitsInSameCounterTest {
counter.incrementIfScannedInSameTimeUnitThanLastScanTime(decodedVisit);
Assertions.assertThat(counter.getLastScanTime()).isEqualTo(currentVisitScanTime);
Assertions.assertThat(counter.getCount()).isEqualTo(initialCount);
assertThat(counter.getLastScanTime()).isEqualTo(currentVisitScanTime);
assertThat(counter.getCount()).isEqualTo(initialCount);
}
}
......@@ -3,10 +3,8 @@ clea:
exposureTimeUnitInSeconds: 1800
duplicateScanThresholdInSeconds: 10800
retentionDurationInDays: 14
security:
report:
checkAuthorization: false
robertJwtPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkp8sKCbrG1elGGG8n/Cq0OVeTA9V/M6ONKArheSEWEOJm/vW60tdQW7hJ+lCQ1Lgg4gLNL3Lp8Gu9R7+nWpCnKnwGWiL0BKWnG31SQ2O01/UMa2yWFJRJCbG49szgPt4PhvrWsNNOyO+Kz1HwO2sTfXkRpJ5dvqZF0Et2wqJy2UeVOzE//a/ZnuBzwuGfJEXBOT774eFEvQWnfX2ZEWOavimiPKsb46Hqg4LpmVR0Q7iH8Dj3D05Hn03O80692tmNjGl4nWn5P/b9YEdJIAWHcTBFiRMgbsKRG2KNAg+04rcZnx/w+xcNqskKvcR11TCzUuNPsKBCpZ4orAtr4O/7QIDAQAB
authorizationCheckActive: false
robertJwtPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkp8sKCbrG1elGGG8n/Cq0OVeTA9V/M6ONKArheSEWEOJm/vW60tdQW7hJ+lCQ1Lgg4gLNL3Lp8Gu9R7+nWpCnKnwGWiL0BKWnG31SQ2O01/UMa2yWFJRJCbG49szgPt4PhvrWsNNOyO+Kz1HwO2sTfXkRpJ5dvqZF0Et2wqJy2UeVOzE//a/ZnuBzwuGfJEXBOT774eFEvQWnfX2ZEWOavimiPKsb46Hqg4LpmVR0Q7iH8Dj3D05Hn03O80692tmNjGl4nWn5P/b9YEdJIAWHcTBFiRMgbsKRG2KNAg+04rcZnx/w+xcNqskKvcR11TCzUuNPsKBCpZ4orAtr4O/7QIDAQAB
controller:
path:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!