From d714889a6d1f4b70dcfb91b7684f78cd65613e58 Mon Sep 17 00:00:00 2001 From: Kostya Date: Wed, 30 Oct 2019 16:30:39 +0300 Subject: [PATCH] P2p change (#19) * Generalize interfaces * Add tests for p2p * Add currency function * Added naming lists * Change logic exception --- pom.xml | 2 +- src/main/antlr4/com.rbkmoney.fraudo/Fraudo.g4 | 10 ++ .../fraudo/aggregator/CountAggregator.java | 19 +-- .../fraudo/aggregator/SumAggregator.java | 19 +-- .../aggregator/UniqueValueAggregator.java | 9 +- .../fraudo/constant/P2PCheckedField.java | 36 ++++++ ...kedField.java => PaymentCheckedField.java} | 11 +- .../exception/NotValidContextException.java | 10 ++ .../factory/FastFraudVisitorFactory.java | 44 ++++--- .../fraudo/factory/FraudVisitorFactory.java | 22 ++-- .../rbkmoney/fraudo/finder/InListFinder.java | 13 +- .../com/rbkmoney/fraudo/model/BaseModel.java | 14 +++ .../rbkmoney/fraudo/model/GroupByModel.java | 15 --- .../com/rbkmoney/fraudo/model/P2PModel.java | 15 +++ .../java/com/rbkmoney/fraudo/model/Pair.java | 15 +++ .../{FraudModel.java => PaymentModel.java} | 10 +- .../fraudo/resolver/CountryResolver.java | 6 +- .../fraudo/resolver/FieldResolver.java | 35 ++---- .../fraudo/resolver/GroupByModelResolver.java | 17 +-- .../fraudo/resolver/GroupFieldsResolver.java | 11 ++ .../fraudo/resolver/TimeWindowResolver.java | 3 + .../resolver/p2p/P2PModelFieldResolver.java | 39 ++++++ .../payout/PaymentModelFieldResolver.java | 37 ++++++ .../key/generator/CommonKeyGenerator.java | 6 +- .../rbkmoney/fraudo/visitor/CountVisitor.java | 13 ++ .../fraudo/visitor/CountVisitorImpl.java | 41 ------- .../fraudo/visitor/CustomFuncVisitor.java | 15 +++ .../fraudo/visitor/CustomFuncVisitorImpl.java | 64 ---------- .../rbkmoney/fraudo/visitor/ListVisitor.java | 15 +++ .../fraudo/visitor/ListVisitorImpl.java | 52 -------- .../rbkmoney/fraudo/visitor/SumVisitor.java | 13 ++ .../fraudo/visitor/SumVisitorImpl.java | 41 ------- .../fraudo/visitor/impl/CountVisitorImpl.java | 54 +++++++++ .../visitor/impl/CustomFuncVisitorImpl.java | 65 ++++++++++ .../{ => impl}/FastFraudVisitorImpl.java | 114 +++++++++++++----- .../fraudo/visitor/impl/ListVisitorImpl.java | 57 +++++++++ .../fraudo/visitor/impl/SumVisitorImpl.java | 52 ++++++++ .../rbkmoney/fraudo/AbstractFraudoTest.java | 61 ---------- .../com/rbkmoney/fraudo/AbstractP2PTest.java | 68 +++++++++++ .../rbkmoney/fraudo/AbstractPaymentTest.java | 68 +++++++++++ .../java/com/rbkmoney/fraudo/CountTest.java | 4 +- .../java/com/rbkmoney/fraudo/CustomTest.java | 19 +-- .../java/com/rbkmoney/fraudo/ListTest.java | 19 ++- .../java/com/rbkmoney/fraudo/P2PTest.java | 101 ++++++++++++++++ .../com/rbkmoney/fraudo/RealTimerTest.java | 71 +++-------- .../java/com/rbkmoney/fraudo/SumTest.java | 4 +- src/test/resources/logback-test.xml | 10 ++ src/test/resources/rules/amount.frd | 2 +- src/test/resources/rules/namingList.frd | 2 + src/test/resources/rules/p2p_template.frd | 12 ++ ...real_template.frd => payment_template.frd} | 0 51 files changed, 965 insertions(+), 490 deletions(-) create mode 100644 src/main/java/com/rbkmoney/fraudo/constant/P2PCheckedField.java rename src/main/java/com/rbkmoney/fraudo/constant/{CheckedField.java => PaymentCheckedField.java} (61%) create mode 100644 src/main/java/com/rbkmoney/fraudo/exception/NotValidContextException.java create mode 100644 src/main/java/com/rbkmoney/fraudo/model/BaseModel.java delete mode 100644 src/main/java/com/rbkmoney/fraudo/model/GroupByModel.java create mode 100644 src/main/java/com/rbkmoney/fraudo/model/P2PModel.java create mode 100644 src/main/java/com/rbkmoney/fraudo/model/Pair.java rename src/main/java/com/rbkmoney/fraudo/model/{FraudModel.java => PaymentModel.java} (58%) create mode 100644 src/main/java/com/rbkmoney/fraudo/resolver/GroupFieldsResolver.java create mode 100644 src/main/java/com/rbkmoney/fraudo/resolver/p2p/P2PModelFieldResolver.java create mode 100644 src/main/java/com/rbkmoney/fraudo/resolver/payout/PaymentModelFieldResolver.java create mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/CountVisitor.java delete mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/CountVisitorImpl.java create mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/CustomFuncVisitor.java delete mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/CustomFuncVisitorImpl.java create mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/ListVisitor.java delete mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/ListVisitorImpl.java create mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/SumVisitor.java delete mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/SumVisitorImpl.java create mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/impl/CountVisitorImpl.java create mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/impl/CustomFuncVisitorImpl.java rename src/main/java/com/rbkmoney/fraudo/visitor/{ => impl}/FastFraudVisitorImpl.java (61%) create mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/impl/ListVisitorImpl.java create mode 100644 src/main/java/com/rbkmoney/fraudo/visitor/impl/SumVisitorImpl.java delete mode 100644 src/test/java/com/rbkmoney/fraudo/AbstractFraudoTest.java create mode 100644 src/test/java/com/rbkmoney/fraudo/AbstractP2PTest.java create mode 100644 src/test/java/com/rbkmoney/fraudo/AbstractPaymentTest.java create mode 100644 src/test/java/com/rbkmoney/fraudo/P2PTest.java create mode 100755 src/test/resources/logback-test.xml create mode 100644 src/test/resources/rules/namingList.frd create mode 100644 src/test/resources/rules/p2p_template.frd rename src/test/resources/rules/{real_template.frd => payment_template.frd} (100%) diff --git a/pom.xml b/pom.xml index a5ae018..c70446b 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ fraudo - 0.0.8-SNAPSHOT + 0.0.9-SNAPSHOT 2.0.0.0 diff --git a/src/main/antlr4/com.rbkmoney.fraudo/Fraudo.g4 b/src/main/antlr4/com.rbkmoney.fraudo/Fraudo.g4 index abc665e..adca360 100644 --- a/src/main/antlr4/com.rbkmoney.fraudo/Fraudo.g4 +++ b/src/main/antlr4/com.rbkmoney.fraudo/Fraudo.g4 @@ -25,10 +25,12 @@ expression | in_white_list #inWhiteListExpression | in_black_list #inBlackListExpression | in_grey_list #inGreyListExpression + | in_list #inListExpression | like #likeFunctionExpression | country #countryFunctionExpression | country_by #countryByFunctionExpression | amount #amountFunctionExpression + | currency #currencyFunctionExpression | IDENTIFIER #identifierExpression | DECIMAL #decimalExpression | STRING #stringExpression @@ -50,6 +52,10 @@ amount : 'amount' LPAREN RPAREN ; +currency + : 'currency' LPAREN RPAREN + ; + count : 'count' LPAREN STRING time_window (group_by)? RPAREN ; @@ -94,6 +100,10 @@ in_grey_list : 'inGreyList' LPAREN string_list RPAREN ; +in_list + : 'inList' LPAREN STRING DELIMETER string_list RPAREN + ; + like : 'like' LPAREN STRING DELIMETER STRING RPAREN ; diff --git a/src/main/java/com/rbkmoney/fraudo/aggregator/CountAggregator.java b/src/main/java/com/rbkmoney/fraudo/aggregator/CountAggregator.java index 2d9b7ee..acac36c 100644 --- a/src/main/java/com/rbkmoney/fraudo/aggregator/CountAggregator.java +++ b/src/main/java/com/rbkmoney/fraudo/aggregator/CountAggregator.java @@ -1,26 +1,15 @@ package com.rbkmoney.fraudo.aggregator; -import com.rbkmoney.fraudo.constant.CheckedField; -import com.rbkmoney.fraudo.model.FraudModel; import com.rbkmoney.fraudo.model.TimeWindow; import java.util.List; -public interface CountAggregator { +public interface CountAggregator { - @Deprecated - Integer count(CheckedField checkedField, FraudModel model, Long timeInMinutes); + Integer count(U checkedField, T model, TimeWindow timeWindow, List fields); - Integer count(CheckedField checkedField, FraudModel model, TimeWindow timeWindow, List fields); + Integer countSuccess(U checkedField, T model, TimeWindow timeWindow, List fields); - @Deprecated - Integer countSuccess(CheckedField checkedField, FraudModel model, Long timeInMinutes); - - Integer countSuccess(CheckedField checkedField, FraudModel model, TimeWindow timeWindow, List fields); - - @Deprecated - Integer countError(CheckedField checkedField, FraudModel model, Long timeInMinutes, String errorCode); - - Integer countError(CheckedField checkedField, FraudModel model, TimeWindow timeWindow, String errorCode, List fields); + Integer countError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List fields); } diff --git a/src/main/java/com/rbkmoney/fraudo/aggregator/SumAggregator.java b/src/main/java/com/rbkmoney/fraudo/aggregator/SumAggregator.java index 563843a..d3d6a08 100644 --- a/src/main/java/com/rbkmoney/fraudo/aggregator/SumAggregator.java +++ b/src/main/java/com/rbkmoney/fraudo/aggregator/SumAggregator.java @@ -1,26 +1,15 @@ package com.rbkmoney.fraudo.aggregator; -import com.rbkmoney.fraudo.constant.CheckedField; -import com.rbkmoney.fraudo.model.FraudModel; import com.rbkmoney.fraudo.model.TimeWindow; import java.util.List; -public interface SumAggregator { +public interface SumAggregator { - @Deprecated - Double sum(CheckedField checkedField, FraudModel model, Long timeInMinutes); + Double sum(U checkedField, T model, TimeWindow timeWindow, List fields); - Double sum(CheckedField checkedField, FraudModel model, TimeWindow timeWindow, List fields); + Double sumSuccess(U checkedField, T model, TimeWindow timeWindow, List fields); - @Deprecated - Double sumSuccess(CheckedField checkedField, FraudModel model, Long timeInMinutes); - - Double sumSuccess(CheckedField checkedField, FraudModel model, TimeWindow timeWindow, List fields); - - @Deprecated - Double sumError(CheckedField checkedField, FraudModel model, Long timeInMinutes, String errorCode); - - Double sumError(CheckedField checkedField, FraudModel model, TimeWindow timeWindow, String errorCode, List fields); + Double sumError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List fields); } diff --git a/src/main/java/com/rbkmoney/fraudo/aggregator/UniqueValueAggregator.java b/src/main/java/com/rbkmoney/fraudo/aggregator/UniqueValueAggregator.java index c3f076f..c25feb7 100644 --- a/src/main/java/com/rbkmoney/fraudo/aggregator/UniqueValueAggregator.java +++ b/src/main/java/com/rbkmoney/fraudo/aggregator/UniqueValueAggregator.java @@ -1,16 +1,11 @@ package com.rbkmoney.fraudo.aggregator; -import com.rbkmoney.fraudo.constant.CheckedField; -import com.rbkmoney.fraudo.model.FraudModel; import com.rbkmoney.fraudo.model.TimeWindow; import java.util.List; -public interface UniqueValueAggregator { +public interface UniqueValueAggregator { - @Deprecated - Integer countUniqueValue(CheckedField countField, FraudModel fraudModel, CheckedField onField, Long time); - - Integer countUniqueValue(CheckedField countField, FraudModel fraudModel, CheckedField onField, TimeWindow timeWindow, List fields); + Integer countUniqueValue(U countField, T payoutModel, U onField, TimeWindow timeWindow, List fields); } diff --git a/src/main/java/com/rbkmoney/fraudo/constant/P2PCheckedField.java b/src/main/java/com/rbkmoney/fraudo/constant/P2PCheckedField.java new file mode 100644 index 0000000..7351e16 --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/constant/P2PCheckedField.java @@ -0,0 +1,36 @@ +package com.rbkmoney.fraudo.constant; + +import java.util.HashMap; +import java.util.Map; + +public enum P2PCheckedField { + + EMAIL("email"), + IP("ip"), + FINGERPRINT("fingerprint"), + COUNTRY_BANK("country_bank"), + BIN("bin"), + PAN("pan"), + CURRENCY("currency"), + IDENTITY_ID("identity_id"), + CARD_TOKEN_FROM("card_token_from"), + CARD_TOKEN_TO("card_token_to"); + + private String value; + private static Map valueMap = new HashMap<>(); + + static { + for (P2PCheckedField value : P2PCheckedField.values()) { + valueMap.put(value.value, value); + } + } + + P2PCheckedField(String value) { + this.value = value; + } + + public static P2PCheckedField getByValue(String value) { + return valueMap.get(value); + } + +} diff --git a/src/main/java/com/rbkmoney/fraudo/constant/CheckedField.java b/src/main/java/com/rbkmoney/fraudo/constant/PaymentCheckedField.java similarity index 61% rename from src/main/java/com/rbkmoney/fraudo/constant/CheckedField.java rename to src/main/java/com/rbkmoney/fraudo/constant/PaymentCheckedField.java index 836736d..af97649 100644 --- a/src/main/java/com/rbkmoney/fraudo/constant/CheckedField.java +++ b/src/main/java/com/rbkmoney/fraudo/constant/PaymentCheckedField.java @@ -3,7 +3,7 @@ package com.rbkmoney.fraudo.constant; import java.util.HashMap; import java.util.Map; -public enum CheckedField { +public enum PaymentCheckedField { EMAIL("email"), IP("ip"), @@ -12,24 +12,25 @@ public enum CheckedField { COUNTRY_IP("country_ip"), BIN("bin"), PAN("pan"), + CURRENCY("currency"), SHOP_ID("shop_id"), PARTY_ID("party_id"), CARD_TOKEN("card_token"); private String value; - private static Map valueMap = new HashMap<>(); + private static Map valueMap = new HashMap<>(); static { - for (CheckedField value : CheckedField.values()) { + for (PaymentCheckedField value : PaymentCheckedField.values()) { valueMap.put(value.value, value); } } - CheckedField(String value) { + PaymentCheckedField(String value) { this.value = value; } - public static CheckedField getByValue(String value) { + public static PaymentCheckedField getByValue(String value) { return valueMap.get(value); } diff --git a/src/main/java/com/rbkmoney/fraudo/exception/NotValidContextException.java b/src/main/java/com/rbkmoney/fraudo/exception/NotValidContextException.java new file mode 100644 index 0000000..244e996 --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/exception/NotValidContextException.java @@ -0,0 +1,10 @@ +package com.rbkmoney.fraudo.exception; + +public class NotValidContextException extends RuntimeException { + + private static final String ERROR_MESSAGE = "Context is not valid!"; + + public NotValidContextException() { + super(ERROR_MESSAGE); + } +} diff --git a/src/main/java/com/rbkmoney/fraudo/factory/FastFraudVisitorFactory.java b/src/main/java/com/rbkmoney/fraudo/factory/FastFraudVisitorFactory.java index f8250fd..87108ac 100644 --- a/src/main/java/com/rbkmoney/fraudo/factory/FastFraudVisitorFactory.java +++ b/src/main/java/com/rbkmoney/fraudo/factory/FastFraudVisitorFactory.java @@ -1,29 +1,39 @@ package com.rbkmoney.fraudo.factory; -import com.rbkmoney.fraudo.FraudoVisitor; import com.rbkmoney.fraudo.aggregator.CountAggregator; import com.rbkmoney.fraudo.aggregator.SumAggregator; import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; import com.rbkmoney.fraudo.finder.InListFinder; -import com.rbkmoney.fraudo.model.FraudModel; +import com.rbkmoney.fraudo.model.BaseModel; import com.rbkmoney.fraudo.resolver.CountryResolver; -import com.rbkmoney.fraudo.visitor.*; +import com.rbkmoney.fraudo.resolver.FieldResolver; +import com.rbkmoney.fraudo.resolver.GroupByModelResolver; +import com.rbkmoney.fraudo.visitor.CountVisitor; +import com.rbkmoney.fraudo.visitor.CustomFuncVisitor; +import com.rbkmoney.fraudo.visitor.ListVisitor; +import com.rbkmoney.fraudo.visitor.SumVisitor; +import com.rbkmoney.fraudo.visitor.impl.*; -public class FastFraudVisitorFactory implements FraudVisitorFactory { +public class FastFraudVisitorFactory implements FraudVisitorFactory { @Override - public FraudoVisitor createVisitor(FraudModel model, - CountAggregator countAggregator, - SumAggregator sumAggregator, - UniqueValueAggregator uniqueValueAggregator, - CountryResolver countryResolver, - InListFinder blackListFinder, - InListFinder whiteListFinder, - InListFinder greyListFinder) { - CountVisitorImpl countVisitor = new CountVisitorImpl(model, countAggregator); - SumVisitorImpl sumVisitor = new SumVisitorImpl(model, sumAggregator); - ListVisitorImpl listVisitor = new ListVisitorImpl(model, blackListFinder, whiteListFinder, greyListFinder); - CustomFuncVisitorImpl customFuncVisitor = new CustomFuncVisitorImpl(model, uniqueValueAggregator, countryResolver); - return new FastFraudVisitorImpl(countVisitor, sumVisitor, listVisitor, customFuncVisitor); + public FastFraudVisitorImpl createVisitor( + CountAggregator countAggregator, + SumAggregator sumAggregator, + UniqueValueAggregator uniqueValueAggregator, + CountryResolver countryResolver, + InListFinder listFinder, + FieldResolver fieldResolver, + GroupByModelResolver groupByModelResolver) { + CountVisitor countVisitor = new CountVisitorImpl<>(countAggregator, fieldResolver, groupByModelResolver); + SumVisitor sumVisitor = new SumVisitorImpl<>(sumAggregator, fieldResolver, groupByModelResolver); + ListVisitor listVisitor = new ListVisitorImpl<>(listFinder, fieldResolver); + CustomFuncVisitor customFuncVisitor = new CustomFuncVisitorImpl<>( + uniqueValueAggregator, + countryResolver, + fieldResolver, + groupByModelResolver); + return new FastFraudVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor); } + } diff --git a/src/main/java/com/rbkmoney/fraudo/factory/FraudVisitorFactory.java b/src/main/java/com/rbkmoney/fraudo/factory/FraudVisitorFactory.java index a1e740d..662cf9b 100644 --- a/src/main/java/com/rbkmoney/fraudo/factory/FraudVisitorFactory.java +++ b/src/main/java/com/rbkmoney/fraudo/factory/FraudVisitorFactory.java @@ -1,22 +1,22 @@ package com.rbkmoney.fraudo.factory; -import com.rbkmoney.fraudo.FraudoVisitor; import com.rbkmoney.fraudo.aggregator.CountAggregator; import com.rbkmoney.fraudo.aggregator.SumAggregator; import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; import com.rbkmoney.fraudo.finder.InListFinder; -import com.rbkmoney.fraudo.model.FraudModel; import com.rbkmoney.fraudo.resolver.CountryResolver; +import com.rbkmoney.fraudo.resolver.FieldResolver; +import com.rbkmoney.fraudo.resolver.GroupByModelResolver; +import com.rbkmoney.fraudo.visitor.impl.FastFraudVisitorImpl; -public interface FraudVisitorFactory { +public interface FraudVisitorFactory { - FraudoVisitor createVisitor(FraudModel model, - CountAggregator countAggregator, - SumAggregator sumAggregator, - UniqueValueAggregator uniqueValueAggregator, - CountryResolver countryResolver, - InListFinder blackListFinder, - InListFinder whiteListFinder, - InListFinder greyListFinder); + FastFraudVisitorImpl createVisitor(CountAggregator countAggregator, + SumAggregator sumAggregator, + UniqueValueAggregator uniqueValueAggregator, + CountryResolver countryResolver, + InListFinder listFinder, + FieldResolver fieldPairResolver, + GroupByModelResolver groupByModelResolver); } diff --git a/src/main/java/com/rbkmoney/fraudo/finder/InListFinder.java b/src/main/java/com/rbkmoney/fraudo/finder/InListFinder.java index b03f54d..693aac5 100644 --- a/src/main/java/com/rbkmoney/fraudo/finder/InListFinder.java +++ b/src/main/java/com/rbkmoney/fraudo/finder/InListFinder.java @@ -1,13 +1,18 @@ package com.rbkmoney.fraudo.finder; -import com.rbkmoney.fraudo.constant.CheckedField; + +import com.rbkmoney.fraudo.model.Pair; import java.util.List; -public interface InListFinder { +public interface InListFinder { - Boolean findInList(String partyId, String shopId, CheckedField field, String value); + Boolean findInBlackList(List> fields, T model); - Boolean findInList(String partyId, String shopId, List fields, List value); + Boolean findInWhiteList(List> fields, T model); + + Boolean findInGreyList(List> fields, T model); + + Boolean findInList(String name, List> fields, T model); } diff --git a/src/main/java/com/rbkmoney/fraudo/model/BaseModel.java b/src/main/java/com/rbkmoney/fraudo/model/BaseModel.java new file mode 100644 index 0000000..a346a82 --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/model/BaseModel.java @@ -0,0 +1,14 @@ +package com.rbkmoney.fraudo.model; + +import lombok.Data; + +@Data +public class BaseModel { + + private String ip; + private String email; + private String fingerprint; + private Long amount; + private String currency; + +} diff --git a/src/main/java/com/rbkmoney/fraudo/model/GroupByModel.java b/src/main/java/com/rbkmoney/fraudo/model/GroupByModel.java deleted file mode 100644 index 3f5ff15..0000000 --- a/src/main/java/com/rbkmoney/fraudo/model/GroupByModel.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.rbkmoney.fraudo.model; - -import com.rbkmoney.fraudo.constant.CheckedField; -import lombok.Builder; -import lombok.Data; - -import java.util.List; - -@Data -@Builder -public class GroupByModel { - - private List checkedFields; - -} diff --git a/src/main/java/com/rbkmoney/fraudo/model/P2PModel.java b/src/main/java/com/rbkmoney/fraudo/model/P2PModel.java new file mode 100644 index 0000000..e71d3a4 --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/model/P2PModel.java @@ -0,0 +1,15 @@ +package com.rbkmoney.fraudo.model; + +import lombok.Data; + +@Data +public class P2PModel extends BaseModel { + + private String bin; + private String pan; + private String country; + private String cardTokenFrom; + private String cardTokenTo; + private String identityId; + +} diff --git a/src/main/java/com/rbkmoney/fraudo/model/Pair.java b/src/main/java/com/rbkmoney/fraudo/model/Pair.java new file mode 100644 index 0000000..b6432cc --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/model/Pair.java @@ -0,0 +1,15 @@ +package com.rbkmoney.fraudo.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Pair { + + private T first; + private U second; + +} diff --git a/src/main/java/com/rbkmoney/fraudo/model/FraudModel.java b/src/main/java/com/rbkmoney/fraudo/model/PaymentModel.java similarity index 58% rename from src/main/java/com/rbkmoney/fraudo/model/FraudModel.java rename to src/main/java/com/rbkmoney/fraudo/model/PaymentModel.java index f0d76c1..d481cef 100644 --- a/src/main/java/com/rbkmoney/fraudo/model/FraudModel.java +++ b/src/main/java/com/rbkmoney/fraudo/model/PaymentModel.java @@ -1,19 +1,19 @@ package com.rbkmoney.fraudo.model; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; @Data -public class FraudModel { +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PaymentModel extends BaseModel { - private String ip; - private String email; private String bin; private String pan; private String binCountryCode; private String cardToken; - private String fingerprint; private String shopId; private String partyId; - private Long amount; } diff --git a/src/main/java/com/rbkmoney/fraudo/resolver/CountryResolver.java b/src/main/java/com/rbkmoney/fraudo/resolver/CountryResolver.java index 47eb034..cf2d834 100644 --- a/src/main/java/com/rbkmoney/fraudo/resolver/CountryResolver.java +++ b/src/main/java/com/rbkmoney/fraudo/resolver/CountryResolver.java @@ -1,11 +1,9 @@ package com.rbkmoney.fraudo.resolver; -import com.rbkmoney.fraudo.constant.CheckedField; - -public interface CountryResolver { +public interface CountryResolver { String UNKNOWN_VALUE = "unknown"; - String resolveCountry(CheckedField checkedField, String value); + String resolveCountry(T checkedField, String value); } diff --git a/src/main/java/com/rbkmoney/fraudo/resolver/FieldResolver.java b/src/main/java/com/rbkmoney/fraudo/resolver/FieldResolver.java index f00300b..d7752d3 100644 --- a/src/main/java/com/rbkmoney/fraudo/resolver/FieldResolver.java +++ b/src/main/java/com/rbkmoney/fraudo/resolver/FieldResolver.java @@ -1,30 +1,19 @@ package com.rbkmoney.fraudo.resolver; -import com.rbkmoney.fraudo.constant.CheckedField; -import com.rbkmoney.fraudo.exception.UnresolvableFieldException; -import com.rbkmoney.fraudo.model.FraudModel; -public class FieldResolver { +import com.rbkmoney.fraudo.model.Pair; - public static String resolveString(String fieldName, FraudModel fraudModel) { - switch (CheckedField.getByValue(fieldName)) { - case BIN: - return fraudModel.getBin(); - case IP: - return fraudModel.getIp(); - case FINGERPRINT: - return fraudModel.getFingerprint(); - case EMAIL: - return fraudModel.getEmail(); - case COUNTRY_BANK: - return fraudModel.getBinCountryCode(); - case CARD_TOKEN: - return fraudModel.getCardToken(); - case PAN: - return fraudModel.getPan(); - default: - throw new UnresolvableFieldException(fieldName); - } +public interface FieldResolver { + + String resolveValue(String fieldName, T model); + + U resolveName(String fieldName); + + default Pair resolve(String fieldName, T model) { + return new Pair<>( + resolveName(fieldName), + resolveValue(fieldName, model) + ); } } diff --git a/src/main/java/com/rbkmoney/fraudo/resolver/GroupByModelResolver.java b/src/main/java/com/rbkmoney/fraudo/resolver/GroupByModelResolver.java index 7ec4563..08b3400 100644 --- a/src/main/java/com/rbkmoney/fraudo/resolver/GroupByModelResolver.java +++ b/src/main/java/com/rbkmoney/fraudo/resolver/GroupByModelResolver.java @@ -1,26 +1,29 @@ package com.rbkmoney.fraudo.resolver; import com.rbkmoney.fraudo.FraudoParser; -import com.rbkmoney.fraudo.constant.CheckedField; import com.rbkmoney.fraudo.utils.TextUtil; +import lombok.RequiredArgsConstructor; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -public class GroupByModelResolver { +@RequiredArgsConstructor +public class GroupByModelResolver implements GroupFieldsResolver { - public static List resolve(FraudoParser.Group_byContext groupByContext) { - List checkedFields = new ArrayList<>(); + private final FieldResolver fieldResolver; + + public List resolve(FraudoParser.Group_byContext groupByContext) { + List fields = new ArrayList<>(); if (groupByContext != null && groupByContext.string_list() != null && groupByContext.string_list().STRING() != null && !groupByContext.string_list().STRING().isEmpty()) { - checkedFields = groupByContext.string_list().STRING().stream() - .map(terminalNode -> CheckedField.getByValue(TextUtil.safeGetText(terminalNode))) + fields = groupByContext.string_list().STRING().stream() + .map(terminalNode -> fieldResolver.resolveName(TextUtil.safeGetText(terminalNode))) .collect(Collectors.toList()); } - return checkedFields; + return fields; } } diff --git a/src/main/java/com/rbkmoney/fraudo/resolver/GroupFieldsResolver.java b/src/main/java/com/rbkmoney/fraudo/resolver/GroupFieldsResolver.java new file mode 100644 index 0000000..9683b04 --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/resolver/GroupFieldsResolver.java @@ -0,0 +1,11 @@ +package com.rbkmoney.fraudo.resolver; + +import com.rbkmoney.fraudo.FraudoParser; + +import java.util.List; + +public interface GroupFieldsResolver { + + List resolve(FraudoParser.Group_byContext groupByContext); + +} diff --git a/src/main/java/com/rbkmoney/fraudo/resolver/TimeWindowResolver.java b/src/main/java/com/rbkmoney/fraudo/resolver/TimeWindowResolver.java index 17f044b..99588e7 100644 --- a/src/main/java/com/rbkmoney/fraudo/resolver/TimeWindowResolver.java +++ b/src/main/java/com/rbkmoney/fraudo/resolver/TimeWindowResolver.java @@ -3,10 +3,13 @@ package com.rbkmoney.fraudo.resolver; import com.rbkmoney.fraudo.FraudoParser; import com.rbkmoney.fraudo.model.TimeWindow; import com.rbkmoney.fraudo.utils.TextUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.antlr.v4.runtime.tree.TerminalNode; import java.util.List; +@NoArgsConstructor(access = AccessLevel.PRIVATE) public class TimeWindowResolver { public static TimeWindow resolve(FraudoParser.Time_windowContext ctx) { diff --git a/src/main/java/com/rbkmoney/fraudo/resolver/p2p/P2PModelFieldResolver.java b/src/main/java/com/rbkmoney/fraudo/resolver/p2p/P2PModelFieldResolver.java new file mode 100644 index 0000000..396ee47 --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/resolver/p2p/P2PModelFieldResolver.java @@ -0,0 +1,39 @@ +package com.rbkmoney.fraudo.resolver.p2p; + +import com.rbkmoney.fraudo.constant.P2PCheckedField; +import com.rbkmoney.fraudo.exception.UnresolvableFieldException; +import com.rbkmoney.fraudo.model.P2PModel; +import com.rbkmoney.fraudo.resolver.FieldResolver; + +public class P2PModelFieldResolver implements FieldResolver { + + @Override + public String resolveValue(String fieldName, P2PModel model) { + switch (P2PCheckedField.getByValue(fieldName)) { + case BIN: + return model.getBin(); + case IP: + return model.getIp(); + case FINGERPRINT: + return model.getFingerprint(); + case EMAIL: + return model.getEmail(); + case COUNTRY_BANK: + return model.getCountry(); + case CARD_TOKEN_FROM: + return model.getCardTokenFrom(); + case CARD_TOKEN_TO: + return model.getCardTokenTo(); + case PAN: + return model.getPan(); + default: + throw new UnresolvableFieldException(fieldName); + } + } + + @Override + public P2PCheckedField resolveName(String fieldName) { + return P2PCheckedField.getByValue(fieldName); + } + +} diff --git a/src/main/java/com/rbkmoney/fraudo/resolver/payout/PaymentModelFieldResolver.java b/src/main/java/com/rbkmoney/fraudo/resolver/payout/PaymentModelFieldResolver.java new file mode 100644 index 0000000..3169afc --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/resolver/payout/PaymentModelFieldResolver.java @@ -0,0 +1,37 @@ +package com.rbkmoney.fraudo.resolver.payout; + +import com.rbkmoney.fraudo.constant.PaymentCheckedField; +import com.rbkmoney.fraudo.exception.UnresolvableFieldException; +import com.rbkmoney.fraudo.model.PaymentModel; +import com.rbkmoney.fraudo.resolver.FieldResolver; + +public class PaymentModelFieldResolver implements FieldResolver { + + @Override + public String resolveValue(String fieldName, PaymentModel paymentModel) { + switch (PaymentCheckedField.getByValue(fieldName)) { + case BIN: + return paymentModel.getBin(); + case IP: + return paymentModel.getIp(); + case FINGERPRINT: + return paymentModel.getFingerprint(); + case EMAIL: + return paymentModel.getEmail(); + case COUNTRY_BANK: + return paymentModel.getBinCountryCode(); + case CARD_TOKEN: + return paymentModel.getCardToken(); + case PAN: + return paymentModel.getPan(); + default: + throw new UnresolvableFieldException(fieldName); + } + } + + @Override + public PaymentCheckedField resolveName(String fieldName) { + return PaymentCheckedField.getByValue(fieldName); + } + +} diff --git a/src/main/java/com/rbkmoney/fraudo/utils/key/generator/CommonKeyGenerator.java b/src/main/java/com/rbkmoney/fraudo/utils/key/generator/CommonKeyGenerator.java index f3eabd0..dbd0cf9 100644 --- a/src/main/java/com/rbkmoney/fraudo/utils/key/generator/CommonKeyGenerator.java +++ b/src/main/java/com/rbkmoney/fraudo/utils/key/generator/CommonKeyGenerator.java @@ -1,7 +1,7 @@ package com.rbkmoney.fraudo.utils.key.generator; import com.rbkmoney.fraudo.FraudoParser; -import com.rbkmoney.fraudo.constant.CheckedField; +import com.rbkmoney.fraudo.constant.PaymentCheckedField; import com.rbkmoney.fraudo.utils.TextUtil; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -19,7 +19,7 @@ public class CommonKeyGenerator { return new StringBuilder() .append(parseTree) .append(countTarget) - .append(CheckedField.getByValue(countTarget)) + .append(PaymentCheckedField.getByValue(countTarget)) .append(timeWindowContext != null ? timeWindowContext.children : "") .append(groupByContext != null ? groupByContext.string_list().children : "") .toString(); @@ -36,7 +36,7 @@ public class CommonKeyGenerator { .append(parseTree) .append(target) .append(errorCode) - .append(CheckedField.getByValue(target)) + .append(PaymentCheckedField.getByValue(target)) .append(timeWindowContext != null ? timeWindowContext.children : "") .append(groupByContext != null ? groupByContext.string_list().children : "") .toString(); diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/CountVisitor.java b/src/main/java/com/rbkmoney/fraudo/visitor/CountVisitor.java new file mode 100644 index 0000000..5fd624e --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/visitor/CountVisitor.java @@ -0,0 +1,13 @@ +package com.rbkmoney.fraudo.visitor; + +import com.rbkmoney.fraudo.FraudoParser; + +public interface CountVisitor { + + Integer visitCount(FraudoParser.CountContext ctx, T model); + + Integer visitCountSuccess(FraudoParser.Count_successContext ctx, T model); + + Integer visitCountError(FraudoParser.Count_errorContext ctx, T model); + +} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/CountVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/CountVisitorImpl.java deleted file mode 100644 index 0a18325..0000000 --- a/src/main/java/com/rbkmoney/fraudo/visitor/CountVisitorImpl.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.rbkmoney.fraudo.visitor; - -import com.rbkmoney.fraudo.FraudoBaseVisitor; -import com.rbkmoney.fraudo.FraudoParser; -import com.rbkmoney.fraudo.aggregator.CountAggregator; -import com.rbkmoney.fraudo.constant.CheckedField; -import com.rbkmoney.fraudo.model.FraudModel; -import com.rbkmoney.fraudo.resolver.GroupByModelResolver; -import com.rbkmoney.fraudo.resolver.TimeWindowResolver; -import com.rbkmoney.fraudo.utils.TextUtil; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -public class CountVisitorImpl extends FraudoBaseVisitor { - - private final FraudModel fraudModel; - private final CountAggregator countAggregator; - - @Override - public Object visitCount(com.rbkmoney.fraudo.FraudoParser.CountContext ctx) { - String countTarget = TextUtil.safeGetText(ctx.STRING()); - return (double) countAggregator.count(CheckedField.getByValue(countTarget), fraudModel, - TimeWindowResolver.resolve(ctx.time_window()), GroupByModelResolver.resolve(ctx.group_by())); - } - - @Override - public Object visitCount_success(FraudoParser.Count_successContext ctx) { - String countTarget = ctx.STRING().getText(); - return (double) countAggregator.countSuccess(CheckedField.getByValue(countTarget), fraudModel, - TimeWindowResolver.resolve(ctx.time_window()), GroupByModelResolver.resolve(ctx.group_by())); - } - - @Override - public Object visitCount_error(FraudoParser.Count_errorContext ctx) { - String countTarget = TextUtil.safeGetText(ctx.STRING(0)); - String errorCode = TextUtil.safeGetText(ctx.STRING(1)); - return (double) countAggregator.countError(CheckedField.getByValue(countTarget), fraudModel, - TimeWindowResolver.resolve(ctx.time_window()), errorCode, GroupByModelResolver.resolve(ctx.group_by())); - } - -} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/CustomFuncVisitor.java b/src/main/java/com/rbkmoney/fraudo/visitor/CustomFuncVisitor.java new file mode 100644 index 0000000..1b8261c --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/visitor/CustomFuncVisitor.java @@ -0,0 +1,15 @@ +package com.rbkmoney.fraudo.visitor; + +import com.rbkmoney.fraudo.FraudoParser; + +public interface CustomFuncVisitor { + + String visitCountryBy(FraudoParser.Country_byContext ctx, T model); + + boolean visitIn(FraudoParser.InContext ctx, T model); + + boolean visitLike(FraudoParser.LikeContext ctx, T model); + + Integer visitUnique(FraudoParser.UniqueContext ctx, T model); + +} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/CustomFuncVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/CustomFuncVisitorImpl.java deleted file mode 100644 index 34e4c92..0000000 --- a/src/main/java/com/rbkmoney/fraudo/visitor/CustomFuncVisitorImpl.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.rbkmoney.fraudo.visitor; - -import com.rbkmoney.fraudo.FraudoBaseVisitor; -import com.rbkmoney.fraudo.FraudoParser; -import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; -import com.rbkmoney.fraudo.constant.CheckedField; -import com.rbkmoney.fraudo.model.FraudModel; -import com.rbkmoney.fraudo.resolver.CountryResolver; -import com.rbkmoney.fraudo.resolver.FieldResolver; -import com.rbkmoney.fraudo.resolver.GroupByModelResolver; -import com.rbkmoney.fraudo.resolver.TimeWindowResolver; -import com.rbkmoney.fraudo.utils.TextUtil; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -public class CustomFuncVisitorImpl extends FraudoBaseVisitor { - - private final FraudModel fraudModel; - private final UniqueValueAggregator uniqueValueAggregator; - private final CountryResolver countryResolver; - - @Override - public Object visitCountry_by(FraudoParser.Country_byContext ctx) { - String fieldName = TextUtil.safeGetText(ctx.STRING()); - String fieldValue = FieldResolver.resolveString(fieldName, fraudModel); - return countryResolver.resolveCountry(CheckedField.getByValue(fieldName), fieldValue); - } - - @Override - public Object visitIn(FraudoParser.InContext ctx) { - final String fieldValue; - if (ctx.STRING() != null && ctx.STRING().getText() != null && !ctx.STRING().getText().isEmpty()) { - String field = TextUtil.safeGetText(ctx.STRING()); - fieldValue = FieldResolver.resolveString(field, fraudModel); - } else { - String fieldName = TextUtil.safeGetText(ctx.country_by().STRING()); - String value = FieldResolver.resolveString(fieldName, fraudModel); - fieldValue = countryResolver.resolveCountry(CheckedField.getByValue(fieldName), value); - } - return ctx.string_list().STRING().stream() - .anyMatch(s -> fieldValue.equals(TextUtil.safeGetText(s))); - } - - @Override - public Object visitLike(FraudoParser.LikeContext ctx) { - String fieldName = TextUtil.safeGetText(ctx.STRING(0)); - String fieldValue = FieldResolver.resolveString(fieldName, fraudModel); - String pattern = TextUtil.safeGetText(ctx.STRING(1)); - return fieldValue.matches(pattern); - } - - @Override - public Object visitUnique(FraudoParser.UniqueContext ctx) { - String field = TextUtil.safeGetText(ctx.STRING(0)); - String fieldBy = TextUtil.safeGetText(ctx.STRING(1)); - return (double) uniqueValueAggregator.countUniqueValue(CheckedField.getByValue(field), fraudModel, - CheckedField.getByValue(fieldBy), TimeWindowResolver.resolve(ctx.time_window()), GroupByModelResolver.resolve(ctx.group_by())); - } - - @Override - public Object visitAmount(FraudoParser.AmountContext ctx) { - return (double) fraudModel.getAmount(); - } -} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/ListVisitor.java b/src/main/java/com/rbkmoney/fraudo/visitor/ListVisitor.java new file mode 100644 index 0000000..f01d81e --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/visitor/ListVisitor.java @@ -0,0 +1,15 @@ +package com.rbkmoney.fraudo.visitor; + +import com.rbkmoney.fraudo.FraudoParser; + +public interface ListVisitor { + + Boolean visitInWhiteList(FraudoParser.In_white_listContext ctx, T model); + + Boolean visitInBlackList(FraudoParser.In_black_listContext ctx, T model); + + Boolean visitInGreyList(FraudoParser.In_grey_listContext ctx, T model); + + Boolean visitInList(FraudoParser.In_listContext ctx, T model); + +} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/ListVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/ListVisitorImpl.java deleted file mode 100644 index fd8374f..0000000 --- a/src/main/java/com/rbkmoney/fraudo/visitor/ListVisitorImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.rbkmoney.fraudo.visitor; - -import com.rbkmoney.fraudo.FraudoBaseVisitor; -import com.rbkmoney.fraudo.FraudoParser; -import com.rbkmoney.fraudo.constant.CheckedField; -import com.rbkmoney.fraudo.finder.InListFinder; -import com.rbkmoney.fraudo.model.FraudModel; -import com.rbkmoney.fraudo.resolver.FieldResolver; -import com.rbkmoney.fraudo.utils.TextUtil; -import lombok.RequiredArgsConstructor; -import org.antlr.v4.runtime.tree.TerminalNode; - -import java.util.List; -import java.util.stream.Collectors; - -@RequiredArgsConstructor -public class ListVisitorImpl extends FraudoBaseVisitor { - - private final FraudModel fraudModel; - private final InListFinder blackListFinder; - private final InListFinder whiteListFinder; - private final InListFinder greyListFinder; - - @Override - public Object visitIn_white_list(FraudoParser.In_white_listContext ctx) { - return findInList(ctx.string_list().STRING(), whiteListFinder); - } - - @Override - public Object visitIn_black_list(FraudoParser.In_black_listContext ctx) { - return findInList(ctx.string_list().STRING(), blackListFinder); - } - - @Override - public Object visitIn_grey_list(FraudoParser.In_grey_listContext ctx) { - return findInList(ctx.string_list().STRING(), greyListFinder); - } - - private Object findInList(List nodes, InListFinder listFinder) { - List fields = nodes.stream() - .map(TextUtil::safeGetText) - .collect(Collectors.toList()); - List values = fields.stream() - .map(field -> FieldResolver.resolveString(field, fraudModel)) - .collect(Collectors.toList()); - List checkedFields = fields.stream() - .map(CheckedField::getByValue) - .collect(Collectors.toList()); - return listFinder.findInList(fraudModel.getPartyId(), fraudModel.getShopId(), - checkedFields, values); - } -} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/SumVisitor.java b/src/main/java/com/rbkmoney/fraudo/visitor/SumVisitor.java new file mode 100644 index 0000000..fc291eb --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/visitor/SumVisitor.java @@ -0,0 +1,13 @@ +package com.rbkmoney.fraudo.visitor; + +import com.rbkmoney.fraudo.FraudoParser; + +public interface SumVisitor { + + Double visitSum(FraudoParser.SumContext ctx, T model); + + Double visitSumSuccess(FraudoParser.Sum_successContext ctx, T model); + + Double visitSumError(FraudoParser.Sum_errorContext ctx, T model); + +} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/SumVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/SumVisitorImpl.java deleted file mode 100644 index a83971e..0000000 --- a/src/main/java/com/rbkmoney/fraudo/visitor/SumVisitorImpl.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.rbkmoney.fraudo.visitor; - -import com.rbkmoney.fraudo.FraudoBaseVisitor; -import com.rbkmoney.fraudo.FraudoParser; -import com.rbkmoney.fraudo.aggregator.SumAggregator; -import com.rbkmoney.fraudo.constant.CheckedField; -import com.rbkmoney.fraudo.model.FraudModel; -import com.rbkmoney.fraudo.resolver.GroupByModelResolver; -import com.rbkmoney.fraudo.resolver.TimeWindowResolver; -import com.rbkmoney.fraudo.utils.TextUtil; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -public class SumVisitorImpl extends FraudoBaseVisitor { - - private final FraudModel fraudModel; - private final SumAggregator sumAggregator; - - @Override - public Object visitSum(FraudoParser.SumContext ctx) { - String countTarget = TextUtil.safeGetText(ctx.STRING()); - return sumAggregator.sum(CheckedField.getByValue(countTarget), fraudModel, - TimeWindowResolver.resolve(ctx.time_window()), GroupByModelResolver.resolve(ctx.group_by())); - } - - @Override - public Object visitSum_success(FraudoParser.Sum_successContext ctx) { - String countTarget = TextUtil.safeGetText(ctx.STRING()); - return sumAggregator.sumSuccess(CheckedField.getByValue(countTarget), fraudModel, - TimeWindowResolver.resolve(ctx.time_window()), GroupByModelResolver.resolve(ctx.group_by())); - } - - @Override - public Object visitSum_error(FraudoParser.Sum_errorContext ctx) { - String countTarget = TextUtil.safeGetText(ctx.STRING(0)); - String errorCode = TextUtil.safeGetText(ctx.STRING(1)); - return sumAggregator.sumError(CheckedField.getByValue(countTarget), fraudModel, - TimeWindowResolver.resolve(ctx.time_window()), errorCode, GroupByModelResolver.resolve(ctx.group_by())); - } - -} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/impl/CountVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/impl/CountVisitorImpl.java new file mode 100644 index 0000000..34ed345 --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/visitor/impl/CountVisitorImpl.java @@ -0,0 +1,54 @@ +package com.rbkmoney.fraudo.visitor.impl; + +import com.rbkmoney.fraudo.FraudoParser; +import com.rbkmoney.fraudo.aggregator.CountAggregator; +import com.rbkmoney.fraudo.resolver.FieldResolver; +import com.rbkmoney.fraudo.resolver.GroupFieldsResolver; +import com.rbkmoney.fraudo.resolver.TimeWindowResolver; +import com.rbkmoney.fraudo.utils.TextUtil; +import com.rbkmoney.fraudo.visitor.CountVisitor; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class CountVisitorImpl implements CountVisitor { + + private final CountAggregator countAggregator; + private final FieldResolver fieldResolver; + private final GroupFieldsResolver groupFieldsResolver; + + @Override + public Integer visitCount(com.rbkmoney.fraudo.FraudoParser.CountContext ctx, T model) { + String countTarget = TextUtil.safeGetText(ctx.STRING()); + return countAggregator.count( + fieldResolver.resolveName(countTarget), + model, + TimeWindowResolver.resolve(ctx.time_window()), + groupFieldsResolver.resolve(ctx.group_by()) + ); + } + + @Override + public Integer visitCountSuccess(FraudoParser.Count_successContext ctx, T model) { + String countTarget = ctx.STRING().getText(); + return countAggregator.countSuccess( + fieldResolver.resolveName(countTarget), + model, + TimeWindowResolver.resolve(ctx.time_window()), + groupFieldsResolver.resolve(ctx.group_by()) + ); + } + + @Override + public Integer visitCountError(FraudoParser.Count_errorContext ctx, T model) { + String countTarget = TextUtil.safeGetText(ctx.STRING(0)); + String errorCode = TextUtil.safeGetText(ctx.STRING(1)); + return countAggregator.countError( + fieldResolver.resolveName(countTarget), + model, + TimeWindowResolver.resolve(ctx.time_window()), + errorCode, + groupFieldsResolver.resolve(ctx.group_by()) + ); + } + +} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/impl/CustomFuncVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/impl/CustomFuncVisitorImpl.java new file mode 100644 index 0000000..b5a6abb --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/visitor/impl/CustomFuncVisitorImpl.java @@ -0,0 +1,65 @@ +package com.rbkmoney.fraudo.visitor.impl; + +import com.rbkmoney.fraudo.FraudoParser; +import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; +import com.rbkmoney.fraudo.model.Pair; +import com.rbkmoney.fraudo.resolver.CountryResolver; +import com.rbkmoney.fraudo.resolver.FieldResolver; +import com.rbkmoney.fraudo.resolver.GroupByModelResolver; +import com.rbkmoney.fraudo.resolver.TimeWindowResolver; +import com.rbkmoney.fraudo.utils.TextUtil; +import com.rbkmoney.fraudo.visitor.CustomFuncVisitor; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class CustomFuncVisitorImpl implements CustomFuncVisitor { + + private final UniqueValueAggregator uniqueValueAggregator; + private final CountryResolver countryResolver; + private final FieldResolver fieldResolver; + private final GroupByModelResolver groupByModelResolver; + + @Override + public String visitCountryBy(FraudoParser.Country_byContext ctx, T model) { + String fieldName = TextUtil.safeGetText(ctx.STRING()); + Pair resolve = fieldResolver.resolve(fieldName, model); + return countryResolver.resolveCountry(resolve.getFirst(), resolve.getSecond()); + } + + @Override + public boolean visitIn(FraudoParser.InContext ctx, T model) { + final String fieldValue; + if (ctx.STRING() != null && ctx.STRING().getText() != null && !ctx.STRING().getText().isEmpty()) { + String field = TextUtil.safeGetText(ctx.STRING()); + fieldValue = fieldResolver.resolve(field, model).getSecond(); + } else { + String fieldName = TextUtil.safeGetText(ctx.country_by().STRING()); + Pair resolve = fieldResolver.resolve(fieldName, model); + fieldValue = countryResolver.resolveCountry(resolve.getFirst(), resolve.getSecond()); + } + return ctx.string_list().STRING().stream() + .anyMatch(s -> fieldValue.equals(TextUtil.safeGetText(s))); + } + + @Override + public boolean visitLike(FraudoParser.LikeContext ctx, T model) { + String fieldName = TextUtil.safeGetText(ctx.STRING(0)); + String fieldValue = fieldResolver.resolve(fieldName, model).getSecond(); + String pattern = TextUtil.safeGetText(ctx.STRING(1)); + return fieldValue.matches(pattern); + } + + @Override + public Integer visitUnique(FraudoParser.UniqueContext ctx, T model) { + String field = TextUtil.safeGetText(ctx.STRING(0)); + String fieldBy = TextUtil.safeGetText(ctx.STRING(1)); + return uniqueValueAggregator.countUniqueValue( + fieldResolver.resolveName(field), + model, + fieldResolver.resolveName(fieldBy), + TimeWindowResolver.resolve(ctx.time_window()), + groupByModelResolver.resolve(ctx.group_by()) + ); + } + +} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/FastFraudVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/impl/FastFraudVisitorImpl.java similarity index 61% rename from src/main/java/com/rbkmoney/fraudo/visitor/FastFraudVisitorImpl.java rename to src/main/java/com/rbkmoney/fraudo/visitor/impl/FastFraudVisitorImpl.java index d6446dd..b70e22e 100644 --- a/src/main/java/com/rbkmoney/fraudo/visitor/FastFraudVisitorImpl.java +++ b/src/main/java/com/rbkmoney/fraudo/visitor/impl/FastFraudVisitorImpl.java @@ -1,15 +1,22 @@ -package com.rbkmoney.fraudo.visitor; +package com.rbkmoney.fraudo.visitor.impl; import com.rbkmoney.fraudo.FraudoBaseVisitor; import com.rbkmoney.fraudo.FraudoParser; import com.rbkmoney.fraudo.constant.ResultStatus; import com.rbkmoney.fraudo.exception.NotImplementedOperatorException; +import com.rbkmoney.fraudo.exception.NotValidContextException; import com.rbkmoney.fraudo.exception.UnknownResultException; +import com.rbkmoney.fraudo.model.BaseModel; import com.rbkmoney.fraudo.model.ResultModel; import com.rbkmoney.fraudo.utils.TextUtil; import com.rbkmoney.fraudo.utils.key.generator.*; +import com.rbkmoney.fraudo.visitor.CountVisitor; +import com.rbkmoney.fraudo.visitor.CustomFuncVisitor; +import com.rbkmoney.fraudo.visitor.ListVisitor; +import com.rbkmoney.fraudo.visitor.SumVisitor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.antlr.v4.runtime.tree.ParseTree; import java.util.ArrayList; import java.util.HashMap; @@ -18,14 +25,31 @@ import java.util.Map; @Slf4j @RequiredArgsConstructor -public class FastFraudVisitorImpl extends FraudoBaseVisitor { +public class FastFraudVisitorImpl extends FraudoBaseVisitor { - private Map localFuncCache = new HashMap<>(); + private ThreadLocal> localFuncCache; + private ThreadLocal threadLocalModel; - private final CountVisitorImpl countVisitor; - private final SumVisitorImpl sumVisitor; - private final ListVisitorImpl listVisitor; - private final CustomFuncVisitorImpl customFuncVisitor; + private final CountVisitor countVisitor; + private final SumVisitor sumVisitor; + private final ListVisitor listVisitor; + private final CustomFuncVisitor customFuncVisitor; + + public Object visit(ParseTree tree, T model) { + if (model == null) { + log.error("Model is not init!"); + throw new NotValidContextException(); + } + + localFuncCache = ThreadLocal.withInitial(HashMap::new); + threadLocalModel = ThreadLocal.withInitial(() -> model); + + Object visit = super.visit(tree); + + localFuncCache.remove(); + threadLocalModel.remove(); + return visit; + } @Override public Object visitFraud_rule(FraudoParser.Fraud_ruleContext ctx) { @@ -34,11 +58,11 @@ public class FastFraudVisitorImpl extends FraudoBaseVisitor { return ResultStatus.getByValue((String) super.visit(ctx.result())); } } catch (Exception e) { - log.warn("Error when FastFraudVisitorImpl visitFraud_rule e: ", e); + log.error("Error when FastFraudVisitorImpl visitFraud_rule e: ", e); if (ctx.catch_result() != null && ctx.catch_result().getText() != null) { return ResultStatus.getByValue(ctx.catch_result().getText()); } - return ResultStatus.THREE_DS; + return ResultStatus.NOTIFY; } return ResultStatus.NORMAL; } @@ -49,12 +73,12 @@ public class FastFraudVisitorImpl extends FraudoBaseVisitor { for (FraudoParser.Fraud_ruleContext fraudRuleContext : ctx.fraud_rule()) { ResultStatus result = (ResultStatus) visitFraud_rule(fraudRuleContext); String key = RuleKeyGenerator.generateRuleKey(fraudRuleContext); - if (ResultStatus.NOTIFY.equals(result)) { - notifications.add(key); - } else if (result != null && !ResultStatus.NORMAL.equals(result)) { - return new ResultModel(result, key, notifications); - } else if (result == null) { + if (result == null) { throw new UnknownResultException(fraudRuleContext.getText()); + } else if (result == ResultStatus.NOTIFY) { + notifications.add(key); + } else if (result != ResultStatus.NORMAL) { + return new ResultModel(result, key, notifications); } } return new ResultModel(ResultStatus.NORMAL, notifications); @@ -119,79 +143,113 @@ public class FastFraudVisitorImpl extends FraudoBaseVisitor { @Override public Object visitCount(FraudoParser.CountContext ctx) { String key = CountKeyGenerator.generate(ctx); - return localFuncCache.computeIfAbsent(key, s -> countVisitor.visitCount(ctx)); + return localFuncCache.get().computeIfAbsent( + key, + s -> Double.valueOf(countVisitor.visitCount(ctx, threadLocalModel.get())) + ); } @Override public Object visitCount_success(FraudoParser.Count_successContext ctx) { String key = CountKeyGenerator.generateSuccessKey(ctx); - return localFuncCache.computeIfAbsent(key, s -> countVisitor.visitCount_success(ctx)); + return localFuncCache.get().computeIfAbsent( + key, + s -> Double.valueOf(countVisitor.visitCountSuccess(ctx, threadLocalModel.get())) + ); } @Override public Object visitCount_error(FraudoParser.Count_errorContext ctx) { String key = CountKeyGenerator.generateErrorKey(ctx); - return localFuncCache.computeIfAbsent(key, s -> countVisitor.visitCount_error(ctx)); + return localFuncCache.get().computeIfAbsent( + key, + s -> Double.valueOf(countVisitor.visitCountError(ctx, threadLocalModel.get())) + ); } @Override public Object visitSum(FraudoParser.SumContext ctx) { String key = SumKeyGenerator.generate(ctx); - return localFuncCache.computeIfAbsent(key, s -> sumVisitor.visitSum(ctx)); + return localFuncCache.get().computeIfAbsent( + key, + s -> sumVisitor.visitSum(ctx, threadLocalModel.get()) + ); } @Override public Object visitSum_success(FraudoParser.Sum_successContext ctx) { String key = SumKeyGenerator.generateSuccessKey(ctx); - return localFuncCache.computeIfAbsent(key, s -> sumVisitor.visitSum_success(ctx)); + return localFuncCache.get().computeIfAbsent( + key, + s -> sumVisitor.visitSumSuccess(ctx, threadLocalModel.get()) + ); } @Override public Object visitSum_error(FraudoParser.Sum_errorContext ctx) { String key = SumKeyGenerator.generateErrorKey(ctx); - return localFuncCache.computeIfAbsent(key, s -> sumVisitor.visitSum_error(ctx)); + return localFuncCache.get().computeIfAbsent( + key, + s -> sumVisitor.visitSumError(ctx, threadLocalModel.get()) + ); } @Override public Object visitCountry_by(FraudoParser.Country_byContext ctx) { String key = CountryKeyGenerator.generate(ctx); - return localFuncCache.computeIfAbsent(key, s -> customFuncVisitor.visitCountry_by(ctx)); + return localFuncCache.get().computeIfAbsent( + key, + s -> customFuncVisitor.visitCountryBy(ctx, threadLocalModel.get()) + ); } @Override public Object visitIn(FraudoParser.InContext ctx) { - return customFuncVisitor.visitIn(ctx); + return customFuncVisitor.visitIn(ctx, threadLocalModel.get()); } @Override public Object visitLike(FraudoParser.LikeContext ctx) { - return customFuncVisitor.visitLike(ctx); + return customFuncVisitor.visitLike(ctx, threadLocalModel.get()); } @Override public Object visitUnique(FraudoParser.UniqueContext ctx) { String key = UniqueKeyGenerator.generate(ctx); - return localFuncCache.computeIfAbsent(key, s -> customFuncVisitor.visitUnique(ctx)); + return localFuncCache.get().computeIfAbsent( + key, + s -> Double.valueOf(customFuncVisitor.visitUnique(ctx, threadLocalModel.get())) + ); } @Override public Object visitIn_white_list(FraudoParser.In_white_listContext ctx) { - return listVisitor.visitIn_white_list(ctx); + return listVisitor.visitInWhiteList(ctx, threadLocalModel.get()); } @Override public Object visitIn_black_list(FraudoParser.In_black_listContext ctx) { - return listVisitor.visitIn_black_list(ctx); + return listVisitor.visitInBlackList(ctx, threadLocalModel.get()); } @Override public Object visitIn_grey_list(FraudoParser.In_grey_listContext ctx) { - return listVisitor.visitIn_grey_list(ctx); + return listVisitor.visitInGreyList(ctx, threadLocalModel.get()); + } + + @Override + public Object visitIn_list(FraudoParser.In_listContext ctx) { + return listVisitor.visitInList(ctx, threadLocalModel.get()); } @Override public Object visitAmount(FraudoParser.AmountContext ctx) { - return customFuncVisitor.visitAmount(ctx); + return Double.valueOf(threadLocalModel.get().getAmount()); + } + + @Override + public Object visitCurrency(FraudoParser.CurrencyContext ctx) { + return threadLocalModel.get().getCurrency(); } private boolean asBoolean(FraudoParser.ExpressionContext ctx) { diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/impl/ListVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/impl/ListVisitorImpl.java new file mode 100644 index 0000000..fb1953e --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/visitor/impl/ListVisitorImpl.java @@ -0,0 +1,57 @@ +package com.rbkmoney.fraudo.visitor.impl; + +import com.rbkmoney.fraudo.FraudoParser; +import com.rbkmoney.fraudo.finder.InListFinder; +import com.rbkmoney.fraudo.model.Pair; +import com.rbkmoney.fraudo.resolver.FieldResolver; +import com.rbkmoney.fraudo.utils.TextUtil; +import com.rbkmoney.fraudo.visitor.ListVisitor; +import lombok.RequiredArgsConstructor; +import org.antlr.v4.runtime.tree.TerminalNode; + +import java.util.List; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class ListVisitorImpl implements ListVisitor { + + private final InListFinder listFinder; + private final FieldResolver fieldResolver; + + @Override + public Boolean visitInWhiteList(FraudoParser.In_white_listContext ctx, T model) { + return findInList(ctx.string_list().STRING(), model, listFinder::findInWhiteList); + } + + @Override + public Boolean visitInBlackList(FraudoParser.In_black_listContext ctx, T model) { + return findInList(ctx.string_list().STRING(), model, listFinder::findInBlackList); + } + + @Override + public Boolean visitInGreyList(FraudoParser.In_grey_listContext ctx, T model) { + return findInList(ctx.string_list().STRING(), model, listFinder::findInGreyList); + } + + @Override + public Boolean visitInList(FraudoParser.In_listContext ctx, T model) { + List> checkedFields = initCheckedFields(model, ctx.string_list().STRING()); + String name = TextUtil.safeGetText(ctx.STRING()); + return listFinder.findInList(name, checkedFields, model); + } + + private List> initCheckedFields(T model, List string) { + List fields = string.stream() + .map(TextUtil::safeGetText) + .collect(Collectors.toList()); + return fields.stream() + .map(s -> fieldResolver.resolve(s, model)) + .collect(Collectors.toList()); + } + + private Boolean findInList(List nodes, T model, BiPredicate>, T> biPredicate) { + List> checkedFields = initCheckedFields(model, nodes); + return biPredicate.test(checkedFields, model); + } +} diff --git a/src/main/java/com/rbkmoney/fraudo/visitor/impl/SumVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/visitor/impl/SumVisitorImpl.java new file mode 100644 index 0000000..a60d40e --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/visitor/impl/SumVisitorImpl.java @@ -0,0 +1,52 @@ +package com.rbkmoney.fraudo.visitor.impl; + +import com.rbkmoney.fraudo.FraudoParser; +import com.rbkmoney.fraudo.aggregator.SumAggregator; +import com.rbkmoney.fraudo.resolver.FieldResolver; +import com.rbkmoney.fraudo.resolver.GroupByModelResolver; +import com.rbkmoney.fraudo.resolver.TimeWindowResolver; +import com.rbkmoney.fraudo.utils.TextUtil; +import com.rbkmoney.fraudo.visitor.SumVisitor; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class SumVisitorImpl implements SumVisitor { + + private final SumAggregator sumAggregator; + private final FieldResolver fieldResolver; + private final GroupByModelResolver groupByModelResolver; + + @Override + public Double visitSum(FraudoParser.SumContext ctx, T model) { + String countTarget = TextUtil.safeGetText(ctx.STRING()); + return sumAggregator.sum( + fieldResolver.resolveName(countTarget), + model, + TimeWindowResolver.resolve(ctx.time_window()), + groupByModelResolver.resolve(ctx.group_by()) + ); + } + + @Override + public Double visitSumSuccess(FraudoParser.Sum_successContext ctx, T model) { + String countTarget = TextUtil.safeGetText(ctx.STRING()); + return sumAggregator.sumSuccess( + fieldResolver.resolveName(countTarget), + model, + TimeWindowResolver.resolve(ctx.time_window()), + groupByModelResolver.resolve(ctx.group_by())); + } + + @Override + public Double visitSumError(FraudoParser.Sum_errorContext ctx, T model) { + String countTarget = TextUtil.safeGetText(ctx.STRING(0)); + String errorCode = TextUtil.safeGetText(ctx.STRING(1)); + return sumAggregator.sumError( + fieldResolver.resolveName(countTarget), + model, + TimeWindowResolver.resolve(ctx.time_window()), + errorCode, + groupByModelResolver.resolve(ctx.group_by())); + } + +} diff --git a/src/test/java/com/rbkmoney/fraudo/AbstractFraudoTest.java b/src/test/java/com/rbkmoney/fraudo/AbstractFraudoTest.java deleted file mode 100644 index 5224290..0000000 --- a/src/test/java/com/rbkmoney/fraudo/AbstractFraudoTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.rbkmoney.fraudo; - -import com.rbkmoney.fraudo.aggregator.CountAggregator; -import com.rbkmoney.fraudo.aggregator.SumAggregator; -import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; -import com.rbkmoney.fraudo.factory.FastFraudVisitorFactory; -import com.rbkmoney.fraudo.finder.InListFinder; -import com.rbkmoney.fraudo.model.FraudModel; -import com.rbkmoney.fraudo.model.ResultModel; -import com.rbkmoney.fraudo.resolver.CountryResolver; -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.CommonTokenStream; -import org.mockito.Mock; - -import java.io.IOException; -import java.io.InputStream; - -public class AbstractFraudoTest { - - public static final String TEST_GMAIL_RU = "test@gmail.ru"; - - @Mock - CountAggregator countAggregator; - @Mock - SumAggregator sumAggregator; - @Mock - UniqueValueAggregator uniqueValueAggregator; - @Mock - CountryResolver countryResolver; - @Mock - InListFinder whiteListFinder; - @Mock - InListFinder blackListFinder; - @Mock - InListFinder greyListFinder; - - protected ResultModel parseAndVisit(InputStream resourceAsStream) throws IOException { - com.rbkmoney.fraudo.FraudoParser.ParseContext parse = getParseContext(resourceAsStream); - return invokeParse(parse); - } - - protected ResultModel invokeParse(com.rbkmoney.fraudo.FraudoParser.ParseContext parse) { - FraudModel model = new FraudModel(); - return invoke(parse, model); - } - - protected ResultModel invoke(com.rbkmoney.fraudo.FraudoParser.ParseContext parse, FraudModel model) { - return (ResultModel) new FastFraudVisitorFactory() - .createVisitor(model, countAggregator, sumAggregator, uniqueValueAggregator, countryResolver, - blackListFinder, whiteListFinder, greyListFinder) - .visit(parse); - } - - protected com.rbkmoney.fraudo.FraudoParser.ParseContext getParseContext(InputStream resourceAsStream) throws IOException { - com.rbkmoney.fraudo.FraudoLexer lexer = new com.rbkmoney.fraudo.FraudoLexer(new ANTLRInputStream(resourceAsStream)); - com.rbkmoney.fraudo.FraudoParser parser = new com.rbkmoney.fraudo.FraudoParser(new CommonTokenStream(lexer)); - - return parser.parse(); - } - -} diff --git a/src/test/java/com/rbkmoney/fraudo/AbstractP2PTest.java b/src/test/java/com/rbkmoney/fraudo/AbstractP2PTest.java new file mode 100644 index 0000000..5aae33f --- /dev/null +++ b/src/test/java/com/rbkmoney/fraudo/AbstractP2PTest.java @@ -0,0 +1,68 @@ +package com.rbkmoney.fraudo; + +import com.rbkmoney.fraudo.aggregator.CountAggregator; +import com.rbkmoney.fraudo.aggregator.SumAggregator; +import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; +import com.rbkmoney.fraudo.constant.P2PCheckedField; +import com.rbkmoney.fraudo.factory.FastFraudVisitorFactory; +import com.rbkmoney.fraudo.finder.InListFinder; +import com.rbkmoney.fraudo.model.P2PModel; +import com.rbkmoney.fraudo.model.ResultModel; +import com.rbkmoney.fraudo.resolver.CountryResolver; +import com.rbkmoney.fraudo.resolver.GroupByModelResolver; +import com.rbkmoney.fraudo.resolver.p2p.P2PModelFieldResolver; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.mockito.Mock; + +import java.io.IOException; +import java.io.InputStream; + +public class AbstractP2PTest { + + @Mock + CountAggregator countAggregator; + @Mock + SumAggregator sumAggregator; + @Mock + UniqueValueAggregator uniqueValueAggregator; + @Mock + CountryResolver countryResolver; + @Mock + InListFinder listFinder; + + private P2PModelFieldResolver fieldResolver = new P2PModelFieldResolver(); + private GroupByModelResolver groupByModelResolver = new GroupByModelResolver<>(fieldResolver); + + + ResultModel parseAndVisit(InputStream resourceAsStream) throws IOException { + com.rbkmoney.fraudo.FraudoParser.ParseContext parse = getParseContext(resourceAsStream); + return invokeParse(parse); + } + + ResultModel invokeParse(com.rbkmoney.fraudo.FraudoParser.ParseContext parse) { + P2PModel model = new P2PModel(); + return invoke(parse, model); + } + + ResultModel invoke(com.rbkmoney.fraudo.FraudoParser.ParseContext parse, P2PModel model) { + return (ResultModel) new FastFraudVisitorFactory() + .createVisitor( + countAggregator, + sumAggregator, + uniqueValueAggregator, + countryResolver, + listFinder, + fieldResolver, + groupByModelResolver) + .visit(parse, model); + } + + com.rbkmoney.fraudo.FraudoParser.ParseContext getParseContext(InputStream resourceAsStream) throws IOException { + com.rbkmoney.fraudo.FraudoLexer lexer = new com.rbkmoney.fraudo.FraudoLexer(new ANTLRInputStream(resourceAsStream)); + com.rbkmoney.fraudo.FraudoParser parser = new com.rbkmoney.fraudo.FraudoParser(new CommonTokenStream(lexer)); + + return parser.parse(); + } + +} diff --git a/src/test/java/com/rbkmoney/fraudo/AbstractPaymentTest.java b/src/test/java/com/rbkmoney/fraudo/AbstractPaymentTest.java new file mode 100644 index 0000000..1db3881 --- /dev/null +++ b/src/test/java/com/rbkmoney/fraudo/AbstractPaymentTest.java @@ -0,0 +1,68 @@ +package com.rbkmoney.fraudo; + +import com.rbkmoney.fraudo.aggregator.CountAggregator; +import com.rbkmoney.fraudo.aggregator.SumAggregator; +import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; +import com.rbkmoney.fraudo.constant.PaymentCheckedField; +import com.rbkmoney.fraudo.factory.FastFraudVisitorFactory; +import com.rbkmoney.fraudo.finder.InListFinder; +import com.rbkmoney.fraudo.model.PaymentModel; +import com.rbkmoney.fraudo.model.ResultModel; +import com.rbkmoney.fraudo.resolver.CountryResolver; +import com.rbkmoney.fraudo.resolver.FieldResolver; +import com.rbkmoney.fraudo.resolver.GroupByModelResolver; +import com.rbkmoney.fraudo.resolver.payout.PaymentModelFieldResolver; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.mockito.Mock; + +import java.io.IOException; +import java.io.InputStream; + +public class AbstractPaymentTest { + + @Mock + CountAggregator countAggregator; + @Mock + SumAggregator sumAggregator; + @Mock + UniqueValueAggregator uniqueValueAggregator; + @Mock + CountryResolver countryResolver; + @Mock + InListFinder inListFinder; + + private FieldResolver fieldResolver = new PaymentModelFieldResolver(); + private GroupByModelResolver groupByModelResolver = new GroupByModelResolver<>(fieldResolver); + + ResultModel parseAndVisit(InputStream resourceAsStream) throws IOException { + com.rbkmoney.fraudo.FraudoParser.ParseContext parse = getParseContext(resourceAsStream); + return invokeParse(parse); + } + + ResultModel invokeParse(com.rbkmoney.fraudo.FraudoParser.ParseContext parse) { + PaymentModel model = new PaymentModel(); + return invoke(parse, model); + } + + ResultModel invoke(com.rbkmoney.fraudo.FraudoParser.ParseContext parse, PaymentModel model) { + return (ResultModel) new FastFraudVisitorFactory() + .createVisitor( + countAggregator, + sumAggregator, + uniqueValueAggregator, + countryResolver, + inListFinder, + fieldResolver, + groupByModelResolver) + .visit(parse, model); + } + + com.rbkmoney.fraudo.FraudoParser.ParseContext getParseContext(InputStream resourceAsStream) throws IOException { + com.rbkmoney.fraudo.FraudoLexer lexer = new com.rbkmoney.fraudo.FraudoLexer(new ANTLRInputStream(resourceAsStream)); + com.rbkmoney.fraudo.FraudoParser parser = new com.rbkmoney.fraudo.FraudoParser(new CommonTokenStream(lexer)); + + return parser.parse(); + } + +} diff --git a/src/test/java/com/rbkmoney/fraudo/CountTest.java b/src/test/java/com/rbkmoney/fraudo/CountTest.java index 8b3baed..fbf492d 100644 --- a/src/test/java/com/rbkmoney/fraudo/CountTest.java +++ b/src/test/java/com/rbkmoney/fraudo/CountTest.java @@ -2,10 +2,8 @@ package com.rbkmoney.fraudo; import com.rbkmoney.fraudo.constant.ResultStatus; import com.rbkmoney.fraudo.model.ResultModel; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.InputStream; @@ -14,7 +12,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; -public class CountTest extends AbstractFraudoTest { +public class CountTest extends AbstractPaymentTest { @Before public void init() { diff --git a/src/test/java/com/rbkmoney/fraudo/CustomTest.java b/src/test/java/com/rbkmoney/fraudo/CustomTest.java index bfe1085..93e4e25 100644 --- a/src/test/java/com/rbkmoney/fraudo/CustomTest.java +++ b/src/test/java/com/rbkmoney/fraudo/CustomTest.java @@ -2,7 +2,7 @@ package com.rbkmoney.fraudo; import com.rbkmoney.fraudo.constant.ResultStatus; import com.rbkmoney.fraudo.exception.UnknownResultException; -import com.rbkmoney.fraudo.model.FraudModel; +import com.rbkmoney.fraudo.model.PaymentModel; import com.rbkmoney.fraudo.model.ResultModel; import org.junit.Before; import org.junit.Test; @@ -14,7 +14,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; -public class CustomTest extends AbstractFraudoTest { +public class CustomTest extends AbstractPaymentTest { public static final String TEST_GMAIL_RU = "test@gmail.ru"; @@ -79,7 +79,7 @@ public class CustomTest extends AbstractFraudoTest { public void inTest() throws Exception { InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in.frd"); com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - FraudModel model = new FraudModel(); + PaymentModel model = new PaymentModel(); model.setEmail(TEST_GMAIL_RU); ResultModel result = invoke(parseContext, model); assertEquals(ResultStatus.ACCEPT, result.getResultStatus()); @@ -91,7 +91,7 @@ public class CustomTest extends AbstractFraudoTest { when(countryResolver.resolveCountry(any(), anyString())).thenReturn("RU"); com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - FraudModel model = new FraudModel(); + PaymentModel model = new PaymentModel(); ResultModel result = invoke(parseContext, model); assertEquals(ResultStatus.ACCEPT, result.getResultStatus()); } @@ -100,10 +100,15 @@ public class CustomTest extends AbstractFraudoTest { public void amountTest() throws Exception { InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/amount.frd"); com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - FraudModel model = new FraudModel(); + PaymentModel model = new PaymentModel(); model.setAmount(56L); + model.setCurrency("RUB"); ResultModel result = invoke(parseContext, model); assertEquals(ResultStatus.ACCEPT, result.getResultStatus()); + + model.setCurrency("USD"); + result = invoke(parseContext, model); + assertEquals(ResultStatus.NORMAL, result.getResultStatus()); } @Test @@ -119,7 +124,7 @@ public class CustomTest extends AbstractFraudoTest { public void likeTest() throws Exception { InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/like.frd"); com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - FraudModel model = new FraudModel(); + PaymentModel model = new PaymentModel(); model.setEmail(TEST_GMAIL_RU); model.setBin("553619"); model.setPan("9137"); @@ -135,7 +140,7 @@ public class CustomTest extends AbstractFraudoTest { public void inNotTest() throws Exception { InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in_not.frd"); com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - FraudModel model = new FraudModel(); + PaymentModel model = new PaymentModel(); model.setEmail(TEST_GMAIL_RU); ResultModel result = invoke(parseContext, model); assertEquals(ResultStatus.NORMAL, result.getResultStatus()); diff --git a/src/test/java/com/rbkmoney/fraudo/ListTest.java b/src/test/java/com/rbkmoney/fraudo/ListTest.java index cd36c1a..99482b1 100644 --- a/src/test/java/com/rbkmoney/fraudo/ListTest.java +++ b/src/test/java/com/rbkmoney/fraudo/ListTest.java @@ -1,8 +1,6 @@ package com.rbkmoney.fraudo; import com.rbkmoney.fraudo.constant.ResultStatus; -import com.rbkmoney.fraudo.exception.UnknownResultException; -import com.rbkmoney.fraudo.model.FraudModel; import com.rbkmoney.fraudo.model.ResultModel; import org.junit.Assert; import org.junit.Before; @@ -14,7 +12,7 @@ import java.io.InputStream; import static org.mockito.Matchers.*; -public class ListTest extends AbstractFraudoTest { +public class ListTest extends AbstractPaymentTest { @Before public void init() { @@ -25,13 +23,13 @@ public class ListTest extends AbstractFraudoTest { public void whiteBlackListTest() throws Exception { InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/whitelist.frd"); com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - Mockito.when(whiteListFinder.findInList(anyString(), anyString(), anyList(), anyList())).thenReturn(true); + Mockito.when(inListFinder.findInWhiteList(anyList(), anyObject())).thenReturn(true); ResultModel result = invokeParse(parseContext); Assert.assertEquals(ResultStatus.DECLINE, result.getResultStatus()); resourceAsStream = ListTest.class.getResourceAsStream("/rules/blacklist.frd"); parseContext = getParseContext(resourceAsStream); - Mockito.when(blackListFinder.findInList(anyString(), anyString(), anyList(), anyList())).thenReturn(true); + Mockito.when(inListFinder.findInBlackList(anyList(), anyObject())).thenReturn(true); result = invokeParse(parseContext); Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus()); Assert.assertEquals(1, result.getNotificationsRule().size()); @@ -41,7 +39,16 @@ public class ListTest extends AbstractFraudoTest { public void greyListTest() throws Exception { InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/greyList.frd"); com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - Mockito.when(greyListFinder.findInList(anyString(), anyString(), anyList(), anyList())).thenReturn(true); + Mockito.when(inListFinder.findInGreyList(anyList(), anyObject())).thenReturn(true); + ResultModel result = invokeParse(parseContext); + Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus()); + } + + @Test + public void namingListTest() throws Exception { + InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/namingList.frd"); + com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); + Mockito.when(inListFinder.findInList(anyString(), anyList(), anyObject())).thenReturn(true); ResultModel result = invokeParse(parseContext); Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus()); } diff --git a/src/test/java/com/rbkmoney/fraudo/P2PTest.java b/src/test/java/com/rbkmoney/fraudo/P2PTest.java new file mode 100644 index 0000000..f2339a2 --- /dev/null +++ b/src/test/java/com/rbkmoney/fraudo/P2PTest.java @@ -0,0 +1,101 @@ +package com.rbkmoney.fraudo; + +import com.rbkmoney.fraudo.constant.ResultStatus; +import com.rbkmoney.fraudo.model.P2PModel; +import com.rbkmoney.fraudo.model.ResultModel; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; + +import java.io.InputStream; +import java.util.concurrent.CountDownLatch; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.when; + +public class P2PTest extends AbstractP2PTest { + + public static final long TIME_CALL_AGGR_FUNC = 200L; + public static final long MILLISTIME_FAST_FUNC = 10L; + public static final long TIME_CALLING = 200L; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void timingTest() throws Exception { + InputStream resourceAsStream = P2PTest.class.getResourceAsStream("/rules/p2p_template.frd"); + CountDownLatch countDownLatch = new CountDownLatch(1); + mockAggr(countDownLatch); + + com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); + + P2PModel model = new P2PModel(); + model.setAmount(MILLISTIME_FAST_FUNC); + model.setBin("444443"); + model.setCardTokenFrom("13213"); + + long start = System.currentTimeMillis(); + ResultModel result = invoke(parseContext, model); + long executionTime = System.currentTimeMillis() - start; + assertEquals(ResultStatus.NORMAL, result.getResultStatus()); + assertEquals(0, countDownLatch.getCount()); + assertTrue(executionTime < TIME_CALL_AGGR_FUNC + 1 + TIME_CALLING); + + System.out.println("executionTime=" + executionTime); + } + + private void mockAggr(CountDownLatch countDownLatch) { + when(countAggregator.count(any(), any(), any(), any())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(TIME_CALL_AGGR_FUNC); + countDownLatch.countDown(); + return 1; + }); + when(countAggregator.countSuccess(any(), any(), any(), any())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(TIME_CALL_AGGR_FUNC); + countDownLatch.countDown(); + return 1; + }); + + when(sumAggregator.sum(any(), any(), any(), any())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(TIME_CALL_AGGR_FUNC); + return 10000.0; + }); + when(sumAggregator.sumSuccess(any(), any(), any(), any())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(TIME_CALL_AGGR_FUNC); + return 10000.0; + }); + + when(listFinder.findInBlackList(anyList(), anyObject())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(MILLISTIME_FAST_FUNC); + return false; + }); + when(listFinder.findInWhiteList(anyList(), anyObject())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(MILLISTIME_FAST_FUNC); + return false; + }); + when(listFinder.findInGreyList(anyList(), anyObject())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(MILLISTIME_FAST_FUNC); + return false; + }); + when(listFinder.findInList(anyString(), anyList(), anyObject())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(MILLISTIME_FAST_FUNC); + return false; + }); + when(countryResolver.resolveCountry(anyObject(), anyString())) + .thenAnswer((Answer) invocationOnMock -> "RUS"); + } +} diff --git a/src/test/java/com/rbkmoney/fraudo/RealTimerTest.java b/src/test/java/com/rbkmoney/fraudo/RealTimerTest.java index d12bb45..424edac 100644 --- a/src/test/java/com/rbkmoney/fraudo/RealTimerTest.java +++ b/src/test/java/com/rbkmoney/fraudo/RealTimerTest.java @@ -1,7 +1,7 @@ package com.rbkmoney.fraudo; import com.rbkmoney.fraudo.constant.ResultStatus; -import com.rbkmoney.fraudo.model.FraudModel; +import com.rbkmoney.fraudo.model.PaymentModel; import com.rbkmoney.fraudo.model.ResultModel; import org.junit.Before; import org.junit.Test; @@ -16,7 +16,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.*; import static org.mockito.Mockito.when; -public class RealTimerTest extends AbstractFraudoTest { +public class RealTimerTest extends AbstractPaymentTest { public static final long TIME_CALL_AGGR_FUNC = 200L; public static final long MILLISTIME_FAST_FUNC = 10L; @@ -29,13 +29,13 @@ public class RealTimerTest extends AbstractFraudoTest { @Test public void timingTest() throws Exception { - InputStream resourceAsStream = RealTimerTest.class.getResourceAsStream("/rules/real_template.frd"); + InputStream resourceAsStream = RealTimerTest.class.getResourceAsStream("/rules/payment_template.frd"); CountDownLatch countDownLatch = new CountDownLatch(1); mockAggr(countDownLatch); com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - FraudModel model = new FraudModel(); + PaymentModel model = new PaymentModel(); model.setAmount(MILLISTIME_FAST_FUNC); model.setBin("444443"); @@ -57,7 +57,7 @@ public class RealTimerTest extends AbstractFraudoTest { com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream); - FraudModel model = new FraudModel(); + PaymentModel model = new PaymentModel(); model.setAmount(MILLISTIME_FAST_FUNC); model.setBin("444443"); @@ -79,71 +79,40 @@ public class RealTimerTest extends AbstractFraudoTest { countDownLatch.countDown(); return 1; }); - when(countAggregator.count(any(), any(), any())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(TIME_CALL_AGGR_FUNC); - countDownLatch.countDown(); - return 1; - }); when(countAggregator.countSuccess(any(), any(), any(), any())) .thenAnswer((Answer) invocationOnMock -> { Thread.sleep(TIME_CALL_AGGR_FUNC); countDownLatch.countDown(); return 1; }); - when(countAggregator.countSuccess(any(), any(), any())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(TIME_CALL_AGGR_FUNC); - countDownLatch.countDown(); - return 1; - }); when(sumAggregator.sum(any(), any(), any(), any())) .thenAnswer((Answer) invocationOnMock -> { Thread.sleep(TIME_CALL_AGGR_FUNC); return 10000.0; }); - when(sumAggregator.sum(any(), any(), any())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(TIME_CALL_AGGR_FUNC); - return 10000.0; - }); when(sumAggregator.sumSuccess(any(), any(), any(), any())) .thenAnswer((Answer) invocationOnMock -> { Thread.sleep(TIME_CALL_AGGR_FUNC); return 10000.0; }); - when(sumAggregator.sumSuccess(any(), any(), any())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(TIME_CALL_AGGR_FUNC); - return 10000.0; + + when(inListFinder.findInWhiteList(anyList(), anyObject())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(MILLISTIME_FAST_FUNC); + return false; + }); + when(inListFinder.findInGreyList(anyList(), anyObject())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(MILLISTIME_FAST_FUNC); + return false; + }); + when(inListFinder.findInBlackList(anyList(), anyObject())) + .thenAnswer((Answer) invocationOnMock -> { + Thread.sleep(MILLISTIME_FAST_FUNC); + return false; }); - when(whiteListFinder.findInList(anyString(), anyString(), anyList(), anyList())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(MILLISTIME_FAST_FUNC); - return false; - }); - when(greyListFinder.findInList(anyString(), anyString(), anyList(), anyList())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(MILLISTIME_FAST_FUNC); - return false; - }); - when(greyListFinder.findInList(anyString(), anyString(), anyObject(), anyString())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(MILLISTIME_FAST_FUNC); - return false; - }); - when(blackListFinder.findInList(anyString(), anyString(), anyObject(), anyString())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(MILLISTIME_FAST_FUNC); - return false; - }); - when(blackListFinder.findInList(anyString(), anyString(), anyList(), anyList())) - .thenAnswer((Answer) invocationOnMock -> { - Thread.sleep(MILLISTIME_FAST_FUNC); - return false; - }); when(countryResolver.resolveCountry(anyObject(), anyString())) .thenAnswer((Answer) invocationOnMock -> "RUS"); } diff --git a/src/test/java/com/rbkmoney/fraudo/SumTest.java b/src/test/java/com/rbkmoney/fraudo/SumTest.java index fa22c4d..b34cf40 100644 --- a/src/test/java/com/rbkmoney/fraudo/SumTest.java +++ b/src/test/java/com/rbkmoney/fraudo/SumTest.java @@ -1,8 +1,6 @@ package com.rbkmoney.fraudo; import com.rbkmoney.fraudo.constant.ResultStatus; -import com.rbkmoney.fraudo.exception.UnknownResultException; -import com.rbkmoney.fraudo.model.FraudModel; import com.rbkmoney.fraudo.model.ResultModel; import org.junit.Assert; import org.junit.Before; @@ -14,7 +12,7 @@ import java.io.InputStream; import static org.mockito.Matchers.*; -public class SumTest extends AbstractFraudoTest { +public class SumTest extends AbstractPaymentTest { @Before public void init() { diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml new file mode 100755 index 0000000..63609dd --- /dev/null +++ b/src/test/resources/logback-test.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/rules/amount.frd b/src/test/resources/rules/amount.frd index da7a528..35d7d1d 100644 --- a/src/test/resources/rules/amount.frd +++ b/src/test/resources/rules/amount.frd @@ -1,2 +1,2 @@ -rule: amount() < 100 +rule: amount() < 100 AND currency() == "RUB" -> accept; \ No newline at end of file diff --git a/src/test/resources/rules/namingList.frd b/src/test/resources/rules/namingList.frd new file mode 100644 index 0000000..adc4abd --- /dev/null +++ b/src/test/resources/rules/namingList.frd @@ -0,0 +1,2 @@ +rule: inList("test", "email") +-> accept; \ No newline at end of file diff --git a/src/test/resources/rules/p2p_template.frd b/src/test/resources/rules/p2p_template.frd new file mode 100644 index 0000000..200c04c --- /dev/null +++ b/src/test/resources/rules/p2p_template.frd @@ -0,0 +1,12 @@ +rule:amount_limit70k:amount()>5000->decline; +rule:grey:inGreyList("card_token_from","email")->accept; +rule:white:inWhiteList("email","fingerprint","card_token_from","bin","ip")->accept; +rule:black:inBlackList("email","fingerprint","card_token_from","bin","ip")->decline; +rule:tur_bk:in("bin","444444") AND amount()<77000 ->accept; +rule:tur_bin2:in("bin","444444") AND count("card_token_from",1440,"party_id")<12->accept; +rule:bad_countries:in(countryBy("country_bank"),"AUS")->decline; +rule:amount_country801R:amount()>8100 AND in(countryBy("country_bank"),"HND")->decline; +rule:amount_country2100R:amount()>12000 AND in(countryBy("country_bank"),"RUS")->decline; +rule:amount_country3500R:amount()>31000 AND in(countryBy("country_bank"),"PER","BRA")->decline; +rule:tur_low:count("card_token_from",1440,"party_id")<21 AND amount()<33000 AND in(countryBy("country_bank"),"UZB")->accept; +rule:cards_test_count_3:unique("fingerprint","card_token_from",1440)>3 AND not in(countryBy("country_bank"),"UZB")->decline; \ No newline at end of file diff --git a/src/test/resources/rules/real_template.frd b/src/test/resources/rules/payment_template.frd similarity index 100% rename from src/test/resources/rules/real_template.frd rename to src/test/resources/rules/payment_template.frd