Skip to content

Commit

Permalink
Fixed findTraceKeys dependent on timezone & corresponding unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lmeinen authored and martinalig committed May 21, 2021
1 parent 058448d commit 5e555bb
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@

import ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey;
import ch.ubique.notifyme.sdk.backend.model.util.DateUtil;

import java.sql.Date;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
Expand All @@ -25,6 +30,8 @@

public class JdbcNotifyMeDataServiceV3Impl implements NotifyMeDataServiceV3 {

protected final Logger logger = LoggerFactory.getLogger(getClass());

private final Long bucketSizeInMs;
private final NamedParameterJdbcTemplate jt;
private final SimpleJdbcInsert traceKeyInsert;
Expand All @@ -46,24 +53,31 @@ public void insertTraceKey(TraceKey traceKey) {

@Override
@Transactional(readOnly = true)
public List<TraceKey> findTraceKeys(Instant after) {
public List<TraceKey> findTraceKeys(Instant before, Instant after) {
var sql = "select * from t_trace_key_v3";
final var before = DateUtil.toInstant(DateUtil.getLastFullBucketEndEpochMilli(bucketSizeInMs));
MapSqlParameterSource params = new MapSqlParameterSource("before", DateUtil.toDate(before));
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("before", Timestamp.from(before));
sql += " where created_at < :before";
if (after != null) {
sql += " and created_at >= :after";
params.addValue("after", DateUtil.toDate(after));
// sql += " where created_at >= :after";
params.addValue("after", Timestamp.from(after));
}
return jt.query(sql, params, new TraceKeyV3RowMapper());
}

@Override
public List<TraceKey> findTraceKeys(Instant after) {
final var before = Instant.ofEpochMilli(DateUtil.getLastFullBucketEndEpochMilli(bucketSizeInMs));
return findTraceKeys(before, after);
}

@Override
@Transactional
public int removeTraceKeys(Instant before) {
final var sql = "delete from t_trace_key_v3 where day < :before";
final var params = new MapSqlParameterSource();
params.addValue("before", DateUtil.toDate(before));
params.addValue("before", Timestamp.from(before));
return jt.update(sql, params);
}

Expand All @@ -80,15 +94,15 @@ public void insertTraceKey(List<TraceKey> traceKeysToInsert) {
}

private MapSqlParameterSource getTraceKeyParams(TraceKey traceKey) {
MapSqlParameterSource params = new MapSqlParameterSource();
var params = new MapSqlParameterSource();
params.addValue("version", traceKey.getVersion());
params.addValue("identity", traceKey.getIdentity());
params.addValue("secret_key_for_identity", traceKey.getSecretKeyForIdentity());
params.addValue("day", DateUtil.toDate(traceKey.getDay()));
params.addValue("day", Date.from(traceKey.getDay()));
if (traceKey.getCreatedAt() != null) {
params.addValue("created_at", DateUtil.toDate(traceKey.getCreatedAt()));
params.addValue("created_at", Timestamp.from(traceKey.getCreatedAt()));
} else {
params.addValue("created_at", new Date());
params.addValue("created_at", Timestamp.from(Instant.now()));
}
params.addValue("encrypted_associated_data", traceKey.getEncryptedAssociatedData());
params.addValue("cipher_text_nonce", traceKey.getCipherTextNonce());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ public interface NotifyMeDataServiceV3 {
* Returns trace keys that where submitted (/created) after the given date.
* Returns all trace keys if after == null.
*
* @param before
* @param after
* @return
*/
public List<TraceKey> findTraceKeys(Instant before, Instant after);

/**
* Wrapper around findTraceKeys where before is set to the end of the previous bucket
*
* @param after
* @return
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public static boolean isInThePast(Long lastKeyBundleTag) {
}

public static long getLastFullBucketEndEpochMilli(Long bucketSizeInMs) {
return (System.currentTimeMillis() / bucketSizeInMs) * bucketSizeInMs;
return (Instant.now().toEpochMilli() / bucketSizeInMs) * bucketSizeInMs;
}

public static String formattedDateTime(final Instant time) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ch.ubique.notifyme.sdk.backend.data.NotifyMeDataServiceV3;
import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass.UploadVenueInfo;
import ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey;
import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.FakeRequestFilter;
import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.IntervalThresholdFilter;
import ch.ubique.notifyme.sdk.backend.ws.insertmanager.insertfilters.OverlappingIntervalsFilter;
Expand All @@ -24,6 +25,7 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.*;

import static org.junit.Assert.*;
Expand Down Expand Up @@ -51,18 +53,18 @@ public void setUp() throws Exception {
@Test
@Transactional
public void testInsertEmptyList() throws Exception {
final LocalDateTime now = LocalDateTime.now();
final var now = Instant.now();
assertTrue(
notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty());
insertWith(new ArrayList<>(), new ArrayList<>(), now);
notifyMeDataServiceV3.findTraceKeys(now.minus(1, ChronoUnit.DAYS)).isEmpty());
insertWith(new ArrayList<>(), new ArrayList<>(), LocalDateTime.ofInstant(now, TimeZone.getDefault().toZoneId()));
assertTrue(
notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty());
notifyMeDataServiceV3.findTraceKeys(now.minus(1, ChronoUnit.DAYS)).isEmpty());
}

@Test
@Transactional
public void testInsertInvalidVenueInfo() throws Exception {
final LocalDateTime now = LocalDateTime.now();
final var now = Instant.now();
UploadInsertionFilter removeAll =
new UploadInsertionFilter() {
@Override
Expand All @@ -80,16 +82,16 @@ public List<UploadVenueInfo> filter(
final List<UploadVenueInfo> uploadVenueInfoList = new ArrayList<>();
uploadVenueInfoList.add(
createUploadVenueInfo(
now, now.plusMinutes(60), false));
insertWith(Collections.singletonList(removeAll), uploadVenueInfoList, now);
now, now.plus(1, ChronoUnit.HOURS), false));
insertWith(Collections.singletonList(removeAll), uploadVenueInfoList, LocalDateTime.ofInstant(now, TimeZone.getDefault().toZoneId()));
assertTrue(
notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).isEmpty());
notifyMeDataServiceV3.findTraceKeys(now.minus(1, ChronoUnit.DAYS)).isEmpty());
}

@Test
@Transactional
public void testInsertValid() throws Exception {
final LocalDateTime now = LocalDateTime.now();
final var now = Instant.now();
UploadInsertionFilter removeNone =
new UploadInsertionFilter() {
@Override
Expand All @@ -107,29 +109,30 @@ public List<UploadVenueInfo> filter(
final List<UploadVenueInfo> uploadVenueInfoList = new ArrayList<>();
uploadVenueInfoList.add(
createUploadVenueInfo(
now, now.plusMinutes(60), false));
insertWith(Collections.singletonList(removeNone), uploadVenueInfoList, now);
now.minus(2, ChronoUnit.HOURS), now.minus(1, ChronoUnit.HOURS), false));
insertWith(Collections.singletonList(removeNone), uploadVenueInfoList, LocalDateTime.ofInstant(now, TimeZone.getDefault().toZoneId()));
final var traceKeys = notifyMeDataServiceV3.findTraceKeys(now.plus(1, ChronoUnit.HOURS), now.minus(1, ChronoUnit.DAYS));
assertEquals(1,
notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size());
traceKeys.size());
}

@Test
@Transactional
public void testAddRequestFilters() throws Exception {
final LocalDateTime now = LocalDateTime.now();
final var now = Instant.now();
final var venueInfoList = new ArrayList<UploadVenueInfo>();
final var fakeUpload = createUploadVenueInfo(now.minusDays(6), now.minusDays(5), true);
final var fakeUpload = createUploadVenueInfo(now.minus(6, ChronoUnit.DAYS), now.minus(6, ChronoUnit.DAYS), true);
venueInfoList.add(fakeUpload);
final var negativeIntervalUpload = createUploadVenueInfo(now.minusDays(3), now.minusDays(4), false);
final var negativeIntervalUpload = createUploadVenueInfo(now.minus(3, ChronoUnit.DAYS), now.minus(4, ChronoUnit.DAYS), false);
venueInfoList.add(negativeIntervalUpload);
final var overlapIntervalUpload1 = createUploadVenueInfo(now.minusHours(60), now.minusDays(2), false);
final var overlapIntervalUpload2 = createUploadVenueInfo(now.minusHours(54), now.minusHours(36), false);
final var overlapIntervalUpload1 = createUploadVenueInfo(now.minus(60, ChronoUnit.HOURS), now.minus(2, ChronoUnit.DAYS), false);
final var overlapIntervalUpload2 = createUploadVenueInfo(now.minus(54, ChronoUnit.HOURS), now.minus(36, ChronoUnit.HOURS), false);
venueInfoList.add(overlapIntervalUpload1);
venueInfoList.add(overlapIntervalUpload2);
final var validUpload = createUploadVenueInfo(now.minusHours(24), now.minusHours(23), false);
final var validUpload = createUploadVenueInfo(now.minus(24, ChronoUnit.HOURS), now.minus(23, ChronoUnit.HOURS), false);
venueInfoList.add(validUpload);
insertWith(Arrays.asList(new FakeRequestFilter(), new IntervalThresholdFilter(), new OverlappingIntervalsFilter()), venueInfoList, now);
assertEquals(1, notifyMeDataServiceV3.findTraceKeys(now.minusDays(1).toInstant(ZoneOffset.UTC)).size());
insertWith(Arrays.asList(new FakeRequestFilter(), new IntervalThresholdFilter(), new OverlappingIntervalsFilter()), venueInfoList, LocalDateTime.ofInstant(now, TimeZone.getDefault().toZoneId()));
assertEquals(1, notifyMeDataServiceV3.findTraceKeys(now.plus(1, ChronoUnit.HOURS), now.minus(1, ChronoUnit.DAYS)).size());
}

private void insertWith(
Expand All @@ -144,16 +147,14 @@ private void insertWith(
}
}
final String userAgent = "ch.admin.bag.notifyMe.dev;1.0.7;1595591959493;Android;29";
final var expiry = LocalDateTime.now().plusMinutes(5).toInstant(ZoneOffset.UTC);
final var expiry = Instant.now().plus(5, ChronoUnit.MINUTES);
final var token =
tokenHelper.createToken(
"2021-04-29", "0", "notifyMe", "userupload", Date.from(expiry), true, Instant.now());
insertManager.insertIntoDatabase(uploadVenueInfoList, userAgent, token, now);
}

private UploadVenueInfo createUploadVenueInfo(LocalDateTime start, LocalDateTime end, boolean fake) {
final var startInstant = start.toInstant(ZoneOffset.UTC);
final var endInstant = end.toInstant(ZoneOffset.UTC);
private UploadVenueInfo createUploadVenueInfo(Instant start, Instant end, boolean fake) {
final var crypto = cryptoWrapper.getCryptoUtilV3();
final var noncesAndNotificationKey =
crypto.getNoncesAndNotificationKey(crypto.createNonce(256));
Expand All @@ -168,13 +169,13 @@ private UploadVenueInfo createUploadVenueInfo(LocalDateTime start, LocalDateTime
crypto.concatenate(
"CN-TIMEKEY".getBytes(StandardCharsets.US_ASCII),
crypto.longToBytes(3600L),
crypto.longToBytes(startInstant.getEpochSecond()),
crypto.longToBytes(start.getEpochSecond()),
noncesAndNotificationKey.nonceTimekey));
return UploadVenueInfo.newBuilder()
.setPreId(ByteString.copyFrom(preid))
.setTimeKey(ByteString.copyFrom(timekey))
.setIntervalStartMs(startInstant.toEpochMilli())
.setIntervalEndMs(endInstant.toEpochMilli())
.setIntervalStartMs(start.toEpochMilli())
.setIntervalEndMs(end.toEpochMilli())
.setNotificationKey(ByteString.copyFrom(noncesAndNotificationKey.notificationKey))
.setFake(fake)
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
package ch.ubique.notifyme.sdk.backend.ws.util;

import static org.junit.Assert.*;

import ch.ubique.notifyme.sdk.backend.model.UserUploadPayloadOuterClass;
import ch.ubique.notifyme.sdk.backend.model.tracekey.v3.TraceKey;
import com.google.gson.Gson;
import com.google.protobuf.ByteString;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CryptoUtilV3Test {

Expand Down Expand Up @@ -69,7 +66,10 @@ public void testCreateTraceV3ForUserUpload() {
.setVersion(3)
.addVenueInfos(uploadVenueInfo)
.build();
final var traceKeys = cryptoWrapper.getCryptoUtilV3().createTraceV3ForUserUpload(userUpload);
final var traceKeys =
cryptoWrapper
.getCryptoUtilV3()
.createTraceV3ForUserUpload(userUpload.getVenueInfosList());
assertNotNull(traceKeys);
assertEquals(1, traceKeys.size());
}
Expand Down

0 comments on commit 5e555bb

Please sign in to comment.