mirror of
https://github.com/valitydev/fraudbusters.git
synced 2024-11-06 17:45:19 +00:00
refactoring time bound
This commit is contained in:
parent
d887242d2b
commit
150c80668f
2
pom.xml
2
pom.xml
@ -21,7 +21,7 @@
|
||||
<management.port>8023</management.port>
|
||||
<exposed.ports>${server.port} ${management.port}</exposed.ports>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<fraudo.version>1.0.0</fraudo.version>
|
||||
<fraudo.version>1.0.2</fraudo.version>
|
||||
<clickhouse-jdbc.version>0.3.1</clickhouse-jdbc.version>
|
||||
<fraudbusters-proto.version>1.102-269908f</fraudbusters-proto.version>
|
||||
<machinegun-proto.version>1.21-e4784ab</machinegun-proto.version>
|
||||
|
@ -5,24 +5,69 @@ import dev.vality.fraudo.model.TimeWindow;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import static dev.vality.fraudo.constant.TimeUnit.*;
|
||||
|
||||
@Service
|
||||
public class TimeBoundaryServiceImpl implements TimeBoundaryService {
|
||||
|
||||
@Override
|
||||
public TimeBoundDto getBoundary(Instant target, TimeWindow timeWindow) {
|
||||
Instant left = calculateTimeBoundary(target, timeWindow.getStartWindowTime(), timeWindow.getTimeUnit());
|
||||
Instant right = calculateTimeBoundary(target, timeWindow.getEndWindowTime(), timeWindow.getTimeUnit());
|
||||
ChronoUnit chronoUnit = resolveTimeUnit(timeWindow.getTimeUnit());
|
||||
if (CALENDAR_MONTHS.equals(timeWindow.getTimeUnit())) {
|
||||
return buildCalendarMonthsTimeBound(target, timeWindow, chronoUnit);
|
||||
}
|
||||
Instant left = target.minus(timeWindow.getStart(), chronoUnit);
|
||||
Instant right = target.minus(timeWindow.getEnd(), chronoUnit);
|
||||
return TimeBoundDto.builder()
|
||||
.left(left)
|
||||
.right(right)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Instant calculateTimeBoundary(Instant target, Long timeInterval, ChronoUnit timeUnit) {
|
||||
return timeInterval != null ? target.minus(timeInterval, timeUnit) : target;
|
||||
private ChronoUnit resolveTimeUnit(String timeUnit) {
|
||||
return switch (timeUnit) {
|
||||
case MINUTES -> ChronoUnit.MINUTES;
|
||||
case DAYS, CALENDAR_MONTHS -> ChronoUnit.DAYS;
|
||||
default -> ChronoUnit.HOURS;
|
||||
};
|
||||
}
|
||||
|
||||
private TimeBoundDto buildCalendarMonthsTimeBound(Instant target, TimeWindow timeWindow, ChronoUnit chronoUnit) {
|
||||
LocalDate targetDate = LocalDate.ofInstant(target, ZoneId.systemDefault());
|
||||
int start = calculateStart(timeWindow.getStart(), targetDate);
|
||||
int end = calculateEnd(timeWindow.getEnd(), targetDate);
|
||||
Instant left = targetDate
|
||||
.minus(start, chronoUnit)
|
||||
.atStartOfDay(ZoneOffset.UTC)
|
||||
.toInstant()
|
||||
.truncatedTo(ChronoUnit.DAYS);
|
||||
Instant right = target
|
||||
.minus(end, chronoUnit);
|
||||
return TimeBoundDto.builder()
|
||||
.left(left)
|
||||
.right(right)
|
||||
.build();
|
||||
}
|
||||
|
||||
private int calculateStart(int start, LocalDate targetDate) {
|
||||
int startInDays = targetDate.getDayOfMonth() - 1;
|
||||
for (int i = 1; i <= start - 1; i++) {
|
||||
startInDays += targetDate.minusMonths(i).lengthOfMonth();
|
||||
}
|
||||
return startInDays;
|
||||
}
|
||||
|
||||
private int calculateEnd(int end, LocalDate targetDate) {
|
||||
int endInDays = 0;
|
||||
for (int i = 1; i <= end; i++) {
|
||||
endInDays += targetDate.minusMonths(i).lengthOfMonth();
|
||||
}
|
||||
return endInDays;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ class DispatchTemplateTest extends JUnit5IntegrationTest {
|
||||
//check that global reference created
|
||||
Unreliables.retryUntilTrue(TIMEOUT, TimeUnit.SECONDS, () -> {
|
||||
String result = referencePoolImpl.get(TemplateLevel.GLOBAL.name());
|
||||
if (StringUtils.isEmpty(result)) {
|
||||
if (!StringUtils.hasLength(result)) {
|
||||
return false;
|
||||
}
|
||||
assertEquals(id, result);
|
||||
|
@ -16,8 +16,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import static dev.vality.fraudo.constant.TimeUnit.MINUTES;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
@ -62,7 +61,7 @@ public class SumAggregatorImplTest {
|
||||
Double some = sumAggregator.sum(
|
||||
PaymentCheckedField.BIN,
|
||||
paymentModel,
|
||||
TimeWindow.builder().startWindowTime(1444L).timeUnit(ChronoUnit.MINUTES).build(),
|
||||
TimeWindow.builder().start(1444).timeUnit(MINUTES).build(),
|
||||
null
|
||||
);
|
||||
|
||||
@ -74,9 +73,9 @@ public class SumAggregatorImplTest {
|
||||
PaymentModel paymentModel = new PaymentModel();
|
||||
paymentModel.setAmount(1L);
|
||||
TimeWindow.TimeWindowBuilder timeWindowBuilder = TimeWindow.builder()
|
||||
.startWindowTime(1444L)
|
||||
.timeUnit(ChronoUnit.MINUTES)
|
||||
.endWindowTime(400L);
|
||||
.start(1444)
|
||||
.timeUnit(MINUTES)
|
||||
.end(400);
|
||||
when(paymentRepository.sumOperationByFieldWithGroupBy(any(), any(), any(), any(), any())).thenReturn(1050100L);
|
||||
|
||||
Double sum = sumAggregator.sum(PaymentCheckedField.BIN, paymentModel, timeWindowBuilder.build(), null);
|
||||
@ -84,9 +83,8 @@ public class SumAggregatorImplTest {
|
||||
assertEquals(Double.valueOf(1050101), sum);
|
||||
|
||||
timeWindowBuilder = TimeWindow.builder()
|
||||
.startWindowTime(1444L)
|
||||
.timeUnit(ChronoUnit.MINUTES)
|
||||
.endWindowTime(null);
|
||||
.start(1444)
|
||||
.timeUnit(MINUTES);
|
||||
sum = sumAggregator.sum(PaymentCheckedField.BIN, paymentModel, timeWindowBuilder.build(), null);
|
||||
|
||||
assertEquals(Double.valueOf(1050101), sum);
|
||||
@ -97,8 +95,8 @@ public class SumAggregatorImplTest {
|
||||
when(paymentRepository.sumOperationSuccessWithGroupBy(any(), any(), any(), any(), any())).thenReturn(1050100L);
|
||||
Double some = sumAggregator.sumSuccess(PaymentCheckedField.BIN, new PaymentModel(),
|
||||
TimeWindow.builder()
|
||||
.startWindowTime(1444L)
|
||||
.timeUnit(ChronoUnit.MINUTES)
|
||||
.start(1444)
|
||||
.timeUnit(MINUTES)
|
||||
.build(),
|
||||
null
|
||||
);
|
||||
@ -112,8 +110,8 @@ public class SumAggregatorImplTest {
|
||||
.thenReturn(1050100L);
|
||||
Double some = sumAggregator.sumError(PaymentCheckedField.BIN, new PaymentModel(),
|
||||
TimeWindow.builder()
|
||||
.startWindowTime(1444L)
|
||||
.timeUnit(ChronoUnit.MINUTES)
|
||||
.start(1444)
|
||||
.timeUnit(MINUTES)
|
||||
.build(),
|
||||
null,
|
||||
null
|
||||
|
@ -4,31 +4,24 @@ import dev.vality.fraudo.model.TimeWindow;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import static dev.vality.fraudo.constant.TimeUnit.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class TimeBoundaryServiceImplTest {
|
||||
|
||||
private TimeBoundaryService timeBoundaryService = new TimeBoundaryServiceImpl();
|
||||
|
||||
@Test
|
||||
void getBoundaryWithEmptyTimeWindow() {
|
||||
Instant now = Instant.now();
|
||||
|
||||
var timeBound = timeBoundaryService.getBoundary(now, TimeWindow.builder().build());
|
||||
|
||||
assertEquals(now.truncatedTo(ChronoUnit.SECONDS), timeBound.getLeft().truncatedTo(ChronoUnit.SECONDS));
|
||||
assertEquals(now.truncatedTo(ChronoUnit.SECONDS), timeBound.getRight().truncatedTo(ChronoUnit.SECONDS));
|
||||
}
|
||||
private final TimeBoundaryService timeBoundaryService = new TimeBoundaryServiceImpl();
|
||||
|
||||
@Test
|
||||
void getBoundaryWithOnlyStartTime() {
|
||||
Instant now = Instant.now();
|
||||
long startValue = 5L;
|
||||
int startValue = 5;
|
||||
TimeWindow timeWindow = TimeWindow.builder()
|
||||
.timeUnit(ChronoUnit.MINUTES)
|
||||
.startWindowTime(startValue)
|
||||
.timeUnit(MINUTES)
|
||||
.start(5)
|
||||
.build();
|
||||
|
||||
var timeBound = timeBoundaryService.getBoundary(now, timeWindow);
|
||||
@ -41,12 +34,12 @@ class TimeBoundaryServiceImplTest {
|
||||
@Test
|
||||
void getBoundaryWithDaysUnit() {
|
||||
Instant now = Instant.now();
|
||||
long startValue = 5L;
|
||||
long endValue = 2L;
|
||||
int startValue = 5;
|
||||
int endValue = 2;
|
||||
TimeWindow timeWindow = TimeWindow.builder()
|
||||
.timeUnit(ChronoUnit.DAYS)
|
||||
.startWindowTime(startValue)
|
||||
.endWindowTime(endValue)
|
||||
.timeUnit(DAYS)
|
||||
.start(startValue)
|
||||
.end(endValue)
|
||||
.build();
|
||||
|
||||
var timeBound = timeBoundaryService.getBoundary(now, timeWindow);
|
||||
@ -60,12 +53,12 @@ class TimeBoundaryServiceImplTest {
|
||||
@Test
|
||||
void getBoundaryWithHoursUnit() {
|
||||
Instant now = Instant.now();
|
||||
long startValue = 5L;
|
||||
long endValue = 2L;
|
||||
int startValue = 5;
|
||||
int endValue = 2;
|
||||
TimeWindow timeWindow = TimeWindow.builder()
|
||||
.timeUnit(ChronoUnit.HOURS)
|
||||
.startWindowTime(startValue)
|
||||
.endWindowTime(endValue)
|
||||
.timeUnit(HOURS)
|
||||
.start(startValue)
|
||||
.end(endValue)
|
||||
.build();
|
||||
|
||||
var timeBound = timeBoundaryService.getBoundary(now, timeWindow);
|
||||
@ -76,4 +69,63 @@ class TimeBoundaryServiceImplTest {
|
||||
timeBound.getRight().truncatedTo(ChronoUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withOneCalMonthsTimeUnitTest() {
|
||||
Instant now = Instant.now();
|
||||
int startValue = 1;
|
||||
TimeWindow timeWindow = TimeWindow.builder()
|
||||
.timeUnit(CALENDAR_MONTHS)
|
||||
.start(startValue)
|
||||
.build();
|
||||
|
||||
var timeBound = timeBoundaryService.getBoundary(now, timeWindow);
|
||||
|
||||
LocalDate dateNow = LocalDate.ofInstant(now, ZoneOffset.UTC);
|
||||
assertEquals(now.minus(dateNow.getDayOfMonth() - 1, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS),
|
||||
timeBound.getLeft());
|
||||
assertEquals(now.truncatedTo(ChronoUnit.SECONDS), timeBound.getRight().truncatedTo(ChronoUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withThreeCalMonthsTimeUnitTest() {
|
||||
Instant now = Instant.now();
|
||||
int startValue = 3;
|
||||
TimeWindow timeWindow = TimeWindow.builder()
|
||||
.timeUnit(CALENDAR_MONTHS)
|
||||
.start(startValue)
|
||||
.build();
|
||||
|
||||
var timeBound = timeBoundaryService.getBoundary(now, timeWindow);
|
||||
|
||||
LocalDate dateNow = LocalDate.ofInstant(now, ZoneOffset.UTC);
|
||||
int leftForThreeCalMonths = dateNow.getDayOfMonth() - 1 + dateNow.minusMonths(1).lengthOfMonth() +
|
||||
dateNow.minusMonths(2).lengthOfMonth();
|
||||
assertEquals(now.minus(leftForThreeCalMonths, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS),
|
||||
timeBound.getLeft());
|
||||
assertEquals(now.truncatedTo(ChronoUnit.SECONDS), timeBound.getRight().truncatedTo(ChronoUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void withCalMonthsTimeUnitAndWithEndTimeTest() {
|
||||
Instant now = Instant.now();
|
||||
int startValue = 4;
|
||||
int endValue = 2;
|
||||
TimeWindow timeWindow = TimeWindow.builder()
|
||||
.timeUnit(CALENDAR_MONTHS)
|
||||
.start(startValue)
|
||||
.end(endValue)
|
||||
.build();
|
||||
|
||||
var timeBound = timeBoundaryService.getBoundary(now, timeWindow);
|
||||
|
||||
LocalDate dateNow = LocalDate.ofInstant(now, ZoneOffset.UTC);
|
||||
int startForFourCalMonths = dateNow.getDayOfMonth() - 1 + dateNow.minusMonths(1).lengthOfMonth() +
|
||||
dateNow.minusMonths(2).lengthOfMonth() + dateNow.minusMonths(3).lengthOfMonth();
|
||||
int endForTwoCalMonths = dateNow.minusMonths(1).lengthOfMonth() + dateNow.minusMonths(2).lengthOfMonth();
|
||||
assertEquals(now.minus(startForFourCalMonths, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS),
|
||||
timeBound.getLeft());
|
||||
assertEquals(now.minus(endForTwoCalMonths, ChronoUnit.DAYS).truncatedTo(ChronoUnit.SECONDS),
|
||||
timeBound.getRight().truncatedTo(ChronoUnit.SECONDS));
|
||||
}
|
||||
|
||||
}
|
@ -8,20 +8,21 @@ import dev.vality.fraudo.model.TimeWindow;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static dev.vality.fraudo.constant.TimeUnit.MINUTES;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class DgraphTestAggregationUtils {
|
||||
|
||||
public static TimeWindow createTestTimeWindow() {
|
||||
return TimeWindow.builder()
|
||||
.startWindowTime(600_000L)
|
||||
.endWindowTime(0L)
|
||||
.timeUnit(ChronoUnit.MINUTES)
|
||||
.start(600_000)
|
||||
.end(0)
|
||||
.timeUnit(MINUTES)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user