mirror of
https://github.com/valitydev/fraudo.git
synced 2024-11-06 01:45:16 +00:00
Create lang fraudo
This commit is contained in:
parent
6e77c9543b
commit
18d59d2e17
73
.gitignore
vendored
Normal file
73
.gitignore
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Maven template
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/dictionaries
|
||||
.idea/vcs.xml
|
||||
.idea/jsLibraryMappings.xml
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/dataSources.ids
|
||||
.idea/dataSources.xml
|
||||
.idea/dataSources.local.xml
|
||||
.idea/sqlDataSources.xml
|
||||
.idea/dynamic.xml
|
||||
.idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/gradle.xml
|
||||
.idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
*.ipr
|
||||
*.iml
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
### Java template
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
env.list
|
92
pom.xml
Normal file
92
pom.xml
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.rbkmoney</groupId>
|
||||
<artifactId>fraudo</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<hamcrest.junit.version>2.0.0.0</hamcrest.junit.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.7.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- tests -->
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-junit</artifactId>
|
||||
<version>${hamcrest.junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-maven-plugin</artifactId>
|
||||
<version>4.7.1</version>
|
||||
<configuration>
|
||||
<arguments>
|
||||
<argument>-package</argument>
|
||||
<argument>com.rbkmoney.fraudo</argument>
|
||||
</arguments>
|
||||
<listener>false</listener>
|
||||
<visitor>true</visitor>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>antlr</id>
|
||||
<goals>
|
||||
<goal>antlr4</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
128
src/main/antlr4/com.rbkmoney.fraudo/Fraudo.g4
Normal file
128
src/main/antlr4/com.rbkmoney.fraudo/Fraudo.g4
Normal file
@ -0,0 +1,128 @@
|
||||
grammar Fraudo;
|
||||
|
||||
parse
|
||||
: fraud_rule* EOF
|
||||
;
|
||||
|
||||
fraud_rule
|
||||
: RULE_BLOCK expression RETURN 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
|
||||
| sum #sumExpression
|
||||
| sum_success #sumSuccessExpression
|
||||
| sum_error #sumErrorExpression
|
||||
| unique #uniqueExpression
|
||||
| in #inFunctionExpression
|
||||
| inWhiteList #inWhiteListExpression
|
||||
| inBlackList #inBlackListExpression
|
||||
| like #likeFunctionExpression
|
||||
| equals_country #equalsCountryFunctionExpression
|
||||
| IDENTIFIER #identifierExpression
|
||||
| DECIMAL #decimalExpression
|
||||
;
|
||||
|
||||
comparator
|
||||
: GT | GE | LT | LE | EQ
|
||||
;
|
||||
|
||||
binary
|
||||
: AND | OR
|
||||
;
|
||||
|
||||
bool
|
||||
: TRUE | FALSE
|
||||
;
|
||||
|
||||
count
|
||||
: 'count' LPAREN STRING DELIMETER DECIMAL RPAREN
|
||||
;
|
||||
|
||||
count_success
|
||||
: 'countSuccess' LPAREN STRING DELIMETER DECIMAL RPAREN
|
||||
;
|
||||
|
||||
count_error
|
||||
: 'countError' LPAREN STRING DELIMETER DECIMAL DELIMETER STRING RPAREN
|
||||
;
|
||||
|
||||
sum
|
||||
: 'sum' LPAREN STRING DELIMETER DECIMAL RPAREN
|
||||
;
|
||||
|
||||
sum_success
|
||||
: 'sumSuccess' LPAREN STRING DELIMETER DECIMAL RPAREN
|
||||
;
|
||||
|
||||
sum_error
|
||||
: 'sumError' LPAREN STRING DELIMETER DECIMAL DELIMETER STRING RPAREN
|
||||
;
|
||||
|
||||
unique
|
||||
: 'unique' LPAREN STRING DELIMETER STRING RPAREN
|
||||
;
|
||||
|
||||
in
|
||||
: 'in' LPAREN STRING DELIMETER string_list RPAREN
|
||||
;
|
||||
|
||||
inWhiteList
|
||||
: 'inWhiteList' LPAREN STRING RPAREN
|
||||
;
|
||||
|
||||
inBlackList
|
||||
: 'inBlackList' LPAREN STRING RPAREN
|
||||
;
|
||||
|
||||
like
|
||||
: 'like' LPAREN STRING DELIMETER STRING RPAREN
|
||||
;
|
||||
|
||||
equals_country
|
||||
: 'equals_country' LPAREN RPAREN
|
||||
;
|
||||
|
||||
DELIMETER : ',' ;
|
||||
|
||||
result
|
||||
: 'accept' | '3ds' | 'decline' | 'notify'
|
||||
;
|
||||
|
||||
STRING
|
||||
: '"' (~["\r\n] | '""')* '"'
|
||||
;
|
||||
|
||||
string_list
|
||||
: STRING (',' STRING | WS)+
|
||||
;
|
||||
|
||||
COMMENT
|
||||
: '#' ~[\r\n]* -> skip
|
||||
;
|
||||
|
||||
RETURN : '->' ;
|
||||
RULE_BLOCK : 'rule:' ;
|
||||
AND : 'AND' ;
|
||||
OR : 'OR' ;
|
||||
NOT : 'NOT';
|
||||
TRUE : 'TRUE' ;
|
||||
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 : ';';
|
@ -0,0 +1,13 @@
|
||||
package com.rbkmoney.fraudo.aggregator;
|
||||
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
|
||||
public interface CountAggregator {
|
||||
|
||||
Integer count(CheckedField checkedField, String valueField, Long timeInMinutes);
|
||||
|
||||
Integer countSuccess(CheckedField checkedField, String valueField, Long timeInMinutes);
|
||||
|
||||
Integer countError(CheckedField checkedField, String valueField, Long timeInMinutes, String errorCode);
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.rbkmoney.fraudo.aggregator;
|
||||
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
|
||||
public interface SumAggregator {
|
||||
|
||||
Double sum(CheckedField checkedField, String email, Long timeInMinutes);
|
||||
|
||||
Double sumSuccess(CheckedField checkedField, String valueField, Long timeInMinutes);
|
||||
|
||||
Double sumError(CheckedField checkedField, String valueField, Long timeInMinutes, String errorCode);
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.rbkmoney.fraudo.aggregator;
|
||||
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
|
||||
public interface UniqueValueAggregator {
|
||||
|
||||
Integer countUniqueValue(CheckedField countField, CheckedField onField);
|
||||
|
||||
}
|
35
src/main/java/com/rbkmoney/fraudo/constant/CheckedField.java
Normal file
35
src/main/java/com/rbkmoney/fraudo/constant/CheckedField.java
Normal file
@ -0,0 +1,35 @@
|
||||
package com.rbkmoney.fraudo.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum CheckedField {
|
||||
|
||||
EMAIL("email"),
|
||||
IP("ip"),
|
||||
FINGERPRINT("fingerprint"),
|
||||
COUNTRY_BANK("country_bank"),
|
||||
COUNTRY_IP("country_ip"),
|
||||
BIN("bin"),
|
||||
SHOP_ID("shop_ip"),
|
||||
PARTY_ID("party_id"),
|
||||
CARD_TOKEN("card_token");
|
||||
|
||||
private String value;
|
||||
private static Map<String, CheckedField> valueMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (CheckedField value : CheckedField.values()) {
|
||||
valueMap.put(value.value, value);
|
||||
}
|
||||
}
|
||||
|
||||
CheckedField(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static CheckedField getByValue(String value) {
|
||||
return valueMap.get(value);
|
||||
}
|
||||
|
||||
}
|
30
src/main/java/com/rbkmoney/fraudo/constant/ResultStatus.java
Normal file
30
src/main/java/com/rbkmoney/fraudo/constant/ResultStatus.java
Normal file
@ -0,0 +1,30 @@
|
||||
package com.rbkmoney.fraudo.constant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum ResultStatus {
|
||||
|
||||
ACCEPT("accept"),
|
||||
THREE_DS("3ds"),
|
||||
DECLINE("decline"),
|
||||
NOTIFY("notify");
|
||||
|
||||
private String value;
|
||||
private static Map<String, ResultStatus> valueMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (ResultStatus value : ResultStatus.values()) {
|
||||
valueMap.put(value.value, value);
|
||||
}
|
||||
}
|
||||
|
||||
ResultStatus(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ResultStatus getByValue(String value) {
|
||||
return valueMap.get(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.rbkmoney.fraudo.exception;
|
||||
|
||||
public class FieldUnsetException extends RuntimeException {
|
||||
|
||||
public static final String ERROR_MESSAGE = "Count target field is not set or bad format! (must be \"*\")";
|
||||
|
||||
public FieldUnsetException() {
|
||||
super(ERROR_MESSAGE);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.rbkmoney.fraudo.exception;
|
||||
|
||||
public class NotImplementedOperatorException extends RuntimeException{
|
||||
|
||||
public static final String ERROR_MESSAGE = "not implemented: operator ";
|
||||
|
||||
public NotImplementedOperatorException(String operator) {
|
||||
super(ERROR_MESSAGE + operator);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.rbkmoney.fraudo.exception;
|
||||
|
||||
public class UnknownResultException extends RuntimeException {
|
||||
|
||||
public static final String ERROR_MESSAGE = "Unknown result: ";
|
||||
|
||||
public UnknownResultException(String result) {
|
||||
super(ERROR_MESSAGE + result);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.rbkmoney.fraudo.exception;
|
||||
|
||||
public class UnresolvableFieldException extends RuntimeException {
|
||||
|
||||
public static final String ERROR_MESSAGE = "Can't find this field: ";
|
||||
|
||||
public UnresolvableFieldException(String fieldName) {
|
||||
super(ERROR_MESSAGE + fieldName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.rbkmoney.fraudo.factory;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoVisitor;
|
||||
import com.rbkmoney.fraudo.aggregator.CountAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.SumAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.model.FraudModel;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.visitor.*;
|
||||
|
||||
public class FastFraudVisitorFactory implements FraudVisitorFactory {
|
||||
|
||||
@Override
|
||||
public FraudoVisitor<Object> createVisitor(FraudModel model, CountAggregator countAggregator,
|
||||
SumAggregator sumAggregator, UniqueValueAggregator uniqueValueAggregator,
|
||||
CountryResolver countryResolver, InListFinder blackListFinder,
|
||||
InListFinder whiteListFinder) {
|
||||
CountVisitorImpl countVisitor = new CountVisitorImpl(model, countAggregator);
|
||||
SumVisitorImpl sumVisitor = new SumVisitorImpl(model, sumAggregator);
|
||||
ListVisitorImpl listVisitor = new ListVisitorImpl(model, blackListFinder, whiteListFinder);
|
||||
CustomFuncVisitorImpl customFuncVisitor = new CustomFuncVisitorImpl(model, uniqueValueAggregator, countryResolver);
|
||||
return new FastFraudVisitorImpl(countVisitor, sumVisitor, listVisitor, customFuncVisitor);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.rbkmoney.fraudo.factory;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoVisitor;
|
||||
import com.rbkmoney.fraudo.aggregator.CountAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.SumAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.model.FraudModel;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
|
||||
public interface FraudVisitorFactory {
|
||||
|
||||
FraudoVisitor<Object> createVisitor(FraudModel model, CountAggregator countAggregator,
|
||||
SumAggregator sumAggregator, UniqueValueAggregator uniqueValueAggregator,
|
||||
CountryResolver countryResolver, InListFinder blackListFinder,
|
||||
InListFinder whiteListFinder);
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.rbkmoney.fraudo.finder;
|
||||
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
|
||||
public interface InListFinder {
|
||||
|
||||
Boolean findInList(CheckedField field, String value);
|
||||
|
||||
}
|
15
src/main/java/com/rbkmoney/fraudo/model/FraudModel.java
Normal file
15
src/main/java/com/rbkmoney/fraudo/model/FraudModel.java
Normal file
@ -0,0 +1,15 @@
|
||||
package com.rbkmoney.fraudo.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FraudModel {
|
||||
|
||||
private String ip;
|
||||
private String email;
|
||||
private String bin;
|
||||
private String fingerprint;
|
||||
private String shopId;
|
||||
private String partyId;
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.rbkmoney.fraudo.resolver;
|
||||
|
||||
public interface CountryResolver {
|
||||
|
||||
String resolveCountryBank(String bank);
|
||||
|
||||
String resolveCountryIp(String ip);
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.rbkmoney.fraudo.resolver;
|
||||
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
import com.rbkmoney.fraudo.exception.UnresolvableFieldException;
|
||||
import com.rbkmoney.fraudo.model.FraudModel;
|
||||
|
||||
public class FieldResolver {
|
||||
|
||||
public static String resolveString(String fieldName, FraudModel fraudModel) {
|
||||
switch (CheckedField.getByValue(fieldName)) {
|
||||
case BIN:
|
||||
return fraudModel.getBin();
|
||||
case IP:
|
||||
return fraudModel.getIp();
|
||||
case FINGERPRINT:
|
||||
return fraudModel.getFingerprint();
|
||||
case EMAIL:
|
||||
return fraudModel.getEmail();
|
||||
default:
|
||||
throw new UnresolvableFieldException(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
16
src/main/java/com/rbkmoney/fraudo/utils/TextUtil.java
Normal file
16
src/main/java/com/rbkmoney/fraudo/utils/TextUtil.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.rbkmoney.fraudo.utils;
|
||||
|
||||
import com.rbkmoney.fraudo.exception.FieldUnsetException;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class TextUtil {
|
||||
|
||||
public static String safeGetText(TerminalNode field) {
|
||||
return Optional.ofNullable(field)
|
||||
.orElseThrow(FieldUnsetException::new)
|
||||
.getText().replace("\"", "");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoBaseVisitor;
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.aggregator.CountAggregator;
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
import com.rbkmoney.fraudo.model.FraudModel;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CountVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
|
||||
private final FraudModel fraudModel;
|
||||
private final CountAggregator countAggregator;
|
||||
|
||||
@Override
|
||||
public Object visitCount(com.rbkmoney.fraudo.FraudoParser.CountContext ctx) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
String time = TextUtil.safeGetText(ctx.DECIMAL());
|
||||
return (double) countAggregator.count(CheckedField.getByValue(countTarget), fraudModel.getEmail(),
|
||||
Long.valueOf(time));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCount_success(FraudoParser.Count_successContext ctx) {
|
||||
String countTarget = ctx.STRING().getText();
|
||||
String time = TextUtil.safeGetText(ctx.DECIMAL());
|
||||
return (double) countAggregator.countSuccess(CheckedField.getByValue(countTarget), fraudModel.getEmail(),
|
||||
Long.valueOf(time));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCount_error(FraudoParser.Count_errorContext ctx) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING(0));
|
||||
String time = TextUtil.safeGetText(ctx.DECIMAL());
|
||||
String errorCode = TextUtil.safeGetText(ctx.STRING(1));
|
||||
return (double) countAggregator.countError(CheckedField.getByValue(countTarget), fraudModel.getEmail(),
|
||||
Long.valueOf(time), errorCode);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoBaseVisitor;
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
import com.rbkmoney.fraudo.model.FraudModel;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CustomFuncVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
|
||||
private final FraudModel fraudModel;
|
||||
private final UniqueValueAggregator uniqueValueAggregator;
|
||||
private final CountryResolver countryResolver;
|
||||
|
||||
@Override
|
||||
public Object visitEquals_country(FraudoParser.Equals_countryContext ctx) {
|
||||
String countryIp = countryResolver.resolveCountryIp(fraudModel.getIp());
|
||||
String countryBank = countryResolver.resolveCountryBank(fraudModel.getBin());
|
||||
return countryBank.equals(countryIp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitIn(FraudoParser.InContext ctx) {
|
||||
String field = TextUtil.safeGetText(ctx.STRING());
|
||||
String fieldValue = FieldResolver.resolveString(field, fraudModel);
|
||||
for (TerminalNode string : ctx.string_list().STRING()) {
|
||||
if (fieldValue.equals(TextUtil.safeGetText(string))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLike(FraudoParser.LikeContext ctx) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING(0));
|
||||
String fieldValue = FieldResolver.resolveString(fieldName, fraudModel);
|
||||
String pattern = TextUtil.safeGetText(ctx.STRING(1));
|
||||
return fieldValue.matches(pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitUnique(FraudoParser.UniqueContext ctx) {
|
||||
String field = TextUtil.safeGetText(ctx.STRING(0));
|
||||
String fieldBy = TextUtil.safeGetText(ctx.STRING(1));
|
||||
return (double) uniqueValueAggregator.countUniqueValue(CheckedField.getByValue(field), CheckedField.getByValue(fieldBy));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
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.UnknownResultException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class FastFraudVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
|
||||
private final CountVisitorImpl countVisitor;
|
||||
private final SumVisitorImpl sumVisitor;
|
||||
private final ListVisitorImpl listVisitor;
|
||||
private final CustomFuncVisitorImpl customFuncVisitor;
|
||||
|
||||
@Override
|
||||
public Object visitFraud_rule(com.rbkmoney.fraudo.FraudoParser.Fraud_ruleContext ctx) {
|
||||
if (asBoolean(ctx.expression())) {
|
||||
return super.visit(ctx.result());
|
||||
}
|
||||
return ResultStatus.ACCEPT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitParse(com.rbkmoney.fraudo.FraudoParser.ParseContext ctx) {
|
||||
for (com.rbkmoney.fraudo.FraudoParser.Fraud_ruleContext fraud_ruleContext : ctx.fraud_rule()) {
|
||||
if (asBoolean(fraud_ruleContext.expression())) {
|
||||
String result = fraud_ruleContext.result().getText();
|
||||
return Optional.ofNullable(ResultStatus.getByValue(result))
|
||||
.orElseThrow(() -> new UnknownResultException(result));
|
||||
}
|
||||
}
|
||||
return ResultStatus.ACCEPT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitResult(com.rbkmoney.fraudo.FraudoParser.ResultContext ctx) {
|
||||
return ctx.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDecimalExpression(com.rbkmoney.fraudo.FraudoParser.DecimalExpressionContext ctx) {
|
||||
return Double.valueOf(ctx.DECIMAL().getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitNotExpression(com.rbkmoney.fraudo.FraudoParser.NotExpressionContext ctx) {
|
||||
return !((Boolean) this.visit(ctx.expression()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitParenExpression(com.rbkmoney.fraudo.FraudoParser.ParenExpressionContext ctx) {
|
||||
return super.visit(ctx.expression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitComparatorExpression(com.rbkmoney.fraudo.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(com.rbkmoney.fraudo.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(com.rbkmoney.fraudo.FraudoParser.BoolExpressionContext ctx) {
|
||||
return Boolean.valueOf(ctx.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCount(com.rbkmoney.fraudo.FraudoParser.CountContext ctx) {
|
||||
return countVisitor.visitCount(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCount_success(FraudoParser.Count_successContext ctx) {
|
||||
return countVisitor.visitCount_success(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCount_error(FraudoParser.Count_errorContext ctx) {
|
||||
return countVisitor.visitCount_error(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitSum(FraudoParser.SumContext ctx) {
|
||||
return sumVisitor.visitSum(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitSum_success(FraudoParser.Sum_successContext ctx) {
|
||||
return sumVisitor.visitSum_success(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitSum_error(FraudoParser.Sum_errorContext ctx) {
|
||||
return sumVisitor.visitSum_error(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitEquals_country(FraudoParser.Equals_countryContext ctx) {
|
||||
return customFuncVisitor.visitEquals_country(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitIn(FraudoParser.InContext ctx) {
|
||||
return customFuncVisitor.visitIn(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLike(FraudoParser.LikeContext ctx) {
|
||||
return customFuncVisitor.visitLike(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitUnique(FraudoParser.UniqueContext ctx) {
|
||||
return customFuncVisitor.visitUnique(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitInWhiteList(FraudoParser.InWhiteListContext ctx) {
|
||||
return listVisitor.visitInWhiteList(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitInBlackList(FraudoParser.InBlackListContext ctx) {
|
||||
return listVisitor.visitInBlackList(ctx);
|
||||
}
|
||||
|
||||
private boolean asBoolean(com.rbkmoney.fraudo.FraudoParser.ExpressionContext ctx) {
|
||||
return (boolean) visit(ctx);
|
||||
}
|
||||
|
||||
private double asDouble(com.rbkmoney.fraudo.FraudoParser.ExpressionContext ctx) {
|
||||
return (double) visit(ctx);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoBaseVisitor;
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.model.FraudModel;
|
||||
import com.rbkmoney.fraudo.resolver.FieldResolver;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ListVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
|
||||
private final FraudModel fraudModel;
|
||||
private final InListFinder blackListFinder;
|
||||
private final InListFinder whiteListFinder;
|
||||
|
||||
@Override
|
||||
public Object visitInWhiteList(FraudoParser.InWhiteListContext ctx) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING());
|
||||
String fieldValue = FieldResolver.resolveString(fieldName, fraudModel);
|
||||
return whiteListFinder.findInList(CheckedField.getByValue(fieldName), fieldValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitInBlackList(FraudoParser.InBlackListContext ctx) {
|
||||
String fieldName = TextUtil.safeGetText(ctx.STRING());
|
||||
String fieldValue = FieldResolver.resolveString(fieldName, fraudModel);
|
||||
return blackListFinder.findInList(CheckedField.getByValue(fieldName), fieldValue);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.rbkmoney.fraudo.visitor;
|
||||
|
||||
import com.rbkmoney.fraudo.FraudoBaseVisitor;
|
||||
import com.rbkmoney.fraudo.FraudoParser;
|
||||
import com.rbkmoney.fraudo.aggregator.SumAggregator;
|
||||
import com.rbkmoney.fraudo.constant.CheckedField;
|
||||
import com.rbkmoney.fraudo.model.FraudModel;
|
||||
import com.rbkmoney.fraudo.utils.TextUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class SumVisitorImpl extends FraudoBaseVisitor<Object> {
|
||||
|
||||
private final FraudModel fraudModel;
|
||||
private final SumAggregator sumAggregator;
|
||||
|
||||
@Override
|
||||
public Object visitSum(FraudoParser.SumContext ctx) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
String time = TextUtil.safeGetText(ctx.DECIMAL());
|
||||
return sumAggregator.sum(CheckedField.getByValue(countTarget), fraudModel.getEmail(), Long.valueOf(time));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitSum_success(FraudoParser.Sum_successContext ctx) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING());
|
||||
return sumAggregator.sumSuccess(CheckedField.getByValue(countTarget), fraudModel.getEmail(), Long.valueOf(ctx.DECIMAL().getText()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitSum_error(FraudoParser.Sum_errorContext ctx) {
|
||||
String countTarget = TextUtil.safeGetText(ctx.STRING(0));
|
||||
String errorCode = TextUtil.safeGetText(ctx.STRING(1));
|
||||
return sumAggregator.sumError(CheckedField.getByValue(countTarget), fraudModel.getEmail(),
|
||||
Long.valueOf(ctx.DECIMAL().getText()), errorCode);
|
||||
}
|
||||
|
||||
}
|
225
src/test/java/com/rbkmoney/fraudo/FraudoTest.java
Normal file
225
src/test/java/com/rbkmoney/fraudo/FraudoTest.java
Normal file
@ -0,0 +1,225 @@
|
||||
package com.rbkmoney.fraudo;
|
||||
|
||||
import com.rbkmoney.fraudo.aggregator.CountAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.SumAggregator;
|
||||
import com.rbkmoney.fraudo.aggregator.UniqueValueAggregator;
|
||||
import com.rbkmoney.fraudo.constant.ResultStatus;
|
||||
import com.rbkmoney.fraudo.exception.UnknownResultException;
|
||||
import com.rbkmoney.fraudo.factory.FastFraudVisitorFactory;
|
||||
import com.rbkmoney.fraudo.finder.InListFinder;
|
||||
import com.rbkmoney.fraudo.model.FraudModel;
|
||||
import com.rbkmoney.fraudo.resolver.CountryResolver;
|
||||
import org.antlr.v4.runtime.ANTLRInputStream;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
|
||||
public class FraudoTest {
|
||||
|
||||
public static final String TEST_GMAIL_RU = "test@gmail.ru";
|
||||
|
||||
@Mock
|
||||
CountAggregator countAggregator;
|
||||
@Mock
|
||||
SumAggregator sumAggregator;
|
||||
@Mock
|
||||
UniqueValueAggregator uniqueValueAggregator;
|
||||
@Mock
|
||||
CountryResolver countryResolver;
|
||||
@Mock
|
||||
InListFinder whiteListFinder;
|
||||
@Mock
|
||||
InListFinder blackListFinder;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void threeDsTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/three_ds.frd");
|
||||
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));
|
||||
|
||||
Mockito.when(countAggregator.count(anyObject(), anyString(), anyLong())).thenReturn(10);
|
||||
Object result = new FastFraudVisitorFactory().createVisitor(new FraudModel(), countAggregator,
|
||||
sumAggregator, uniqueValueAggregator, countryResolver, blackListFinder, whiteListFinder).visit(parser.parse());
|
||||
Assert.assertEquals(ResultStatus.THREE_DS, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notifyTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/notify.frd");
|
||||
Object result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void declineTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/decline.frd");
|
||||
Object result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.DECLINE, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/accept.frd");
|
||||
Object result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ruleIsNotFireTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/rule_is_not_fire.frd");
|
||||
Object result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result);
|
||||
}
|
||||
|
||||
@Test(expected = UnknownResultException.class)
|
||||
public void notImplOperatorTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/unknownResult.frd");
|
||||
parseAndVisit(resourceAsStream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void countTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/count.frd");
|
||||
Mockito.when(countAggregator.count(anyObject(), anyString(), anyLong())).thenReturn(10);
|
||||
Mockito.when(countAggregator.countError(anyObject(), anyString(), anyLong(), anyString())).thenReturn(6);
|
||||
Mockito.when(countAggregator.countSuccess(anyObject(), anyString(), anyLong())).thenReturn(4);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Object result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
|
||||
Mockito.when(countAggregator.count(anyObject(), anyString(), anyLong())).thenReturn(9);
|
||||
Mockito.when(countAggregator.countError(anyObject(), anyString(), anyLong(), anyString())).thenReturn(6);
|
||||
Mockito.when(countAggregator.countSuccess(anyObject(), anyString(), anyLong())).thenReturn(6);
|
||||
|
||||
result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sumTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/sum.frd");
|
||||
Mockito.when(sumAggregator.sum(anyObject(), anyString(), anyLong())).thenReturn(10500.60);
|
||||
Mockito.when(sumAggregator.sumError(anyObject(), anyString(), anyLong(), anyString())).thenReturn(524.0);
|
||||
Mockito.when(sumAggregator.sumSuccess(anyObject(), anyString(), anyLong())).thenReturn(4.0);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Object result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
|
||||
Mockito.when(sumAggregator.sum(anyObject(), anyString(), anyLong())).thenReturn(90.0);
|
||||
Mockito.when(sumAggregator.sumError(anyObject(), anyString(), anyLong(), anyString())).thenReturn(524.0);
|
||||
Mockito.when(sumAggregator.sumSuccess(anyObject(), anyString(), anyLong())).thenReturn(501.0);
|
||||
|
||||
result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/in.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
FraudModel model = new FraudModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
Object result = invoke(parseContext, model);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void likeTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/like.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
FraudModel model = new FraudModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
Object result = invoke(parseContext, model);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
|
||||
model.setEmail("teeeee");
|
||||
result = invoke(parseContext, model);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inNotTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/in_not.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
FraudModel model = new FraudModel();
|
||||
model.setEmail(TEST_GMAIL_RU);
|
||||
Object result = invoke(parseContext, model);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uniqCountTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/count_uniq.frd");
|
||||
Mockito.when(uniqueValueAggregator.countUniqueValue(any(), any())).thenReturn(2);
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Object result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.DECLINE, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whiteBlackListTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/whitelist.frd");
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parseContext = getParseContext(resourceAsStream);
|
||||
Mockito.when(whiteListFinder.findInList(any(), anyString())).thenReturn(true);
|
||||
Object result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
|
||||
resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/blacklist.frd");
|
||||
parseContext = getParseContext(resourceAsStream);
|
||||
Mockito.when(blackListFinder.findInList(any(), anyString())).thenReturn(true);
|
||||
result = invokeParse(parseContext);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eqCountryTest() throws Exception {
|
||||
InputStream resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/eq_country.frd");
|
||||
|
||||
Mockito.when(countryResolver.resolveCountryBank(anyString())).thenReturn("RU");
|
||||
Mockito.when(countryResolver.resolveCountryIp(anyString())).thenReturn("RU");
|
||||
|
||||
Object result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.NOTIFY, result);
|
||||
|
||||
Mockito.when(countryResolver.resolveCountryBank(anyString())).thenReturn("US");
|
||||
resourceAsStream = FraudoTest.class.getResourceAsStream("/rules/eq_country.frd");
|
||||
result = parseAndVisit(resourceAsStream);
|
||||
Assert.assertEquals(ResultStatus.ACCEPT, result);
|
||||
}
|
||||
|
||||
private Object parseAndVisit(InputStream resourceAsStream) throws IOException {
|
||||
com.rbkmoney.fraudo.FraudoParser.ParseContext parse = getParseContext(resourceAsStream);
|
||||
return invokeParse(parse);
|
||||
}
|
||||
|
||||
private Object invokeParse(com.rbkmoney.fraudo.FraudoParser.ParseContext parse) {
|
||||
FraudModel model = new FraudModel();
|
||||
return invoke(parse, model);
|
||||
}
|
||||
|
||||
private Object invoke(com.rbkmoney.fraudo.FraudoParser.ParseContext parse, FraudModel model) {
|
||||
return new FastFraudVisitorFactory().createVisitor(model, countAggregator,
|
||||
sumAggregator, uniqueValueAggregator, countryResolver, blackListFinder, whiteListFinder).visit(parse);
|
||||
}
|
||||
|
||||
private com.rbkmoney.fraudo.FraudoParser.ParseContext getParseContext(InputStream resourceAsStream) throws IOException {
|
||||
com.rbkmoney.fraudo.FraudoLexer lexer = new com.rbkmoney.fraudo.FraudoLexer(new ANTLRInputStream(resourceAsStream));
|
||||
com.rbkmoney.fraudo.FraudoParser parser = new com.rbkmoney.fraudo.FraudoParser(new CommonTokenStream(lexer));
|
||||
|
||||
return parser.parse();
|
||||
}
|
||||
}
|
2
src/test/resources/rules/accept.frd
Normal file
2
src/test/resources/rules/accept.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: 3 > 2 AND 1 = 1
|
||||
-> accept;
|
2
src/test/resources/rules/blacklist.frd
Normal file
2
src/test/resources/rules/blacklist.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: inBlackList("email")
|
||||
-> notify;
|
2
src/test/resources/rules/count.frd
Normal file
2
src/test/resources/rules/count.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: (count("ip", 1444) >= 10 OR countSuccess("email", 1444) > 5) AND countError("fingerprint", 1444, "error_code") > 5
|
||||
-> notify;
|
2
src/test/resources/rules/count_uniq.frd
Normal file
2
src/test/resources/rules/count_uniq.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: unique("email", "ip") < 4
|
||||
-> decline;
|
2
src/test/resources/rules/decline.frd
Normal file
2
src/test/resources/rules/decline.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: 3 > 2 AND 1 = 1
|
||||
-> decline;
|
2
src/test/resources/rules/eq_country.frd
Normal file
2
src/test/resources/rules/eq_country.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: equals_country()
|
||||
-> notify;
|
2
src/test/resources/rules/in.frd
Normal file
2
src/test/resources/rules/in.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: in("email", "test@gmail", "test@gmail.ru")
|
||||
-> notify;
|
2
src/test/resources/rules/in_not.frd
Normal file
2
src/test/resources/rules/in_not.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: in("email", "testgmail", "test@g")
|
||||
-> notify;
|
2
src/test/resources/rules/like.frd
Normal file
2
src/test/resources/rules/like.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: like("email", "test.*")
|
||||
-> notify;
|
2
src/test/resources/rules/notify.frd
Normal file
2
src/test/resources/rules/notify.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: 3 > 2 AND 1 = 1
|
||||
-> notify;
|
2
src/test/resources/rules/rule_is_not_fire.frd
Normal file
2
src/test/resources/rules/rule_is_not_fire.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: 3 < 2
|
||||
-> decline;
|
2
src/test/resources/rules/sum.frd
Normal file
2
src/test/resources/rules/sum.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: (sum("ip", 1444) >= 10500.50 OR sumSuccess("email", 1444) > 500) AND sumError("fingerprint", 1444, "error_code") > 523.12
|
||||
-> notify;
|
5
src/test/resources/rules/three_ds.frd
Normal file
5
src/test/resources/rules/three_ds.frd
Normal file
@ -0,0 +1,5 @@
|
||||
rule: 3 > 2 AND 1 > 1
|
||||
-> decline;
|
||||
|
||||
rule: count("email", 10) <= 10 AND count("ip", 1444) = 10
|
||||
-> 3ds;
|
2
src/test/resources/rules/unknownResult.frd
Normal file
2
src/test/resources/rules/unknownResult.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: 3 > 2
|
||||
-> asd;
|
2
src/test/resources/rules/whitelist.frd
Normal file
2
src/test/resources/rules/whitelist.frd
Normal file
@ -0,0 +1,2 @@
|
||||
rule: inWhiteList("email")
|
||||
-> notify;
|
Loading…
Reference in New Issue
Block a user