Skip to content
This repository has been archived by the owner on May 16, 2023. It is now read-only.

Release/1.4 log submission keys #797

Merged
merged 3 commits into from
Sep 22, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,15 @@ public int hashCode() {
result = 31 * result + Arrays.hashCode(keyData);
return result;
}

@Override
public String toString() {
return "DiagnosisKey{"
+ "keyData=HIDDEN"
+ ", rollingStartIntervalNumber=" + rollingStartIntervalNumber
+ ", rollingPeriod=" + rollingPeriod
+ ", transmissionRiskLevel=" + transmissionRiskLevel
+ ", submissionTimestamp=" + submissionTimestamp
+ '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,14 @@ public interface DiagnosisKeyRepository extends PagingAndSortingRepository<Diagn
* @param rollingPeriod The rolling period of the diagnosis key.
* @param submissionTimestamp The submission timestamp of the diagnosis key.
* @param transmissionRisk The transmission risk level of the diagnosis key.
* @return {@literal true} if the diagnosis key was inserted successfully, {@literal false} otherwise.
*/
@Modifying
@Query("INSERT INTO diagnosis_key "
+ "(key_data, rolling_start_interval_number, rolling_period, submission_timestamp, transmission_risk_level) "
+ "VALUES (:keyData, :rollingStartIntervalNumber, :rollingPeriod, :submissionTimestamp, :transmissionRisk) "
+ "ON CONFLICT DO NOTHING")
void saveDoNothingOnConflict(
boolean saveDoNothingOnConflict(
@Param("keyData") byte[] keyData,
@Param("rollingStartIntervalNumber") int rollingStartIntervalNumber,
@Param("rollingPeriod") int rollingPeriod,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,36 @@ public DiagnosisKeyService(DiagnosisKeyRepository keyRepository) {
}

/**
* Persists the specified collection of {@link DiagnosisKey} instances. If the key data of a particular diagnosis key
* already exists in the database, this diagnosis key is not persisted.
* Persists the specified collection of {@link DiagnosisKey} instances and returns the number of inserted diagnosis
* keys. If the key data of a particular diagnosis key already exists in the database, this diagnosis key is not
* persisted.
*
* @param diagnosisKeys must not contain {@literal null}.
* @return Number of successfully inserted diagnosis keys.
* @throws IllegalArgumentException in case the given collection contains {@literal null}.
*/
@Timed
@Transactional
public void saveDiagnosisKeys(Collection<DiagnosisKey> diagnosisKeys) {
public int saveDiagnosisKeys(Collection<DiagnosisKey> diagnosisKeys) {
int numberOfInsertedKeys = 0;

for (DiagnosisKey diagnosisKey : diagnosisKeys) {
keyRepository.saveDoNothingOnConflict(
boolean keyInsertedSuccessfully = keyRepository.saveDoNothingOnConflict(
diagnosisKey.getKeyData(), diagnosisKey.getRollingStartIntervalNumber(), diagnosisKey.getRollingPeriod(),
diagnosisKey.getSubmissionTimestamp(), diagnosisKey.getTransmissionRiskLevel());

if (keyInsertedSuccessfully) {
numberOfInsertedKeys++;
}
}

int conflictingKeys = diagnosisKeys.size() - numberOfInsertedKeys;
if (conflictingKeys > 0) {
logger.warn("{} out of {} diagnosis keys conflicted with existing database entries and were ignored.",
conflictingKeys, diagnosisKeys.size());
}

return numberOfInsertedKeys;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,22 @@ void shouldNotUpdateExistingKey() {
.withTransmissionRiskLevel(3)
.withSubmissionTimestamp(0L).build());

diagnosisKeyService.saveDiagnosisKeys(keys);

int actNumberOfInsertedRows = diagnosisKeyService.saveDiagnosisKeys(keys);
var actKeys = diagnosisKeyService.getDiagnosisKeys();

assertThat(actKeys.size()).isEqualTo(1);
assertThat(actNumberOfInsertedRows).isEqualTo(1);
assertThat(actKeys).hasSize(1);
assertThat(actKeys.iterator().next().getTransmissionRiskLevel()).isEqualTo(2);
}

@Test
void testReturnedNumberOfInsertedKeysForNoConflict() {
var keys = List.of(
buildDiagnosisKeyForSubmissionTimestamp(1L),
buildDiagnosisKeyForSubmissionTimestamp(0L));

int actNumberOfInsertedRows = diagnosisKeyService.saveDiagnosisKeys(keys);

assertThat(actNumberOfInsertedRows).isEqualTo(2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

package app.coronawarn.server.services.submission.controller;

import static java.time.ZoneOffset.UTC;

import app.coronawarn.server.common.persistence.domain.DiagnosisKey;
import app.coronawarn.server.common.persistence.service.DiagnosisKeyService;
import app.coronawarn.server.common.protocols.external.exposurenotification.TemporaryExposureKey;
Expand All @@ -30,8 +32,13 @@
import app.coronawarn.server.services.submission.verification.TanVerifier;
import io.micrometer.core.annotation.Timed;
import java.security.SecureRandom;
import java.time.Instant;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -130,13 +137,36 @@ public void persistDiagnosisKeysPayload(SubmissionPayload protoBufDiagnosisKeys)
if (diagnosisKey.isYoungerThanRetentionThreshold(retentionDays)) {
diagnosisKeys.add(diagnosisKey);
} else {
logger.info("Not persisting a diagnosis key, as it is outdated beyond retention threshold.");
logger.warn("Not persisting a diagnosis key, as it is outdated beyond retention threshold.");
}
}

checkDiagnosisKeysStructure(diagnosisKeys);
diagnosisKeyService.saveDiagnosisKeys(padDiagnosisKeys(diagnosisKeys));
}

private void checkDiagnosisKeysStructure(List<DiagnosisKey> diagnosisKeys) {
diagnosisKeys.sort(Comparator.comparing(DiagnosisKey::getRollingStartIntervalNumber));
Predicate<DiagnosisKey> hasRiskLevel6 = diagnosisKey -> diagnosisKey.getTransmissionRiskLevel() == 6;

if (diagnosisKeys.stream().noneMatch(hasRiskLevel6)) {
logger.warn("Submission payload was sent with missing key having transmission risk level 6. {}",
Arrays.toString(diagnosisKeys.toArray()));
}

diagnosisKeys.stream().filter(hasRiskLevel6).findFirst().ifPresent(diagnosisKey -> {
long todayMidnightUtc = LocalDate
.ofInstant(Instant.now(), UTC)
.atStartOfDay()
.toEpochSecond(UTC) / (60 * 10);
if (diagnosisKey.getRollingStartIntervalNumber() == todayMidnightUtc) {
logger.warn("Submission payload was sent with a key having transmission risk level 6"
+ " and rolling start interval number of today midnight. {}",
Arrays.toString(diagnosisKeys.toArray()));
}
});
}

private List<DiagnosisKey> padDiagnosisKeys(List<DiagnosisKey> diagnosisKeys) {
List<DiagnosisKey> paddedDiagnosisKeys = new ArrayList<>();
diagnosisKeys.forEach(diagnosisKey -> {
Expand Down