mirror of
https://github.com/valitydev/fraudo.git
synced 2024-11-06 01:45:16 +00:00
parent
f85dade3c0
commit
44be6b8481
13
pom.xml
13
pom.xml
@ -11,7 +11,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>fraudo</artifactId>
|
||||
<version>0.0.14</version>
|
||||
<version>0.0.15</version>
|
||||
|
||||
<name>Fraudo</name>
|
||||
<description>Language for describing antifraud patterns</description>
|
||||
@ -33,10 +33,9 @@
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>8</java.version>
|
||||
<dockerfile.base.service.tag>bc95d0d6dc13c693acd2b274531a7d604b877bf3</dockerfile.base.service.tag>
|
||||
<dockerfile.registry>${env.REGISTRY}</dockerfile.registry>
|
||||
<hamcrest.junit.version>2.0.0.0</hamcrest.junit.version>
|
||||
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
|
||||
</properties>
|
||||
@ -79,6 +78,12 @@
|
||||
<version>1.9.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.7.25</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -1,187 +0,0 @@
|
||||
grammar Fraudo;
|
||||
|
||||
parse
|
||||
: fraud_rule* EOF
|
||||
;
|
||||
|
||||
fraud_rule
|
||||
: RULE_BLOCK (IDENTIFIER ':')? expression RETURN result (CATCH_ERROR catch_result)? SCOL
|
||||
;
|
||||
|
||||
expression
|
||||
: LPAREN expression RPAREN #parenExpression
|
||||
| NOT expression #notExpression
|
||||
| left=expression op=comparator right=expression #comparatorExpression
|
||||
| left=expression op=binary right=expression #binaryExpression
|
||||
| bool #boolExpression
|
||||
| count #countExpression
|
||||
| count_success #countSuccessExpression
|
||||
| count_error #countErrorExpression
|
||||
| count_chargeback #countChargebackExpression
|
||||
| count_refund #countRefundExpression
|
||||
| sum #sumExpression
|
||||
| sum_success #sumSuccessExpression
|
||||
| sum_error #sumErrorExpression
|
||||
| sum_chargeback #sumChargebackExpression
|
||||
| sum_refund #sumRefundExpression
|
||||
| unique #uniqueExpression
|
||||
| in #inFunctionExpression
|
||||
| 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
|
||||
;
|
||||
|
||||
comparator
|
||||
: GT | GE | LT | LE | EQ
|
||||
;
|
||||
|
||||
binary
|
||||
: AND | OR
|
||||
;
|
||||
|
||||
bool
|
||||
: TRUE | FALSE
|
||||
;
|
||||
|
||||
amount
|
||||
: 'amount' LPAREN RPAREN
|
||||
;
|
||||
|
||||
currency
|
||||
: 'currency' LPAREN RPAREN
|
||||
;
|
||||
|
||||
count
|
||||
: 'count' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
count_success
|
||||
: 'countSuccess' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
count_error
|
||||
: 'countError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN
|
||||
;
|
||||
|
||||
count_chargeback
|
||||
: 'countChargeback' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
count_refund
|
||||
: 'countRefund' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum
|
||||
: 'sum' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum_success
|
||||
: 'sumSuccess' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum_error
|
||||
: 'sumError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum_chargeback
|
||||
: 'sumChargeback' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum_refund
|
||||
: 'sumRefund' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
unique
|
||||
: 'unique' LPAREN STRING DELIMETER STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
in
|
||||
: 'in' LPAREN (country_by | STRING) DELIMETER string_list RPAREN
|
||||
;
|
||||
|
||||
in_white_list
|
||||
: 'inWhiteList' LPAREN string_list RPAREN
|
||||
;
|
||||
|
||||
in_black_list
|
||||
: 'inBlackList' LPAREN string_list RPAREN
|
||||
;
|
||||
|
||||
in_grey_list
|
||||
: 'inGreyList' LPAREN string_list RPAREN
|
||||
;
|
||||
|
||||
in_list
|
||||
: 'inList' LPAREN STRING DELIMETER string_list RPAREN
|
||||
;
|
||||
|
||||
like
|
||||
: 'like' LPAREN STRING DELIMETER STRING RPAREN
|
||||
;
|
||||
|
||||
country
|
||||
: 'country' LPAREN RPAREN
|
||||
;
|
||||
|
||||
country_by
|
||||
: 'countryBy' LPAREN STRING RPAREN
|
||||
;
|
||||
|
||||
result
|
||||
: 'accept' | '3ds' | 'highRisk' | 'decline' | 'notify'
|
||||
;
|
||||
|
||||
catch_result
|
||||
: 'accept' | '3ds' | 'highRisk' | 'notify'
|
||||
;
|
||||
|
||||
string_list
|
||||
: STRING (DELIMETER STRING | WS)*
|
||||
;
|
||||
|
||||
time_window
|
||||
: DELIMETER DECIMAL | DELIMETER DECIMAL DELIMETER DECIMAL
|
||||
;
|
||||
|
||||
group_by
|
||||
: DELIMETER string_list
|
||||
;
|
||||
|
||||
STRING
|
||||
: '"' (~["\r\n] | '""')* '"'
|
||||
;
|
||||
|
||||
DELIMETER : ',' ;
|
||||
|
||||
COMMENT
|
||||
: '#' ~[\r\n]* -> skip
|
||||
;
|
||||
|
||||
RETURN : '->' ;
|
||||
CATCH_ERROR: 'catch:' ;
|
||||
RULE_BLOCK : 'rule:' ;
|
||||
AND : 'AND' | 'and';
|
||||
OR : 'OR' | 'or' ;
|
||||
NOT : 'NOT' | 'not';
|
||||
TRUE : 'TRUE' | 'true';
|
||||
FALSE : 'FALSE' | 'false';
|
||||
GT : '>' ;
|
||||
GE : '>=' ;
|
||||
LT : '<' ;
|
||||
LE : '<=' ;
|
||||
EQ : '=' ;
|
||||
LPAREN : '(' ;
|
||||
RPAREN : ')' ;
|
||||
DECIMAL : '-'? [0-9]+ ( '.' [0-9]+ )? ;
|
||||
IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ;
|
||||
WS : [ \u000C\n]+ -> skip;
|
||||
SCOL : ';';
|
61
src/main/antlr4/com.rbkmoney.fraudo/FraudoP2P.g4
Normal file
61
src/main/antlr4/com.rbkmoney.fraudo/FraudoP2P.g4
Normal file
@ -0,0 +1,61 @@
|
||||
grammar FraudoP2P;
|
||||
|
||||
import Fraudo;
|
||||
|
||||
//This rule override for run test in idea plugin
|
||||
parse
|
||||
: fraud_rule* EOF
|
||||
;
|
||||
|
||||
expression
|
||||
: booleanAndExpression ( OR booleanAndExpression )*
|
||||
;
|
||||
|
||||
booleanAndExpression
|
||||
: equalityExpression ( AND equalityExpression )*
|
||||
;
|
||||
|
||||
equalityExpression
|
||||
: relationalExpression
|
||||
| stringExpression (EQ | NEQ) stringExpression
|
||||
| NOT expression
|
||||
| LPAREN expression RPAREN
|
||||
;
|
||||
|
||||
stringExpression
|
||||
: country_by
|
||||
| currency
|
||||
| STRING
|
||||
;
|
||||
|
||||
relationalExpression
|
||||
: unaryExpression (LT | LE | GT | GE | EQ | NEQ) unaryExpression
|
||||
| in
|
||||
| in_white_list
|
||||
| in_black_list
|
||||
| in_grey_list
|
||||
| in_list
|
||||
| like
|
||||
;
|
||||
|
||||
unaryExpression
|
||||
: integerExpression
|
||||
| floatExpression
|
||||
;
|
||||
|
||||
integerExpression
|
||||
: count
|
||||
| unique
|
||||
| INTEGER
|
||||
;
|
||||
|
||||
floatExpression
|
||||
: sum
|
||||
| amount
|
||||
| INTEGER
|
||||
| DECIMAL
|
||||
;
|
||||
|
||||
in
|
||||
: 'in' LPAREN (stringExpression) DELIMETER string_list RPAREN
|
||||
;
|
101
src/main/antlr4/com.rbkmoney.fraudo/FraudoPayment.g4
Normal file
101
src/main/antlr4/com.rbkmoney.fraudo/FraudoPayment.g4
Normal file
@ -0,0 +1,101 @@
|
||||
grammar FraudoPayment;
|
||||
|
||||
import Fraudo;
|
||||
|
||||
//This rule override for run test in idea plugin
|
||||
parse
|
||||
: fraud_rule* EOF
|
||||
;
|
||||
|
||||
expression
|
||||
: booleanAndExpression ( OR booleanAndExpression )*
|
||||
;
|
||||
|
||||
booleanAndExpression
|
||||
: equalityExpression ( AND equalityExpression )*
|
||||
;
|
||||
|
||||
equalityExpression
|
||||
: relationalExpression
|
||||
| stringExpression (EQ | NEQ) stringExpression
|
||||
| NOT expression
|
||||
| LPAREN expression RPAREN
|
||||
;
|
||||
|
||||
stringExpression
|
||||
: country_by
|
||||
| currency
|
||||
| STRING
|
||||
;
|
||||
|
||||
relationalExpression
|
||||
: unaryExpression (LT | LE | GT | GE | EQ | NEQ) unaryExpression
|
||||
| in
|
||||
| in_white_list
|
||||
| in_black_list
|
||||
| in_grey_list
|
||||
| in_list
|
||||
| like
|
||||
;
|
||||
|
||||
unaryExpression
|
||||
: integerExpression
|
||||
| floatExpression
|
||||
;
|
||||
|
||||
integerExpression
|
||||
: count
|
||||
| count_success
|
||||
| count_error
|
||||
| count_chargeback
|
||||
| count_refund
|
||||
| unique
|
||||
| INTEGER
|
||||
;
|
||||
|
||||
floatExpression
|
||||
: sum
|
||||
| sum_success
|
||||
| sum_error
|
||||
| sum_chargeback
|
||||
| sum_refund
|
||||
| amount
|
||||
| INTEGER
|
||||
| DECIMAL
|
||||
;
|
||||
|
||||
count_success
|
||||
: 'countSuccess' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
count_error
|
||||
: 'countError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN
|
||||
;
|
||||
|
||||
count_chargeback
|
||||
: 'countChargeback' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
count_refund
|
||||
: 'countRefund' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum_success
|
||||
: 'sumSuccess' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum_error
|
||||
: 'sumError' LPAREN STRING time_window DELIMETER STRING (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum_chargeback
|
||||
: 'sumChargeback' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum_refund
|
||||
: 'sumRefund' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
in
|
||||
: 'in' LPAREN (stringExpression) DELIMETER string_list RPAREN
|
||||
;
|
126
src/main/antlr4/imports/Fraudo.g4
Normal file
126
src/main/antlr4/imports/Fraudo.g4
Normal file
@ -0,0 +1,126 @@
|
||||
grammar Fraudo;
|
||||
|
||||
parse
|
||||
: fraud_rule* EOF
|
||||
;
|
||||
|
||||
fraud_rule
|
||||
: RULE_BLOCK (IDENTIFIER ':')? expression RETURN result (CATCH_ERROR catch_result)? SCOL
|
||||
;
|
||||
|
||||
expression
|
||||
: LPAREN expression RPAREN #parenExpression
|
||||
;
|
||||
|
||||
comparator
|
||||
: GT | GE | LT | LE | EQ
|
||||
;
|
||||
|
||||
binary
|
||||
: AND | OR
|
||||
;
|
||||
|
||||
bool
|
||||
: TRUE | FALSE
|
||||
;
|
||||
|
||||
amount
|
||||
: 'amount' LPAREN RPAREN
|
||||
;
|
||||
|
||||
currency
|
||||
: 'currency' LPAREN RPAREN
|
||||
;
|
||||
|
||||
count
|
||||
: 'count' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
sum
|
||||
: 'sum' LPAREN STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
unique
|
||||
: 'unique' LPAREN STRING DELIMETER STRING time_window (group_by)? RPAREN
|
||||
;
|
||||
|
||||
in
|
||||
: 'in' LPAREN (country_by | STRING) DELIMETER string_list RPAREN
|
||||
;
|
||||
|
||||
in_white_list
|
||||
: 'inWhiteList' LPAREN string_list RPAREN
|
||||
;
|
||||
|
||||
in_black_list
|
||||
: 'inBlackList' LPAREN string_list RPAREN
|
||||
;
|
||||
|
||||
in_grey_list
|
||||
: 'inGreyList' LPAREN string_list RPAREN
|
||||
;
|
||||
|
||||
in_list
|
||||
: 'inList' LPAREN STRING DELIMETER string_list RPAREN
|
||||
;
|
||||
|
||||
like
|
||||
: 'like' LPAREN STRING DELIMETER STRING RPAREN
|
||||
;
|
||||
|
||||
country_by
|
||||
: 'countryBy' LPAREN STRING RPAREN
|
||||
;
|
||||
|
||||
result
|
||||
: 'accept' | '3ds' | 'highRisk' | 'decline' | 'notify'
|
||||
;
|
||||
|
||||
catch_result
|
||||
: 'accept' | '3ds' | 'highRisk' | 'notify'
|
||||
;
|
||||
|
||||
string_list
|
||||
: STRING (DELIMETER STRING | WS)*
|
||||
;
|
||||
|
||||
time_window
|
||||
: DELIMETER INTEGER | DELIMETER INTEGER DELIMETER INTEGER
|
||||
;
|
||||
|
||||
group_by
|
||||
: DELIMETER string_list
|
||||
;
|
||||
|
||||
STRING
|
||||
: '"' (~["\r\n] | '""')* '"'
|
||||
;
|
||||
|
||||
DELIMETER : ',' ;
|
||||
|
||||
COMMENT
|
||||
: '#' ~[\r\n]* -> skip
|
||||
;
|
||||
|
||||
RETURN : '->' ;
|
||||
CATCH_ERROR: 'catch:' ;
|
||||
RULE_BLOCK : 'rule:' ;
|
||||
AND : 'AND' | 'and';
|
||||
OR : 'OR' | 'or' ;
|
||||
NOT : 'NOT' | 'not';
|
||||
TRUE : 'TRUE' | 'true';
|
||||
FALSE : 'FALSE' | 'false';
|
||||
GT : '>' ;
|
||||
GE : '>=' ;
|
||||
LT : '<' ;
|
||||
LE : '<=' ;
|
||||
EQ : '=' ;
|
||||
NEQ : '!=' ;
|
||||
LPAREN : '(' ;
|
||||
RPAREN : ')' ;
|
||||
DECIMAL : '-'? ('0'..'9')+ '.' ('0'..'9')+;
|
||||
INTEGER : '-'? ('0'..'9')+;
|
||||
IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ;
|
||||
WS : [ \u000C\n]+ -> skip;
|
||||
SCOL : ';';
|
||||
BOOLEAN : TRUE | FALSE;
|
@ -8,12 +8,4 @@ public interface CountAggregator<T, U> {
|
||||
|
||||
Integer count(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Integer countSuccess(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Integer countError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List<U> fields);
|
||||
|
||||
Integer countChargeback(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Integer countRefund(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
}
|
||||
|
@ -8,12 +8,4 @@ public interface SumAggregator<T, U> {
|
||||
|
||||
Double sum(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Double sumSuccess(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Double sumError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List<U> fields);
|
||||
|
||||
Double sumChargeback(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Double sumRefund(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
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<String, P2PCheckedField> 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);
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package com.rbkmoney.fraudo.factory;
|
||||
|
||||
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.BaseModel;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
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 FirstFraudVisitorFactory implements FraudVisitorFactory {
|
||||
|
||||
@Override
|
||||
public <T extends BaseModel, U> FirstFindVisitorImpl<T, U> createVisitor(
|
||||
CountAggregator<T, U> countAggregator,
|
||||
SumAggregator<T, U> sumAggregator,
|
||||
UniqueValueAggregator<T, U> uniqueValueAggregator,
|
||||
CountryResolver<U> countryResolver,
|
||||
InListFinder<T, U> listFinder,
|
||||
FieldResolver<T, U> fieldResolver,
|
||||
GroupByModelResolver<T, U> groupByModelResolver) {
|
||||
CountVisitor<T> countVisitor = new CountVisitorImpl<>(countAggregator, fieldResolver, groupByModelResolver);
|
||||
SumVisitor<T> sumVisitor = new SumVisitorImpl<>(sumAggregator, fieldResolver, groupByModelResolver);
|
||||
ListVisitor<T> listVisitor = new ListVisitorImpl<>(listFinder, fieldResolver);
|
||||
CustomFuncVisitor<T> customFuncVisitor = new CustomFuncVisitorImpl<>(
|
||||
uniqueValueAggregator,
|
||||
countryResolver,
|
||||
fieldResolver,
|
||||
groupByModelResolver);
|
||||
return new FirstFindVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver);
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package com.rbkmoney.fraudo.factory;
|
||||
|
||||
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.BaseModel;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
|
||||
import com.rbkmoney.fraudo.visitor.impl.FirstFindVisitorImpl;
|
||||
|
||||
public interface FraudVisitorFactory {
|
||||
|
||||
<T extends BaseModel, U> FirstFindVisitorImpl createVisitor(CountAggregator<T, U> countAggregator,
|
||||
SumAggregator<T, U> sumAggregator,
|
||||
UniqueValueAggregator<T, U> uniqueValueAggregator,
|
||||
CountryResolver<U> countryResolver,
|
||||
InListFinder<T, U> listFinder,
|
||||
FieldResolver<T, U> fieldPairResolver,
|
||||
GroupByModelResolver<T, U> groupByModelResolver);
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.rbkmoney.fraudo.p2p.factory;
|
||||
|
||||
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.BaseModel;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.impl.FirstFindP2PVisitorImpl;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
|
||||
public interface FraudP2PVisitorFactory {
|
||||
|
||||
<T extends BaseModel, U> FirstFindP2PVisitorImpl<T, U> createVisitor(CountAggregator<T, U> countAggregator,
|
||||
SumAggregator<T, U> sumAggregator,
|
||||
UniqueValueAggregator<T, U> uniqueValueAggregator,
|
||||
CountryResolver<U> countryResolver,
|
||||
InListFinder<T, U> listFinder,
|
||||
FieldResolver<T, U> fieldPairResolver,
|
||||
P2PGroupResolver<T, U> paymentGroupResolver,
|
||||
P2PTimeWindowResolver timeWindowResolver);
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.rbkmoney.fraudo.p2p.factory;
|
||||
|
||||
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.BaseModel;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.CountP2PVisitor;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.CustomP2PFuncVisitor;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.ListP2PVisitor;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.SumP2PVisitor;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.impl.*;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
|
||||
public class P2PFraudVisitorFactory implements FraudP2PVisitorFactory {
|
||||
|
||||
@Override
|
||||
public <T extends BaseModel, U> FirstFindP2PVisitorImpl<T, U> createVisitor(
|
||||
CountAggregator<T, U> countAggregator,
|
||||
SumAggregator<T, U> sumAggregator,
|
||||
UniqueValueAggregator<T, U> uniqueValueAggregator,
|
||||
CountryResolver<U> countryResolver,
|
||||
InListFinder<T, U> listFinder,
|
||||
FieldResolver<T, U> fieldResolver,
|
||||
P2PGroupResolver<T, U> groupResolver,
|
||||
P2PTimeWindowResolver timeWindowResolver) {
|
||||
CountP2PVisitor<T> countVisitor = new CountP2PVisitorImpl<>(countAggregator, fieldResolver, groupResolver, timeWindowResolver);
|
||||
SumP2PVisitor<T> sumVisitor = new SumP2PVisitorImpl<>(sumAggregator, fieldResolver, groupResolver, timeWindowResolver);
|
||||
ListP2PVisitor<T> listVisitor = new ListP2PVisitorImpl<>(listFinder, fieldResolver);
|
||||
CustomP2PFuncVisitor<T> customFuncVisitor = new CustomP2PFuncVisitorImpl<>(uniqueValueAggregator, countryResolver,
|
||||
fieldResolver, groupResolver, timeWindowResolver);
|
||||
return new FirstFindP2PVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.rbkmoney.fraudo.p2p.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CommonP2PKeyGenerator {
|
||||
|
||||
static <T> String generateKeyGroupedFunction(TerminalNode string,
|
||||
ParseTree parseTree,
|
||||
FraudoP2PParser.Time_windowContext timeWindowContext,
|
||||
FraudoP2PParser.Group_byContext groupByContext,
|
||||
Function<String, T> resolve) {
|
||||
String countTarget = TextUtil.safeGetText(string);
|
||||
return new StringBuilder()
|
||||
.append(parseTree)
|
||||
.append(countTarget)
|
||||
.append(resolve.apply(countTarget))
|
||||
.append(timeWindowContext != null ? timeWindowContext.children : "")
|
||||
.append(groupByContext != null ? groupByContext.string_list().children : "")
|
||||
.toString();
|
||||
}
|
||||
|
||||
static <T> String generateKeyGroupedTwoFieldFunction(TerminalNode firstField,
|
||||
TerminalNode secondField,
|
||||
ParseTree parseTree,
|
||||
FraudoP2PParser.Time_windowContext timeWindowContext,
|
||||
FraudoP2PParser.Group_byContext groupByContext,
|
||||
Function<String, T> resolve) {
|
||||
String target = TextUtil.safeGetText(firstField);
|
||||
String errorCode = TextUtil.safeGetText(secondField);
|
||||
return new StringBuilder()
|
||||
.append(parseTree)
|
||||
.append(target)
|
||||
.append(errorCode)
|
||||
.append(resolve.apply(target))
|
||||
.append(timeWindowContext != null ? timeWindowContext.children : "")
|
||||
.append(groupByContext != null ? groupByContext.string_list().children : "")
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.rbkmoney.fraudo.p2p.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CountP2PKeyGenerator {
|
||||
|
||||
public static <T> String generate(FraudoP2PParser.CountContext ctx, Function<String, T> resolve) {
|
||||
return CommonP2PKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
ctx.group_by(),
|
||||
resolve);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.rbkmoney.fraudo.p2p.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CountryP2PKeyGenerator {
|
||||
|
||||
public static String generate(FraudoP2PParser.Country_byContext ctx) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING());
|
||||
return new StringBuilder()
|
||||
.append(ctx.children.get(0))
|
||||
.append(fieldName)
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.rbkmoney.fraudo.p2p.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class RuleP2PKeyGenerator {
|
||||
|
||||
public static String generateRuleKey(FraudoP2PParser.Fraud_ruleContext fraudRuleContext, int index) {
|
||||
if (fraudRuleContext.IDENTIFIER() != null && !fraudRuleContext.IDENTIFIER().getText().isEmpty()) {
|
||||
return fraudRuleContext.IDENTIFIER().getText();
|
||||
}
|
||||
return String.valueOf(index);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.rbkmoney.fraudo.p2p.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class SumP2PKeyGenerator {
|
||||
|
||||
public static <T> String generate(FraudoP2PParser.SumContext ctx, Function<String, T> resolve) {
|
||||
return CommonP2PKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
ctx.group_by(),
|
||||
resolve);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.rbkmoney.fraudo.p2p.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class UniqueP2PKeyGenerator {
|
||||
|
||||
public static <T> String generate(FraudoP2PParser.UniqueContext ctx, Function<String, T> resolve) {
|
||||
return CommonP2PKeyGenerator.generateKeyGroupedTwoFieldFunction(
|
||||
ctx.STRING(0),
|
||||
ctx.STRING(1),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
ctx.group_by(),
|
||||
resolve);
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.rbkmoney.fraudo.resolver;
|
||||
package com.rbkmoney.fraudo.p2p.resolver;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.resolver.GroupFieldsResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@ -8,12 +9,14 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoP2PParser.Group_byContext;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class GroupByModelResolver<T, U> implements GroupFieldsResolver<U> {
|
||||
public class P2PGroupResolver<T, U> implements GroupFieldsResolver<Group_byContext, U> {
|
||||
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
|
||||
public List<U> resolve(FraudoParser.Group_byContext groupByContext) {
|
||||
public List<U> resolve(Group_byContext groupByContext) {
|
||||
List<U> fields = new ArrayList<>();
|
||||
if (groupByContext != null
|
||||
&& groupByContext.string_list() != null
|
@ -0,0 +1,28 @@
|
||||
package com.rbkmoney.fraudo.p2p.resolver;
|
||||
|
||||
import com.rbkmoney.fraudo.model.TimeWindow;
|
||||
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoP2PParser.Time_windowContext;
|
||||
|
||||
public class P2PTimeWindowResolver implements TimeWindowResolver<Time_windowContext> {
|
||||
|
||||
@Override
|
||||
public TimeWindow resolve(Time_windowContext ctx) {
|
||||
TimeWindow.TimeWindowBuilder builder = TimeWindow.builder();
|
||||
List<TerminalNode> times = ctx.INTEGER();
|
||||
String startWindow = TextUtil.safeGetText(times.get(0));
|
||||
if (times.size() == 2) {
|
||||
String endWindow = TextUtil.safeGetText(times.get(1));
|
||||
builder.endWindowTime(Long.valueOf(endWindow));
|
||||
}
|
||||
return builder
|
||||
.startWindowTime(Long.valueOf(startWindow))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
|
||||
public interface CountP2PVisitor<T> {
|
||||
|
||||
Integer visitCount(FraudoP2PParser.CountContext ctx, T model);
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
|
||||
public interface CustomP2PFuncVisitor<T> {
|
||||
|
||||
String visitCountryBy(FraudoP2PParser.Country_byContext ctx, T model);
|
||||
|
||||
boolean visitLike(FraudoP2PParser.LikeContext ctx, T model);
|
||||
|
||||
Integer visitUnique(FraudoP2PParser.UniqueContext ctx, T model);
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
|
||||
public interface ListP2PVisitor<T> {
|
||||
|
||||
Boolean visitInWhiteList(FraudoP2PParser.In_white_listContext ctx, T model);
|
||||
|
||||
Boolean visitInBlackList(FraudoP2PParser.In_black_listContext ctx, T model);
|
||||
|
||||
Boolean visitInGreyList(FraudoP2PParser.In_grey_listContext ctx, T model);
|
||||
|
||||
Boolean visitInList(FraudoP2PParser.In_listContext ctx, T model);
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
|
||||
public interface SumP2PVisitor<T> {
|
||||
|
||||
Double visitSum(FraudoP2PParser.SumContext ctx, T model);
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.CountAggregator;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.CountP2PVisitor;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoP2PParser.CountContext;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CountP2PVisitorImpl<T, U> implements CountP2PVisitor<T> {
|
||||
|
||||
private final CountAggregator<T, U> countAggregator;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final P2PGroupResolver<T, U> groupResolver;
|
||||
private final P2PTimeWindowResolver timeWindowResolver;
|
||||
|
||||
@Override
|
||||
public Integer visitCount(CountContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return countAggregator.count(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.model.Pair;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.CustomP2PFuncVisitor;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoP2PParser.*;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CustomP2PFuncVisitorImpl<T, U> implements CustomP2PFuncVisitor<T> {
|
||||
|
||||
private final UniqueValueAggregator<T, U> uniqueValueAggregator;
|
||||
private final CountryResolver<U> countryResolver;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final P2PGroupResolver<T, U> groupResolver;
|
||||
private final P2PTimeWindowResolver timeWindowResolver;
|
||||
|
||||
@Override
|
||||
public String visitCountryBy(Country_byContext ctx, T model) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING());
|
||||
Pair<U, String> resolve = fieldResolver.resolve(fieldName, model);
|
||||
return countryResolver.resolveCountry(resolve.getFirst(), resolve.getSecond());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitLike(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(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()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PBaseVisitor;
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser.*;
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser;
|
||||
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.p2p.generator.*;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.CountP2PVisitor;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.CustomP2PFuncVisitor;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.ListP2PVisitor;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.SumP2PVisitor;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import com.rbkmoney.fraudo.visitor.TemplateVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class FirstFindP2PVisitorImpl<T extends BaseModel, U> extends FraudoP2PBaseVisitor<Object> implements TemplateVisitor<T, ResultModel> {
|
||||
|
||||
private ThreadLocal<Map<String, Object>> localFuncCache = ThreadLocal.withInitial(HashMap::new);
|
||||
private ThreadLocal<T> threadLocalModel = new ThreadLocal<>();
|
||||
|
||||
private final CountP2PVisitor<T> countVisitor;
|
||||
private final SumP2PVisitor<T> sumVisitor;
|
||||
private final ListP2PVisitor<T> listVisitor;
|
||||
private final CustomP2PFuncVisitor<T> customFuncVisitor;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
localFuncCache.remove();
|
||||
threadLocalModel.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultStatus visitFraud_rule(Fraud_ruleContext ctx) {
|
||||
try {
|
||||
if (visitExpression(ctx.expression())) {
|
||||
return ResultStatus.getByValue(ctx.result().getText());
|
||||
}
|
||||
} catch (Exception 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.NOTIFY;
|
||||
}
|
||||
return ResultStatus.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultModel visitParse(ParseContext ctx) {
|
||||
List<String> notifications = new ArrayList<>();
|
||||
for (int i = 0; i < ctx.fraud_rule().size(); i++) {
|
||||
Fraud_ruleContext fraudRuleContext = ctx.fraud_rule().get(i);
|
||||
ResultStatus result = (ResultStatus) visit(fraudRuleContext);
|
||||
String key = RuleP2PKeyGenerator.generateRuleKey(fraudRuleContext, i);
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultModel visit(ParseTree tree, T model) {
|
||||
try {
|
||||
validateModel(model);
|
||||
threadLocalModel.set(model);
|
||||
return (ResultModel) visit(tree);
|
||||
} finally {
|
||||
localFuncCache.get().clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateModel(T model) {
|
||||
if (model == null) {
|
||||
log.error("Model is not init!");
|
||||
throw new NotValidContextException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitExpression(ExpressionContext ctx) {
|
||||
if (ctx.OR() != null && !ctx.OR().isEmpty()) {
|
||||
boolean result = false;
|
||||
for (BooleanAndExpressionContext booleanAndExpressionContext : ctx.booleanAndExpression()) {
|
||||
result = result || (Boolean) visit(booleanAndExpressionContext);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return visitBooleanAndExpression(ctx.booleanAndExpression(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitBooleanAndExpression(BooleanAndExpressionContext ctx) {
|
||||
if (ctx.AND() != null && !ctx.AND().isEmpty()) {
|
||||
boolean result = true;
|
||||
for (EqualityExpressionContext equalityExpressionContext : ctx.equalityExpression()) {
|
||||
result = result && visitEqualityExpression(equalityExpressionContext);
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return visitEqualityExpression(ctx.equalityExpression(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitEqualityExpression(EqualityExpressionContext ctx) {
|
||||
if (ctx.stringExpression() != null && !ctx.stringExpression().isEmpty()) {
|
||||
String left = visitStringExpression(ctx.stringExpression(0));
|
||||
String right = visitStringExpression(ctx.stringExpression(1));
|
||||
if (ctx.EQ() != null) {
|
||||
return left.equals(right);
|
||||
} else if (ctx.NEQ() != null) {
|
||||
return !left.equals(right);
|
||||
}
|
||||
} else if (ctx.NOT() != null) {
|
||||
return !(Boolean) visit(ctx.expression());
|
||||
} else if (ctx.LPAREN() != null) {
|
||||
return (Boolean) visit(ctx.expression());
|
||||
}
|
||||
return visitRelationalExpression(ctx.relationalExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitRelationalExpression(RelationalExpressionContext ctx) {
|
||||
|
||||
if (ctx.unaryExpression() != null && !ctx.unaryExpression().isEmpty()) {
|
||||
Double left = visitUnaryExpression(ctx.unaryExpression(0));
|
||||
Double right = visitUnaryExpression(ctx.unaryExpression(1));
|
||||
if (ctx.EQ() != null) {
|
||||
return left.equals(right);
|
||||
} else if (ctx.NEQ() != null) {
|
||||
return !left.equals(right);
|
||||
} else if (ctx.GE() != null) {
|
||||
return left >= right;
|
||||
} else if (ctx.LT() != null) {
|
||||
return left < right;
|
||||
} else if (ctx.GT() != null) {
|
||||
return left > right;
|
||||
} else if (ctx.LE() != null) {
|
||||
return left <= right;
|
||||
}
|
||||
}
|
||||
return (Boolean) visitChildren(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitUnaryExpression(UnaryExpressionContext ctx) {
|
||||
if (ctx.floatExpression() != null) {
|
||||
return visitFloatExpression(ctx.floatExpression());
|
||||
} else if (ctx.integerExpression() != null) {
|
||||
return Double.valueOf(visitIntegerExpression(ctx.integerExpression()));
|
||||
}
|
||||
throw new NotImplementedOperatorException(ctx.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitFloatExpression(FloatExpressionContext ctx) {
|
||||
if (ctx.INTEGER() != null) {
|
||||
return Double.valueOf(TextUtil.safeGetText(ctx.INTEGER()));
|
||||
} else if (ctx.DECIMAL() != null) {
|
||||
return Double.valueOf(TextUtil.safeGetText(ctx.DECIMAL()));
|
||||
}
|
||||
return (Double) visitChildren(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitIntegerExpression(IntegerExpressionContext ctx) {
|
||||
if (ctx.INTEGER() != null) {
|
||||
return Integer.valueOf(TextUtil.safeGetText(ctx.INTEGER()));
|
||||
}
|
||||
return (Integer) visitChildren(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitStringExpression(StringExpressionContext ctx) {
|
||||
if (ctx.STRING() != null) {
|
||||
return TextUtil.safeGetText(ctx.STRING());
|
||||
}
|
||||
return (String) visitChildren(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCount(CountContext ctx) {
|
||||
String key = CountP2PKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
return (Integer) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> countVisitor.visitCount(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitAmount(AmountContext ctx) {
|
||||
return Double.valueOf(threadLocalModel.get().getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSum(SumContext ctx) {
|
||||
String key = SumP2PKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
return (Double) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSum(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitCurrency(CurrencyContext ctx) {
|
||||
return threadLocalModel.get().getCurrency();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn_white_list(In_white_listContext ctx) {
|
||||
return listVisitor.visitInWhiteList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn_black_list(In_black_listContext ctx) {
|
||||
return listVisitor.visitInBlackList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn_grey_list(In_grey_listContext ctx) {
|
||||
return listVisitor.visitInGreyList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn_list(In_listContext ctx) {
|
||||
return listVisitor.visitInList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn(InContext ctx) {
|
||||
String fieldValue;
|
||||
if (ctx.stringExpression().STRING() != null && ctx.stringExpression().getText() != null
|
||||
&& !ctx.stringExpression().STRING().getText().isEmpty()) {
|
||||
String field = TextUtil.safeGetText(ctx.stringExpression().STRING());
|
||||
fieldValue = fieldResolver.resolve(field, threadLocalModel.get()).getSecond();
|
||||
} else {
|
||||
fieldValue = (String) visitChildren(ctx.stringExpression());
|
||||
}
|
||||
return ctx.string_list().STRING().stream()
|
||||
.anyMatch(s -> fieldValue.equals(TextUtil.safeGetText(s)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitUnique(UniqueContext ctx) {
|
||||
String key = UniqueP2PKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
return (Integer) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> customFuncVisitor.visitUnique(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitLike(LikeContext ctx) {
|
||||
return customFuncVisitor.visitLike(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitCountry_by(Country_byContext ctx) {
|
||||
String key = CountryP2PKeyGenerator.generate(ctx);
|
||||
return (String) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> customFuncVisitor.visitCountryBy(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.model.Pair;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.ListP2PVisitor;
|
||||
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.function.BiPredicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoP2PParser.*;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ListP2PVisitorImpl<T, U> implements ListP2PVisitor<T> {
|
||||
|
||||
private final InListFinder<T, U> listFinder;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
|
||||
@Override
|
||||
public Boolean visitInWhiteList(In_white_listContext ctx, T model) {
|
||||
return findInList(ctx.string_list().STRING(), model, listFinder::findInWhiteList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitInBlackList(In_black_listContext ctx, T model) {
|
||||
return findInList(ctx.string_list().STRING(), model, listFinder::findInBlackList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitInGreyList(In_grey_listContext ctx, T model) {
|
||||
return findInList(ctx.string_list().STRING(), model, listFinder::findInGreyList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitInList(In_listContext ctx, T model) {
|
||||
List<Pair<U, String>> checkedFields = initCheckedFields(model, ctx.string_list().STRING());
|
||||
String name = TextUtil.safeGetText(ctx.STRING());
|
||||
return listFinder.findInList(name, checkedFields, model);
|
||||
}
|
||||
|
||||
private List<Pair<U, String>> initCheckedFields(T model, List<TerminalNode> string) {
|
||||
List<String> 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<TerminalNode> nodes, T model, BiPredicate<List<Pair<U, String>>, T> biPredicate) {
|
||||
List<Pair<U, String>> checkedFields = initCheckedFields(model, nodes);
|
||||
return biPredicate.test(checkedFields, model);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.rbkmoney.fraudo.p2p.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.SumAggregator;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
|
||||
import com.rbkmoney.fraudo.p2p.visitor.SumP2PVisitor;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoP2PParser.SumContext;
|
||||
import static com.rbkmoney.fraudo.FraudoP2PParser.Time_windowContext;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class SumP2PVisitorImpl<T, U> implements SumP2PVisitor<T> {
|
||||
|
||||
private final SumAggregator<T, U> sumAggregator;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final P2PGroupResolver<T, U> paymentGroupResolver;
|
||||
private final TimeWindowResolver<Time_windowContext> timeWindowResolver;
|
||||
|
||||
@Override
|
||||
public Double visitSum(SumContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return sumAggregator.sum(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
paymentGroupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.rbkmoney.fraudo.payment.aggregator;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.CountAggregator;
|
||||
import com.rbkmoney.fraudo.model.TimeWindow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CountPaymentAggregator<T, U> extends CountAggregator<T, U> {
|
||||
|
||||
Integer countSuccess(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Integer countError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List<U> fields);
|
||||
|
||||
Integer countChargeback(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Integer countRefund(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.rbkmoney.fraudo.payment.aggregator;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.SumAggregator;
|
||||
import com.rbkmoney.fraudo.model.TimeWindow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SumPaymentAggregator<T, U> extends SumAggregator<T, U> {
|
||||
|
||||
Double sumSuccess(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Double sumError(U checkedField, T model, TimeWindow timeWindow, String errorCode, List<U> fields);
|
||||
|
||||
Double sumChargeback(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
Double sumRefund(U checkedField, T model, TimeWindow timeWindow, List<U> fields);
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.rbkmoney.fraudo.payment.factory;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.model.BaseModel;
|
||||
import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator;
|
||||
import com.rbkmoney.fraudo.payment.aggregator.SumPaymentAggregator;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.payment.visitor.impl.FirstFindVisitorImpl;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
|
||||
public interface FraudVisitorFactory {
|
||||
|
||||
<T extends BaseModel, U> FirstFindVisitorImpl<T, U> createVisitor(CountPaymentAggregator<T, U> countPaymentAggregator,
|
||||
SumPaymentAggregator<T, U> sumPaymentAggregator,
|
||||
UniqueValueAggregator<T, U> uniqueValueAggregator,
|
||||
CountryResolver<U> countryResolver,
|
||||
InListFinder<T, U> listFinder,
|
||||
FieldResolver<T, U> fieldPairResolver,
|
||||
PaymentGroupResolver<T, U> paymentGroupResolver,
|
||||
PaymentTimeWindowResolver timeWindowResolver);
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.rbkmoney.fraudo.payment.factory;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.model.BaseModel;
|
||||
import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator;
|
||||
import com.rbkmoney.fraudo.payment.aggregator.SumPaymentAggregator;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.payment.visitor.CountVisitor;
|
||||
import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor;
|
||||
import com.rbkmoney.fraudo.payment.visitor.ListVisitor;
|
||||
import com.rbkmoney.fraudo.payment.visitor.SumVisitor;
|
||||
import com.rbkmoney.fraudo.payment.visitor.impl.*;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
|
||||
public class FraudVisitorFactoryImpl implements FraudVisitorFactory {
|
||||
|
||||
@Override
|
||||
public <T extends BaseModel, U> FirstFindVisitorImpl<T, U> createVisitor(
|
||||
CountPaymentAggregator<T, U> countPaymentAggregator,
|
||||
SumPaymentAggregator<T, U> sumPaymentAggregator,
|
||||
UniqueValueAggregator<T, U> uniqueValueAggregator,
|
||||
CountryResolver<U> countryResolver,
|
||||
InListFinder<T, U> listFinder,
|
||||
FieldResolver<T, U> fieldResolver,
|
||||
PaymentGroupResolver<T, U> paymentGroupResolver,
|
||||
PaymentTimeWindowResolver timeWindowResolver) {
|
||||
CountVisitor<T> countVisitor = new CountVisitorImpl<>(countPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver);
|
||||
SumVisitor<T> sumVisitor = new SumVisitorImpl<>(sumPaymentAggregator, fieldResolver, paymentGroupResolver, timeWindowResolver);
|
||||
ListVisitor<T> listVisitor = new ListVisitorImpl<>(listFinder, fieldResolver);
|
||||
CustomFuncVisitor<T> customFuncVisitor = new CustomFuncVisitorImpl<>(
|
||||
uniqueValueAggregator, countryResolver, fieldResolver, paymentGroupResolver, timeWindowResolver);
|
||||
return new FirstFindVisitorImpl<>(countVisitor, sumVisitor, listVisitor, customFuncVisitor, fieldResolver);
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
package com.rbkmoney.fraudo.utils.key.generator;
|
||||
package com.rbkmoney.fraudo.payment.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class RuleKeyGenerator {
|
||||
|
||||
public static String generateRuleKey(FraudoParser.Fraud_ruleContext fraudRuleContext) {
|
||||
public static String generateRuleKey(FraudoPaymentParser.Fraud_ruleContext fraudRuleContext, int index) {
|
||||
if (fraudRuleContext.IDENTIFIER() != null && !fraudRuleContext.IDENTIFIER().getText().isEmpty()) {
|
||||
return fraudRuleContext.IDENTIFIER().getText();
|
||||
}
|
||||
return String.valueOf(fraudRuleContext.getRuleIndex());
|
||||
return String.valueOf(index);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.rbkmoney.fraudo.payment.resolver;
|
||||
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.resolver.GroupFieldsResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.Group_byContext;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class PaymentGroupResolver<T, U> implements GroupFieldsResolver<Group_byContext, U> {
|
||||
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
|
||||
public List<U> resolve(Group_byContext groupByContext) {
|
||||
List<U> fields = new ArrayList<>();
|
||||
if (groupByContext != null
|
||||
&& groupByContext.string_list() != null
|
||||
&& groupByContext.string_list().STRING() != null
|
||||
&& !groupByContext.string_list().STRING().isEmpty()) {
|
||||
fields = groupByContext.string_list().STRING().stream()
|
||||
.map(terminalNode -> fieldResolver.resolveName(TextUtil.safeGetText(terminalNode)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.rbkmoney.fraudo.payment.resolver;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser;
|
||||
import com.rbkmoney.fraudo.model.TimeWindow;
|
||||
import com.rbkmoney.fraudo.resolver.TimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PaymentTimeWindowResolver implements TimeWindowResolver<FraudoPaymentParser.Time_windowContext> {
|
||||
|
||||
@Override
|
||||
public TimeWindow resolve(FraudoPaymentParser.Time_windowContext ctx) {
|
||||
TimeWindow.TimeWindowBuilder builder = TimeWindow.builder();
|
||||
List<TerminalNode> times = ctx.INTEGER();
|
||||
String startWindow = TextUtil.safeGetText(times.get(0));
|
||||
if (times.size() == 2) {
|
||||
String endWindow = TextUtil.safeGetText(times.get(1));
|
||||
builder.endWindowTime(Long.valueOf(endWindow));
|
||||
}
|
||||
return builder
|
||||
.startWindowTime(Long.valueOf(startWindow))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.rbkmoney.fraudo.payment.visitor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
public interface CountVisitor<T> {
|
||||
|
||||
Integer visitCount(CountContext ctx, T model);
|
||||
|
||||
Integer visitCountSuccess(Count_successContext ctx, T model);
|
||||
|
||||
Integer visitCountError(Count_errorContext ctx, T model);
|
||||
|
||||
Integer visitCountChargeback(Count_chargebackContext ctx, T model);
|
||||
|
||||
Integer visitCountRefund(Count_refundContext ctx, T model);
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.rbkmoney.fraudo.payment.visitor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
public interface CustomFuncVisitor<T> {
|
||||
|
||||
String visitCountryBy(Country_byContext ctx, T model);
|
||||
|
||||
boolean visitLike(LikeContext ctx, T model);
|
||||
|
||||
Integer visitUnique(UniqueContext ctx, T model);
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.rbkmoney.fraudo.payment.visitor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
public interface ListVisitor<T> {
|
||||
|
||||
Boolean visitInWhiteList(In_white_listContext ctx, T model);
|
||||
|
||||
Boolean visitInBlackList(In_black_listContext ctx, T model);
|
||||
|
||||
Boolean visitInGreyList(In_grey_listContext ctx, T model);
|
||||
|
||||
Boolean visitInList(In_listContext ctx, T model);
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.rbkmoney.fraudo.payment.visitor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
public interface SumVisitor<T> {
|
||||
|
||||
Double visitSum(SumContext ctx, T model);
|
||||
|
||||
Double visitSumSuccess(Sum_successContext ctx, T model);
|
||||
|
||||
Double visitSumError(Sum_errorContext ctx, T model);
|
||||
|
||||
Double visitSumChargeback(Sum_chargebackContext ctx, T model);
|
||||
|
||||
Double visitSumRefund(Sum_refundContext ctx, T model);
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package com.rbkmoney.fraudo.payment.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser;
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser;
|
||||
import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.payment.visitor.CountVisitor;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CountVisitorImpl<T, U> implements CountVisitor<T> {
|
||||
|
||||
private final CountPaymentAggregator<T, U> countPaymentAggregator;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final PaymentGroupResolver<T, U> groupResolver;
|
||||
private final PaymentTimeWindowResolver timeWindowResolver;
|
||||
|
||||
@Override
|
||||
public Integer visitCount(FraudoPaymentParser.CountContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return countPaymentAggregator.count(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCountSuccess(FraudoPaymentParser.Count_successContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return countPaymentAggregator.countSuccess(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCountError(FraudoPaymentParser.Count_errorContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING(0));
|
||||
String errorCode = TextUtil.safeGetText(ctx.STRING(1));
|
||||
return countPaymentAggregator.countError(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
errorCode,
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCountChargeback(FraudoPaymentParser.Count_chargebackContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return countPaymentAggregator.countChargeback(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCountRefund(FraudoPaymentParser.Count_refundContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return countPaymentAggregator.countRefund(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.rbkmoney.fraudo.payment.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.model.Pair;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CustomFuncVisitorImpl<T, U> implements CustomFuncVisitor<T> {
|
||||
|
||||
private final UniqueValueAggregator<T, U> uniqueValueAggregator;
|
||||
private final CountryResolver<U> countryResolver;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final PaymentGroupResolver<T, U> groupResolver;
|
||||
private final PaymentTimeWindowResolver timeWindowResolver;
|
||||
|
||||
@Override
|
||||
public String visitCountryBy(Country_byContext ctx, T model) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING());
|
||||
Pair<U, String> resolve = fieldResolver.resolve(fieldName, model);
|
||||
return countryResolver.resolveCountry(resolve.getFirst(), resolve.getSecond());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitLike(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(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()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,368 @@
|
||||
package com.rbkmoney.fraudo.payment.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoPaymentBaseVisitor;
|
||||
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.payment.generator.RuleKeyGenerator;
|
||||
import com.rbkmoney.fraudo.payment.visitor.CountVisitor;
|
||||
import com.rbkmoney.fraudo.payment.visitor.CustomFuncVisitor;
|
||||
import com.rbkmoney.fraudo.payment.visitor.ListVisitor;
|
||||
import com.rbkmoney.fraudo.payment.visitor.SumVisitor;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import com.rbkmoney.fraudo.utils.key.generator.CountKeyGenerator;
|
||||
import com.rbkmoney.fraudo.utils.key.generator.CountryKeyGenerator;
|
||||
import com.rbkmoney.fraudo.utils.key.generator.SumKeyGenerator;
|
||||
import com.rbkmoney.fraudo.utils.key.generator.UniqueKeyGenerator;
|
||||
import com.rbkmoney.fraudo.visitor.TemplateVisitor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class FirstFindVisitorImpl<T extends BaseModel, U> extends FraudoPaymentBaseVisitor<Object> implements TemplateVisitor<T, ResultModel> {
|
||||
|
||||
private ThreadLocal<Map<String, Object>> localFuncCache = ThreadLocal.withInitial(HashMap::new);
|
||||
private ThreadLocal<T> threadLocalModel = new ThreadLocal<>();
|
||||
|
||||
private final CountVisitor<T> countVisitor;
|
||||
private final SumVisitor<T> sumVisitor;
|
||||
private final ListVisitor<T> listVisitor;
|
||||
private final CustomFuncVisitor<T> customFuncVisitor;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
localFuncCache.remove();
|
||||
threadLocalModel.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultStatus visitFraud_rule(Fraud_ruleContext ctx) {
|
||||
try {
|
||||
if (visitExpression(ctx.expression())) {
|
||||
return ResultStatus.getByValue(ctx.result().getText());
|
||||
}
|
||||
} catch (Exception 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.NOTIFY;
|
||||
}
|
||||
return ResultStatus.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultModel visitParse(ParseContext ctx) {
|
||||
List<String> notifications = new ArrayList<>();
|
||||
for (int i = 0; i < ctx.fraud_rule().size(); i++) {
|
||||
Fraud_ruleContext fraudRuleContext = ctx.fraud_rule().get(i);
|
||||
ResultStatus result = (ResultStatus) visit(fraudRuleContext);
|
||||
String key = RuleKeyGenerator.generateRuleKey(fraudRuleContext, i);
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultModel visit(ParseTree tree, T model) {
|
||||
try {
|
||||
validateModel(model);
|
||||
threadLocalModel.set(model);
|
||||
return (ResultModel) visit(tree);
|
||||
} finally {
|
||||
localFuncCache.get().clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateModel(T model) {
|
||||
if (model == null) {
|
||||
log.error("Model is not init!");
|
||||
throw new NotValidContextException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitExpression(ExpressionContext ctx) {
|
||||
if (ctx.OR() != null && !ctx.OR().isEmpty()) {
|
||||
boolean result = false;
|
||||
for (BooleanAndExpressionContext booleanAndExpressionContext : ctx.booleanAndExpression()) {
|
||||
result = result || (Boolean) visit(booleanAndExpressionContext);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return visitBooleanAndExpression(ctx.booleanAndExpression(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitBooleanAndExpression(BooleanAndExpressionContext ctx) {
|
||||
if (ctx.AND() != null && !ctx.AND().isEmpty()) {
|
||||
boolean result = true;
|
||||
for (EqualityExpressionContext equalityExpressionContext : ctx.equalityExpression()) {
|
||||
result = result && visitEqualityExpression(equalityExpressionContext);
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return visitEqualityExpression(ctx.equalityExpression(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitEqualityExpression(EqualityExpressionContext ctx) {
|
||||
if (ctx.stringExpression() != null && !ctx.stringExpression().isEmpty()) {
|
||||
String left = visitStringExpression(ctx.stringExpression(0));
|
||||
String right = visitStringExpression(ctx.stringExpression(1));
|
||||
if (ctx.EQ() != null) {
|
||||
return left.equals(right);
|
||||
} else if (ctx.NEQ() != null) {
|
||||
return !left.equals(right);
|
||||
}
|
||||
} else if (ctx.NOT() != null) {
|
||||
return !(Boolean) visit(ctx.expression());
|
||||
} else if (ctx.LPAREN() != null) {
|
||||
return (Boolean) visit(ctx.expression());
|
||||
}
|
||||
return visitRelationalExpression(ctx.relationalExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitRelationalExpression(RelationalExpressionContext ctx) {
|
||||
|
||||
if (ctx.unaryExpression() != null && !ctx.unaryExpression().isEmpty()) {
|
||||
Double left = visitUnaryExpression(ctx.unaryExpression(0));
|
||||
Double right = visitUnaryExpression(ctx.unaryExpression(1));
|
||||
if (ctx.EQ() != null) {
|
||||
return left.equals(right);
|
||||
} else if (ctx.NEQ() != null) {
|
||||
return !left.equals(right);
|
||||
} else if (ctx.GE() != null) {
|
||||
return left >= right;
|
||||
} else if (ctx.LT() != null) {
|
||||
return left < right;
|
||||
} else if (ctx.GT() != null) {
|
||||
return left > right;
|
||||
} else if (ctx.LE() != null) {
|
||||
return left <= right;
|
||||
}
|
||||
}
|
||||
return (Boolean) visitChildren(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitUnaryExpression(UnaryExpressionContext ctx) {
|
||||
if (ctx.floatExpression() != null) {
|
||||
return visitFloatExpression(ctx.floatExpression());
|
||||
} else if (ctx.integerExpression() != null) {
|
||||
return Double.valueOf(visitIntegerExpression(ctx.integerExpression()));
|
||||
}
|
||||
throw new NotImplementedOperatorException(ctx.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitFloatExpression(FloatExpressionContext ctx) {
|
||||
if (ctx.INTEGER() != null) {
|
||||
return Double.valueOf(TextUtil.safeGetText(ctx.INTEGER()));
|
||||
} else if (ctx.DECIMAL() != null) {
|
||||
return Double.valueOf(TextUtil.safeGetText(ctx.DECIMAL()));
|
||||
}
|
||||
return (Double) visitChildren(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitIntegerExpression(IntegerExpressionContext ctx) {
|
||||
if (ctx.INTEGER() != null) {
|
||||
return Integer.valueOf(TextUtil.safeGetText(ctx.INTEGER()));
|
||||
}
|
||||
return (Integer) visitChildren(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitStringExpression(StringExpressionContext ctx) {
|
||||
if (ctx.STRING() != null) {
|
||||
return TextUtil.safeGetText(ctx.STRING());
|
||||
}
|
||||
return (String) visitChildren(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitAmount(AmountContext ctx) {
|
||||
return Double.valueOf(threadLocalModel.get().getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitCurrency(CurrencyContext ctx) {
|
||||
return threadLocalModel.get().getCurrency();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn_white_list(In_white_listContext ctx) {
|
||||
return listVisitor.visitInWhiteList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn_black_list(In_black_listContext ctx) {
|
||||
return listVisitor.visitInBlackList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn_grey_list(In_grey_listContext ctx) {
|
||||
return listVisitor.visitInGreyList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn_list(In_listContext ctx) {
|
||||
return listVisitor.visitInList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitIn(InContext ctx) {
|
||||
String fieldValue;
|
||||
if (ctx.stringExpression().STRING() != null && ctx.stringExpression().getText() != null
|
||||
&& !ctx.stringExpression().STRING().getText().isEmpty()) {
|
||||
String field = TextUtil.safeGetText(ctx.stringExpression().STRING());
|
||||
fieldValue = fieldResolver.resolve(field, threadLocalModel.get()).getSecond();
|
||||
} else {
|
||||
fieldValue = (String) visitChildren(ctx.stringExpression());
|
||||
}
|
||||
return ctx.string_list().STRING().stream()
|
||||
.anyMatch(s -> fieldValue.equals(TextUtil.safeGetText(s)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitUnique(UniqueContext ctx) {
|
||||
String key = UniqueKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
return (Integer) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> customFuncVisitor.visitUnique(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitLike(LikeContext ctx) {
|
||||
return customFuncVisitor.visitLike(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitCountry_by(Country_byContext ctx) {
|
||||
String key = CountryKeyGenerator.generate(ctx);
|
||||
return (String) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> customFuncVisitor.visitCountryBy(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCount(CountContext ctx) {
|
||||
String key = CountKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
return (Integer) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> countVisitor.visitCount(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCount_success(Count_successContext ctx) {
|
||||
String key = CountKeyGenerator.generateSuccessKey(ctx, fieldResolver::resolveName);
|
||||
return (Integer) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> countVisitor.visitCountSuccess(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCount_error(Count_errorContext ctx) {
|
||||
String key = CountKeyGenerator.generateErrorKey(ctx, fieldResolver::resolveName);
|
||||
return (Integer) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> countVisitor.visitCountError(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCount_chargeback(Count_chargebackContext ctx) {
|
||||
String key = CountKeyGenerator.generateChargebackKey(ctx, fieldResolver::resolveName);
|
||||
return (Integer) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> countVisitor.visitCountChargeback(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCount_refund(Count_refundContext ctx) {
|
||||
String key = CountKeyGenerator.generateRefundKey(ctx, fieldResolver::resolveName);
|
||||
return (Integer) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> countVisitor.visitCountRefund(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSum(SumContext ctx) {
|
||||
String key = SumKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
return (Double) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSum(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSum_success(Sum_successContext ctx) {
|
||||
String key = SumKeyGenerator.generateSuccessKey(ctx, fieldResolver::resolveName);
|
||||
return (Double) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSumSuccess(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSum_error(Sum_errorContext ctx) {
|
||||
String key = SumKeyGenerator.generateErrorKey(ctx, fieldResolver::resolveName);
|
||||
return (Double) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSumError(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSum_chargeback(Sum_chargebackContext ctx) {
|
||||
String key = SumKeyGenerator.generateChargebackKey(ctx, fieldResolver::resolveName);
|
||||
return (Double) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSumChargeback(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSum_refund(Sum_refundContext ctx) {
|
||||
String key = SumKeyGenerator.generateRefundKey(ctx, fieldResolver::resolveName);
|
||||
return (Double) localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSumRefund(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
package com.rbkmoney.fraudo.visitor.impl;
|
||||
package com.rbkmoney.fraudo.payment.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.model.Pair;
|
||||
import com.rbkmoney.fraudo.payment.visitor.ListVisitor;
|
||||
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;
|
||||
|
||||
@ -13,6 +12,8 @@ import java.util.List;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ListVisitorImpl<T, U> implements ListVisitor<T> {
|
||||
|
||||
@ -20,22 +21,22 @@ public class ListVisitorImpl<T, U> implements ListVisitor<T> {
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
|
||||
@Override
|
||||
public Boolean visitInWhiteList(FraudoParser.In_white_listContext ctx, T model) {
|
||||
public Boolean visitInWhiteList(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) {
|
||||
public Boolean visitInBlackList(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) {
|
||||
public Boolean visitInGreyList(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) {
|
||||
public Boolean visitInList(In_listContext ctx, T model) {
|
||||
List<Pair<U, String>> checkedFields = initCheckedFields(model, ctx.string_list().STRING());
|
||||
String name = TextUtil.safeGetText(ctx.STRING());
|
||||
return listFinder.findInList(name, checkedFields, model);
|
@ -0,0 +1,76 @@
|
||||
package com.rbkmoney.fraudo.payment.visitor.impl;
|
||||
|
||||
import com.rbkmoney.fraudo.payment.aggregator.SumPaymentAggregator;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.payment.visitor.SumVisitor;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class SumVisitorImpl<T, U> implements SumVisitor<T> {
|
||||
|
||||
private final SumPaymentAggregator<T, U> sumPaymentAggregator;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final PaymentGroupResolver<T, U> groupResolver;
|
||||
private final PaymentTimeWindowResolver timeWindowResolver;
|
||||
|
||||
@Override
|
||||
public Double visitSum(SumContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return sumPaymentAggregator.sum(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSumSuccess(Sum_successContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return sumPaymentAggregator.sumSuccess(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSumError(Sum_errorContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING(0));
|
||||
String errorCode = TextUtil.safeGetText(ctx.STRING(1));
|
||||
return sumPaymentAggregator.sumError(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
errorCode,
|
||||
groupResolver.resolve(ctx.group_by()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSumChargeback(Sum_chargebackContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return sumPaymentAggregator.sumChargeback(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSumRefund(Sum_refundContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return sumPaymentAggregator.sumRefund(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
timeWindowResolver.resolve(ctx.time_window()),
|
||||
groupResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -2,8 +2,6 @@ package com.rbkmoney.fraudo.resolver;
|
||||
|
||||
public interface CountryResolver<T> {
|
||||
|
||||
String UNKNOWN_VALUE = "unknown";
|
||||
|
||||
String resolveCountry(T checkedField, String value);
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
package com.rbkmoney.fraudo.resolver;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GroupFieldsResolver<T> {
|
||||
public interface GroupFieldsResolver<T, R> {
|
||||
|
||||
List<T> resolve(FraudoParser.Group_byContext groupByContext);
|
||||
List<R> resolve(T groupByContext);
|
||||
|
||||
}
|
||||
|
@ -1,28 +1,9 @@
|
||||
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;
|
||||
public interface TimeWindowResolver<T> {
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class TimeWindowResolver {
|
||||
|
||||
public static TimeWindow resolve(FraudoParser.Time_windowContext ctx) {
|
||||
TimeWindow.TimeWindowBuilder builder = TimeWindow.builder();
|
||||
List<TerminalNode> times = ctx.DECIMAL();
|
||||
String startWindow = TextUtil.safeGetText(times.get(0));
|
||||
if (times.size() == 2) {
|
||||
String endWindow = TextUtil.safeGetText(times.get(1));
|
||||
builder.endWindowTime(Long.valueOf(endWindow));
|
||||
}
|
||||
return builder
|
||||
.startWindowTime(Long.valueOf(startWindow))
|
||||
.build();
|
||||
}
|
||||
TimeWindow resolve(T ctx);
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package com.rbkmoney.fraudo.utils;
|
||||
|
||||
import com.rbkmoney.fraudo.exception.FieldUnsetException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class TextUtil {
|
||||
|
||||
public static String safeGetText(TerminalNode field) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.rbkmoney.fraudo.utils.key.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -9,13 +8,16 @@ import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.Group_byContext;
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.Time_windowContext;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CommonKeyGenerator {
|
||||
|
||||
static <T> String generateKeyGroupedFunction(TerminalNode string,
|
||||
ParseTree parseTree,
|
||||
FraudoParser.Time_windowContext timeWindowContext,
|
||||
FraudoParser.Group_byContext groupByContext,
|
||||
Time_windowContext timeWindowContext,
|
||||
Group_byContext groupByContext,
|
||||
Function<String, T> resolve) {
|
||||
String countTarget = TextUtil.safeGetText(string);
|
||||
return new StringBuilder()
|
||||
@ -30,8 +32,8 @@ public class CommonKeyGenerator {
|
||||
static <T> String generateKeyGroupedTwoFieldFunction(TerminalNode firstField,
|
||||
TerminalNode secondField,
|
||||
ParseTree parseTree,
|
||||
FraudoParser.Time_windowContext timeWindowContext,
|
||||
FraudoParser.Group_byContext groupByContext,
|
||||
Time_windowContext timeWindowContext,
|
||||
Group_byContext groupByContext,
|
||||
Function<String, T> resolve) {
|
||||
String target = TextUtil.safeGetText(firstField);
|
||||
String errorCode = TextUtil.safeGetText(secondField);
|
||||
|
@ -1,17 +1,16 @@
|
||||
package com.rbkmoney.fraudo.utils.key.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CountKeyGenerator {
|
||||
|
||||
public static <T> String generate(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.CountContext ctx = (FraudoParser.CountContext) context;
|
||||
public static <T> String generate(CountContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
@ -19,8 +18,7 @@ public class CountKeyGenerator {
|
||||
resolve);
|
||||
}
|
||||
|
||||
public static <T> String generateSuccessKey(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.Count_successContext ctx = (FraudoParser.Count_successContext) context;
|
||||
public static <T> String generateSuccessKey(Count_successContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
@ -28,8 +26,7 @@ public class CountKeyGenerator {
|
||||
resolve);
|
||||
}
|
||||
|
||||
public static <T> String generateErrorKey(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.Count_errorContext ctx = (FraudoParser.Count_errorContext) context;
|
||||
public static <T> String generateErrorKey(Count_errorContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedTwoFieldFunction(ctx.STRING(0),
|
||||
ctx.STRING(1),
|
||||
ctx.children.get(0),
|
||||
@ -38,8 +35,7 @@ public class CountKeyGenerator {
|
||||
resolve);
|
||||
}
|
||||
|
||||
public static <T> String generateChargebackKey(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.Count_chargebackContext ctx = (FraudoParser.Count_chargebackContext) context;
|
||||
public static <T> String generateChargebackKey(Count_chargebackContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
@ -47,8 +43,7 @@ public class CountKeyGenerator {
|
||||
resolve);
|
||||
}
|
||||
|
||||
public static <T> String generateRefundKey(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.Count_refundContext ctx = (FraudoParser.Count_refundContext) context;
|
||||
public static <T> String generateRefundKey(Count_refundContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
|
@ -1,16 +1,14 @@
|
||||
package com.rbkmoney.fraudo.utils.key.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CountryKeyGenerator {
|
||||
|
||||
public static String generate(ParserRuleContext context) {
|
||||
FraudoParser.Country_byContext ctx = (FraudoParser.Country_byContext) context;
|
||||
public static String generate(FraudoPaymentParser.Country_byContext ctx) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING());
|
||||
return new StringBuilder()
|
||||
.append(ctx.children.get(0))
|
||||
|
@ -1,17 +1,16 @@
|
||||
package com.rbkmoney.fraudo.utils.key.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.*;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class SumKeyGenerator {
|
||||
|
||||
public static <T> String generate(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.SumContext ctx = (FraudoParser.SumContext) context;
|
||||
public static <T> String generate(SumContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
@ -19,8 +18,7 @@ public class SumKeyGenerator {
|
||||
resolve);
|
||||
}
|
||||
|
||||
public static <T> String generateSuccessKey(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.Sum_successContext ctx = (FraudoParser.Sum_successContext) context;
|
||||
public static <T> String generateSuccessKey(Sum_successContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
@ -28,8 +26,7 @@ public class SumKeyGenerator {
|
||||
resolve);
|
||||
}
|
||||
|
||||
public static <T> String generateErrorKey(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.Sum_errorContext ctx = (FraudoParser.Sum_errorContext) context;
|
||||
public static <T> String generateErrorKey(Sum_errorContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedTwoFieldFunction(ctx.STRING(0),
|
||||
ctx.STRING(1),
|
||||
ctx.children.get(0),
|
||||
@ -38,8 +35,7 @@ public class SumKeyGenerator {
|
||||
resolve);
|
||||
}
|
||||
|
||||
public static <T> String generateChargebackKey(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.Sum_chargebackContext ctx = (FraudoParser.Sum_chargebackContext) context;
|
||||
public static <T> String generateChargebackKey(Sum_chargebackContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
@ -47,8 +43,7 @@ public class SumKeyGenerator {
|
||||
resolve);
|
||||
}
|
||||
|
||||
public static <T> String generateRefundKey(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.Sum_refundContext ctx = (FraudoParser.Sum_refundContext) context;
|
||||
public static <T> String generateRefundKey(Sum_refundContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedFunction(ctx.STRING(),
|
||||
ctx.children.get(0),
|
||||
ctx.time_window(),
|
||||
|
@ -1,17 +1,16 @@
|
||||
package com.rbkmoney.fraudo.utils.key.generator;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.rbkmoney.fraudo.FraudoPaymentParser.UniqueContext;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class UniqueKeyGenerator {
|
||||
|
||||
public static <T> String generate(ParserRuleContext context, Function<String, T> resolve) {
|
||||
FraudoParser.UniqueContext ctx = (FraudoParser.UniqueContext) context;
|
||||
public static <T> String generate(UniqueContext ctx, Function<String, T> resolve) {
|
||||
return CommonKeyGenerator.generateKeyGroupedTwoFieldFunction(
|
||||
ctx.STRING(0),
|
||||
ctx.STRING(1),
|
||||
|
@ -1,17 +0,0 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
|
||||
public interface CountVisitor<T> {
|
||||
|
||||
Integer visitCount(FraudoParser.CountContext ctx, T model);
|
||||
|
||||
Integer visitCountSuccess(FraudoParser.Count_successContext ctx, T model);
|
||||
|
||||
Integer visitCountError(FraudoParser.Count_errorContext ctx, T model);
|
||||
|
||||
Integer visitCountChargeback(FraudoParser.Count_chargebackContext ctx, T model);
|
||||
|
||||
Integer visitCountRefund(FraudoParser.Count_refundContext ctx, T model);
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
|
||||
public interface CustomFuncVisitor<T> {
|
||||
|
||||
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);
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
|
||||
public interface ListVisitor<T> {
|
||||
|
||||
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);
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
|
||||
public interface SumVisitor<T> {
|
||||
|
||||
Double visitSum(FraudoParser.SumContext ctx, T model);
|
||||
|
||||
Double visitSumSuccess(FraudoParser.Sum_successContext ctx, T model);
|
||||
|
||||
Double visitSumError(FraudoParser.Sum_errorContext ctx, T model);
|
||||
|
||||
Double visitSumChargeback(FraudoParser.Sum_chargebackContext ctx, T model);
|
||||
|
||||
Double visitSumRefund(FraudoParser.Sum_refundContext ctx, T model);
|
||||
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.model.BaseModel;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.Map;
|
||||
|
||||
public interface TemplateVisitor<T extends BaseModel> extends Closeable {
|
||||
public interface TemplateVisitor<T, R> extends Closeable {
|
||||
|
||||
Object visit(ParseTree tree, T model);
|
||||
R visit(ParseTree tree, T model);
|
||||
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
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<T, U> implements CountVisitor<T> {
|
||||
|
||||
private final CountAggregator<T, U> countAggregator;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final GroupFieldsResolver<U> 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 = TextUtil.safeGetText(ctx.STRING());
|
||||
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())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCountChargeback(FraudoParser.Count_chargebackContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return countAggregator.countChargeback(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
TimeWindowResolver.resolve(ctx.time_window()),
|
||||
groupFieldsResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer visitCountRefund(FraudoParser.Count_refundContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return countAggregator.countRefund(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
TimeWindowResolver.resolve(ctx.time_window()),
|
||||
groupFieldsResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
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<T, U> implements CustomFuncVisitor<T> {
|
||||
|
||||
private final UniqueValueAggregator<T, U> uniqueValueAggregator;
|
||||
private final CountryResolver<U> countryResolver;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final GroupByModelResolver<T, U> groupByModelResolver;
|
||||
|
||||
@Override
|
||||
public String visitCountryBy(FraudoParser.Country_byContext ctx, T model) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING());
|
||||
Pair<U, String> 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<U, String> 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())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,305 +0,0 @@
|
||||
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.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import com.rbkmoney.fraudo.utils.key.generator.*;
|
||||
import com.rbkmoney.fraudo.visitor.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class FirstFindVisitorImpl<T extends BaseModel, U> extends FraudoBaseVisitor<Object> implements TemplateVisitor<T> {
|
||||
|
||||
private ThreadLocal<Map<String, Object>> localFuncCache = ThreadLocal.withInitial(HashMap::new);
|
||||
private ThreadLocal<T> threadLocalModel = new ThreadLocal<>();
|
||||
|
||||
private final CountVisitor<T> countVisitor;
|
||||
private final SumVisitor<T> sumVisitor;
|
||||
private final ListVisitor<T> listVisitor;
|
||||
private final CustomFuncVisitor<T> customFuncVisitor;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
localFuncCache.remove();
|
||||
threadLocalModel.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ParseTree tree, T model) {
|
||||
try {
|
||||
validateModel(model);
|
||||
threadLocalModel.set(model);
|
||||
return super.visit(tree);
|
||||
} finally {
|
||||
localFuncCache.get().clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateModel(T model) {
|
||||
if (model == null) {
|
||||
log.error("Model is not init!");
|
||||
throw new NotValidContextException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFraud_rule(FraudoParser.Fraud_ruleContext ctx) {
|
||||
try {
|
||||
if (asBoolean(ctx.expression())) {
|
||||
return ResultStatus.getByValue((String) super.visit(ctx.result()));
|
||||
}
|
||||
} catch (Exception 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.NOTIFY;
|
||||
}
|
||||
return ResultStatus.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitParse(FraudoParser.ParseContext ctx) {
|
||||
List<String> notifications = new ArrayList<>();
|
||||
for (FraudoParser.Fraud_ruleContext fraudRuleContext : ctx.fraud_rule()) {
|
||||
ResultStatus result = (ResultStatus) visitFraud_rule(fraudRuleContext);
|
||||
String key = RuleKeyGenerator.generateRuleKey(fraudRuleContext);
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitResult(FraudoParser.ResultContext ctx) {
|
||||
return ctx.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDecimalExpression(FraudoParser.DecimalExpressionContext ctx) {
|
||||
return Double.valueOf(ctx.DECIMAL().getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitStringExpression(FraudoParser.StringExpressionContext ctx) {
|
||||
return TextUtil.safeGetText(ctx.STRING());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitNotExpression(FraudoParser.NotExpressionContext ctx) {
|
||||
return !((Boolean) this.visit(ctx.expression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitParenExpression(FraudoParser.ParenExpressionContext ctx) {
|
||||
return super.visit(ctx.expression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitComparatorExpression(FraudoParser.ComparatorExpressionContext ctx) {
|
||||
if (ctx.op.EQ() != null) {
|
||||
return this.visit(ctx.left).equals(this.visit(ctx.right));
|
||||
} else if (ctx.op.LE() != null) {
|
||||
return asDouble(ctx.left) <= asDouble(ctx.right);
|
||||
} else if (ctx.op.GE() != null) {
|
||||
return asDouble(ctx.left) >= asDouble(ctx.right);
|
||||
} else if (ctx.op.LT() != null) {
|
||||
return asDouble(ctx.left) < asDouble(ctx.right);
|
||||
} else if (ctx.op.GT() != null) {
|
||||
return asDouble(ctx.left) > asDouble(ctx.right);
|
||||
}
|
||||
throw new NotImplementedOperatorException(ctx.op.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitBinaryExpression(FraudoParser.BinaryExpressionContext ctx) {
|
||||
if (ctx.op.AND() != null) {
|
||||
return asBoolean(ctx.left) && asBoolean(ctx.right);
|
||||
} else if (ctx.op.OR() != null) {
|
||||
return asBoolean(ctx.left) || asBoolean(ctx.right);
|
||||
}
|
||||
throw new NotImplementedOperatorException(ctx.op.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitBoolExpression(FraudoParser.BoolExpressionContext ctx) {
|
||||
return Boolean.valueOf(ctx.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCount(FraudoParser.CountContext ctx) {
|
||||
String key = CountKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
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, fieldResolver::resolveName);
|
||||
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, fieldResolver::resolveName);
|
||||
return localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> Double.valueOf(countVisitor.visitCountError(ctx, threadLocalModel.get()))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCount_chargeback(FraudoParser.Count_chargebackContext ctx) {
|
||||
String key = CountKeyGenerator.generateChargebackKey(ctx, fieldResolver::resolveName);
|
||||
return localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> Double.valueOf(countVisitor.visitCountChargeback(ctx, threadLocalModel.get()))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCount_refund(FraudoParser.Count_refundContext ctx) {
|
||||
String key = CountKeyGenerator.generateRefundKey(ctx, fieldResolver::resolveName);
|
||||
return localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> Double.valueOf(countVisitor.visitCountRefund(ctx, threadLocalModel.get()))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitSum(FraudoParser.SumContext ctx) {
|
||||
String key = SumKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
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, fieldResolver::resolveName);
|
||||
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, fieldResolver::resolveName);
|
||||
return localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSumError(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitSum_chargeback(FraudoParser.Sum_chargebackContext ctx) {
|
||||
String key = SumKeyGenerator.generateChargebackKey(ctx, fieldResolver::resolveName);
|
||||
return localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSumChargeback(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitSum_refund(FraudoParser.Sum_refundContext ctx) {
|
||||
String key = SumKeyGenerator.generateRefundKey(ctx, fieldResolver::resolveName);
|
||||
return localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> sumVisitor.visitSumRefund(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCountry_by(FraudoParser.Country_byContext ctx) {
|
||||
String key = CountryKeyGenerator.generate(ctx);
|
||||
return localFuncCache.get().computeIfAbsent(
|
||||
key,
|
||||
s -> customFuncVisitor.visitCountryBy(ctx, threadLocalModel.get())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitIn(FraudoParser.InContext ctx) {
|
||||
return customFuncVisitor.visitIn(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLike(FraudoParser.LikeContext ctx) {
|
||||
return customFuncVisitor.visitLike(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitUnique(FraudoParser.UniqueContext ctx) {
|
||||
String key = UniqueKeyGenerator.generate(ctx, fieldResolver::resolveName);
|
||||
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.visitInWhiteList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitIn_black_list(FraudoParser.In_black_listContext ctx) {
|
||||
return listVisitor.visitInBlackList(ctx, threadLocalModel.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitIn_grey_list(FraudoParser.In_grey_listContext 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 Double.valueOf(threadLocalModel.get().getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCurrency(FraudoParser.CurrencyContext ctx) {
|
||||
return threadLocalModel.get().getCurrency();
|
||||
}
|
||||
|
||||
private boolean asBoolean(FraudoParser.ExpressionContext ctx) {
|
||||
return (boolean) visit(ctx);
|
||||
}
|
||||
|
||||
private double asDouble(FraudoParser.ExpressionContext ctx) {
|
||||
return (double) visit(ctx);
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
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<T, U> implements SumVisitor<T> {
|
||||
|
||||
private final SumAggregator<T, U> sumAggregator;
|
||||
private final FieldResolver<T, U> fieldResolver;
|
||||
private final GroupByModelResolver<T, U> 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()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSumChargeback(FraudoParser.Sum_chargebackContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return sumAggregator.sumChargeback(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
TimeWindowResolver.resolve(ctx.time_window()),
|
||||
groupByModelResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double visitSumRefund(FraudoParser.Sum_refundContext ctx, T model) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return sumAggregator.sumRefund(
|
||||
fieldResolver.resolveName(countTarget),
|
||||
model,
|
||||
TimeWindowResolver.resolve(ctx.time_window()),
|
||||
groupByModelResolver.resolve(ctx.group_by())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +1,19 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.CountAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.SumAggregator;
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.test.constant.PaymentCheckedField;
|
||||
import com.rbkmoney.fraudo.factory.FirstFraudVisitorFactory;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.test.model.PaymentModel;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import com.rbkmoney.fraudo.payment.aggregator.CountPaymentAggregator;
|
||||
import com.rbkmoney.fraudo.payment.aggregator.SumPaymentAggregator;
|
||||
import com.rbkmoney.fraudo.payment.factory.FraudVisitorFactoryImpl;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentGroupResolver;
|
||||
import com.rbkmoney.fraudo.payment.resolver.PaymentTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
|
||||
import com.rbkmoney.fraudo.test.payout.PaymentModelFieldResolver;
|
||||
import com.rbkmoney.fraudo.test.constant.PaymentCheckedField;
|
||||
import com.rbkmoney.fraudo.test.model.PaymentModel;
|
||||
import com.rbkmoney.fraudo.test.payment.PaymentModelFieldResolver;
|
||||
import org.antlr.v4.runtime.ANTLRInputStream;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.mockito.Mock;
|
||||
@ -22,46 +24,48 @@ import java.io.InputStream;
|
||||
public class AbstractPaymentTest {
|
||||
|
||||
@Mock
|
||||
CountAggregator<PaymentModel, PaymentCheckedField> countAggregator;
|
||||
CountPaymentAggregator<PaymentModel, PaymentCheckedField> countPaymentAggregator;
|
||||
@Mock
|
||||
SumAggregator<PaymentModel, PaymentCheckedField> sumAggregator;
|
||||
SumPaymentAggregator<PaymentModel, PaymentCheckedField> sumPaymentAggregator;
|
||||
@Mock
|
||||
UniqueValueAggregator<PaymentModel, PaymentCheckedField> uniqueValueAggregator;
|
||||
@Mock
|
||||
CountryResolver<PaymentCheckedField> countryResolver;
|
||||
@Mock
|
||||
InListFinder<PaymentModel, PaymentCheckedField> inListFinder;
|
||||
@Mock
|
||||
PaymentTimeWindowResolver timeWindowResolver;
|
||||
|
||||
private FieldResolver<PaymentModel, PaymentCheckedField> fieldResolver = new PaymentModelFieldResolver();
|
||||
private GroupByModelResolver<PaymentModel, PaymentCheckedField> groupByModelResolver = new GroupByModelResolver<>(fieldResolver);
|
||||
private PaymentGroupResolver<PaymentModel, PaymentCheckedField> paymentGroupResolver = new PaymentGroupResolver<>(fieldResolver);
|
||||
|
||||
ResultModel parseAndVisit(InputStream resourceAsStream) throws IOException {
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parse = getParseContext(resourceAsStream);
|
||||
ParseContext parse = getParseContext(resourceAsStream);
|
||||
return invokeParse(parse);
|
||||
}
|
||||
|
||||
ResultModel invokeParse(com.rbkmoney.fraudo.FraudoParser.ParseContext parse) {
|
||||
ResultModel invokeParse(ParseContext parse) {
|
||||
PaymentModel model = new PaymentModel();
|
||||
return invoke(parse, model);
|
||||
}
|
||||
|
||||
ResultModel invoke(com.rbkmoney.fraudo.FraudoParser.ParseContext parse, PaymentModel model) {
|
||||
return (ResultModel) new FirstFraudVisitorFactory()
|
||||
ResultModel invoke(ParseContext parse, PaymentModel model) {
|
||||
return new FraudVisitorFactoryImpl()
|
||||
.createVisitor(
|
||||
countAggregator,
|
||||
sumAggregator,
|
||||
countPaymentAggregator,
|
||||
sumPaymentAggregator,
|
||||
uniqueValueAggregator,
|
||||
countryResolver,
|
||||
inListFinder,
|
||||
fieldResolver,
|
||||
groupByModelResolver)
|
||||
paymentGroupResolver,
|
||||
timeWindowResolver)
|
||||
.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));
|
||||
|
||||
ParseContext getParseContext(InputStream resourceAsStream) throws IOException {
|
||||
com.rbkmoney.fraudo.FraudoPaymentLexer lexer = new com.rbkmoney.fraudo.FraudoPaymentLexer(new ANTLRInputStream(resourceAsStream));
|
||||
com.rbkmoney.fraudo.FraudoPaymentParser parser = new com.rbkmoney.fraudo.FraudoPaymentParser(new CommonTokenStream(lexer));
|
||||
return parser.parse();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import org.junit.Before;
|
||||
@ -22,19 +23,19 @@ public class CountTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void countTest() throws Exception {
|
||||
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/count.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
when(countAggregator.countError(anyObject(), any(), any(), anyString(), any())).thenReturn(6);
|
||||
when(countAggregator.countSuccess(anyObject(), any(), any(), any())).thenReturn(4);
|
||||
when(countAggregator.countChargeback(anyObject(), any(), any(), any())).thenReturn(0);
|
||||
when(countAggregator.countRefund(anyObject(), any(), any(), any())).thenReturn(1);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
when(countPaymentAggregator.countError(anyObject(), any(), any(), anyString(), any())).thenReturn(6);
|
||||
when(countPaymentAggregator.countSuccess(anyObject(), any(), any(), any())).thenReturn(4);
|
||||
when(countPaymentAggregator.countChargeback(anyObject(), any(), any(), any())).thenReturn(0);
|
||||
when(countPaymentAggregator.countRefund(anyObject(), any(), any(), any())).thenReturn(1);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals("1", result.getRuleChecked());
|
||||
assertEquals("0", result.getRuleChecked());
|
||||
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(9);
|
||||
when(countAggregator.countError(anyObject(), any(), any(), anyString(), any())).thenReturn(6);
|
||||
when(countAggregator.countSuccess(anyObject(), any(), any(), any())).thenReturn(6);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(9);
|
||||
when(countPaymentAggregator.countError(anyObject(), any(), any(), anyString(), any())).thenReturn(6);
|
||||
when(countPaymentAggregator.countSuccess(anyObject(), any(), any(), any())).thenReturn(6);
|
||||
|
||||
result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
@ -43,24 +44,24 @@ public class CountTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void countCargeRefundTest() throws Exception {
|
||||
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/count_chargeback_refund.frd");
|
||||
when(countAggregator.countChargeback(anyObject(), any(), any(), any())).thenReturn(3);
|
||||
when(countAggregator.countRefund(anyObject(), any(), any(), any())).thenReturn(5);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
when(countPaymentAggregator.countChargeback(anyObject(), any(), any(), any())).thenReturn(3);
|
||||
when(countPaymentAggregator.countRefund(anyObject(), any(), any(), any())).thenReturn(5);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals("1", result.getRuleChecked());
|
||||
assertEquals("0", result.getRuleChecked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countGroupByTest() throws Exception {
|
||||
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/countGroupBy.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals("1", result.getRuleChecked());
|
||||
assertEquals("0", result.getRuleChecked());
|
||||
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
|
||||
result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
}
|
||||
@ -68,33 +69,33 @@ public class CountTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void countTimeWindowGroupByTest() throws Exception {
|
||||
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/countTimeWindowGroupBy.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals("1", result.getRuleChecked());
|
||||
assertEquals("0", result.getRuleChecked());
|
||||
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
|
||||
result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
|
||||
resourceAsStream = CountTest.class.getResourceAsStream("/rules/countTimeWindowGroupBy_2.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
parseContext = getParseContext(resourceAsStream);
|
||||
result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals("1", result.getRuleChecked());
|
||||
assertEquals("0", result.getRuleChecked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countCardTokenTest() throws Exception {
|
||||
InputStream resourceAsStream = CountTest.class.getResourceAsStream("/rules/count_card_token.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
verify(countAggregator, times(1)).count(anyObject(), any(), any(), any());
|
||||
verify(countPaymentAggregator, times(1)).count(anyObject(), any(), any(), any());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.exception.UnknownResultException;
|
||||
import com.rbkmoney.fraudo.test.model.PaymentModel;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import com.rbkmoney.fraudo.test.model.PaymentModel;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@ -27,7 +27,7 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void threeDsTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/three_ds.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.THREE_DS, result.getResultStatus());
|
||||
}
|
||||
@ -35,7 +35,7 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void highRiskTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/highRisk.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
when(countPaymentAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.HIGH_RISK, result.getResultStatus());
|
||||
}
|
||||
@ -79,7 +79,7 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void inTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
PaymentModel model = new PaymentModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
@ -91,17 +91,28 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in_country.frd");
|
||||
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("RU");
|
||||
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
PaymentModel model = new PaymentModel();
|
||||
model.setAmount(500L);
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inCurrencyTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in_currency.frd");
|
||||
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
PaymentModel model = new PaymentModel();
|
||||
model.setCurrency("EUR");
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void amountTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/amount.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
PaymentModel model = new PaymentModel();
|
||||
model.setAmount(56L);
|
||||
model.setCurrency("RUB");
|
||||
@ -117,7 +128,7 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
public void catchTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/catch.frd");
|
||||
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenThrow(new UnknownResultException("as"));
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
}
|
||||
@ -125,7 +136,7 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void likeTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/like.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
PaymentModel model = new PaymentModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
model.setBin("553619");
|
||||
@ -141,7 +152,7 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void inNotTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/in_not.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
PaymentModel model = new PaymentModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
@ -152,7 +163,7 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
public void uniqCountTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/count_uniq.frd");
|
||||
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenReturn(2);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
}
|
||||
@ -161,7 +172,7 @@ public class CustomTest extends AbstractPaymentTest {
|
||||
public void uniqCountGroupByTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/count_uniqGroupBy_window.frd");
|
||||
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenReturn(2);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import org.junit.Assert;
|
||||
@ -22,7 +23,7 @@ public class ListTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void whiteBlackListTest() throws Exception {
|
||||
InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/whitelist.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Mockito.when(inListFinder.findInWhiteList(anyList(), anyObject())).thenReturn(true);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
@ -38,7 +39,7 @@ public class ListTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void greyListTest() throws Exception {
|
||||
InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/greyList.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Mockito.when(inListFinder.findInGreyList(anyList(), anyObject())).thenReturn(true);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
@ -47,7 +48,7 @@ public class ListTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void namingListTest() throws Exception {
|
||||
InputStream resourceAsStream = ListTest.class.getResourceAsStream("/rules/namingList.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Mockito.when(inListFinder.findInList(anyString(), anyList(), anyObject())).thenReturn(true);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
|
@ -1,8 +1,9 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.test.model.PaymentModel;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import com.rbkmoney.fraudo.test.model.PaymentModel;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
@ -33,7 +34,7 @@ public class RealTimerTest extends AbstractPaymentTest {
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
mockAggr(countDownLatch);
|
||||
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
|
||||
PaymentModel model = new PaymentModel();
|
||||
model.setAmount(MILLISTIME_FAST_FUNC);
|
||||
@ -55,7 +56,7 @@ public class RealTimerTest extends AbstractPaymentTest {
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
mockAggr(countDownLatch);
|
||||
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
|
||||
PaymentModel model = new PaymentModel();
|
||||
model.setAmount(MILLISTIME_FAST_FUNC);
|
||||
@ -73,25 +74,25 @@ public class RealTimerTest extends AbstractPaymentTest {
|
||||
}
|
||||
|
||||
private void mockAggr(CountDownLatch countDownLatch) {
|
||||
when(countAggregator.count(any(), any(), any(), any()))
|
||||
when(countPaymentAggregator.count(any(), any(), any(), any()))
|
||||
.thenAnswer((Answer<Integer>) invocationOnMock -> {
|
||||
Thread.sleep(TIME_CALL_AGGR_FUNC);
|
||||
countDownLatch.countDown();
|
||||
return 1;
|
||||
});
|
||||
when(countAggregator.countSuccess(any(), any(), any(), any()))
|
||||
when(countPaymentAggregator.countSuccess(any(), any(), any(), any()))
|
||||
.thenAnswer((Answer<Integer>) invocationOnMock -> {
|
||||
Thread.sleep(TIME_CALL_AGGR_FUNC);
|
||||
countDownLatch.countDown();
|
||||
return 1;
|
||||
});
|
||||
|
||||
when(sumAggregator.sum(any(), any(), any(), any()))
|
||||
when(sumPaymentAggregator.sum(any(), any(), any(), any()))
|
||||
.thenAnswer((Answer<Double>) invocationOnMock -> {
|
||||
Thread.sleep(TIME_CALL_AGGR_FUNC);
|
||||
return 10000.0;
|
||||
});
|
||||
when(sumAggregator.sumSuccess(any(), any(), any(), any()))
|
||||
when(sumPaymentAggregator.sumSuccess(any(), any(), any(), any()))
|
||||
.thenAnswer((Answer<Double>) invocationOnMock -> {
|
||||
Thread.sleep(TIME_CALL_AGGR_FUNC);
|
||||
return 10000.0;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser.ParseContext;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import org.junit.Assert;
|
||||
@ -22,17 +23,17 @@ public class SumTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void sumTest() throws Exception {
|
||||
InputStream resourceAsStream = SumTest.class.getResourceAsStream("/rules/sum.frd");
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
|
||||
Mockito.when(sumAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(524.0);
|
||||
Mockito.when(sumAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(4.0);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Mockito.when(sumPaymentAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
|
||||
Mockito.when(sumPaymentAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(524.0);
|
||||
Mockito.when(sumPaymentAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(4.0);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
Assert.assertEquals(1, result.getNotificationsRule().size());
|
||||
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
|
||||
Mockito.when(sumAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(504.0);
|
||||
Mockito.when(sumAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(501.0);
|
||||
Mockito.when(sumPaymentAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
|
||||
Mockito.when(sumPaymentAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(504.0);
|
||||
Mockito.when(sumPaymentAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(501.0);
|
||||
|
||||
result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
@ -42,9 +43,9 @@ public class SumTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void sumChargeRefundTest() throws Exception {
|
||||
InputStream resourceAsStream = SumTest.class.getResourceAsStream("/rules/sum_chargeback_refund.frd");
|
||||
Mockito.when(sumAggregator.sumChargeback(anyObject(), any(), any(), any())).thenReturn(10000.60);
|
||||
Mockito.when(sumAggregator.sumRefund(anyObject(), any(), any(), any())).thenReturn(10000.60);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Mockito.when(sumPaymentAggregator.sumChargeback(anyObject(), any(), any(), any())).thenReturn(10000.60);
|
||||
Mockito.when(sumPaymentAggregator.sumRefund(anyObject(), any(), any(), any())).thenReturn(10000.60);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
@ -52,17 +53,17 @@ public class SumTest extends AbstractPaymentTest {
|
||||
@Test
|
||||
public void sumGroupByTest() throws Exception {
|
||||
InputStream resourceAsStream = SumTest.class.getResourceAsStream("/rules/sumGroupBy.frd");
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
|
||||
Mockito.when(sumAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(524.0);
|
||||
Mockito.when(sumAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(4.0);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Mockito.when(sumPaymentAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
|
||||
Mockito.when(sumPaymentAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(524.0);
|
||||
Mockito.when(sumPaymentAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(4.0);
|
||||
ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
Assert.assertEquals(1, result.getNotificationsRule().size());
|
||||
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
|
||||
Mockito.when(sumAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(504.0);
|
||||
Mockito.when(sumAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(501.0);
|
||||
Mockito.when(sumPaymentAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
|
||||
Mockito.when(sumPaymentAggregator.sumError(anyObject(), any(), any(), anyString(), any())).thenReturn(504.0);
|
||||
Mockito.when(sumPaymentAggregator.sumSuccess(anyObject(), any(), any(), any())).thenReturn(501.0);
|
||||
|
||||
result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
|
@ -1,15 +1,16 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
package com.rbkmoney.fraudo.p2p;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.CountAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.SumAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.test.constant.P2PCheckedField;
|
||||
import com.rbkmoney.fraudo.factory.FirstFraudVisitorFactory;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.test.model.P2PModel;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import com.rbkmoney.fraudo.p2p.factory.P2PFraudVisitorFactory;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PGroupResolver;
|
||||
import com.rbkmoney.fraudo.p2p.resolver.P2PTimeWindowResolver;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.GroupByModelResolver;
|
||||
import com.rbkmoney.fraudo.test.constant.P2PCheckedField;
|
||||
import com.rbkmoney.fraudo.test.model.P2PModel;
|
||||
import com.rbkmoney.fraudo.test.p2p.P2PModelFieldResolver;
|
||||
import org.antlr.v4.runtime.ANTLRInputStream;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
@ -30,23 +31,25 @@ public class AbstractP2PTest {
|
||||
CountryResolver<P2PCheckedField> countryResolver;
|
||||
@Mock
|
||||
InListFinder<P2PModel, P2PCheckedField> listFinder;
|
||||
@Mock
|
||||
P2PTimeWindowResolver timeWindowResolver;
|
||||
|
||||
private P2PModelFieldResolver fieldResolver = new P2PModelFieldResolver();
|
||||
private GroupByModelResolver<P2PModel, P2PCheckedField> groupByModelResolver = new GroupByModelResolver<>(fieldResolver);
|
||||
private P2PGroupResolver<P2PModel, P2PCheckedField> paymentGroupResolver = new P2PGroupResolver<>(fieldResolver);
|
||||
|
||||
|
||||
ResultModel parseAndVisit(InputStream resourceAsStream) throws IOException {
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parse = getParseContext(resourceAsStream);
|
||||
com.rbkmoney.fraudo.FraudoP2PParser.ParseContext parse = getParseContext(resourceAsStream);
|
||||
return invokeParse(parse);
|
||||
}
|
||||
|
||||
ResultModel invokeParse(com.rbkmoney.fraudo.FraudoParser.ParseContext parse) {
|
||||
ResultModel invokeParse(com.rbkmoney.fraudo.FraudoP2PParser.ParseContext parse) {
|
||||
P2PModel model = new P2PModel();
|
||||
return invoke(parse, model);
|
||||
}
|
||||
|
||||
ResultModel invoke(com.rbkmoney.fraudo.FraudoParser.ParseContext parse, P2PModel model) {
|
||||
return (ResultModel) new FirstFraudVisitorFactory()
|
||||
ResultModel invoke(com.rbkmoney.fraudo.FraudoP2PParser.ParseContext parse, P2PModel model) {
|
||||
return new P2PFraudVisitorFactory()
|
||||
.createVisitor(
|
||||
countAggregator,
|
||||
sumAggregator,
|
||||
@ -54,13 +57,14 @@ public class AbstractP2PTest {
|
||||
countryResolver,
|
||||
listFinder,
|
||||
fieldResolver,
|
||||
groupByModelResolver)
|
||||
paymentGroupResolver,
|
||||
timeWindowResolver)
|
||||
.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));
|
||||
com.rbkmoney.fraudo.FraudoP2PParser.ParseContext getParseContext(InputStream resourceAsStream) throws IOException {
|
||||
com.rbkmoney.fraudo.FraudoP2PLexer lexer = new com.rbkmoney.fraudo.FraudoP2PLexer(new ANTLRInputStream(resourceAsStream));
|
||||
com.rbkmoney.fraudo.FraudoP2PParser parser = new com.rbkmoney.fraudo.FraudoP2PParser(new CommonTokenStream(lexer));
|
||||
|
||||
return parser.parse();
|
||||
}
|
91
src/test/java/com/rbkmoney/fraudo/p2p/CountP2PTest.java
Normal file
91
src/test/java/com/rbkmoney/fraudo/p2p/CountP2PTest.java
Normal file
@ -0,0 +1,91 @@
|
||||
package com.rbkmoney.fraudo.p2p;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class CountP2PTest extends AbstractP2PTest {
|
||||
|
||||
public static final String FIRST_RULE_INDEX = "0";
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countTest() throws Exception {
|
||||
InputStream resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/count.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
|
||||
Mockito.when(listFinder.findInWhiteList(any(), any())).thenReturn(true);
|
||||
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals(FIRST_RULE_INDEX, result.getRuleChecked());
|
||||
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(14);
|
||||
|
||||
result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countGroupByTest() throws Exception {
|
||||
InputStream resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/countGroupBy.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals(FIRST_RULE_INDEX, result.getRuleChecked());
|
||||
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
|
||||
result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countTimeWindowGroupByTest() throws Exception {
|
||||
InputStream resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/countTimeWindowGroupBy.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals(FIRST_RULE_INDEX, result.getRuleChecked());
|
||||
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(1);
|
||||
result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
|
||||
resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/countTimeWindowGroupBy_2.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
parseContext = getParseContext(resourceAsStream);
|
||||
result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals(FIRST_RULE_INDEX, result.getRuleChecked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countCardTokenTest() throws Exception {
|
||||
InputStream resourceAsStream = CountP2PTest.class.getResourceAsStream("/rules/p2p/count_card_token.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
verify(countAggregator, times(1)).count(anyObject(), any(), any(), any());
|
||||
}
|
||||
|
||||
}
|
209
src/test/java/com/rbkmoney/fraudo/p2p/CustomP2PTest.java
Normal file
209
src/test/java/com/rbkmoney/fraudo/p2p/CustomP2PTest.java
Normal file
@ -0,0 +1,209 @@
|
||||
package com.rbkmoney.fraudo.p2p;
|
||||
|
||||
import com.rbkmoney.fraudo.CustomTest;
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import com.rbkmoney.fraudo.FraudoPaymentParser;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.exception.UnknownResultException;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import com.rbkmoney.fraudo.test.model.P2PModel;
|
||||
import com.rbkmoney.fraudo.test.model.PaymentModel;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class CustomP2PTest extends AbstractP2PTest {
|
||||
|
||||
public static final String TEST_GMAIL_RU = "test@gmail.ru";
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void threeDsTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/three_ds.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.THREE_DS, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void highRiskTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/highRisk.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.HIGH_RISK, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notifyTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/notify.frd");
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
assertEquals(1, result.getNotificationsRule().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void declineTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/decline.frd");
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
assertEquals("test_11", result.getRuleChecked());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/accept.frd");
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ruleIsNotFireTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/rule_is_not_fire.frd");
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test(expected = UnknownResultException.class)
|
||||
public void notImplOperatorTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/unknownResult.frd");
|
||||
parseAndVisit(resourceAsStream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/in.frd");
|
||||
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("SD");
|
||||
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
P2PModel model = new P2PModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
model.setBin("123213");
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inCurrencyTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomTest.class.getResourceAsStream("/rules/p2p/in_currency.frd");
|
||||
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
P2PModel model = new P2PModel();
|
||||
model.setCurrency("EUR");
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inCountryTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/in_country.frd");
|
||||
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("RU");
|
||||
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
P2PModel model = new P2PModel();
|
||||
model.setAmount(500L);
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void amountTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/amount.frd");
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
P2PModel model = new P2PModel();
|
||||
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
|
||||
public void catchTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/catch.frd");
|
||||
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenThrow(new UnknownResultException("as"));
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void likeTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/like.frd");
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
P2PModel model = new P2PModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
model.setBin("553619");
|
||||
model.setPan("9137");
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
|
||||
model.setPan("9111");
|
||||
result = invoke(parseContext, model);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inNotTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/in_not.frd");
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
P2PModel model = new P2PModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
ResultModel result = invoke(parseContext, model);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uniqCountTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/count_uniq.frd");
|
||||
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenReturn(2);
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uniqCountGroupByTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/count_uniqGroupBy_window.frd");
|
||||
when(uniqueValueAggregator.countUniqueValue(any(), any(), any(), any(), any())).thenReturn(2);
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
verify(uniqueValueAggregator, times(1)).countUniqueValue(any(), any(), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eqCountryTest() throws Exception {
|
||||
InputStream resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/eq_country.frd");
|
||||
|
||||
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("RU");
|
||||
|
||||
ResultModel result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
assertEquals(1, result.getNotificationsRule().size());
|
||||
|
||||
when(countryResolver.resolveCountry(any(), anyString())).thenReturn("US");
|
||||
resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/eq_country.frd");
|
||||
result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
assertEquals(0, result.getNotificationsRule().size());
|
||||
|
||||
resourceAsStream = CustomP2PTest.class.getResourceAsStream("/rules/p2p/accept_with_notify.frd");
|
||||
result = parseAndVisit(resourceAsStream);
|
||||
assertEquals(ResultStatus.ACCEPT, result.getResultStatus());
|
||||
assertEquals(2, result.getNotificationsRule().size());
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
package com.rbkmoney.fraudo.p2p;
|
||||
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.test.model.P2PModel;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import com.rbkmoney.fraudo.test.model.P2PModel;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
@ -29,11 +29,11 @@ public class P2PTest extends AbstractP2PTest {
|
||||
|
||||
@Test
|
||||
public void timingTest() throws Exception {
|
||||
InputStream resourceAsStream = P2PTest.class.getResourceAsStream("/rules/p2p_template.frd");
|
||||
InputStream resourceAsStream = P2PTest.class.getResourceAsStream("/rules/p2p/p2p_template.frd");
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
mockAggr(countDownLatch);
|
||||
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
com.rbkmoney.fraudo.FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
|
||||
P2PModel model = new P2PModel();
|
||||
model.setAmount(MILLISTIME_FAST_FUNC);
|
||||
@ -57,23 +57,12 @@ public class P2PTest extends AbstractP2PTest {
|
||||
countDownLatch.countDown();
|
||||
return 1;
|
||||
});
|
||||
when(countAggregator.countSuccess(any(), any(), any(), any()))
|
||||
.thenAnswer((Answer<Integer>) invocationOnMock -> {
|
||||
Thread.sleep(TIME_CALL_AGGR_FUNC);
|
||||
countDownLatch.countDown();
|
||||
return 1;
|
||||
});
|
||||
|
||||
when(sumAggregator.sum(any(), any(), any(), any()))
|
||||
.thenAnswer((Answer<Double>) invocationOnMock -> {
|
||||
Thread.sleep(TIME_CALL_AGGR_FUNC);
|
||||
return 10000.0;
|
||||
});
|
||||
when(sumAggregator.sumSuccess(any(), any(), any(), any()))
|
||||
.thenAnswer((Answer<Double>) invocationOnMock -> {
|
||||
Thread.sleep(TIME_CALL_AGGR_FUNC);
|
||||
return 10000.0;
|
||||
});
|
||||
|
||||
when(listFinder.findInBlackList(anyList(), anyObject()))
|
||||
.thenAnswer((Answer<Boolean>) invocationOnMock -> {
|
38
src/test/java/com/rbkmoney/fraudo/p2p/ParenP2PTest.java
Normal file
38
src/test/java/com/rbkmoney/fraudo/p2p/ParenP2PTest.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.rbkmoney.fraudo.p2p;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.model.ResultModel;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class ParenP2PTest extends AbstractP2PTest {
|
||||
|
||||
public static final String FIRST_RULE_INDEX = "0";
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countCardTokenTest() throws Exception {
|
||||
InputStream resourceAsStream = ParenP2PTest.class.getResourceAsStream("/rules/p2p/paren.frd");
|
||||
when(countAggregator.count(anyObject(), any(), any(), any())).thenReturn(10);
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
|
||||
assertEquals(ResultStatus.DECLINE, result.getResultStatus());
|
||||
verify(countAggregator, times(2)).count(anyObject(), any(), any(), any());
|
||||
}
|
||||
|
||||
}
|
56
src/test/java/com/rbkmoney/fraudo/p2p/SumP2PTest.java
Normal file
56
src/test/java/com/rbkmoney/fraudo/p2p/SumP2PTest.java
Normal file
@ -0,0 +1,56 @@
|
||||
package com.rbkmoney.fraudo.p2p;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoP2PParser;
|
||||
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;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
|
||||
public class SumP2PTest extends AbstractP2PTest {
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sumTest() throws Exception {
|
||||
InputStream resourceAsStream = SumP2PTest.class.getResourceAsStream("/rules/p2p/sum.frd");
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
Assert.assertEquals(1, result.getNotificationsRule().size());
|
||||
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
|
||||
|
||||
result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
Assert.assertEquals(0, result.getNotificationsRule().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sumGroupByTest() throws Exception {
|
||||
InputStream resourceAsStream = SumP2PTest.class.getResourceAsStream("/rules/p2p/sumGroupBy.frd");
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(10500.60);
|
||||
FraudoP2PParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
ResultModel result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
Assert.assertEquals(1, result.getNotificationsRule().size());
|
||||
|
||||
Mockito.when(sumAggregator.sum(anyObject(), any(), any(), any())).thenReturn(90.0);
|
||||
|
||||
result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NORMAL, result.getResultStatus());
|
||||
Assert.assertEquals(0, result.getNotificationsRule().size());
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.rbkmoney.fraudo.test.payout;
|
||||
package com.rbkmoney.fraudo.test.payment;
|
||||
|
||||
import com.rbkmoney.fraudo.exception.UnresolvableFieldException;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
3
src/test/resources/log4j.properties
Normal file
3
src/test/resources/log4j.properties
Normal file
@ -0,0 +1,3 @@
|
||||
log4j.rootLogger=DEBUG, stdout
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
|
||||
|
||||
<root level="warn">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
<logger name="com.rbkmoney" level="ALL"/>
|
||||
</configuration>
|
2
src/test/resources/rules/in_currency.frd
Normal file
2
src/test/resources/rules/in_currency.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: in(currency(), "RUB", "EUR")
|
||||
-> accept;
|
2
src/test/resources/rules/p2p/accept.frd
Normal file
2
src/test/resources/rules/p2p/accept.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: 3 > 2 AND 1 = 1
|
||||
-> accept;
|
8
src/test/resources/rules/p2p/accept_with_notify.frd
Normal file
8
src/test/resources/rules/p2p/accept_with_notify.frd
Normal file
@ -0,0 +1,8 @@
|
||||
rule: 12 > 3
|
||||
-> notify;
|
||||
|
||||
rule: 12 > 3
|
||||
-> notify;
|
||||
|
||||
rule: 12 > 3
|
||||
-> accept;
|
2
src/test/resources/rules/p2p/amount.frd
Normal file
2
src/test/resources/rules/p2p/amount.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: amount() < 100 AND currency() = "RUB"
|
||||
-> accept;
|
3
src/test/resources/rules/p2p/catch.frd
Normal file
3
src/test/resources/rules/p2p/catch.frd
Normal file
@ -0,0 +1,3 @@
|
||||
rule: unique("email", "ip") < 4
|
||||
-> accept
|
||||
catch: decline;
|
2
src/test/resources/rules/p2p/count.frd
Normal file
2
src/test/resources/rules/p2p/count.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: count("ip", 1444) >= 10 AND count("ip", 1444) < 10 OR sum("ip", 1444) >= 10500.50 AND inWhiteList("email")
|
||||
-> decline;
|
2
src/test/resources/rules/p2p/countGroupBy.frd
Normal file
2
src/test/resources/rules/p2p/countGroupBy.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: count("ip", 1444, "party_id") >= 10
|
||||
-> decline;
|
2
src/test/resources/rules/p2p/countTimeWindowGroupBy.frd
Normal file
2
src/test/resources/rules/p2p/countTimeWindowGroupBy.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: count("ip", 1444, 60, "party_id") >= 10
|
||||
-> decline;
|
@ -0,0 +1,2 @@
|
||||
rule: count("ip", 1444, 60, "partyId", "shop_id") >= 10
|
||||
-> decline;
|
2
src/test/resources/rules/p2p/count_card_token.frd
Normal file
2
src/test/resources/rules/p2p/count_card_token.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: count("card_token", 1444) >= 10 AND count("card_token", 1444) >= 9
|
||||
-> decline;
|
2
src/test/resources/rules/p2p/count_uniq.frd
Normal file
2
src/test/resources/rules/p2p/count_uniq.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: unique("email", "ip", 1444) < 4
|
||||
-> decline;
|
@ -0,0 +1,3 @@
|
||||
rule: unique("email", "ip", 1444, 123, "party_id", "shop_id") < 4
|
||||
AND unique("email", "ip", 1444, 123, "party_id", "shop_id") < 4
|
||||
-> decline;
|
2
src/test/resources/rules/p2p/decline.frd
Normal file
2
src/test/resources/rules/p2p/decline.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule:test_11: 3 > 2 AND 1 = 1
|
||||
-> decline;
|
2
src/test/resources/rules/p2p/eq_country.frd
Normal file
2
src/test/resources/rules/p2p/eq_country.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: countryBy("ip") = "RU"
|
||||
-> notify;
|
5
src/test/resources/rules/p2p/highRisk.frd
Normal file
5
src/test/resources/rules/p2p/highRisk.frd
Normal file
@ -0,0 +1,5 @@
|
||||
rule: 3 > 2 AND 1 > 1
|
||||
-> decline;
|
||||
|
||||
rule: count("email", 10) <= 10 AND count("ip", 1444) = 10
|
||||
-> highRisk;
|
2
src/test/resources/rules/p2p/in.frd
Normal file
2
src/test/resources/rules/p2p/in.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: in("email", "test@gmail", "test@gmail.ru") and in(countryBy("bin"), "AS", "SD", "TR", "WE", "SD", "CD", "KL", "EW", "VF", "XZ", "CD")
|
||||
-> accept;
|
2
src/test/resources/rules/p2p/in_country.frd
Normal file
2
src/test/resources/rules/p2p/in_country.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: in(countryBy("ip"), "RU", "EN")
|
||||
-> accept;
|
2
src/test/resources/rules/p2p/in_currency.frd
Normal file
2
src/test/resources/rules/p2p/in_currency.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: in(currency(), "RUB", "EUR")
|
||||
-> accept;
|
2
src/test/resources/rules/p2p/in_not.frd
Normal file
2
src/test/resources/rules/p2p/in_not.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: in("email", "testgmail", "test@g")
|
||||
-> notify;
|
1
src/test/resources/rules/p2p/like.frd
Normal file
1
src/test/resources/rules/p2p/like.frd
Normal file
@ -0,0 +1 @@
|
||||
rule:cb:like("bin", "5536.*") AND in("pan","9137")->decline;
|
2
src/test/resources/rules/p2p/notify.frd
Normal file
2
src/test/resources/rules/p2p/notify.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: 3 > 2 AND 1 = 1
|
||||
-> notify;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user