From 5b70d04d60b3d1045a257134e21b6a640ec1053a Mon Sep 17 00:00:00 2001 From: mr-impossibru <64555470+mr-impossibru@users.noreply.github.com> Date: Wed, 10 Nov 2021 12:20:09 +0300 Subject: [PATCH] ft/JD-741: add isTrusted() with conditions templates (#41) * JD-741: add isTrusted() with conditions lists * JD-741: fix typo DELIMETER -> DELIMITER * JD-741: remove unused dependencies, bump junit4 --- build_utils | 2 +- pom.xml | 40 +------- .../antlr4/com.rbkmoney.fraudo/FraudoP2P.g4 | 4 +- .../com.rbkmoney.fraudo/FraudoPayment.g4 | 36 ++++++- src/main/antlr4/imports/Fraudo.g4 | 20 ++-- .../converter/TrustConditionConverter.java | 42 ++++++++ .../rbkmoney/fraudo/model/TrustCondition.java | 15 +++ .../factory/FraudVisitorFactoryImpl.java | 25 ++++- .../factory/FullVisitorFactoryImpl.java | 17 +++- .../resolver/CustomerTypeResolver.java | 6 ++ .../payment/visitor/CustomFuncVisitor.java | 2 - .../payment/visitor/IsTrustedFuncVisitor.java | 13 +++ .../visitor/impl/CustomFuncVisitorImpl.java | 6 -- .../visitor/impl/FirstFindVisitorImpl.java | 34 ++++++- .../payment/visitor/impl/FullVisitorImpl.java | 15 ++- .../impl/IsTrustedFuncVisitorImpl.java | 26 +++++ .../com/rbkmoney/fraudo/utils/TextUtil.java | 6 ++ .../java/com/rbkmoney/fraudo/CustomTest.java | 11 --- .../com/rbkmoney/fraudo/IsTrustedTest.java | 98 +++++++++++++++++++ .../com/rbkmoney/fraudo/RealTimerTest.java | 5 +- ...th_payments_and_withdrawals_conditions.frd | 10 ++ ...ents_and_withdrawals_single_conditions.frd | 8 ++ .../is_trusted_with_payments_conditions.frd | 6 ++ ...is_trusted_with_withdrawals_conditions.frd | 6 ++ 24 files changed, 368 insertions(+), 85 deletions(-) create mode 100644 src/main/java/com/rbkmoney/fraudo/converter/TrustConditionConverter.java create mode 100644 src/main/java/com/rbkmoney/fraudo/model/TrustCondition.java create mode 100644 src/main/java/com/rbkmoney/fraudo/payment/visitor/IsTrustedFuncVisitor.java create mode 100644 src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/IsTrustedFuncVisitorImpl.java create mode 100644 src/test/java/com/rbkmoney/fraudo/IsTrustedTest.java create mode 100644 src/test/resources/rules/is_trusted_with_payments_and_withdrawals_conditions.frd create mode 100644 src/test/resources/rules/is_trusted_with_payments_and_withdrawals_single_conditions.frd create mode 100644 src/test/resources/rules/is_trusted_with_payments_conditions.frd create mode 100644 src/test/resources/rules/is_trusted_with_withdrawals_conditions.frd diff --git a/build_utils b/build_utils index 5401838..be44d69 160000 --- a/build_utils +++ b/build_utils @@ -1 +1 @@ -Subproject commit 540183862bc9fd04682e226de2056a320fd44be9 +Subproject commit be44d69fc87b22a0bb82d98d6eae7658d1647f98 diff --git a/pom.xml b/pom.xml index 91fc104..4f55f64 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ fraudo - 0.0.22 + 0.0.23 Fraudo Language for describing antifraud patterns @@ -33,15 +33,14 @@ - 2.0.0.0 - ${project.basedir}/../target/jacoco.exec + 4.7.1 org.antlr antlr4-runtime - 4.7.1 + ${antlr4.version} org.projectlombok @@ -60,13 +59,7 @@ junit junit - 4.13.1 - test - - - org.hamcrest - hamcrest-junit - ${hamcrest.junit.version} + 4.13.2 test @@ -88,7 +81,7 @@ org.antlr antlr4-maven-plugin - 4.7.1 + ${antlr4.version} -package @@ -106,29 +99,6 @@ - - - org.jacoco - jacoco-maven-plugin - 0.8.4 - - ${sonar.jacoco.reportPath} - true - - com/rbkmoney/fraudo/constant/**/* - com/rbkmoney/fraudo/model/**/* - - - - - agent - - prepare-agent - - - - - diff --git a/src/main/antlr4/com.rbkmoney.fraudo/FraudoP2P.g4 b/src/main/antlr4/com.rbkmoney.fraudo/FraudoP2P.g4 index 39a6399..277787c 100644 --- a/src/main/antlr4/com.rbkmoney.fraudo/FraudoP2P.g4 +++ b/src/main/antlr4/com.rbkmoney.fraudo/FraudoP2P.g4 @@ -56,5 +56,5 @@ floatExpression ; in - : 'in' LPAREN (stringExpression) DELIMETER string_list RPAREN - ; \ No newline at end of file + : 'in' LPAREN (stringExpression) DELIMITER string_list RPAREN + ; diff --git a/src/main/antlr4/com.rbkmoney.fraudo/FraudoPayment.g4 b/src/main/antlr4/com.rbkmoney.fraudo/FraudoPayment.g4 index 6fdfce9..012c9e2 100644 --- a/src/main/antlr4/com.rbkmoney.fraudo/FraudoPayment.g4 +++ b/src/main/antlr4/com.rbkmoney.fraudo/FraudoPayment.g4 @@ -71,7 +71,7 @@ count_success ; count_error - : 'countError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN + : 'countError' LPAREN STRING time_window DELIMITER STRING (group_by)? RPAREN ; count_chargeback @@ -87,7 +87,7 @@ sum_success ; sum_error - : 'sumError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN + : 'sumError' LPAREN STRING time_window DELIMITER STRING (group_by)? RPAREN ; sum_chargeback @@ -99,7 +99,7 @@ sum_refund ; in - : 'in' LPAREN (stringExpression) DELIMETER string_list RPAREN + : 'in' LPAREN (stringExpression) DELIMITER string_list RPAREN ; is_mobile @@ -111,5 +111,33 @@ is_recurrent ; is_trusted - : 'isTrusted' LPAREN RPAREN + : 'isTrusted' LPAREN RPAREN #isTrusted + | 'isTrusted' LPAREN (payment_conditions | withdrawal_conditions) RPAREN #isTrustedConditionsSingleList + | 'isTrusted' LPAREN payment_conditions DELIMITER withdrawal_conditions RPAREN #isTrustedPaymentsAndWithdrawalConditions + ; + +payment_conditions + : 'paymentsConditions' LPAREN conditions_list RPAREN + ; + +withdrawal_conditions + : 'withdrawalsConditions' LPAREN conditions_list RPAREN + ; + +conditions_list + : trusted_token_condition (DELIMITER trusted_token_condition | WS)* + ; + +trusted_token_condition + : 'condition' LPAREN + STRING DELIMITER //transactions_currency + INTEGER DELIMITER //transactions_years_offset + INTEGER DELIMITER //transactions_count + INTEGER //transactions_sum + RPAREN + | 'condition' LPAREN + STRING DELIMITER //transactions_currency + INTEGER DELIMITER //transactions_years_offset + INTEGER //transactions_count + RPAREN ; diff --git a/src/main/antlr4/imports/Fraudo.g4 b/src/main/antlr4/imports/Fraudo.g4 index df91aee..238c019 100644 --- a/src/main/antlr4/imports/Fraudo.g4 +++ b/src/main/antlr4/imports/Fraudo.g4 @@ -49,11 +49,11 @@ sum ; unique - : 'unique' LPAREN STRING DELIMETER STRING time_window (group_by)? RPAREN + : 'unique' LPAREN STRING DELIMITER STRING time_window (group_by)? RPAREN ; in - : 'in' LPAREN (country_by | STRING) DELIMETER string_list RPAREN + : 'in' LPAREN (country_by | STRING) DELIMITER string_list RPAREN ; in_white_list @@ -69,11 +69,11 @@ in_grey_list ; in_list - : 'inList' LPAREN STRING DELIMETER string_list RPAREN + : 'inList' LPAREN STRING DELIMITER string_list RPAREN ; like - : 'like' LPAREN STRING DELIMETER STRING RPAREN + : 'like' LPAREN STRING DELIMITER STRING RPAREN ; country_by @@ -98,22 +98,22 @@ catch_result ; string_list - : STRING (DELIMETER STRING | WS)* + : STRING (DELIMITER STRING | WS)* ; time_window - : DELIMETER INTEGER | DELIMETER INTEGER DELIMETER INTEGER + : DELIMITER INTEGER | DELIMITER INTEGER DELIMITER INTEGER ; group_by - : DELIMETER string_list + : DELIMITER string_list ; STRING : '"' (~["\r\n] | '""')* '"' ; -DELIMETER : ',' ; +DELIMITER : ',' ; COMMENT : '#' ~[\r\n]* -> skip @@ -138,6 +138,6 @@ RPAREN : ')' ; DECIMAL : '-'? ('0'..'9')+ '.' ('0'..'9')+; INTEGER : '-'? ('0'..'9')+; IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ; -WS : [ \u000C\n]+ -> skip; +WS : [ \u000C\t\n]+ -> skip; SCOL : ';'; -BOOLEAN : TRUE | FALSE; \ No newline at end of file +BOOLEAN : TRUE | FALSE; diff --git a/src/main/java/com/rbkmoney/fraudo/converter/TrustConditionConverter.java b/src/main/java/com/rbkmoney/fraudo/converter/TrustConditionConverter.java new file mode 100644 index 0000000..abbec4c --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/converter/TrustConditionConverter.java @@ -0,0 +1,42 @@ +package com.rbkmoney.fraudo.converter; + +import com.rbkmoney.fraudo.FraudoPaymentParser; +import com.rbkmoney.fraudo.model.TrustCondition; +import lombok.RequiredArgsConstructor; +import org.antlr.v4.runtime.tree.TerminalNode; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.rbkmoney.fraudo.utils.TextUtil.safeGetInteger; +import static com.rbkmoney.fraudo.utils.TextUtil.safeGetText; + +@RequiredArgsConstructor +public class TrustConditionConverter { + + private static final int YEARS_OFFSET_INDEX = 0; + private static final int COUNT_INDEX = 1; + private static final int SUM_INDEX = 2; + + public List convertToList(FraudoPaymentParser.Conditions_listContext conditionsListContext) { + return conditionsListContext.trusted_token_condition().stream() + .map(this::convert) + .collect(Collectors.toList()); + } + + public TrustCondition convert(FraudoPaymentParser.Trusted_token_conditionContext ctx) { + List intNodes = ctx.INTEGER(); + return TrustCondition.builder() + .transactionsCurrency(safeGetText(ctx.STRING())) + .transactionsYearsOffset(safeGetInteger(intNodes.get(YEARS_OFFSET_INDEX))) + .transactionsCount(safeGetInteger(intNodes.get(COUNT_INDEX))) + .transactionsSum( + hasSumArgument(intNodes.size()) ? safeGetInteger(intNodes.get(SUM_INDEX)) : null) + .build(); + } + + private boolean hasSumArgument(int intNodesSize) { + return intNodesSize > SUM_INDEX; + } + +} diff --git a/src/main/java/com/rbkmoney/fraudo/model/TrustCondition.java b/src/main/java/com/rbkmoney/fraudo/model/TrustCondition.java new file mode 100644 index 0000000..267abfd --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/model/TrustCondition.java @@ -0,0 +1,15 @@ +package com.rbkmoney.fraudo.model; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class TrustCondition { + + private String transactionsCurrency; + private Integer transactionsYearsOffset; + private Integer transactionsSum; + private Integer transactionsCount; + +} diff --git a/src/main/java/com/rbkmoney/fraudo/payment/factory/FraudVisitorFactoryImpl.java b/src/main/java/com/rbkmoney/fraudo/payment/factory/FraudVisitorFactoryImpl.java index 435994b..87a89b6 100644 --- a/src/main/java/com/rbkmoney/fraudo/payment/factory/FraudVisitorFactoryImpl.java +++ b/src/main/java/com/rbkmoney/fraudo/payment/factory/FraudVisitorFactoryImpl.java @@ -1,6 +1,7 @@ package com.rbkmoney.fraudo.payment.factory; import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; +import com.rbkmoney.fraudo.converter.TrustConditionConverter; import com.rbkmoney.fraudo.finder.InListFinder; import com.rbkmoney.fraudo.model.BaseModel; import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator; @@ -11,6 +12,7 @@ import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver; import com.rbkmoney.fraudo.payment.resolver.PaymentTypeResolver; import com.rbkmoney.fraudo.payment.visitor.CountVisitor; import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor; +import com.rbkmoney.fraudo.payment.visitor.IsTrustedFuncVisitor; import com.rbkmoney.fraudo.payment.visitor.ListVisitor; import com.rbkmoney.fraudo.payment.visitor.SumVisitor; import com.rbkmoney.fraudo.payment.visitor.impl.*; @@ -31,8 +33,10 @@ public class FraudVisitorFactoryImpl implements FraudVisitorFactory { PaymentTimeWindowResolver timeWindowResolver, PaymentTypeResolver paymentTypeResolver, CustomerTypeResolver customerTypeResolver) { - CountVisitor countVisitor = new CountVisitorImpl<>(countPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver); - SumVisitor sumVisitor = new SumVisitorImpl<>(sumPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver); + CountVisitor countVisitor = + new CountVisitorImpl<>(countPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver); + SumVisitor sumVisitor = + new SumVisitorImpl<>(sumPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver); ListVisitor listVisitor = new ListVisitorImpl<>(listFinder, fieldResolver); CustomFuncVisitor customFuncVisitor = new CustomFuncVisitorImpl<>( uniqueValueAggregator, @@ -40,9 +44,20 @@ public class FraudVisitorFactoryImpl implements FraudVisitorFactory { fieldResolver, paymentGroupResolver, timeWindowResolver, - paymentTypeResolver, - customerTypeResolver); - return new FirstFindVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver); + paymentTypeResolver + ); + IsTrustedFuncVisitor isTrustedFuncVisitor = new IsTrustedFuncVisitorImpl<>(customerTypeResolver); + TrustConditionConverter trustConditionConverter = new TrustConditionConverter(); + + return new FirstFindVisitorImpl<>( + countVisitor, + sumVisitor, + listVisitor, + customFuncVisitor, + isTrustedFuncVisitor, + fieldResolver, + trustConditionConverter + ); } } diff --git a/src/main/java/com/rbkmoney/fraudo/payment/factory/FullVisitorFactoryImpl.java b/src/main/java/com/rbkmoney/fraudo/payment/factory/FullVisitorFactoryImpl.java index ebd03db..4370dea 100644 --- a/src/main/java/com/rbkmoney/fraudo/payment/factory/FullVisitorFactoryImpl.java +++ b/src/main/java/com/rbkmoney/fraudo/payment/factory/FullVisitorFactoryImpl.java @@ -1,6 +1,7 @@ package com.rbkmoney.fraudo.payment.factory; import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator; +import com.rbkmoney.fraudo.converter.TrustConditionConverter; import com.rbkmoney.fraudo.finder.InListFinder; import com.rbkmoney.fraudo.model.BaseModel; import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator; @@ -11,6 +12,7 @@ import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver; import com.rbkmoney.fraudo.payment.resolver.PaymentTypeResolver; import com.rbkmoney.fraudo.payment.visitor.CountVisitor; import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor; +import com.rbkmoney.fraudo.payment.visitor.IsTrustedFuncVisitor; import com.rbkmoney.fraudo.payment.visitor.ListVisitor; import com.rbkmoney.fraudo.payment.visitor.SumVisitor; import com.rbkmoney.fraudo.payment.visitor.impl.*; @@ -34,15 +36,24 @@ public class FullVisitorFactoryImpl implements FraudVisitorFactory { CountVisitor countVisitor = new CountVisitorImpl<>(countPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver); SumVisitor sumVisitor = new SumVisitorImpl<>(sumPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver); ListVisitor listVisitor = new ListVisitorImpl<>(listFinder, fieldResolver); + IsTrustedFuncVisitor isTrustedFuncVisitor = new IsTrustedFuncVisitorImpl<>(customerTypeResolver); + TrustConditionConverter trustConditionConverter = new TrustConditionConverter(); CustomFuncVisitor customFuncVisitor = new CustomFuncVisitorImpl<>( uniqueValueAggregator, countryResolver, fieldResolver, paymentGroupResolver, timeWindowResolver, - paymentTypeResolver, - customerTypeResolver); - return new FullVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver); + paymentTypeResolver); + return new FullVisitorImpl<>( + countVisitor, + sumVisitor, + listVisitor, + customFuncVisitor, + isTrustedFuncVisitor, + fieldResolver, + trustConditionConverter + ); } } diff --git a/src/main/java/com/rbkmoney/fraudo/payment/resolver/CustomerTypeResolver.java b/src/main/java/com/rbkmoney/fraudo/payment/resolver/CustomerTypeResolver.java index 51379bc..42ea7b0 100644 --- a/src/main/java/com/rbkmoney/fraudo/payment/resolver/CustomerTypeResolver.java +++ b/src/main/java/com/rbkmoney/fraudo/payment/resolver/CustomerTypeResolver.java @@ -1,7 +1,13 @@ package com.rbkmoney.fraudo.payment.resolver; +import com.rbkmoney.fraudo.model.TrustCondition; + +import java.util.List; + public interface CustomerTypeResolver { Boolean isTrusted(T model); + Boolean isTrusted(List paymentsConditions, List withdrawalsConditions); + } diff --git a/src/main/java/com/rbkmoney/fraudo/payment/visitor/CustomFuncVisitor.java b/src/main/java/com/rbkmoney/fraudo/payment/visitor/CustomFuncVisitor.java index a44b00e..77558cb 100644 --- a/src/main/java/com/rbkmoney/fraudo/payment/visitor/CustomFuncVisitor.java +++ b/src/main/java/com/rbkmoney/fraudo/payment/visitor/CustomFuncVisitor.java @@ -14,6 +14,4 @@ public interface CustomFuncVisitor { boolean visitCheckRecurrent(Is_recurrentContext ctx, T model); - boolean visitCheckTrusted(Is_trustedContext ctx, T model); - } diff --git a/src/main/java/com/rbkmoney/fraudo/payment/visitor/IsTrustedFuncVisitor.java b/src/main/java/com/rbkmoney/fraudo/payment/visitor/IsTrustedFuncVisitor.java new file mode 100644 index 0000000..08a543f --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/payment/visitor/IsTrustedFuncVisitor.java @@ -0,0 +1,13 @@ +package com.rbkmoney.fraudo.payment.visitor; + +import com.rbkmoney.fraudo.model.TrustCondition; + +import java.util.List; + +public interface IsTrustedFuncVisitor { + + boolean visitCheckTrusted(T model); + + boolean visitCheckTrusted(List paymentsConditionsList, + List withdrawalConditionsList); +} diff --git a/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/CustomFuncVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/CustomFuncVisitorImpl.java index 45d3bcc..f7868cf 100644 --- a/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/CustomFuncVisitorImpl.java +++ b/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/CustomFuncVisitorImpl.java @@ -23,7 +23,6 @@ public class CustomFuncVisitorImpl implements CustomFuncVisitor { private final PaymentGroupResolver groupResolver; private final PaymentTimeWindowResolver timeWindowResolver; private final PaymentTypeResolver paymentTypeResolver; - private final CustomerTypeResolver customerTypeResolver; @Override public String visitCountryBy(Country_byContext ctx, T model) { @@ -63,9 +62,4 @@ public class CustomFuncVisitorImpl implements CustomFuncVisitor { return paymentTypeResolver.isRecurrent(model); } - @Override - public boolean visitCheckTrusted(Is_trustedContext ctx, T model) { - return customerTypeResolver.isTrusted(model); - } - } diff --git a/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/FirstFindVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/FirstFindVisitorImpl.java index bb9105c..42e2191 100644 --- a/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/FirstFindVisitorImpl.java +++ b/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/FirstFindVisitorImpl.java @@ -2,15 +2,18 @@ package com.rbkmoney.fraudo.payment.visitor.impl; import com.rbkmoney.fraudo.FraudoPaymentBaseVisitor; import com.rbkmoney.fraudo.constant.ResultStatus; +import com.rbkmoney.fraudo.converter.TrustConditionConverter; 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.model.RuleResult; +import com.rbkmoney.fraudo.model.TrustCondition; import com.rbkmoney.fraudo.payment.generator.RuleKeyGenerator; import com.rbkmoney.fraudo.payment.visitor.CountVisitor; import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor; +import com.rbkmoney.fraudo.payment.visitor.IsTrustedFuncVisitor; import com.rbkmoney.fraudo.payment.visitor.ListVisitor; import com.rbkmoney.fraudo.payment.visitor.SumVisitor; import com.rbkmoney.fraudo.resolver.FieldResolver; @@ -42,7 +45,9 @@ public class FirstFindVisitorImpl extends FraudoPaymentB private final SumVisitor sumVisitor; private final ListVisitor listVisitor; private final CustomFuncVisitor customFuncVisitor; + private final IsTrustedFuncVisitor isTrustedFuncVisitor; private final FieldResolver fieldResolver; + private final TrustConditionConverter trustConditionConverter; @Override public void close() { @@ -376,7 +381,32 @@ public class FirstFindVisitorImpl extends FraudoPaymentB } @Override - public Boolean visitIs_trusted(Is_trustedContext ctx) { - return customFuncVisitor.visitCheckTrusted(ctx, threadLocalModel.get()); + public Object visitIsTrusted(IsTrustedContext ctx) { + return isTrustedFuncVisitor.visitCheckTrusted(threadLocalModel.get()); } + + @Override + public Object visitIsTrustedConditionsSingleList(IsTrustedConditionsSingleListContext ctx) { + if (ctx.payment_conditions() != null && !ctx.payment_conditions().isEmpty()) { + List paymentsConditions = + trustConditionConverter.convertToList(ctx.payment_conditions().conditions_list()); + return isTrustedFuncVisitor.visitCheckTrusted(paymentsConditions, null); + } + if (ctx.withdrawal_conditions() != null && !ctx.withdrawal_conditions().isEmpty()) { + List withdrawalsConditions = + trustConditionConverter.convertToList(ctx.withdrawal_conditions().conditions_list()); + return isTrustedFuncVisitor.visitCheckTrusted(null, withdrawalsConditions); + } + throw new NotValidContextException(); + } + + @Override + public Object visitIsTrustedPaymentsAndWithdrawalConditions(IsTrustedPaymentsAndWithdrawalConditionsContext ctx) { + List paymentsConditions = + trustConditionConverter.convertToList(ctx.payment_conditions().conditions_list()); + List withdrawalsConditions = + trustConditionConverter.convertToList(ctx.withdrawal_conditions().conditions_list()); + return isTrustedFuncVisitor.visitCheckTrusted(paymentsConditions, withdrawalsConditions); + } + } diff --git a/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/FullVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/FullVisitorImpl.java index f029906..baab01b 100644 --- a/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/FullVisitorImpl.java +++ b/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/FullVisitorImpl.java @@ -1,6 +1,7 @@ package com.rbkmoney.fraudo.payment.visitor.impl; import com.rbkmoney.fraudo.constant.ResultStatus; +import com.rbkmoney.fraudo.converter.TrustConditionConverter; import com.rbkmoney.fraudo.exception.UnknownResultException; import com.rbkmoney.fraudo.model.BaseModel; import com.rbkmoney.fraudo.model.ResultModel; @@ -8,6 +9,7 @@ import com.rbkmoney.fraudo.model.RuleResult; import com.rbkmoney.fraudo.payment.generator.RuleKeyGenerator; import com.rbkmoney.fraudo.payment.visitor.CountVisitor; import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor; +import com.rbkmoney.fraudo.payment.visitor.IsTrustedFuncVisitor; import com.rbkmoney.fraudo.payment.visitor.ListVisitor; import com.rbkmoney.fraudo.payment.visitor.SumVisitor; import com.rbkmoney.fraudo.resolver.FieldResolver; @@ -22,8 +24,17 @@ import static com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext; @Slf4j public class FullVisitorImpl extends FirstFindVisitorImpl { - public FullVisitorImpl(CountVisitor countVisitor, SumVisitor sumVisitor, ListVisitor listVisitor, CustomFuncVisitor customFuncVisitor, FieldResolver fieldResolver) { - super(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver); + public FullVisitorImpl( + CountVisitor countVisitor, + SumVisitor sumVisitor, + ListVisitor listVisitor, + CustomFuncVisitor customFuncVisitor, + IsTrustedFuncVisitor isTrustedFuncVisitor, + FieldResolver fieldResolver, + TrustConditionConverter trustConditionConverter + ) { + super(countVisitor, sumVisitor, listVisitor, customFuncVisitor, isTrustedFuncVisitor, fieldResolver, + trustConditionConverter); } @Override diff --git a/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/IsTrustedFuncVisitorImpl.java b/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/IsTrustedFuncVisitorImpl.java new file mode 100644 index 0000000..c3cb506 --- /dev/null +++ b/src/main/java/com/rbkmoney/fraudo/payment/visitor/impl/IsTrustedFuncVisitorImpl.java @@ -0,0 +1,26 @@ +package com.rbkmoney.fraudo.payment.visitor.impl; + +import com.rbkmoney.fraudo.model.TrustCondition; +import com.rbkmoney.fraudo.payment.resolver.CustomerTypeResolver; +import com.rbkmoney.fraudo.payment.visitor.IsTrustedFuncVisitor; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +@RequiredArgsConstructor +public class IsTrustedFuncVisitorImpl implements IsTrustedFuncVisitor { + + private final CustomerTypeResolver customerTypeResolver; + + @Override + public boolean visitCheckTrusted(T model) { + return customerTypeResolver.isTrusted(model); + } + + @Override + public boolean visitCheckTrusted(List paymentsConditionsList, + List withdrawalConditionsList) { + return customerTypeResolver.isTrusted(paymentsConditionsList, withdrawalConditionsList); + } + +} diff --git a/src/main/java/com/rbkmoney/fraudo/utils/TextUtil.java b/src/main/java/com/rbkmoney/fraudo/utils/TextUtil.java index a3160c6..d72bea9 100644 --- a/src/main/java/com/rbkmoney/fraudo/utils/TextUtil.java +++ b/src/main/java/com/rbkmoney/fraudo/utils/TextUtil.java @@ -16,4 +16,10 @@ public class TextUtil { .getText().replace("\"", ""); } + public static Integer safeGetInteger(TerminalNode field) { + return Optional.ofNullable(field) + .map(node -> Integer.parseInt(node.getText())) + .orElseThrow(FieldUnsetException::new); + } + } diff --git a/src/test/java/com/rbkmoney/fraudo/CustomTest.java b/src/test/java/com/rbkmoney/fraudo/CustomTest.java index ed83427..7dee2ae 100644 --- a/src/test/java/com/rbkmoney/fraudo/CustomTest.java +++ b/src/test/java/com/rbkmoney/fraudo/CustomTest.java @@ -134,17 +134,6 @@ public class CustomTest extends AbstractPaymentTest { assertEquals(ResultStatus.ACCEPT, ResultUtils.findFirstNotNotifyStatus(result).get().getResultStatus()); } - @Test - public void trustedTest() throws Exception { - InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/is_trusted.frd"); - when(customerTypeResolver.isTrusted(any())).thenReturn(true); - - ParseContext parseContext = getParseContext(resourceAsStream); - PaymentModel model = new PaymentModel(); - ResultModel result = invoke(parseContext, model); - assertEquals(ResultStatus.ACCEPT, ResultUtils.findFirstNotNotifyStatus(result).get().getResultStatus()); - } - @Test public void payerTypeTest() throws Exception { InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/is_recurrent.frd"); diff --git a/src/test/java/com/rbkmoney/fraudo/IsTrustedTest.java b/src/test/java/com/rbkmoney/fraudo/IsTrustedTest.java new file mode 100644 index 0000000..c38420e --- /dev/null +++ b/src/test/java/com/rbkmoney/fraudo/IsTrustedTest.java @@ -0,0 +1,98 @@ +package com.rbkmoney.fraudo; + +import com.rbkmoney.fraudo.constant.ResultStatus; +import com.rbkmoney.fraudo.model.ResultModel; +import com.rbkmoney.fraudo.model.TrustCondition; +import com.rbkmoney.fraudo.test.model.PaymentModel; +import com.rbkmoney.fraudo.utils.ResultUtils; +import lombok.SneakyThrows; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.MockitoAnnotations; + +import java.io.InputStream; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyListOf; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class IsTrustedTest extends AbstractPaymentTest { + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void trustedTest() { + when(customerTypeResolver.isTrusted(any())).thenReturn(true); + testIsTrusted("/rules/is_trusted.frd"); + } + + @Test + public void trustedWithWithdrawalsConditionsTest() { + when(customerTypeResolver.isTrusted(isNull(List.class), anyListOf(TrustCondition.class))) + .thenReturn(true); + testIsTrusted("/rules/is_trusted_with_withdrawals_conditions.frd"); + } + + @Test + public void trustedWithPaymentsConditionsTest() { + when(customerTypeResolver.isTrusted(anyListOf(TrustCondition.class), isNull(List.class))) + .thenReturn(true); + testIsTrusted("/rules/is_trusted_with_payments_conditions.frd"); + } + + @Test + public void trustedWithPaymentsAndWithdrawalSingleConditionsTest() { + when(customerTypeResolver.isTrusted(anyListOf(TrustCondition.class), anyListOf(TrustCondition.class))) + .thenReturn(true); + testIsTrusted("/rules/is_trusted_with_payments_and_withdrawals_single_conditions.frd"); + } + + @Test + public void trustedWithPaymentsAndWithdrawalTest() { + when(customerTypeResolver.isTrusted(anyListOf(TrustCondition.class), anyListOf(TrustCondition.class))) + .thenReturn(true); + testIsTrusted("/rules/is_trusted_with_payments_and_withdrawals_conditions.frd"); + + ArgumentCaptor> paymentsCaptor = ArgumentCaptor.forClass((Class) List.class); + ArgumentCaptor> withdrawalsCaptor = ArgumentCaptor.forClass((Class) List.class); + verify(customerTypeResolver, times(1)) + .isTrusted(paymentsCaptor.capture(), withdrawalsCaptor.capture()); + + assertEquals(1, paymentsCaptor.getAllValues().size()); + List payments = paymentsCaptor.getValue(); + assertTrustedCondition("RUB",1,1000,10, payments.get(0)); + assertTrustedCondition("EUR", 2, 20, null, payments.get(1)); + assertEquals(1, withdrawalsCaptor.getAllValues().size()); + List withdrawals = withdrawalsCaptor.getValue(); + assertTrustedCondition("USD",3,3000,3, withdrawals.get(0)); + assertTrustedCondition("CAD", 4, 4, null, withdrawals.get(1)); + + } + + @SneakyThrows + private void testIsTrusted(String testCaseFilePath) { + InputStream resourceAsStream = IsTrustedTest.class.getResourceAsStream(testCaseFilePath); + com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext parseContext = getParseContext(resourceAsStream); + PaymentModel model = new PaymentModel(); + ResultModel result = invoke(parseContext, model); + assertEquals(ResultStatus.ACCEPT, ResultUtils.findFirstNotNotifyStatus(result).get().getResultStatus()); + } + + private void assertTrustedCondition( + String currency, Integer yearsOffset, Integer count, Integer sum, TrustCondition condition) { + assertEquals(currency, condition.getTransactionsCurrency()); + assertEquals(yearsOffset, condition.getTransactionsYearsOffset()); + assertEquals(count, condition.getTransactionsCount()); + assertEquals(sum, condition.getTransactionsSum()); + } + +} diff --git a/src/test/java/com/rbkmoney/fraudo/RealTimerTest.java b/src/test/java/com/rbkmoney/fraudo/RealTimerTest.java index 85de71a..5c3689c 100644 --- a/src/test/java/com/rbkmoney/fraudo/RealTimerTest.java +++ b/src/test/java/com/rbkmoney/fraudo/RealTimerTest.java @@ -23,7 +23,7 @@ public class RealTimerTest extends AbstractPaymentTest { public static final long TIME_CALL_AGGR_FUNC = 200L; public static final long MILLISTIME_FAST_FUNC = 10L; - public static final long TIME_CALLING = 200L; + public static final long TIME_CALLING = 300L; @Before public void init() { @@ -50,7 +50,7 @@ public class RealTimerTest extends AbstractPaymentTest { assertEquals(0, countDownLatch.getCount()); assertTrue(executionTime < TIME_CALL_AGGR_FUNC + 1 + TIME_CALLING); - System.out.println("executionTime=" + executionTime); + System.out.println("timingTest.executionTime=" + executionTime); result = invokeFullVisitor(parseContext, model); assertEquals(2, result.getRuleResults().size()); @@ -71,6 +71,7 @@ public class RealTimerTest extends AbstractPaymentTest { long start = System.currentTimeMillis(); ResultModel result = invoke(parseContext, model); long executionTime = System.currentTimeMillis() - start; + System.out.println("timingWithSuccessTest.executionTime=" + executionTime); Assert.assertEquals(ResultStatus.ACCEPT, ResultUtils.findFirstNotNotifyStatus(result).get().getResultStatus()); assertTrue(executionTime < TIME_CALL_AGGR_FUNC * 4 + TIME_CALLING); diff --git a/src/test/resources/rules/is_trusted_with_payments_and_withdrawals_conditions.frd b/src/test/resources/rules/is_trusted_with_payments_and_withdrawals_conditions.frd new file mode 100644 index 0000000..1c82a9d --- /dev/null +++ b/src/test/resources/rules/is_trusted_with_payments_and_withdrawals_conditions.frd @@ -0,0 +1,10 @@ +rule: isTrusted( + paymentsConditions( + condition("RUB",1,1000,10), + condition("EUR", 2, 20) + ), + withdrawalsConditions( + condition("USD",3,3000,3), + condition("CAD", 4, 4) + ) +) -> accept; diff --git a/src/test/resources/rules/is_trusted_with_payments_and_withdrawals_single_conditions.frd b/src/test/resources/rules/is_trusted_with_payments_and_withdrawals_single_conditions.frd new file mode 100644 index 0000000..489d981 --- /dev/null +++ b/src/test/resources/rules/is_trusted_with_payments_and_withdrawals_single_conditions.frd @@ -0,0 +1,8 @@ +rule: isTrusted( + paymentsConditions( + condition("RUB",1,1000,10) + ), + withdrawalsConditions( + condition("CAD", 4, 4) + ) +) -> accept; diff --git a/src/test/resources/rules/is_trusted_with_payments_conditions.frd b/src/test/resources/rules/is_trusted_with_payments_conditions.frd new file mode 100644 index 0000000..f19109b --- /dev/null +++ b/src/test/resources/rules/is_trusted_with_payments_conditions.frd @@ -0,0 +1,6 @@ +rule: isTrusted( + paymentsConditions( + condition("RUB",1,1000,10), + condition("EUR", 2, 20) + ) +) -> accept; diff --git a/src/test/resources/rules/is_trusted_with_withdrawals_conditions.frd b/src/test/resources/rules/is_trusted_with_withdrawals_conditions.frd new file mode 100644 index 0000000..ed7fda1 --- /dev/null +++ b/src/test/resources/rules/is_trusted_with_withdrawals_conditions.frd @@ -0,0 +1,6 @@ +rule: isTrusted( + withdrawalsConditions( + condition("USD",3,3000,3), + condition("CAD", 4, 4) + ) +) -> accept;