From 352262167efe17a75535a9865ff1825d257f127b Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 11:06:07 +0300 Subject: [PATCH 01/12] Fix tests --- .../converter/CardTokenNormalizationTest.java | 79 +++++++ .../converter/FilterConverterTest.java | 11 +- .../factory/TestObjectsFactory.java | 2 + .../payment/ManyEmailsPerCardRuleTest.java | 203 ++++++++++++++++++ .../impl/HistoricalFraudResultDataTest.java | 34 ++- .../impl/HistoricalPaymentDataTest.java | 35 ++- .../clickhouse/util/FilterUtilTest.java | 68 ++++++ 7 files changed, 429 insertions(+), 3 deletions(-) create mode 100644 src/test/java/dev/vality/fraudbusters/converter/CardTokenNormalizationTest.java create mode 100644 src/test/java/dev/vality/fraudbusters/fraud/payment/ManyEmailsPerCardRuleTest.java create mode 100644 src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java diff --git a/src/test/java/dev/vality/fraudbusters/converter/CardTokenNormalizationTest.java b/src/test/java/dev/vality/fraudbusters/converter/CardTokenNormalizationTest.java new file mode 100644 index 00000000..9a3ba4a4 --- /dev/null +++ b/src/test/java/dev/vality/fraudbusters/converter/CardTokenNormalizationTest.java @@ -0,0 +1,79 @@ +package dev.vality.fraudbusters.converter; + +import dev.vality.damsel.domain.PaymentTool; +import dev.vality.damsel.fraudbusters.Payment; +import dev.vality.damsel.fraudbusters.PaymentStatus; +import dev.vality.damsel.proxy_inspector.Context; +import dev.vality.fraudbusters.domain.CheckedPayment; +import dev.vality.fraudbusters.domain.FraudRequest; +import dev.vality.fraudbusters.fraud.model.PaymentModel; +import dev.vality.fraudbusters.util.BeanUtil; +import dev.vality.fraudbusters.util.PaymentTypeByContextResolver; +import org.junit.jupiter.api.Test; + +import static dev.vality.fraudbusters.constant.ClickhouseUtilsValue.UNKNOWN; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CardTokenNormalizationTest { + + private final ContextToFraudRequestConverter contextConverter = + new ContextToFraudRequestConverter(new PaymentTypeByContextResolver()); + private final PaymentToPaymentModelConverter historicalPaymentConverter = + new PaymentToPaymentModelConverter(); + private final PaymentToCheckedPaymentConverter checkedPaymentConverter = + new PaymentToCheckedPaymentConverter(new PaymentTypeByContextResolver()); + + @Test + void normalizesAbsentOnlineBankCardToUnknownToken() { + Context context = BeanUtil.createContext(); + context.getPayment().getPayment().getPayer().getPaymentResource() + .getResource().setPaymentTool(new PaymentTool()); + + FraudRequest fraudRequest = contextConverter.convert(context); + + assertEquals(UNKNOWN, fraudRequest.getFraudModel().getCardToken()); + } + + @Test + void normalizesMissingOnlineCardTokenToUnknown() { + Context context = BeanUtil.createContext(); + context.getPayment().getPayment().getPayer().getPaymentResource() + .getResource().getPaymentTool().getBankCard().unsetToken(); + + FraudRequest fraudRequest = contextConverter.convert(context); + + assertEquals(UNKNOWN, fraudRequest.getFraudModel().getCardToken()); + } + + @Test + void normalizesMissingHistoricalCardTokenToUnknown() { + Payment payment = BeanUtil.createPayment(PaymentStatus.captured); + payment.getPaymentTool().getBankCard().unsetToken(); + + PaymentModel paymentModel = historicalPaymentConverter.convert(payment); + + assertEquals(UNKNOWN, paymentModel.getCardToken()); + } + + @Test + void normalizesMissingStoredPaymentCardTokenToUnknown() { + Payment payment = BeanUtil.createPayment(PaymentStatus.captured); + payment.getPaymentTool().getBankCard().unsetToken(); + + CheckedPayment checkedPayment = checkedPaymentConverter.convert(payment); + + assertEquals(UNKNOWN, checkedPayment.getCardToken()); + } + + @Test + void preservesPresentCardToken() { + String cardToken = "card-token"; + Context context = BeanUtil.createContext(); + context.getPayment().getPayment().getPayer().getPaymentResource() + .getResource().getPaymentTool().getBankCard().setToken(cardToken); + + FraudRequest fraudRequest = contextConverter.convert(context); + + assertEquals(cardToken, fraudRequest.getFraudModel().getCardToken()); + } +} diff --git a/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java b/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java index fad39c98..54202f93 100644 --- a/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java +++ b/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java @@ -6,6 +6,7 @@ import dev.vality.damsel.fraudbusters.SortOrder; import dev.vality.fraudbusters.constant.PaymentField; import dev.vality.fraudbusters.factory.TestObjectsFactory; +import dev.vality.fraudbusters.service.dto.FieldType; import dev.vality.fraudbusters.service.dto.FilterDto; import dev.vality.fraudbusters.service.dto.SearchFieldDto; import org.junit.jupiter.api.Test; @@ -93,7 +94,15 @@ void convert() { .filter(searchFieldDto -> searchFieldDto.getField().equals(PaymentField.LAST_DIGITS)) .map(SearchFieldDto::getValue) .anyMatch(value -> filter.getMaskedPan().equals(value))); + assertTrue(searchFields.stream() + .anyMatch(searchFieldDto -> searchFieldDto.getField().equals(PaymentField.CHECKED_TEMPLATE) + && searchFieldDto.getType().equals(FieldType.FRAUD_RESULT) + && filter.getTemplate().equals(searchFieldDto.getValue()))); + assertTrue(searchFields.stream() + .anyMatch(searchFieldDto -> searchFieldDto.getField().equals(PaymentField.CHECKED_RULE) + && searchFieldDto.getType().equals(FieldType.FRAUD_RESULT) + && filter.getRule().equals(searchFieldDto.getValue()))); assertEquals(sort.getField(), dto.getSort().getField()); assertEquals(sort.getOrder(), SortOrder.valueOf(dto.getSort().getOrder().name())); } -} \ No newline at end of file +} diff --git a/src/test/java/dev/vality/fraudbusters/factory/TestObjectsFactory.java b/src/test/java/dev/vality/fraudbusters/factory/TestObjectsFactory.java index b4b24ed4..3f5f80df 100644 --- a/src/test/java/dev/vality/fraudbusters/factory/TestObjectsFactory.java +++ b/src/test/java/dev/vality/fraudbusters/factory/TestObjectsFactory.java @@ -96,6 +96,8 @@ public static Filter testFilter() { filter.setPaymentId(id); filter.setMaskedPan(lastDigits); filter.setInvoiceId(invoiceId); + filter.setTemplate(randomString()); + filter.setRule(randomString()); TimestampInterval timestampInterval = new TimestampInterval(); TimestampIntervalBound lowerBound = new TimestampIntervalBound(); String lowerBoundTime = LocalDateTime.now().toString(); diff --git a/src/test/java/dev/vality/fraudbusters/fraud/payment/ManyEmailsPerCardRuleTest.java b/src/test/java/dev/vality/fraudbusters/fraud/payment/ManyEmailsPerCardRuleTest.java new file mode 100644 index 00000000..77552963 --- /dev/null +++ b/src/test/java/dev/vality/fraudbusters/fraud/payment/ManyEmailsPerCardRuleTest.java @@ -0,0 +1,203 @@ +package dev.vality.fraudbusters.fraud.payment; + +import dev.vality.fraudbusters.config.payment.PaymentFraudoConfig; +import dev.vality.fraudbusters.fraud.constant.PaymentCheckedField; +import dev.vality.fraudbusters.fraud.model.PaymentModel; +import dev.vality.fraudbusters.fraud.payment.aggregator.clickhouse.UniqueValueAggregatorImpl; +import dev.vality.fraudbusters.fraud.payment.resolver.DatabasePaymentFieldResolver; +import dev.vality.fraudbusters.fraud.payment.resolver.PaymentModelFieldResolver; +import dev.vality.fraudbusters.fraud.payment.resolver.PaymentTypeResolverImpl; +import dev.vality.fraudbusters.fraud.payment.validator.PaymentTemplateValidator; +import dev.vality.fraudbusters.repository.PaymentRepository; +import dev.vality.fraudbusters.service.TimeBoundaryServiceImpl; +import dev.vality.fraudo.aggregator.UniqueValueAggregator; +import dev.vality.fraudo.constant.ResultStatus; +import dev.vality.fraudo.finder.InListFinder; +import dev.vality.fraudo.model.ResultModel; +import dev.vality.fraudo.payment.aggregator.CountPaymentAggregator; +import dev.vality.fraudo.payment.aggregator.SumPaymentAggregator; +import dev.vality.fraudo.payment.resolver.CustomerTypeResolver; +import dev.vality.fraudo.payment.visitor.impl.FirstFindVisitorImpl; +import dev.vality.fraudo.resolver.CountryResolver; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Proxy; +import java.time.Instant; +import java.util.concurrent.atomic.AtomicReference; + +import static dev.vality.fraudbusters.constant.ClickhouseUtilsValue.UNKNOWN; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ManyEmailsPerCardRuleTest { + + private static final String CARD_TOKEN = "card-token"; + private static final String EMAIL = "test_af_as@test.com"; + private static final long TIMESTAMP = Instant.parse("2026-08-11T07:43:52Z").toEpochMilli(); + private static final String UNPARENTHESIZED_RULE = """ + rule: many_emails_per_card: + not in("card_token", "UNKNOWN") + and not in("email", "UNKNOWN") + and unique("card_token", "email", 24, hours) > 5 + -> decline; + """; + private static final String RULE = """ + rule: many_emails_per_card: + (not in("card_token", "UNKNOWN")) + and (not in("email", "UNKNOWN")) + and unique("card_token", "email", 24, hours) > 5 + -> decline; + """; + + @Test + void unparenthesizedNotNegatesTheRemainingExpressionAndSkipsUnique() { + RepositoryStub repository = new RepositoryStub(1); + + ResultModel result = applyRule(UNPARENTHESIZED_RULE, createPayment(CARD_TOKEN), repository); + + assertEquals(1, result.getRuleResults().size()); + assertEquals(ResultStatus.DECLINE, result.getRuleResults().get(0).getResultStatus()); + assertEquals("many_emails_per_card", result.getRuleResults().get(0).getRuleChecked()); + assertNull(repository.getAggregationFields()); + } + + @Test + void doesNotDeclineWhenFunctionResultIsTwo() { + RepositoryStub repository = new RepositoryStub(1); + + ResultModel result = applyRule(RULE, createPayment(CARD_TOKEN), repository); + + assertTrue(result.getRuleResults().isEmpty(), result.toString()); + assertArrayEquals( + new Object[]{"cardToken", CARD_TOKEN, "email"}, + repository.getAggregationFields() + ); + } + + @Test + void declinesWhenFunctionResultIsSix() { + RepositoryStub repository = new RepositoryStub(5); + + ResultModel result = applyRule(RULE, createPayment(CARD_TOKEN), repository); + + assertEquals(1, result.getRuleResults().size()); + assertEquals(ResultStatus.DECLINE, result.getRuleResults().get(0).getResultStatus()); + assertEquals("many_emails_per_card", result.getRuleResults().get(0).getRuleChecked()); + assertArrayEquals( + new Object[]{"cardToken", CARD_TOKEN, "email"}, + repository.getAggregationFields() + ); + } + + @Test + void doesNotQueryHistoryForUnknownCardToken() { + RepositoryStub repository = new RepositoryStub(100); + + ResultModel result = applyRule(RULE, createPayment(UNKNOWN), repository); + + assertTrue(result.getRuleResults().isEmpty()); + assertNull(repository.getAggregationFields()); + } + + @Test + void nullCardTokenProducesNotificationInsteadOfDecline() { + RepositoryStub repository = new RepositoryStub(100); + + ResultModel result = applyRule(RULE, createPayment(null), repository); + + assertEquals(1, result.getRuleResults().size()); + assertEquals(ResultStatus.NOTIFY, result.getRuleResults().get(0).getResultStatus()); + assertEquals("many_emails_per_card", result.getRuleResults().get(0).getRuleChecked()); + assertNull(repository.getAggregationFields()); + } + + private ResultModel applyRule(String rule, PaymentModel paymentModel, RepositoryStub repository) { + assertTrue(new PaymentTemplateValidator().validate(rule).isEmpty()); + FirstFindVisitorImpl visitor = createVisitor(repository.asRepository()); + return visitor.visit(new PaymentContextParserImpl().parse(rule), paymentModel); + } + + private FirstFindVisitorImpl createVisitor(PaymentRepository repository) { + DatabasePaymentFieldResolver databaseResolver = new DatabasePaymentFieldResolver(); + UniqueValueAggregator uniqueAggregator = + new UniqueValueAggregatorImpl(databaseResolver, repository, new TimeBoundaryServiceImpl()); + PaymentFraudoConfig config = new PaymentFraudoConfig(); + return config.paymentRuleVisitor( + unusedProxy(CountPaymentAggregator.class), + unusedProxy(SumPaymentAggregator.class), + uniqueAggregator, + unusedProxy(CountryResolver.class), + unusedProxy(InListFinder.class), + new PaymentModelFieldResolver(), + new PaymentTypeResolverImpl(), + unusedProxy(CustomerTypeResolver.class) + ); + } + + private PaymentModel createPayment(String cardToken) { + PaymentModel paymentModel = new PaymentModel(); + paymentModel.setCardToken(cardToken); + paymentModel.setEmail(EMAIL); + paymentModel.setTimestamp(TIMESTAMP); + return paymentModel; + } + + @SuppressWarnings("unchecked") + private T unusedProxy(Class type) { + return (T) Proxy.newProxyInstance( + type.getClassLoader(), + new Class[]{type}, + (proxy, method, args) -> defaultValue(method.getReturnType()) + ); + } + + private Object defaultValue(Class type) { + if (type == Boolean.class || type == boolean.class) { + return false; + } + if (type == Integer.class || type == int.class) { + return 0; + } + if (type == Long.class || type == long.class) { + return 0L; + } + if (type == Double.class || type == double.class) { + return 0D; + } + return null; + } + + private static final class RepositoryStub { + + private final int historicalCount; + private final AtomicReference aggregationArguments = new AtomicReference<>(); + + private RepositoryStub(int historicalCount) { + this.historicalCount = historicalCount; + } + + private PaymentRepository asRepository() { + return (PaymentRepository) Proxy.newProxyInstance( + PaymentRepository.class.getClassLoader(), + new Class[]{PaymentRepository.class}, + (proxy, method, args) -> { + if (method.getName().equals("uniqCountOperationWithGroupBy")) { + aggregationArguments.set(args); + return historicalCount; + } + return null; + } + ); + } + + private Object[] getAggregationFields() { + Object[] arguments = aggregationArguments.get(); + if (arguments == null) { + return null; + } + return new Object[]{arguments[0], arguments[1], arguments[2]}; + } + } +} diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java index d6ce7627..b2573b5d 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java @@ -102,6 +102,38 @@ void getFraudResultsByTimeSlotAndSearchPatterns() { assertEquals("partyId_2", fraudResults.get(0).getPartyId()); } + @Test + void getFraudResultsByEmailTemplateAndRule() { + FilterDto filter = new FilterDto(); + filter.setTimeFrom("2020-05-01T18:04:53"); + filter.setTimeTo("2020-10-01T18:04:53"); + filter.setSearchFields(Set.of( + SearchFieldDto.builder() + .field(PaymentField.EMAIL) + .type(FieldType.STRING) + .value("email_2") + .build(), + SearchFieldDto.builder() + .field(PaymentField.CHECKED_TEMPLATE) + .type(FieldType.FRAUD_RESULT) + .value("3DS_TEMPLATE") + .build(), + SearchFieldDto.builder() + .field(PaymentField.CHECKED_RULE) + .type(FieldType.FRAUD_RESULT) + .value("3DS_RULE") + .build() + )); + SortDto sortDto = new SortDto(); + sortDto.setOrder(SortOrder.DESC); + filter.setSort(sortDto); + + List fraudResults = fraudResultRepository.getByFilter(filter); + + assertEquals(1, fraudResults.size()); + assertEquals("1VMI3GwdR5s.1", fraudResults.get(0).getId()); + } + @Test void getFraudResultsByTimeSlotAndLimitSize() { FilterDto filter = new FilterDto(); @@ -168,4 +200,4 @@ public void initialize(ConfigurableApplicationContext configurableApplicationCon )); } } -} \ No newline at end of file +} diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java index e4a6387a..b6f49ffd 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java @@ -50,7 +50,8 @@ class HistoricalPaymentDataTest { @BeforeAll static void setUp() throws Exception { ChInitializer.initAllScripts(ClickHouseContainerExtension.CLICKHOUSE_CONTAINER, List.of( - "sql/data/insert_history_payments.sql" + "sql/data/insert_history_payments.sql", + "sql/data/insert_history_fraud_results.sql" )); } @@ -98,6 +99,38 @@ void getPaymentsByTimeSlotAndSearchPatterns() { assertEquals("partyId_2", payments.get(0).getPartyId()); } + @Test + void getPaymentsByEmailTemplateAndRule() { + FilterDto filter = new FilterDto(); + filter.setTimeFrom("2020-05-01T18:04:53"); + filter.setTimeTo("2020-10-01T18:04:53"); + filter.setSearchFields(Set.of( + SearchFieldDto.builder() + .field(PaymentField.EMAIL) + .type(FieldType.STRING) + .value("email_2") + .build(), + SearchFieldDto.builder() + .field(PaymentField.CHECKED_TEMPLATE) + .type(FieldType.FRAUD_RESULT) + .value("3DS_TEMPLATE") + .build(), + SearchFieldDto.builder() + .field(PaymentField.CHECKED_RULE) + .type(FieldType.FRAUD_RESULT) + .value("3DS_RULE") + .build() + )); + SortDto sortDto = new SortDto(); + sortDto.setOrder(SortOrder.DESC); + filter.setSort(sortDto); + + List payments = paymentRepository.getByFilter(filter); + + assertEquals(1, payments.size()); + assertEquals("1VMI3GwdR5s.1", payments.get(0).getId()); + } + @Test void getPaymentsByTimeSlotAndLimitSize() { FilterDto filter = new FilterDto(); diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java new file mode 100644 index 00000000..12d9be55 --- /dev/null +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java @@ -0,0 +1,68 @@ +package dev.vality.fraudbusters.repository.clickhouse.util; + +import dev.vality.fraudbusters.constant.PaymentField; +import dev.vality.fraudbusters.constant.SortOrder; +import dev.vality.fraudbusters.service.dto.FieldType; +import dev.vality.fraudbusters.service.dto.FilterDto; +import dev.vality.fraudbusters.service.dto.SearchFieldDto; +import dev.vality.fraudbusters.service.dto.SortDto; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class FilterUtilTest { + + @Test + void combinesEmailTemplateAndRuleFilters() { + FilterDto filter = new FilterDto(); + filter.setTimeFrom("2020-05-01T00:00:00"); + filter.setTimeTo("2020-05-31T23:59:59"); + SortDto sort = new SortDto(); + sort.setOrder(SortOrder.DESC); + filter.setSort(sort); + filter.setSearchFields(Set.of( + searchField(PaymentField.EMAIL, FieldType.STRING, "test@example.com"), + searchField(PaymentField.CHECKED_TEMPLATE, FieldType.FRAUD_RESULT, "shop-template"), + searchField(PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, "many_emails_per_card") + )); + + String sql = FilterUtil.appendFilters(filter); + + assertTrue(sql.contains("like(email,'test@example.com')")); + assertTrue(sql.contains("id in (select id from fraud.events_unique")); + assertTrue(sql.contains("checkedTemplate = :checkedTemplate")); + assertTrue(sql.contains("checkedRule = :checkedRule")); + assertEquals("shop-template", FilterUtil.initParams(filter).getValue("checkedTemplate")); + assertEquals("many_emails_per_card", FilterUtil.initParams(filter).getValue("checkedRule")); + } + + @Test + void appliesTemplateAndRuleDirectlyForFraudResults() { + FilterDto filter = new FilterDto(); + SortDto sort = new SortDto(); + sort.setOrder(SortOrder.DESC); + filter.setSort(sort); + filter.setSearchFields(Set.of( + searchField(PaymentField.CHECKED_TEMPLATE, FieldType.FRAUD_RESULT, "shop-template"), + searchField(PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, "many_emails_per_card") + )); + + String sql = FilterUtil.appendFraudResultFilters(filter); + + assertTrue(sql.contains("checkedTemplate = :checkedTemplate")); + assertTrue(sql.contains("checkedRule = :checkedRule")); + assertFalse(sql.contains("id in (select id")); + } + + private SearchFieldDto searchField(PaymentField field, FieldType type, String value) { + return SearchFieldDto.builder() + .field(field) + .type(type) + .value(value) + .build(); + } +} From 8e45af9c61ea88dfe0c0c520028c7ee46e54e177 Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 11:06:26 +0300 Subject: [PATCH 02/12] Fix tests --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad45f74b..22da5c32 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ UTF-8 1.0.9 0.3.1 - 1.128-79c32f2 + 1.134-b64531d 1.7-6d29f86 1.44-5dbd6d4 21.12.0 From 11d1c0d8bf4dcaef126765d005970b0db6fc278c Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 11:09:36 +0300 Subject: [PATCH 03/12] Add filter --- .../fraudbusters/constant/PaymentField.java | 2 + .../converter/FilterConverter.java | 6 +++ .../impl/FraudResultRepository.java | 2 +- .../clickhouse/util/FilterUtil.java | 53 +++++++++++++++++++ .../fraudbusters/service/dto/FieldType.java | 2 +- 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/constant/PaymentField.java b/src/main/java/dev/vality/fraudbusters/constant/PaymentField.java index 325d3601..df206886 100644 --- a/src/main/java/dev/vality/fraudbusters/constant/PaymentField.java +++ b/src/main/java/dev/vality/fraudbusters/constant/PaymentField.java @@ -32,6 +32,8 @@ public enum PaymentField { PAYMENT_ID("paymentId"), BIN("bin"), BANK_NAME("bankName"), + CHECKED_TEMPLATE("checkedTemplate"), + CHECKED_RULE("checkedRule"), MOBILE("mobile"), RECURRENT("recurrent"); diff --git a/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java b/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java index 135241b1..61320e23 100644 --- a/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java +++ b/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java @@ -75,6 +75,12 @@ private Set assembleSearchFields(Filter filter) { if (filter.isSetInvoiceId() && StringUtils.hasLength(filter.getInvoiceId())) { addSearchField(searchFields, PaymentField.INVOICE_ID, FieldType.STRING, filter.getInvoiceId()); } + if (filter.isSetTemplate() && StringUtils.hasLength(filter.getTemplate())) { + addSearchField(searchFields, PaymentField.CHECKED_TEMPLATE, FieldType.FRAUD_RESULT, filter.getTemplate()); + } + if (filter.isSetRule() && StringUtils.hasLength(filter.getRule())) { + addSearchField(searchFields, PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, filter.getRule()); + } return searchFields; } diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/impl/FraudResultRepository.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/impl/FraudResultRepository.java index 630089e0..62ab258a 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/impl/FraudResultRepository.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/impl/FraudResultRepository.java @@ -65,7 +65,7 @@ public void insertBatch(List events) { @Override public List getByFilter(FilterDto filter) { - String filters = FilterUtil.appendFilters(filter); + String filters = FilterUtil.appendFraudResultFilters(filter); String query = FraudResultQuery.SELECT_HISTORY_FRAUD_RESULT + filters; MapSqlParameterSource params = FilterUtil.initParams(filter); return namedParameterJdbcTemplate.query(query, params, eventMapper); diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java index 66e3d53b..40b21bba 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java @@ -1,6 +1,7 @@ package dev.vality.fraudbusters.repository.clickhouse.util; +import dev.vality.fraudbusters.constant.EventSource; import dev.vality.fraudbusters.constant.QueryParamName; import dev.vality.fraudbusters.service.dto.FieldType; import dev.vality.fraudbusters.service.dto.FilterDto; @@ -11,6 +12,7 @@ import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.util.CollectionUtils; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -18,11 +20,24 @@ public class FilterUtil { public static String appendFilters(FilterDto filter) { + return appendFilters(filter, false); + } + + public static String appendFraudResultFilters(FilterDto filter) { + return appendFilters(filter, true); + } + + private static String appendFilters(FilterDto filter, boolean directFraudResultSearch) { StringBuilder filters = new StringBuilder(); Set searchFields = filter.getSearchFields(); if (!CollectionUtils.isEmpty(searchFields)) { addLikeSearchFields(filters, searchFields); addEqualSearchFields(filters, searchFields); + if (directFraudResultSearch) { + addDirectFraudResultSearchFields(filters, searchFields); + } else { + addFraudResultSearchFields(filters, searchFields); + } } String sorting = String.format(" ORDER BY (eventTime, id) %s ", filter.getSort().getOrder().name()); String limit = " LIMIT :size "; @@ -57,6 +72,37 @@ private static void addEqualSearchFields(StringBuilder filters, Set searchFields) { + List fraudResultFields = searchFields.stream() + .filter(searchField -> searchField.getType().equals(FieldType.FRAUD_RESULT)) + .toList(); + if (fraudResultFields.isEmpty()) { + return; + } + filters.append(" and id in (select id from ") + .append(EventSource.FRAUD_EVENTS_UNIQUE.getTable()) + .append(" where timestamp >= toDate(:from)") + .append(" and timestamp <= toDate(:to)") + .append(" and toDateTime(eventTime) >= toDateTime(:from)") + .append(" and toDateTime(eventTime) <= toDateTime(:to)"); + fraudResultFields.forEach(searchField -> filters + .append(" and ") + .append(searchField.getField().getValue()) + .append(" = :") + .append(searchField.getField().getValue())); + filters.append(")"); + } + + private static void addDirectFraudResultSearchFields(StringBuilder filters, Set searchFields) { + searchFields.stream() + .filter(searchField -> searchField.getType().equals(FieldType.FRAUD_RESULT)) + .forEach(searchField -> filters + .append(" and ") + .append(searchField.getField().getValue()) + .append(" = :") + .append(searchField.getField().getValue())); + } + public static MapSqlParameterSource initParams(FilterDto filter) { MapSqlParameterSource params = new MapSqlParameterSource(); if (Objects.nonNull(filter.getLastId())) { @@ -70,6 +116,13 @@ private static MapSqlParameterSource addTimeParams(MapSqlParameterSource params, params.addValue(QueryParamName.FROM, filter.getTimeFrom()) .addValue(QueryParamName.TO, filter.getTimeTo()) .addValue(QueryParamName.SIZE, filter.getSize()); + if (!CollectionUtils.isEmpty(filter.getSearchFields())) { + filter.getSearchFields().stream() + .filter(searchField -> searchField.getType().equals(FieldType.FRAUD_RESULT)) + .forEach(searchField -> params.addValue( + searchField.getField().getValue(), + searchField.getValue())); + } return params; } diff --git a/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java b/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java index 85a0f4fd..c1c6f12c 100644 --- a/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java +++ b/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java @@ -2,5 +2,5 @@ public enum FieldType { - STRING, ENUM + STRING, ENUM, FRAUD_RESULT } From 4f8913f00a0109c398ab5f90c96dad3e927cc71f Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 11:12:12 +0300 Subject: [PATCH 04/12] Add filter --- .../repository/clickhouse/util/FilterUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java index 40b21bba..e297b4ad 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java @@ -23,10 +23,6 @@ public static String appendFilters(FilterDto filter) { return appendFilters(filter, false); } - public static String appendFraudResultFilters(FilterDto filter) { - return appendFilters(filter, true); - } - private static String appendFilters(FilterDto filter, boolean directFraudResultSearch) { StringBuilder filters = new StringBuilder(); Set searchFields = filter.getSearchFields(); @@ -48,6 +44,10 @@ private static String appendFilters(FilterDto filter, boolean directFraudResultS return filters.append(sorting).append(limit).toString(); } + public static String appendFraudResultFilters(FilterDto filter) { + return appendFilters(filter, true); + } + private static void addLikeSearchFields(StringBuilder filters, Set searchFields) { searchFields.stream() .filter(searchField -> searchField.getType().equals(FieldType.STRING)) From 0f74c7b42d1cd13c4d43f7c4fc628e45487a04a9 Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 16:47:42 +0300 Subject: [PATCH 05/12] Fix test --- .../fraud/payment/ManyEmailsPerCardRuleTest.java | 6 ++---- .../impl/HistoricalPaymentDataTest.java | 14 +++++++++----- .../data/insert_recent_payment_rule_filter.sql | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 src/test/resources/sql/data/insert_recent_payment_rule_filter.sql diff --git a/src/test/java/dev/vality/fraudbusters/fraud/payment/ManyEmailsPerCardRuleTest.java b/src/test/java/dev/vality/fraudbusters/fraud/payment/ManyEmailsPerCardRuleTest.java index 77552963..bdcd51ea 100644 --- a/src/test/java/dev/vality/fraudbusters/fraud/payment/ManyEmailsPerCardRuleTest.java +++ b/src/test/java/dev/vality/fraudbusters/fraud/payment/ManyEmailsPerCardRuleTest.java @@ -102,14 +102,12 @@ void doesNotQueryHistoryForUnknownCardToken() { } @Test - void nullCardTokenProducesNotificationInsteadOfDecline() { + void doesNotQueryHistoryForNullCardToken() { RepositoryStub repository = new RepositoryStub(100); ResultModel result = applyRule(RULE, createPayment(null), repository); - assertEquals(1, result.getRuleResults().size()); - assertEquals(ResultStatus.NOTIFY, result.getRuleResults().get(0).getResultStatus()); - assertEquals("many_emails_per_card", result.getRuleResults().get(0).getRuleChecked()); + assertTrue(result.getRuleResults().isEmpty()); assertNull(repository.getAggregationFields()); } diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java index b6f49ffd..e6068fbb 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java @@ -25,6 +25,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.testcontainers.junit.jupiter.Testcontainers; +import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -51,7 +53,8 @@ class HistoricalPaymentDataTest { static void setUp() throws Exception { ChInitializer.initAllScripts(ClickHouseContainerExtension.CLICKHOUSE_CONTAINER, List.of( "sql/data/insert_history_payments.sql", - "sql/data/insert_history_fraud_results.sql" + "sql/data/insert_history_fraud_results.sql", + "sql/data/insert_recent_payment_rule_filter.sql" )); } @@ -101,14 +104,15 @@ void getPaymentsByTimeSlotAndSearchPatterns() { @Test void getPaymentsByEmailTemplateAndRule() { + LocalDate today = LocalDate.now(ZoneOffset.UTC); FilterDto filter = new FilterDto(); - filter.setTimeFrom("2020-05-01T18:04:53"); - filter.setTimeTo("2020-10-01T18:04:53"); + filter.setTimeFrom(today.minusDays(1) + "T00:00:00"); + filter.setTimeTo(today.plusDays(1) + "T00:00:00"); filter.setSearchFields(Set.of( SearchFieldDto.builder() .field(PaymentField.EMAIL) .type(FieldType.STRING) - .value("email_2") + .value("rule_filter_email") .build(), SearchFieldDto.builder() .field(PaymentField.CHECKED_TEMPLATE) @@ -128,7 +132,7 @@ void getPaymentsByEmailTemplateAndRule() { List payments = paymentRepository.getByFilter(filter); assertEquals(1, payments.size()); - assertEquals("1VMI3GwdR5s.1", payments.get(0).getId()); + assertEquals("rule-filter-payment.1", payments.get(0).getId()); } @Test diff --git a/src/test/resources/sql/data/insert_recent_payment_rule_filter.sql b/src/test/resources/sql/data/insert_recent_payment_rule_filter.sql new file mode 100644 index 00000000..737828bb --- /dev/null +++ b/src/test/resources/sql/data/insert_recent_payment_rule_filter.sql @@ -0,0 +1,16 @@ +INSERT INTO fraud.payment +(timestamp, eventTime, eventTimeHour, partyId, shopId, email, fingerprint, amount, currency, status, errorReason, id, + ip, bin, lastDigits, paymentTool, cardToken, paymentSystem, terminal, providerId, bankCountry, errorCode, + tokenProvider) +VALUES (today(), toUInt64(toUnixTimestamp(now())), toUInt64(toUnixTimestamp(toStartOfHour(now()))) * 1000, + 'rule_filter_party', 'rule_filter_shop', 'rule_filter_email', 'rule_filter_fingerprint', + 50000, 'RUB', 'captured', '', 'rule-filter-payment.1', '127.0.0.1', '666', '3125', 'bank_card', + 'rule_filter_card_token', 'VISA', '123', '1', 'RUS', '', 'tprovider'); + +INSERT INTO fraud.events_unique +(timestamp, eventTime, eventTimeHour, partyId, shopId, email, fingerprint, amount, currency, mobile, id, paymentId, + ip, bin, lastDigits, cardToken, resultStatus, checkedRule, checkedTemplate, bankCountry, invoiceId, bankName) +VALUES (today(), toUInt64(toUnixTimestamp(now())), toUInt64(toUnixTimestamp(toStartOfHour(now()))) * 1000, + 'rule_filter_party', 'rule_filter_shop', 'rule_filter_email', 'rule_filter_fingerprint', + 50000, 'RUB', 0, 'rule-filter-payment.1', '1', '127.0.0.1', '666', '3125', + 'rule_filter_card_token', 'DECLINE', '3DS_RULE', '3DS_TEMPLATE', 'RUS', 'rule-filter-invoice', 'SBER'); From b8e5e4cfc57dc3b12f58a7024c71938a51a4c74c Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 17:17:20 +0300 Subject: [PATCH 06/12] Refactor --- .../impl/PaymentRepositoryImpl.java | 2 +- .../clickhouse/query/FraudResultQuery.java | 25 ++++++---- .../clickhouse/util/FilterUtil.java | 46 ++++++++++--------- .../clickhouse/util/FilterUtilTest.java | 25 +++++++++- 4 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/impl/PaymentRepositoryImpl.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/impl/PaymentRepositoryImpl.java index a332728c..b21e83b6 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/impl/PaymentRepositoryImpl.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/impl/PaymentRepositoryImpl.java @@ -58,7 +58,7 @@ public void insertBatch(List batch) { @Override public List getByFilter(FilterDto filter) { - String filters = FilterUtil.appendFilters(filter); + String filters = FilterUtil.appendPaymentFilters(filter); String query = PaymentQuery.SELECT_HISTORY_PAYMENT + filters; MapSqlParameterSource params = FilterUtil.initParams(filter); return namedParameterJdbcTemplate.query(query, params, checkedPaymentMapper); diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/query/FraudResultQuery.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/query/FraudResultQuery.java index be33f739..3fb74f23 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/query/FraudResultQuery.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/query/FraudResultQuery.java @@ -7,7 +7,20 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class FraudResultQuery { - public static final String SELECT_HISTORY_FRAUD_RESULT = String.format(""" + private static final String HISTORY_FRAUD_RESULT_SOURCE = String.format(""" + FROM + %s + WHERE + timestamp >= toDate(:from) + and timestamp <= toDate(:to) + and toDateTime(eventTime) >= toDateTime(:from) + and toDateTime(eventTime) <= toDateTime(:to) + and shopId != 'TEST'""", + EventSource.FRAUD_EVENTS_UNIQUE.getTable()); + + public static final String SELECT_HISTORY_FRAUD_RESULT_IDS = "SELECT id\n" + HISTORY_FRAUD_RESULT_SOURCE; + + public static final String SELECT_HISTORY_FRAUD_RESULT = """ SELECT eventTime, partyId, @@ -30,13 +43,5 @@ public class FraudResultQuery { checkedTemplate, mobile, recurrent - FROM - %s - WHERE - timestamp >= toDate(:from) - and timestamp <= toDate(:to) - and toDateTime(eventTime) >= toDateTime(:from) - and toDateTime(eventTime) <= toDateTime(:to) - and shopId != 'TEST'""", - EventSource.FRAUD_EVENTS_UNIQUE.getTable()); + """ + HISTORY_FRAUD_RESULT_SOURCE; } diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java index e297b4ad..6c36ac3b 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java @@ -1,8 +1,8 @@ package dev.vality.fraudbusters.repository.clickhouse.util; -import dev.vality.fraudbusters.constant.EventSource; import dev.vality.fraudbusters.constant.QueryParamName; +import dev.vality.fraudbusters.repository.clickhouse.query.FraudResultQuery; import dev.vality.fraudbusters.service.dto.FieldType; import dev.vality.fraudbusters.service.dto.FilterDto; import dev.vality.fraudbusters.service.dto.SearchFieldDto; @@ -20,19 +20,27 @@ public class FilterUtil { public static String appendFilters(FilterDto filter) { - return appendFilters(filter, false); + return appendFilters(filter, FraudResultFilterMode.NONE); } - private static String appendFilters(FilterDto filter, boolean directFraudResultSearch) { + public static String appendPaymentFilters(FilterDto filter) { + return appendFilters(filter, FraudResultFilterMode.PAYMENT_SUBQUERY); + } + + public static String appendFraudResultFilters(FilterDto filter) { + return appendFilters(filter, FraudResultFilterMode.DIRECT); + } + + private static String appendFilters(FilterDto filter, FraudResultFilterMode fraudResultFilterMode) { StringBuilder filters = new StringBuilder(); Set searchFields = filter.getSearchFields(); if (!CollectionUtils.isEmpty(searchFields)) { addLikeSearchFields(filters, searchFields); addEqualSearchFields(filters, searchFields); - if (directFraudResultSearch) { + if (fraudResultFilterMode == FraudResultFilterMode.DIRECT) { addDirectFraudResultSearchFields(filters, searchFields); - } else { - addFraudResultSearchFields(filters, searchFields); + } else if (fraudResultFilterMode == FraudResultFilterMode.PAYMENT_SUBQUERY) { + addPaymentFraudResultSearchFields(filters, searchFields); } } String sorting = String.format(" ORDER BY (eventTime, id) %s ", filter.getSort().getOrder().name()); @@ -44,10 +52,6 @@ private static String appendFilters(FilterDto filter, boolean directFraudResultS return filters.append(sorting).append(limit).toString(); } - public static String appendFraudResultFilters(FilterDto filter) { - return appendFilters(filter, true); - } - private static void addLikeSearchFields(StringBuilder filters, Set searchFields) { searchFields.stream() .filter(searchField -> searchField.getType().equals(FieldType.STRING)) @@ -72,24 +76,16 @@ private static void addEqualSearchFields(StringBuilder filters, Set searchFields) { + private static void addPaymentFraudResultSearchFields(StringBuilder filters, Set searchFields) { List fraudResultFields = searchFields.stream() .filter(searchField -> searchField.getType().equals(FieldType.FRAUD_RESULT)) .toList(); if (fraudResultFields.isEmpty()) { return; } - filters.append(" and id in (select id from ") - .append(EventSource.FRAUD_EVENTS_UNIQUE.getTable()) - .append(" where timestamp >= toDate(:from)") - .append(" and timestamp <= toDate(:to)") - .append(" and toDateTime(eventTime) >= toDateTime(:from)") - .append(" and toDateTime(eventTime) <= toDateTime(:to)"); - fraudResultFields.forEach(searchField -> filters - .append(" and ") - .append(searchField.getField().getValue()) - .append(" = :") - .append(searchField.getField().getValue())); + filters.append(" and id in (") + .append(FraudResultQuery.SELECT_HISTORY_FRAUD_RESULT_IDS); + addDirectFraudResultSearchFields(filters, searchFields); filters.append(")"); } @@ -126,4 +122,10 @@ private static MapSqlParameterSource addTimeParams(MapSqlParameterSource params, return params; } + private enum FraudResultFilterMode { + NONE, + PAYMENT_SUBQUERY, + DIRECT + } + } diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java index 12d9be55..352ba08c 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java @@ -30,10 +30,13 @@ void combinesEmailTemplateAndRuleFilters() { searchField(PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, "many_emails_per_card") )); - String sql = FilterUtil.appendFilters(filter); + String sql = FilterUtil.appendPaymentFilters(filter); assertTrue(sql.contains("like(email,'test@example.com')")); - assertTrue(sql.contains("id in (select id from fraud.events_unique")); + assertTrue(sql.contains("id in (")); + assertTrue(sql.contains("SELECT id")); + assertTrue(sql.contains("fraud.events_unique")); + assertTrue(sql.contains("shopId != 'TEST'")); assertTrue(sql.contains("checkedTemplate = :checkedTemplate")); assertTrue(sql.contains("checkedRule = :checkedRule")); assertEquals("shop-template", FilterUtil.initParams(filter).getValue("checkedTemplate")); @@ -58,6 +61,24 @@ void appliesTemplateAndRuleDirectlyForFraudResults() { assertFalse(sql.contains("id in (select id")); } + @Test + void doesNotApplyFraudResultFieldsToOtherHistoryQueries() { + FilterDto filter = new FilterDto(); + SortDto sort = new SortDto(); + sort.setOrder(SortOrder.DESC); + filter.setSort(sort); + filter.setSearchFields(Set.of( + searchField(PaymentField.CHECKED_TEMPLATE, FieldType.FRAUD_RESULT, "shop-template"), + searchField(PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, "many_emails_per_card") + )); + + String sql = FilterUtil.appendFilters(filter); + + assertFalse(sql.contains("checkedTemplate")); + assertFalse(sql.contains("checkedRule")); + assertFalse(sql.contains("id in (select id")); + } + private SearchFieldDto searchField(PaymentField field, FieldType type, String value) { return SearchFieldDto.builder() .field(field) From 97ececb55669b31f196dfecf53a5d60cdba805a6 Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 18:03:46 +0300 Subject: [PATCH 07/12] Refactor --- .../repository/clickhouse/util/FilterUtil.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java index 6c36ac3b..d72c4374 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java @@ -23,14 +23,6 @@ public static String appendFilters(FilterDto filter) { return appendFilters(filter, FraudResultFilterMode.NONE); } - public static String appendPaymentFilters(FilterDto filter) { - return appendFilters(filter, FraudResultFilterMode.PAYMENT_SUBQUERY); - } - - public static String appendFraudResultFilters(FilterDto filter) { - return appendFilters(filter, FraudResultFilterMode.DIRECT); - } - private static String appendFilters(FilterDto filter, FraudResultFilterMode fraudResultFilterMode) { StringBuilder filters = new StringBuilder(); Set searchFields = filter.getSearchFields(); @@ -52,6 +44,14 @@ private static String appendFilters(FilterDto filter, FraudResultFilterMode frau return filters.append(sorting).append(limit).toString(); } + public static String appendPaymentFilters(FilterDto filter) { + return appendFilters(filter, FraudResultFilterMode.PAYMENT_SUBQUERY); + } + + public static String appendFraudResultFilters(FilterDto filter) { + return appendFilters(filter, FraudResultFilterMode.DIRECT); + } + private static void addLikeSearchFields(StringBuilder filters, Set searchFields) { searchFields.stream() .filter(searchField -> searchField.getType().equals(FieldType.STRING)) From f8f0da411f6c7f57d726cca675584c9fc6ac7a8c Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 18:36:00 +0300 Subject: [PATCH 08/12] Refactor --- .../constant/FraudResultField.java | 2 +- .../fraudbusters/constant/PaymentField.java | 4 +--- .../converter/FilterConverter.java | 18 ++++++++++-------- .../repository/clickhouse/util/FilterUtil.java | 16 +++++++++------- .../fraudbusters/service/dto/FieldType.java | 2 +- .../service/dto/SearchFieldDto.java | 4 ++-- .../converter/FilterConverterTest.java | 9 +++++---- .../dgraph/DgraphAbstractIntegrationTest.java | 3 +-- .../DgraphCountPaymentsAggregatorTest.java | 2 -- .../DgraphSumPaymentsAggregatorTest.java | 2 -- .../aggregator/DgraphUniqueAggregatorTest.java | 2 -- .../AbstractDgraphQueryBuilderServiceTest.java | 2 ++ .../query/DgraphEntityResolverTest.java | 4 ++-- ...aphPaymentCountQueryBuilderServiceTest.java | 2 -- ...graphPaymentSumQueryBuilderServiceTest.java | 2 -- ...raphRefundCountQueryBuilderServiceTest.java | 2 -- ...DgraphRefundSumQueryBuilderServiceTest.java | 2 -- .../DgraphUniqueQueryBuilderServiceTest.java | 2 -- .../impl/HistoricalFraudResultDataTest.java | 9 +++++---- .../impl/HistoricalPaymentDataTest.java | 9 +++++---- .../clickhouse/util/FilterUtilTest.java | 16 +++++++++------- 21 files changed, 53 insertions(+), 61 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/constant/FraudResultField.java b/src/main/java/dev/vality/fraudbusters/constant/FraudResultField.java index b5021f83..b8f39c75 100644 --- a/src/main/java/dev/vality/fraudbusters/constant/FraudResultField.java +++ b/src/main/java/dev/vality/fraudbusters/constant/FraudResultField.java @@ -4,7 +4,7 @@ import lombok.Getter; @AllArgsConstructor -public enum FraudResultField { +public enum FraudResultField implements FilterField { RESULT_STATUS("resultStatus"), CHECKED_RULE("checkedRule"), diff --git a/src/main/java/dev/vality/fraudbusters/constant/PaymentField.java b/src/main/java/dev/vality/fraudbusters/constant/PaymentField.java index df206886..f49a0d2b 100644 --- a/src/main/java/dev/vality/fraudbusters/constant/PaymentField.java +++ b/src/main/java/dev/vality/fraudbusters/constant/PaymentField.java @@ -4,7 +4,7 @@ import lombok.Getter; @AllArgsConstructor -public enum PaymentField { +public enum PaymentField implements FilterField { EVENT_TIME("eventTime"), SHOP_ID("shopId"), @@ -32,8 +32,6 @@ public enum PaymentField { PAYMENT_ID("paymentId"), BIN("bin"), BANK_NAME("bankName"), - CHECKED_TEMPLATE("checkedTemplate"), - CHECKED_RULE("checkedRule"), MOBILE("mobile"), RECURRENT("recurrent"); diff --git a/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java b/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java index 61320e23..57bf704e 100644 --- a/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java +++ b/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java @@ -3,6 +3,8 @@ import dev.vality.damsel.fraudbusters.Filter; import dev.vality.damsel.fraudbusters.Page; import dev.vality.damsel.fraudbusters.Sort; +import dev.vality.fraudbusters.constant.FilterField; +import dev.vality.fraudbusters.constant.FraudResultField; import dev.vality.fraudbusters.constant.PaymentField; import dev.vality.fraudbusters.constant.SortOrder; import dev.vality.fraudbusters.service.dto.FieldType; @@ -76,23 +78,23 @@ private Set assembleSearchFields(Filter filter) { addSearchField(searchFields, PaymentField.INVOICE_ID, FieldType.STRING, filter.getInvoiceId()); } if (filter.isSetTemplate() && StringUtils.hasLength(filter.getTemplate())) { - addSearchField(searchFields, PaymentField.CHECKED_TEMPLATE, FieldType.FRAUD_RESULT, filter.getTemplate()); + addSearchField(searchFields, FraudResultField.CHECKED_TEMPLATE, FieldType.EXACT, filter.getTemplate()); } if (filter.isSetRule() && StringUtils.hasLength(filter.getRule())) { - addSearchField(searchFields, PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, filter.getRule()); + addSearchField(searchFields, FraudResultField.CHECKED_RULE, FieldType.EXACT, filter.getRule()); } return searchFields; } private void addSearchField(Set searchFields, - PaymentField cardToken, - FieldType string, - String filter) { + FilterField field, + FieldType type, + String filterValue) { searchFields.add( SearchFieldDto.builder() - .field(cardToken) - .type(string) - .value(filter) + .field(field) + .type(type) + .value(filterValue) .build() ); } diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java index d72c4374..b70fc394 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtil.java @@ -1,6 +1,8 @@ package dev.vality.fraudbusters.repository.clickhouse.util; +import dev.vality.fraudbusters.constant.FraudResultField; +import dev.vality.fraudbusters.constant.PaymentField; import dev.vality.fraudbusters.constant.QueryParamName; import dev.vality.fraudbusters.repository.clickhouse.query.FraudResultQuery; import dev.vality.fraudbusters.service.dto.FieldType; @@ -12,7 +14,6 @@ import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.util.CollectionUtils; -import java.util.List; import java.util.Objects; import java.util.Set; @@ -55,6 +56,7 @@ public static String appendFraudResultFilters(FilterDto filter) { private static void addLikeSearchFields(StringBuilder filters, Set searchFields) { searchFields.stream() .filter(searchField -> searchField.getType().equals(FieldType.STRING)) + .filter(searchField -> searchField.getField() instanceof PaymentField) .forEach(searchField -> filters .append(" and like(") @@ -67,6 +69,7 @@ private static void addLikeSearchFields(StringBuilder filters, Set searchFields) { searchFields.stream() .filter(searchField -> searchField.getType().equals(FieldType.ENUM)) + .filter(searchField -> searchField.getField() instanceof PaymentField) .forEach(searchField -> filters .append(" and ") @@ -77,10 +80,9 @@ private static void addEqualSearchFields(StringBuilder filters, Set searchFields) { - List fraudResultFields = searchFields.stream() - .filter(searchField -> searchField.getType().equals(FieldType.FRAUD_RESULT)) - .toList(); - if (fraudResultFields.isEmpty()) { + boolean containsFraudResultFields = searchFields.stream() + .anyMatch(searchField -> searchField.getField() instanceof FraudResultField); + if (!containsFraudResultFields) { return; } filters.append(" and id in (") @@ -91,7 +93,7 @@ private static void addPaymentFraudResultSearchFields(StringBuilder filters, Set private static void addDirectFraudResultSearchFields(StringBuilder filters, Set searchFields) { searchFields.stream() - .filter(searchField -> searchField.getType().equals(FieldType.FRAUD_RESULT)) + .filter(searchField -> searchField.getField() instanceof FraudResultField) .forEach(searchField -> filters .append(" and ") .append(searchField.getField().getValue()) @@ -114,7 +116,7 @@ private static MapSqlParameterSource addTimeParams(MapSqlParameterSource params, .addValue(QueryParamName.SIZE, filter.getSize()); if (!CollectionUtils.isEmpty(filter.getSearchFields())) { filter.getSearchFields().stream() - .filter(searchField -> searchField.getType().equals(FieldType.FRAUD_RESULT)) + .filter(searchField -> searchField.getField() instanceof FraudResultField) .forEach(searchField -> params.addValue( searchField.getField().getValue(), searchField.getValue())); diff --git a/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java b/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java index c1c6f12c..4701e92b 100644 --- a/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java +++ b/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java @@ -2,5 +2,5 @@ public enum FieldType { - STRING, ENUM, FRAUD_RESULT + STRING, ENUM, EXACT } diff --git a/src/main/java/dev/vality/fraudbusters/service/dto/SearchFieldDto.java b/src/main/java/dev/vality/fraudbusters/service/dto/SearchFieldDto.java index 3b22dcb2..c4a55687 100644 --- a/src/main/java/dev/vality/fraudbusters/service/dto/SearchFieldDto.java +++ b/src/main/java/dev/vality/fraudbusters/service/dto/SearchFieldDto.java @@ -1,6 +1,6 @@ package dev.vality.fraudbusters.service.dto; -import dev.vality.fraudbusters.constant.PaymentField; +import dev.vality.fraudbusters.constant.FilterField; import lombok.Builder; import lombok.Data; @@ -8,7 +8,7 @@ @Builder public class SearchFieldDto { - private PaymentField field; + private FilterField field; private FieldType type; private String value; } diff --git a/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java b/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java index 54202f93..6f5db4cf 100644 --- a/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java +++ b/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java @@ -4,6 +4,7 @@ import dev.vality.damsel.fraudbusters.Page; import dev.vality.damsel.fraudbusters.Sort; import dev.vality.damsel.fraudbusters.SortOrder; +import dev.vality.fraudbusters.constant.FraudResultField; import dev.vality.fraudbusters.constant.PaymentField; import dev.vality.fraudbusters.factory.TestObjectsFactory; import dev.vality.fraudbusters.service.dto.FieldType; @@ -95,12 +96,12 @@ void convert() { .map(SearchFieldDto::getValue) .anyMatch(value -> filter.getMaskedPan().equals(value))); assertTrue(searchFields.stream() - .anyMatch(searchFieldDto -> searchFieldDto.getField().equals(PaymentField.CHECKED_TEMPLATE) - && searchFieldDto.getType().equals(FieldType.FRAUD_RESULT) + .anyMatch(searchFieldDto -> searchFieldDto.getField().equals(FraudResultField.CHECKED_TEMPLATE) + && searchFieldDto.getType().equals(FieldType.EXACT) && filter.getTemplate().equals(searchFieldDto.getValue()))); assertTrue(searchFields.stream() - .anyMatch(searchFieldDto -> searchFieldDto.getField().equals(PaymentField.CHECKED_RULE) - && searchFieldDto.getType().equals(FieldType.FRAUD_RESULT) + .anyMatch(searchFieldDto -> searchFieldDto.getField().equals(FraudResultField.CHECKED_RULE) + && searchFieldDto.getType().equals(FieldType.EXACT) && filter.getRule().equals(searchFieldDto.getValue()))); assertEquals(sort.getField(), dto.getSort().getField()); assertEquals(sort.getOrder(), SortOrder.valueOf(dto.getSort().getOrder().name())); diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/DgraphAbstractIntegrationTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/DgraphAbstractIntegrationTest.java index ab1aa697..9e2ed026 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/DgraphAbstractIntegrationTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/DgraphAbstractIntegrationTest.java @@ -28,7 +28,6 @@ import org.apache.thrift.TBase; import org.awaitility.Awaitility; import org.awaitility.Durations; -import org.junit.Ignore; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.extension.ExtendWith; import org.rnorth.ducttape.unreliables.Unreliables; @@ -75,7 +74,7 @@ "dgraph.negotiationType=PLAINTEXT" }) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) -@Ignore +@DgraphDisabled public abstract class DgraphAbstractIntegrationTest { @Autowired diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphCountPaymentsAggregatorTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphCountPaymentsAggregatorTest.java index 5e7b4ba7..d2aa942f 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphCountPaymentsAggregatorTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphCountPaymentsAggregatorTest.java @@ -5,7 +5,6 @@ import dev.vality.fraudbusters.fraud.model.PaymentModel; import dev.vality.fraudo.payment.aggregator.CountPaymentAggregator; import lombok.extern.slf4j.Slf4j; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ActiveProfiles; @@ -15,7 +14,6 @@ import static dev.vality.fraudbusters.util.DgraphTestAggregationUtils.*; import static org.junit.jupiter.api.Assertions.assertEquals; -@Ignore @Slf4j @ActiveProfiles("full-prod") public class DgraphCountPaymentsAggregatorTest extends AbstractDgraphPaymentAggregatorTest { diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphSumPaymentsAggregatorTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphSumPaymentsAggregatorTest.java index e6a75737..a7887eba 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphSumPaymentsAggregatorTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphSumPaymentsAggregatorTest.java @@ -5,7 +5,6 @@ import dev.vality.fraudbusters.fraud.model.PaymentModel; import dev.vality.fraudo.payment.aggregator.SumPaymentAggregator; import lombok.extern.slf4j.Slf4j; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ActiveProfiles; @@ -15,7 +14,6 @@ import static dev.vality.fraudbusters.util.DgraphTestAggregationUtils.*; import static org.junit.jupiter.api.Assertions.assertEquals; -@Ignore @Slf4j @ActiveProfiles("full-prod") public class DgraphSumPaymentsAggregatorTest extends AbstractDgraphPaymentAggregatorTest { diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphUniqueAggregatorTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphUniqueAggregatorTest.java index 70af24aa..0f4c29bf 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphUniqueAggregatorTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/aggregator/DgraphUniqueAggregatorTest.java @@ -5,7 +5,6 @@ import dev.vality.fraudbusters.fraud.model.PaymentModel; import dev.vality.fraudo.aggregator.UniqueValueAggregator; import lombok.extern.slf4j.Slf4j; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ActiveProfiles; @@ -15,7 +14,6 @@ import static dev.vality.fraudbusters.util.DgraphTestAggregationUtils.*; import static org.junit.jupiter.api.Assertions.assertEquals; -@Ignore @Slf4j @ActiveProfiles("full-prod") public class DgraphUniqueAggregatorTest extends AbstractDgraphPaymentAggregatorTest { diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/AbstractDgraphQueryBuilderServiceTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/AbstractDgraphQueryBuilderServiceTest.java index 05a3f3b6..e51e4b19 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/AbstractDgraphQueryBuilderServiceTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/AbstractDgraphQueryBuilderServiceTest.java @@ -1,6 +1,7 @@ package dev.vality.fraudbusters.dgraph.service.query; import dev.vality.fraudbusters.config.dgraph.TemplateConfig; +import dev.vality.fraudbusters.dgraph.DgraphDisabled; import dev.vality.fraudbusters.fraud.payment.aggregator.dgraph.query.builder.DgraphCountQueryBuilderService; import dev.vality.fraudbusters.fraud.payment.aggregator.dgraph.query.builder.DgraphSumQueryBuilderService; import dev.vality.fraudbusters.fraud.payment.aggregator.dgraph.query.builder.DgraphUniqueQueryBuilderService; @@ -15,6 +16,7 @@ import dev.vality.fraudbusters.service.template.aggregate.unique.UniqueQueryTemplateService; import org.apache.velocity.app.VelocityEngine; +@DgraphDisabled public abstract class AbstractDgraphQueryBuilderServiceTest { private VelocityEngine velocityEngine = new TemplateConfig().velocityEngine(); diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphEntityResolverTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphEntityResolverTest.java index 91d937ac..4951c90e 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphEntityResolverTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphEntityResolverTest.java @@ -1,9 +1,9 @@ package dev.vality.fraudbusters.dgraph.service.query; +import dev.vality.fraudbusters.dgraph.DgraphDisabled; import dev.vality.fraudbusters.fraud.constant.DgraphEntity; import dev.vality.fraudbusters.fraud.constant.PaymentCheckedField; import dev.vality.fraudbusters.fraud.payment.resolver.DgraphEntityResolver; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import java.util.List; @@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -@Ignore +@DgraphDisabled public class DgraphEntityResolverTest { private DgraphEntityResolver dgraphEntityResolver = new DgraphEntityResolver(); diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphPaymentCountQueryBuilderServiceTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphPaymentCountQueryBuilderServiceTest.java index a5aabcb6..a4768ee9 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphPaymentCountQueryBuilderServiceTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphPaymentCountQueryBuilderServiceTest.java @@ -4,7 +4,6 @@ import dev.vality.fraudbusters.dgraph.service.data.DgraphPaymentCountQueryBuilderServiceTestData; import dev.vality.fraudbusters.fraud.constant.DgraphEntity; import dev.vality.fraudbusters.fraud.constant.PaymentCheckedField; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import java.time.Instant; @@ -15,7 +14,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -@Ignore public class DgraphPaymentCountQueryBuilderServiceTest extends AbstractDgraphQueryBuilderServiceTest { @Test diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphPaymentSumQueryBuilderServiceTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphPaymentSumQueryBuilderServiceTest.java index dbd2b247..6369bf95 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphPaymentSumQueryBuilderServiceTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphPaymentSumQueryBuilderServiceTest.java @@ -3,7 +3,6 @@ import dev.vality.fraudbusters.constant.PaymentStatus; import dev.vality.fraudbusters.fraud.constant.DgraphEntity; import dev.vality.fraudbusters.fraud.constant.PaymentCheckedField; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import java.time.Instant; @@ -15,7 +14,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -@Ignore public class DgraphPaymentSumQueryBuilderServiceTest extends AbstractDgraphQueryBuilderServiceTest { @Test diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphRefundCountQueryBuilderServiceTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphRefundCountQueryBuilderServiceTest.java index 9c63848e..842b6bf2 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphRefundCountQueryBuilderServiceTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphRefundCountQueryBuilderServiceTest.java @@ -3,7 +3,6 @@ import dev.vality.fraudbusters.constant.RefundStatus; import dev.vality.fraudbusters.fraud.constant.DgraphEntity; import dev.vality.fraudbusters.fraud.constant.PaymentCheckedField; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import java.time.Instant; @@ -15,7 +14,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -@Ignore public class DgraphRefundCountQueryBuilderServiceTest extends AbstractDgraphQueryBuilderServiceTest { @Test diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphRefundSumQueryBuilderServiceTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphRefundSumQueryBuilderServiceTest.java index 78661818..854dec61 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphRefundSumQueryBuilderServiceTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphRefundSumQueryBuilderServiceTest.java @@ -3,7 +3,6 @@ import dev.vality.fraudbusters.constant.RefundStatus; import dev.vality.fraudbusters.fraud.constant.DgraphEntity; import dev.vality.fraudbusters.fraud.constant.PaymentCheckedField; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import java.time.Instant; @@ -15,7 +14,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -@Ignore public class DgraphRefundSumQueryBuilderServiceTest extends AbstractDgraphQueryBuilderServiceTest { @Test diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphUniqueQueryBuilderServiceTest.java b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphUniqueQueryBuilderServiceTest.java index a14d5cf3..2c2032ac 100644 --- a/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphUniqueQueryBuilderServiceTest.java +++ b/src/test/java/dev/vality/fraudbusters/dgraph/service/query/DgraphUniqueQueryBuilderServiceTest.java @@ -3,7 +3,6 @@ import dev.vality.fraudbusters.constant.PaymentStatus; import dev.vality.fraudbusters.fraud.constant.DgraphEntity; import dev.vality.fraudbusters.fraud.constant.PaymentCheckedField; -import org.junit.Ignore; import org.junit.jupiter.api.Test; import java.time.Instant; @@ -16,7 +15,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -@Ignore public class DgraphUniqueQueryBuilderServiceTest extends AbstractDgraphQueryBuilderServiceTest { @Test diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java index b2573b5d..871b3610 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java @@ -3,6 +3,7 @@ import dev.vality.clickhouse.initializer.ChInitializer; import dev.vality.fraudbusters.config.TestClickhouseConfig; import dev.vality.fraudbusters.config.properties.ClickhouseProperties; +import dev.vality.fraudbusters.constant.FraudResultField; import dev.vality.fraudbusters.constant.PaymentField; import dev.vality.fraudbusters.constant.SortOrder; import dev.vality.fraudbusters.domain.Event; @@ -114,13 +115,13 @@ void getFraudResultsByEmailTemplateAndRule() { .value("email_2") .build(), SearchFieldDto.builder() - .field(PaymentField.CHECKED_TEMPLATE) - .type(FieldType.FRAUD_RESULT) + .field(FraudResultField.CHECKED_TEMPLATE) + .type(FieldType.EXACT) .value("3DS_TEMPLATE") .build(), SearchFieldDto.builder() - .field(PaymentField.CHECKED_RULE) - .type(FieldType.FRAUD_RESULT) + .field(FraudResultField.CHECKED_RULE) + .type(FieldType.EXACT) .value("3DS_RULE") .build() )); diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java index e6068fbb..de9d95f8 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java @@ -3,6 +3,7 @@ import dev.vality.clickhouse.initializer.ChInitializer; import dev.vality.fraudbusters.config.TestClickhouseConfig; import dev.vality.fraudbusters.config.properties.ClickhouseProperties; +import dev.vality.fraudbusters.constant.FraudResultField; import dev.vality.fraudbusters.constant.PaymentField; import dev.vality.fraudbusters.constant.SortOrder; import dev.vality.fraudbusters.domain.CheckedPayment; @@ -115,13 +116,13 @@ void getPaymentsByEmailTemplateAndRule() { .value("rule_filter_email") .build(), SearchFieldDto.builder() - .field(PaymentField.CHECKED_TEMPLATE) - .type(FieldType.FRAUD_RESULT) + .field(FraudResultField.CHECKED_TEMPLATE) + .type(FieldType.EXACT) .value("3DS_TEMPLATE") .build(), SearchFieldDto.builder() - .field(PaymentField.CHECKED_RULE) - .type(FieldType.FRAUD_RESULT) + .field(FraudResultField.CHECKED_RULE) + .type(FieldType.EXACT) .value("3DS_RULE") .build() )); diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java index 352ba08c..d999dd2f 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java @@ -1,5 +1,7 @@ package dev.vality.fraudbusters.repository.clickhouse.util; +import dev.vality.fraudbusters.constant.FilterField; +import dev.vality.fraudbusters.constant.FraudResultField; import dev.vality.fraudbusters.constant.PaymentField; import dev.vality.fraudbusters.constant.SortOrder; import dev.vality.fraudbusters.service.dto.FieldType; @@ -26,8 +28,8 @@ void combinesEmailTemplateAndRuleFilters() { filter.setSort(sort); filter.setSearchFields(Set.of( searchField(PaymentField.EMAIL, FieldType.STRING, "test@example.com"), - searchField(PaymentField.CHECKED_TEMPLATE, FieldType.FRAUD_RESULT, "shop-template"), - searchField(PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, "many_emails_per_card") + searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.EXACT, "shop-template"), + searchField(FraudResultField.CHECKED_RULE, FieldType.EXACT, "many_emails_per_card") )); String sql = FilterUtil.appendPaymentFilters(filter); @@ -50,8 +52,8 @@ void appliesTemplateAndRuleDirectlyForFraudResults() { sort.setOrder(SortOrder.DESC); filter.setSort(sort); filter.setSearchFields(Set.of( - searchField(PaymentField.CHECKED_TEMPLATE, FieldType.FRAUD_RESULT, "shop-template"), - searchField(PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, "many_emails_per_card") + searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.EXACT, "shop-template"), + searchField(FraudResultField.CHECKED_RULE, FieldType.EXACT, "many_emails_per_card") )); String sql = FilterUtil.appendFraudResultFilters(filter); @@ -68,8 +70,8 @@ void doesNotApplyFraudResultFieldsToOtherHistoryQueries() { sort.setOrder(SortOrder.DESC); filter.setSort(sort); filter.setSearchFields(Set.of( - searchField(PaymentField.CHECKED_TEMPLATE, FieldType.FRAUD_RESULT, "shop-template"), - searchField(PaymentField.CHECKED_RULE, FieldType.FRAUD_RESULT, "many_emails_per_card") + searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.EXACT, "shop-template"), + searchField(FraudResultField.CHECKED_RULE, FieldType.EXACT, "many_emails_per_card") )); String sql = FilterUtil.appendFilters(filter); @@ -79,7 +81,7 @@ void doesNotApplyFraudResultFieldsToOtherHistoryQueries() { assertFalse(sql.contains("id in (select id")); } - private SearchFieldDto searchField(PaymentField field, FieldType type, String value) { + private SearchFieldDto searchField(FilterField field, FieldType type, String value) { return SearchFieldDto.builder() .field(field) .type(type) From 47da038909b70fa66b2a5cc9681b8d5a07d4bd84 Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 18:37:24 +0300 Subject: [PATCH 09/12] Refactor --- .../repository/clickhouse/query/FraudResultQuery.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/query/FraudResultQuery.java b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/query/FraudResultQuery.java index 3fb74f23..d541404d 100644 --- a/src/main/java/dev/vality/fraudbusters/repository/clickhouse/query/FraudResultQuery.java +++ b/src/main/java/dev/vality/fraudbusters/repository/clickhouse/query/FraudResultQuery.java @@ -7,7 +7,7 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class FraudResultQuery { - private static final String HISTORY_FRAUD_RESULT_SOURCE = String.format(""" + private static final String FROM_WHERE_PARAMS_SOURCE = String.format(""" FROM %s WHERE @@ -18,7 +18,7 @@ and toDateTime(eventTime) <= toDateTime(:to) and shopId != 'TEST'""", EventSource.FRAUD_EVENTS_UNIQUE.getTable()); - public static final String SELECT_HISTORY_FRAUD_RESULT_IDS = "SELECT id\n" + HISTORY_FRAUD_RESULT_SOURCE; + public static final String SELECT_HISTORY_FRAUD_RESULT_IDS = "SELECT id\n" + FROM_WHERE_PARAMS_SOURCE; public static final String SELECT_HISTORY_FRAUD_RESULT = """ SELECT @@ -43,5 +43,5 @@ and toDateTime(eventTime) <= toDateTime(:to) checkedTemplate, mobile, recurrent - """ + HISTORY_FRAUD_RESULT_SOURCE; + """ + FROM_WHERE_PARAMS_SOURCE; } From f5c42991f21b4a80986df77e11065261efad13c7 Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 18:37:58 +0300 Subject: [PATCH 10/12] Refactor --- .../java/dev/vality/fraudbusters/constant/FilterField.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/dev/vality/fraudbusters/constant/FilterField.java diff --git a/src/main/java/dev/vality/fraudbusters/constant/FilterField.java b/src/main/java/dev/vality/fraudbusters/constant/FilterField.java new file mode 100644 index 00000000..bbe65515 --- /dev/null +++ b/src/main/java/dev/vality/fraudbusters/constant/FilterField.java @@ -0,0 +1,6 @@ +package dev.vality.fraudbusters.constant; + +public interface FilterField { + + String getValue(); +} From 6050a80119443418f025a9e8154f6571c864d1f4 Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 18:38:13 +0300 Subject: [PATCH 11/12] Refactor --- .../fraudbusters/dgraph/DgraphDisabled.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/java/dev/vality/fraudbusters/dgraph/DgraphDisabled.java diff --git a/src/test/java/dev/vality/fraudbusters/dgraph/DgraphDisabled.java b/src/test/java/dev/vality/fraudbusters/dgraph/DgraphDisabled.java new file mode 100644 index 00000000..4a5a6700 --- /dev/null +++ b/src/test/java/dev/vality/fraudbusters/dgraph/DgraphDisabled.java @@ -0,0 +1,16 @@ +package dev.vality.fraudbusters.dgraph; + +import org.junit.jupiter.api.Disabled; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Inherited +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Disabled("Dgraph is no longer used") +public @interface DgraphDisabled { +} From b85d9ed57561b97ff41ca36e94ca009370b8c2e5 Mon Sep 17 00:00:00 2001 From: stdevman91 Date: Thu, 20 Aug 2026 18:41:46 +0300 Subject: [PATCH 12/12] Refactor --- .../fraudbusters/converter/FilterConverter.java | 4 ++-- .../vality/fraudbusters/service/dto/FieldType.java | 2 +- .../fraudbusters/converter/FilterConverterTest.java | 4 ++-- .../impl/HistoricalFraudResultDataTest.java | 4 ++-- .../clickhouse/impl/HistoricalPaymentDataTest.java | 4 ++-- .../repository/clickhouse/util/FilterUtilTest.java | 12 ++++++------ 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java b/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java index 57bf704e..f9ebe35a 100644 --- a/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java +++ b/src/main/java/dev/vality/fraudbusters/converter/FilterConverter.java @@ -78,10 +78,10 @@ private Set assembleSearchFields(Filter filter) { addSearchField(searchFields, PaymentField.INVOICE_ID, FieldType.STRING, filter.getInvoiceId()); } if (filter.isSetTemplate() && StringUtils.hasLength(filter.getTemplate())) { - addSearchField(searchFields, FraudResultField.CHECKED_TEMPLATE, FieldType.EXACT, filter.getTemplate()); + addSearchField(searchFields, FraudResultField.CHECKED_TEMPLATE, FieldType.STRING, filter.getTemplate()); } if (filter.isSetRule() && StringUtils.hasLength(filter.getRule())) { - addSearchField(searchFields, FraudResultField.CHECKED_RULE, FieldType.EXACT, filter.getRule()); + addSearchField(searchFields, FraudResultField.CHECKED_RULE, FieldType.STRING, filter.getRule()); } return searchFields; } diff --git a/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java b/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java index 4701e92b..85a0f4fd 100644 --- a/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java +++ b/src/main/java/dev/vality/fraudbusters/service/dto/FieldType.java @@ -2,5 +2,5 @@ public enum FieldType { - STRING, ENUM, EXACT + STRING, ENUM } diff --git a/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java b/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java index 6f5db4cf..5e726cab 100644 --- a/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java +++ b/src/test/java/dev/vality/fraudbusters/converter/FilterConverterTest.java @@ -97,11 +97,11 @@ void convert() { .anyMatch(value -> filter.getMaskedPan().equals(value))); assertTrue(searchFields.stream() .anyMatch(searchFieldDto -> searchFieldDto.getField().equals(FraudResultField.CHECKED_TEMPLATE) - && searchFieldDto.getType().equals(FieldType.EXACT) + && searchFieldDto.getType().equals(FieldType.STRING) && filter.getTemplate().equals(searchFieldDto.getValue()))); assertTrue(searchFields.stream() .anyMatch(searchFieldDto -> searchFieldDto.getField().equals(FraudResultField.CHECKED_RULE) - && searchFieldDto.getType().equals(FieldType.EXACT) + && searchFieldDto.getType().equals(FieldType.STRING) && filter.getRule().equals(searchFieldDto.getValue()))); assertEquals(sort.getField(), dto.getSort().getField()); assertEquals(sort.getOrder(), SortOrder.valueOf(dto.getSort().getOrder().name())); diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java index 871b3610..caaf41dd 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalFraudResultDataTest.java @@ -116,12 +116,12 @@ void getFraudResultsByEmailTemplateAndRule() { .build(), SearchFieldDto.builder() .field(FraudResultField.CHECKED_TEMPLATE) - .type(FieldType.EXACT) + .type(FieldType.STRING) .value("3DS_TEMPLATE") .build(), SearchFieldDto.builder() .field(FraudResultField.CHECKED_RULE) - .type(FieldType.EXACT) + .type(FieldType.STRING) .value("3DS_RULE") .build() )); diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java index de9d95f8..93087ae8 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/impl/HistoricalPaymentDataTest.java @@ -117,12 +117,12 @@ void getPaymentsByEmailTemplateAndRule() { .build(), SearchFieldDto.builder() .field(FraudResultField.CHECKED_TEMPLATE) - .type(FieldType.EXACT) + .type(FieldType.STRING) .value("3DS_TEMPLATE") .build(), SearchFieldDto.builder() .field(FraudResultField.CHECKED_RULE) - .type(FieldType.EXACT) + .type(FieldType.STRING) .value("3DS_RULE") .build() )); diff --git a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java index d999dd2f..ef8f56cd 100644 --- a/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java +++ b/src/test/java/dev/vality/fraudbusters/repository/clickhouse/util/FilterUtilTest.java @@ -28,8 +28,8 @@ void combinesEmailTemplateAndRuleFilters() { filter.setSort(sort); filter.setSearchFields(Set.of( searchField(PaymentField.EMAIL, FieldType.STRING, "test@example.com"), - searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.EXACT, "shop-template"), - searchField(FraudResultField.CHECKED_RULE, FieldType.EXACT, "many_emails_per_card") + searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.STRING, "shop-template"), + searchField(FraudResultField.CHECKED_RULE, FieldType.STRING, "many_emails_per_card") )); String sql = FilterUtil.appendPaymentFilters(filter); @@ -52,8 +52,8 @@ void appliesTemplateAndRuleDirectlyForFraudResults() { sort.setOrder(SortOrder.DESC); filter.setSort(sort); filter.setSearchFields(Set.of( - searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.EXACT, "shop-template"), - searchField(FraudResultField.CHECKED_RULE, FieldType.EXACT, "many_emails_per_card") + searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.STRING, "shop-template"), + searchField(FraudResultField.CHECKED_RULE, FieldType.STRING, "many_emails_per_card") )); String sql = FilterUtil.appendFraudResultFilters(filter); @@ -70,8 +70,8 @@ void doesNotApplyFraudResultFieldsToOtherHistoryQueries() { sort.setOrder(SortOrder.DESC); filter.setSort(sort); filter.setSearchFields(Set.of( - searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.EXACT, "shop-template"), - searchField(FraudResultField.CHECKED_RULE, FieldType.EXACT, "many_emails_per_card") + searchField(FraudResultField.CHECKED_TEMPLATE, FieldType.STRING, "shop-template"), + searchField(FraudResultField.CHECKED_RULE, FieldType.STRING, "many_emails_per_card") )); String sql = FilterUtil.appendFilters(filter);