From 2136c4a6ba6497311e2bb980d532f78c29d9ecc6 Mon Sep 17 00:00:00 2001 From: rchen9 Date: Mon, 11 Nov 2024 19:20:16 +0800 Subject: [PATCH 1/2] feat: use java 21 --- .github/workflows/maven-core-publish.yml | 4 ++-- .github/workflows/maven-extension-publish.yml | 4 ++-- .github/workflows/maven-parent-publish.yml | 4 ++-- .github/workflows/ut.yml | 2 +- pom.xml | 12 ++++++------ 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/maven-core-publish.yml b/.github/workflows/maven-core-publish.yml index ab04855..b936216 100644 --- a/.github/workflows/maven-core-publish.yml +++ b/.github/workflows/maven-core-publish.yml @@ -16,10 +16,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '21' distribution: 'temurin' server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml server-username: MAVEN_USERNAME # env variable for username in deploy diff --git a/.github/workflows/maven-extension-publish.yml b/.github/workflows/maven-extension-publish.yml index 72af674..f18d0bc 100644 --- a/.github/workflows/maven-extension-publish.yml +++ b/.github/workflows/maven-extension-publish.yml @@ -16,10 +16,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '21' distribution: 'temurin' server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml server-username: MAVEN_USERNAME # env variable for username in deploy diff --git a/.github/workflows/maven-parent-publish.yml b/.github/workflows/maven-parent-publish.yml index ceee795..1929fea 100644 --- a/.github/workflows/maven-parent-publish.yml +++ b/.github/workflows/maven-parent-publish.yml @@ -16,10 +16,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - java-version: '11' + java-version: '21' distribution: 'temurin' server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml server-username: MAVEN_USERNAME # env variable for username in deploy diff --git a/.github/workflows/ut.yml b/.github/workflows/ut.yml index 902e2bd..b1e01d7 100644 --- a/.github/workflows/ut.yml +++ b/.github/workflows/ut.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java-version: [ 8, 11 ] + java-version: [21] steps: - uses: actions/checkout@v3 - name: "Test for JDK ${{ matrix.java-version }}" diff --git a/pom.xml b/pom.xml index 07ae0cf..92c18cf 100644 --- a/pom.xml +++ b/pom.xml @@ -14,8 +14,8 @@ - 8 - 8 + 21 + 21 UTF-8 @@ -123,8 +123,8 @@ maven-compiler-plugin 3.6.0 - 1.8 - 1.8 + 21 + 21 @@ -227,8 +227,8 @@ maven-compiler-plugin 3.6.0 - 1.8 - 1.8 + 21 + 21 From fa3d662f914a477fc04624eb414714b4595344ee Mon Sep 17 00:00:00 2001 From: rchen9 Date: Mon, 11 Nov 2024 19:15:08 +0800 Subject: [PATCH 2/2] feat: support script compare --- arex-compare-core/pom.xml | 6 +- .../arextest/diff/compare/GenericCompare.java | 16 +++ .../arextest/diff/compare/ScriptCompare.java | 72 ++++++++++ .../diff/factory/TaskThreadFactory.java | 32 ++++- .../arextest/diff/handler/CompareHandler.java | 3 + .../arextest/diff/handler/log/LogMarker.java | 67 +++++++--- .../handler/log/register/LogRegister.java | 4 + .../arextest/diff/model/CompareOptions.java | 31 ++++- .../arextest/diff/model/GlobalOptions.java | 40 ++++++ .../com/arextest/diff/model/RulesConfig.java | 23 ++++ .../diff/model/compare/CompareContext.java | 6 + .../diff/model/log/UnmatchedPairEntity.java | 3 + .../model/script/ScriptCompareConfig.java | 65 +++++++++ .../diff/model/script/ScriptContentInfo.java | 44 ++++++ .../model/script/ScriptMethodContext.java | 26 ++++ .../diff/model/script/ScriptSandbox.java | 68 ++++++++++ .../diff/utils/OptionsToRulesConvert.java | 20 +++ .../com/arextest/diff/sdk/CompareSDKTest.java | 125 ++++++++++++++++++ pom.xml | 7 +- 19 files changed, 627 insertions(+), 31 deletions(-) create mode 100644 arex-compare-core/src/main/java/com/arextest/diff/compare/ScriptCompare.java create mode 100644 arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptCompareConfig.java create mode 100644 arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptContentInfo.java create mode 100644 arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptMethodContext.java create mode 100644 arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptSandbox.java diff --git a/arex-compare-core/pom.xml b/arex-compare-core/pom.xml index f0c843e..96d5519 100644 --- a/arex-compare-core/pom.xml +++ b/arex-compare-core/pom.xml @@ -5,7 +5,7 @@ arex-compare-parent com.arextest - 0.2.17 + 0.2.18 4.0.0 @@ -36,6 +36,10 @@ org.slf4j slf4j-api + + org.javadelight + delight-nashorn-sandbox + org.junit.jupiter junit-jupiter-engine diff --git a/arex-compare-core/src/main/java/com/arextest/diff/compare/GenericCompare.java b/arex-compare-core/src/main/java/com/arextest/diff/compare/GenericCompare.java index e6acaa2..0332130 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/compare/GenericCompare.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/compare/GenericCompare.java @@ -4,6 +4,7 @@ import com.arextest.diff.handler.log.register.LogRegister; import com.arextest.diff.model.compare.CompareContext; import com.arextest.diff.model.enumeration.ParentNodeType; +import com.arextest.diff.model.exception.FindErrorException; import com.arextest.diff.model.log.NodeEntity; import com.arextest.diff.utils.IgnoreUtil; import com.arextest.diff.utils.ListUti; @@ -12,9 +13,12 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.List; import java.util.Objects; +import java.util.logging.Logger; public class GenericCompare { + private static final Logger LOGGER = Logger.getLogger(GenericCompare.class.getName()); + public static void jsonCompare(Object obj1, Object obj2, CompareContext compareContext) throws Exception { @@ -42,6 +46,18 @@ public static void jsonCompare(Object obj1, Object obj2, CompareContext compareC return; } + // custom compare + try { + if (ScriptCompare.isScriptComparisonRequired(fuzzyPath, compareContext)) { + ScriptCompare.scriptCompare(obj1, obj2, fuzzyPath, compareContext); + return; + } + } catch (FindErrorException e) { + throw e; + } catch (Exception e) { + LOGGER.warning("Script compare error: " + e.getMessage()); + } + // field missing if (obj1 == null && obj2 == null) { return; diff --git a/arex-compare-core/src/main/java/com/arextest/diff/compare/ScriptCompare.java b/arex-compare-core/src/main/java/com/arextest/diff/compare/ScriptCompare.java new file mode 100644 index 0000000..1b4de76 --- /dev/null +++ b/arex-compare-core/src/main/java/com/arextest/diff/compare/ScriptCompare.java @@ -0,0 +1,72 @@ +package com.arextest.diff.compare; + +import com.arextest.diff.handler.log.LogMarker; +import com.arextest.diff.handler.log.register.LogRegister; +import com.arextest.diff.model.compare.CompareContext; +import com.arextest.diff.model.enumeration.ParentNodeType; +import com.arextest.diff.model.exception.FindErrorException; +import com.arextest.diff.model.script.ScriptCompareConfig.ScriptMethod; +import com.arextest.diff.model.script.ScriptMethodContext; +import com.arextest.diff.model.script.ScriptSandbox; +import com.arextest.diff.utils.JacksonHelperUtil; +import java.util.List; +import javax.script.ScriptException; + +public class ScriptCompare { + + public static boolean isScriptComparisonRequired(List fuzzyPath, + CompareContext compareContext) { + return compareContext.scriptCompareConfigMap != null + && compareContext.scriptCompareConfigMap.containsKey(fuzzyPath); + } + + // custom compare + public static void scriptCompare(Object obj1, Object obj2, List fuzzyPath, + CompareContext compareContext) + throws ScriptException, NoSuchMethodException, FindErrorException { + + ScriptMethodContext context = new ScriptMethodContext(); + context.setBasePath(compareContext.currentNodeLeft); + context.setTestPath(compareContext.currentNodeRight); + + Object baseValue = JacksonHelperUtil.objectMapper.convertValue(obj1, Object.class); + Object testValue = JacksonHelperUtil.objectMapper.convertValue(obj2, Object.class); + ScriptSandbox scriptSandbox = compareContext.scriptSandbox; + ScriptMethod scriptMethod = compareContext.scriptCompareConfigMap.get(fuzzyPath); + int result = scriptSandbox.invoke(context, baseValue, testValue, scriptMethod); + if (result == ScriptCompareType.Matched) { + return; + } + LogRegister.register(obj1, obj2, + ScriptCompareType.convert(result, compareContext.parentNodeType), compareContext); + } + + public interface ScriptCompareType { + + int Matched = 1; + int Unmatched = 2; + // the node of basic msg is missing + int LEFT_MISSING = 3; + // the node of test msg is missing + int RIGHT_MISSING = 4; + + static LogMarker convert(int type, int parentType) { + switch (type) { + case Unmatched: + return LogMarker.VALUE_DIFF; + case LEFT_MISSING: + return parentType == ParentNodeType.OBJECT ? LogMarker.LEFT_OBJECT_MISSING + : LogMarker.LEFT_ARRAY_MISSING; + case RIGHT_MISSING: + return parentType == ParentNodeType.OBJECT ? LogMarker.RIGHT_OBJECT_MISSING + : LogMarker.RIGHT_ARRAY_MISSING; + default: + return LogMarker.UNKNOWN; + } + + } + + } + + +} diff --git a/arex-compare-core/src/main/java/com/arextest/diff/factory/TaskThreadFactory.java b/arex-compare-core/src/main/java/com/arextest/diff/factory/TaskThreadFactory.java index 6e3c986..30646c7 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/factory/TaskThreadFactory.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/factory/TaskThreadFactory.java @@ -10,15 +10,35 @@ public class TaskThreadFactory { private static final int CORE_SIZE = Runtime.getRuntime().availableProcessors(); private static final int MAX_POOL_SIZE = CORE_SIZE + 1; private static final int QUENE_SIZE = 500; - public static ExecutorService jsonObjectThreadPool = new ThreadPoolExecutor(CORE_SIZE, + + public static ExecutorService jsonObjectThreadPool = new ThreadPoolExecutor( + CORE_SIZE, MAX_POOL_SIZE, - 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(QUENE_SIZE), + 1, + TimeUnit.MINUTES, + new LinkedBlockingQueue<>(QUENE_SIZE), new NamedThreadFactory("JsonObject"), - new CallerRunsPolicyWithReport("JsonObject")); - public static ExecutorService structureHandlerThreadPool = new ThreadPoolExecutor(CORE_SIZE, + new CallerRunsPolicyWithReport("JsonObject") + ); + + public static ExecutorService structureHandlerThreadPool = new ThreadPoolExecutor( + CORE_SIZE, MAX_POOL_SIZE, - 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(QUENE_SIZE), + 1, + TimeUnit.MINUTES, + new LinkedBlockingQueue<>(QUENE_SIZE), new NamedThreadFactory("structureHandler"), - new CallerRunsPolicyWithReport("structureHandler")); + new CallerRunsPolicyWithReport("structureHandler") + ); + + public static ExecutorService jsEvalThreadPool = new ThreadPoolExecutor( + CORE_SIZE, + MAX_POOL_SIZE, + 1, + TimeUnit.MINUTES, + new LinkedBlockingQueue<>(QUENE_SIZE), + new NamedThreadFactory("jsEval"), + new CallerRunsPolicyWithReport("jsEval") + ); } diff --git a/arex-compare-core/src/main/java/com/arextest/diff/handler/CompareHandler.java b/arex-compare-core/src/main/java/com/arextest/diff/handler/CompareHandler.java index 7eeb7ab..05a4fa5 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/handler/CompareHandler.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/handler/CompareHandler.java @@ -37,6 +37,9 @@ public List doHandler(RulesConfig rulesConfig, KeyComputeResponse key compareContext.logProcess = logProcess; compareContext.quickCompare = rulesConfig.isQuickCompare(); + compareContext.scriptSandbox = rulesConfig.getScriptSandbox(); + compareContext.scriptCompareConfigMap = rulesConfig.getScriptCompareConfigMap(); + if (msgStructureFuture != null) { MutablePair msgStructureMutablePair = msgStructureFuture.join(); compareContext.baseMsgStructure = msgStructureMutablePair.getLeft(); diff --git a/arex-compare-core/src/main/java/com/arextest/diff/handler/log/LogMarker.java b/arex-compare-core/src/main/java/com/arextest/diff/handler/log/LogMarker.java index 516590c..eb78e25 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/handler/log/LogMarker.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/handler/log/LogMarker.java @@ -1,47 +1,70 @@ package com.arextest.diff.handler.log; public enum LogMarker { - ZERO, - // This marker indicates that there is a null value at the recursive entry - NULL_CHECK, - // This marker indicates that there is different type - TYPE_DIFF, + UNKNOWN(0), + + // This mark indicates that there is unmatched value at the comparison of value + VALUE_DIFF(1), // This marker indicates that there is right missing at the comparison of object - RIGHT_OBJECT_MISSING, + RIGHT_OBJECT_MISSING(2), // This marker indicates that there is left missing at the comparison of object - LEFT_OBJECT_MISSING, + LEFT_OBJECT_MISSING(3), - // This marker indicates that there is different count at the comparison of array - DIFF_ARRAY_COUNT, + // This mark indicates that there is left missing at the comparision of array + LEFT_ARRAY_MISSING(4), // This marker indicates that there is right missing at the comparison of array - RIGHT_ARRAY_MISSING, + RIGHT_ARRAY_MISSING(5), - // This marker indicates that there is not unique key at the left search of listkey - REPEAT_LEFT_KEY, + // This marker indicates that there is a null value at the recursive entry + NULL_CHECK(6), - // This mark indicates that there is right missing at the comparison of listKey mode - RIGHT_ARRAY_MISSING_KEY, + // This marker indicates that there is different type + TYPE_DIFF(7), - // This mark indicates that there is left missing at the comparision of array - LEFT_ARRAY_MISSING, + // This marker indicates that there is different count at the comparison of array + DIFF_ARRAY_COUNT(8), + + // This marker indicates that there is not unique key at the left search of listkey + REPEAT_LEFT_KEY(9), // This marker indicates that there is not unique key at the right search of listkey - REPEAT_RIGHT_KEY, + REPEAT_RIGHT_KEY(10), + + // This mark indicates that there is right missing at the comparison of listKey mode + RIGHT_ARRAY_MISSING_KEY(11), // This mark indicates that there is left missing at the comparison of listKey mode - LEFT_ARRAY_MISSING_KEY, + LEFT_ARRAY_MISSING_KEY(12), // This mark indicates that there is left reference not fund at the comparison of value - LEFT_REF_NOT_FOUND, + LEFT_REF_NOT_FOUND(13), // This mark indicates that there is right reference not found at the comparison of value - RIGHT_REF_NOT_FOUND, + RIGHT_REF_NOT_FOUND(14); + + private Integer code; + + LogMarker(int code) { + this.code = code; + } + + public Integer getCode() { + return code; + } + + public static LogMarker from(int code) { + for (LogMarker type : LogMarker.values()) { + if (type.getCode() == code) { + return type; + } + } + return UNKNOWN; + } + - // This mark indicates that there is unmatched value at the comparison of value - VALUE_DIFF, } diff --git a/arex-compare-core/src/main/java/com/arextest/diff/handler/log/register/LogRegister.java b/arex-compare-core/src/main/java/com/arextest/diff/handler/log/register/LogRegister.java index ff887eb..2b845a2 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/handler/log/register/LogRegister.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/handler/log/register/LogRegister.java @@ -32,6 +32,10 @@ public static void register(Object obj1, Object obj2, LogMarker logMarker, } LogEntity log = null; switch (logMarker) { + case UNKNOWN: + log = produceLog(obj1, obj2, UnmatchedType.UNMATCHED, ErrorType.NA, + compareContext.currentListKeysLeft, compareContext); + break; case NULL_CHECK: log = nullCheck(obj1, obj2, logMarker, compareContext); break; diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/CompareOptions.java b/arex-compare-core/src/main/java/com/arextest/diff/model/CompareOptions.java index e04e015..87cc283 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/model/CompareOptions.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/CompareOptions.java @@ -1,6 +1,7 @@ package com.arextest.diff.model; import com.arextest.diff.model.enumeration.CategoryType; +import com.arextest.diff.model.script.ScriptCompareConfig; import com.arextest.diff.utils.ListUti; import com.arextest.diff.utils.StringUtil; import java.util.ArrayList; @@ -23,7 +24,6 @@ public class CompareOptions { * The decompressService which is loaded from this pluginJarUrl is the level of each compare. */ private String pluginJarUrl; - /** * the collection of the node path chosen to compare */ @@ -60,6 +60,9 @@ public class CompareOptions { */ private Map, List>> listSortConfig; + + private List scriptCompareConfigList; + /** * change the message and configuration to lowercase, for the inconsistency between the actual * message and the contract case @@ -255,6 +258,28 @@ public CompareOptions putListSortConfig(Map, List>> li return this; } + public CompareOptions putScriptCompareConfig(ScriptCompareConfig scriptCompareConfig) { + if (scriptCompareConfig == null || ListUti.isEmpty(scriptCompareConfig.getNodePath())) { + return this; + } + if (this.scriptCompareConfigList == null) { + this.scriptCompareConfigList = new ArrayList<>(); + } + this.scriptCompareConfigList.add(scriptCompareConfig); + return this; + } + + public CompareOptions putScriptCompareConfig(Collection scriptCompareConfigList) { + if (scriptCompareConfigList == null || scriptCompareConfigList.isEmpty()) { + return this; + } + if (this.scriptCompareConfigList == null) { + this.scriptCompareConfigList = new ArrayList<>(); + } + this.scriptCompareConfigList.addAll(scriptCompareConfigList); + return this; + } + public CompareOptions putNameToLower(Boolean nameToLower) { this.nameToLower = nameToLower; return this; @@ -332,6 +357,10 @@ public Map, List>> getListSortConfig() { return listSortConfig; } + public List getScriptCompareConfigList() { + return scriptCompareConfigList; + } + public Boolean getNameToLower() { return nameToLower; } diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/GlobalOptions.java b/arex-compare-core/src/main/java/com/arextest/diff/model/GlobalOptions.java index 8209885..31faa90 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/model/GlobalOptions.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/GlobalOptions.java @@ -1,11 +1,16 @@ package com.arextest.diff.model; import com.arextest.diff.handler.decompress.TransformServiceBuilder; +import com.arextest.diff.model.script.ScriptContentInfo; +import com.arextest.diff.model.script.ScriptSandbox; import com.arextest.diff.utils.StringUtil; +import java.util.Collection; import java.util.Set; public class GlobalOptions { + private ScriptSandbox scriptSandbox = new ScriptSandbox(); + /** * The url address of the plug-in jar which is specified by the interface http or absolute path. * The decompressService which is loaded from this pluginJarUrl is the level of SYSTEM. @@ -177,4 +182,39 @@ public Boolean getOnlyCompareExistListElements() { return onlyCompareExistListElements; } + // region scriptSandbox + public GlobalOptions putCompareScript(ScriptContentInfo scriptContentInfo) { + scriptSandbox.putCompareScript(scriptContentInfo); + return this; + } + + public GlobalOptions putCompareScript(Collection scriptContentInfo) { + if (scriptContentInfo == null || scriptContentInfo.isEmpty()) { + return this; + } + for (ScriptContentInfo script : scriptContentInfo) { + scriptSandbox.putCompareScript(script); + } + return this; + } + + public GlobalOptions putScriptMaxCPUTime(long maxCPUTime) { + scriptSandbox.getSandbox().setMaxCPUTime(maxCPUTime); + return this; + } + + public GlobalOptions putScriptMaxMemory(long maxMemory) { + scriptSandbox.getSandbox().setMaxMemory(maxMemory); + return this; + } + + public GlobalOptions putScriptMaxPreparedStatements(int maxPreparedStatements) { + scriptSandbox.getSandbox().setMaxPreparedStatements(maxPreparedStatements); + return this; + } + + public ScriptSandbox getScriptSandbox() { + return scriptSandbox; + } + // endregion } diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/RulesConfig.java b/arex-compare-core/src/main/java/com/arextest/diff/model/RulesConfig.java index fe47bf0..30ccf6a 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/model/RulesConfig.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/RulesConfig.java @@ -5,6 +5,8 @@ import com.arextest.diff.model.key.ListSortEntity; import com.arextest.diff.model.key.ReferenceEntity; import com.arextest.diff.model.pathparse.ExpressionNodeEntity; +import com.arextest.diff.model.script.ScriptCompareConfig.ScriptMethod; +import com.arextest.diff.model.script.ScriptSandbox; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -14,6 +16,8 @@ public class RulesConfig { + private ScriptSandbox scriptSandbox; + /** * @see CategoryType */ @@ -41,6 +45,8 @@ public class RulesConfig { private List listSortEntities = Collections.emptyList(); + private Map, ScriptMethod> scriptCompareConfigMap; + private boolean nameToLower; private boolean nullEqualsEmpty; @@ -69,6 +75,14 @@ public class RulesConfig { public RulesConfig() { } + public ScriptSandbox getScriptSandbox() { + return scriptSandbox; + } + + public void setScriptSandbox(ScriptSandbox scriptSandbox) { + this.scriptSandbox = scriptSandbox; + } + public String getCategoryType() { return categoryType; } @@ -159,6 +173,15 @@ public void setListSortEntities(List listSortEntities) { this.listSortEntities = listSortEntities; } + public Map, ScriptMethod> getScriptCompareConfigMap() { + return scriptCompareConfigMap; + } + + public void setScriptCompareConfigMap( + Map, ScriptMethod> scriptCompareConfigMap) { + this.scriptCompareConfigMap = scriptCompareConfigMap; + } + public boolean isNameToLower() { return nameToLower; } diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/compare/CompareContext.java b/arex-compare-core/src/main/java/com/arextest/diff/model/compare/CompareContext.java index 1d26f30..1dc7dbe 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/model/compare/CompareContext.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/compare/CompareContext.java @@ -6,6 +6,8 @@ import com.arextest.diff.model.log.NodeEntity; import com.arextest.diff.model.parse.MsgStructure; import com.arextest.diff.model.pathparse.ExpressionNodeEntity; +import com.arextest.diff.model.script.ScriptCompareConfig.ScriptMethod; +import com.arextest.diff.model.script.ScriptSandbox; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -61,6 +63,10 @@ public class CompareContext { public MsgStructure baseMsgStructure; public MsgStructure testMsgStructure; + public ScriptSandbox scriptSandbox; + + public Map, ScriptMethod> scriptCompareConfigMap; + public byte ignoreReferenceNotFound = 0; // 0:object 1:array diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/log/UnmatchedPairEntity.java b/arex-compare-core/src/main/java/com/arextest/diff/model/log/UnmatchedPairEntity.java index 8234706..a4784a6 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/model/log/UnmatchedPairEntity.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/log/UnmatchedPairEntity.java @@ -61,6 +61,9 @@ public void setRightUnmatchedPath(List rightUnmatchedPath) { } public UnmatchedPairEntity buildListKeys(List listKeys) { + if (listKeys == null) { + return this; + } this.listKeys = new ArrayList<>(listKeys); return this; } diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptCompareConfig.java b/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptCompareConfig.java new file mode 100644 index 0000000..fe87595 --- /dev/null +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptCompareConfig.java @@ -0,0 +1,65 @@ +package com.arextest.diff.model.script; + +import java.util.List; + +public class ScriptCompareConfig { + + List nodePath; + ScriptMethod scriptMethod; + + public ScriptCompareConfig() { + } + + public ScriptCompareConfig(List nodePath, ScriptMethod scriptMethod) { + this.nodePath = nodePath; + this.scriptMethod = scriptMethod; + } + + public List getNodePath() { + return nodePath; + } + + public void setNodePath(List nodePath) { + this.nodePath = nodePath; + } + + public ScriptMethod getScriptMethod() { + return scriptMethod; + } + + public void setScriptMethod( + ScriptMethod scriptMethod) { + this.scriptMethod = scriptMethod; + } + + public static class ScriptMethod { + + private String methodName; + private String methodArgs; + + public ScriptMethod() { + } + + public ScriptMethod(String methodName, String methodArgs) { + this.methodName = methodName; + this.methodArgs = methodArgs; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public String getMethodArgs() { + return methodArgs; + } + + public void setMethodArgs(String methodArgs) { + this.methodArgs = methodArgs; + } + } + +} diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptContentInfo.java b/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptContentInfo.java new file mode 100644 index 0000000..9458584 --- /dev/null +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptContentInfo.java @@ -0,0 +1,44 @@ +package com.arextest.diff.model.script; + +public class ScriptContentInfo { + + private String aliasName; + + private String functionName; + + private String scriptContent; + + + public ScriptContentInfo() { + } + + public ScriptContentInfo(String aliasName, String functionName, String scriptContent) { + this.aliasName = aliasName; + this.functionName = functionName; + this.scriptContent = scriptContent; + } + + public String getAliasName() { + return aliasName; + } + + public void setAliasName(String aliasName) { + this.aliasName = aliasName; + } + + public String getFunctionName() { + return functionName; + } + + public void setFunctionName(String functionName) { + this.functionName = functionName; + } + + public String getScriptContent() { + return scriptContent; + } + + public void setScriptContent(String scriptContent) { + this.scriptContent = scriptContent; + } +} diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptMethodContext.java b/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptMethodContext.java new file mode 100644 index 0000000..7401e9b --- /dev/null +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptMethodContext.java @@ -0,0 +1,26 @@ +package com.arextest.diff.model.script; + +import com.arextest.diff.model.log.NodeEntity; +import java.util.List; + +public class ScriptMethodContext { + + private List basePath; + private List testPath; + + public List getBasePath() { + return basePath; + } + + public void setBasePath(List basePath) { + this.basePath = basePath; + } + + public List getTestPath() { + return testPath; + } + + public void setTestPath(List testPath) { + this.testPath = testPath; + } +} \ No newline at end of file diff --git a/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptSandbox.java b/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptSandbox.java new file mode 100644 index 0000000..2015f1d --- /dev/null +++ b/arex-compare-core/src/main/java/com/arextest/diff/model/script/ScriptSandbox.java @@ -0,0 +1,68 @@ +package com.arextest.diff.model.script; + +import com.arextest.diff.factory.TaskThreadFactory; +import com.arextest.diff.model.script.ScriptCompareConfig.ScriptMethod; +import delight.nashornsandbox.NashornSandbox; +import delight.nashornsandbox.NashornSandboxes; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.script.Invocable; +import javax.script.ScriptException; + +public class ScriptSandbox { + + private NashornSandbox sandbox = createSandbox(); + + public ScriptSandbox() { + } + + private Map compareScripts = new HashMap<>(); + + private Set loadedScripts = new HashSet<>(); + + public NashornSandbox getSandbox() { + return sandbox; + } + + public void putCompareScript(ScriptContentInfo scriptContentInfo) { + if (scriptContentInfo.getAliasName() != null && !scriptContentInfo.getAliasName().isEmpty()) { + compareScripts.put(scriptContentInfo.getAliasName(), scriptContentInfo); + } + if (scriptContentInfo.getFunctionName() != null && !scriptContentInfo.getFunctionName() + .isEmpty()) { + compareScripts.put(scriptContentInfo.getFunctionName(), scriptContentInfo); + } + } + + public int invoke(ScriptMethodContext context, Object obj1, Object obj2, + ScriptMethod scriptMethod) + throws ScriptException, NoSuchMethodException { + + String methodName = scriptMethod.getMethodName(); + String methodArgs = scriptMethod.getMethodArgs(); + if (!loadedScripts.contains(methodName)) { + ScriptContentInfo contentInfo = compareScripts.get(methodName); + if (contentInfo == null || contentInfo.getScriptContent() == null + || contentInfo.getScriptContent().isEmpty()) { + throw new IllegalArgumentException("Script content is empty for method: " + methodName); + } + sandbox.eval(contentInfo.getScriptContent()); + loadedScripts.add(methodName); + } + String functionName = compareScripts.get(methodName).getFunctionName(); + Invocable invocable = sandbox.getSandboxedInvocable(); + return (Integer) invocable.invokeFunction(functionName, context, obj1, obj2, methodArgs); + } + + private NashornSandbox createSandbox() { + NashornSandbox nashornSandbox = NashornSandboxes.create(); + nashornSandbox.setMaxCPUTime(2 * 60 * 1000); + nashornSandbox.setMaxMemory(512 * 1024 * 1024 * 8L); + nashornSandbox.setMaxPreparedStatements(50); + nashornSandbox.setExecutor(TaskThreadFactory.jsEvalThreadPool); + return nashornSandbox; + } + +} diff --git a/arex-compare-core/src/main/java/com/arextest/diff/utils/OptionsToRulesConvert.java b/arex-compare-core/src/main/java/com/arextest/diff/utils/OptionsToRulesConvert.java index 1406c90..b3af32a 100644 --- a/arex-compare-core/src/main/java/com/arextest/diff/utils/OptionsToRulesConvert.java +++ b/arex-compare-core/src/main/java/com/arextest/diff/utils/OptionsToRulesConvert.java @@ -9,6 +9,8 @@ import com.arextest.diff.model.TransformConfig.TransformMethod; import com.arextest.diff.model.key.ListSortEntity; import com.arextest.diff.model.key.ReferenceEntity; +import com.arextest.diff.model.script.ScriptCompareConfig; +import com.arextest.diff.model.script.ScriptCompareConfig.ScriptMethod; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -22,6 +24,7 @@ public static RulesConfig optionsToConfig(String baseMsg, String testMsg, RulesConfig rulesConfig = new RulesConfig(); rulesConfig.setBaseMsg(baseMsg); rulesConfig.setTestMsg(testMsg); + rulesConfig.setScriptSandbox(globalOptions.getScriptSandbox()); systemToRules(rulesConfig); globalOptionsToRules(globalOptions, rulesConfig); @@ -43,6 +46,8 @@ private static void configToLower(RulesConfig rulesConfig) { FieldToLowerUtil.mapKeyToLower(rulesConfig.getTransformConfigMap())); FieldToLowerUtil.referenceToLower(rulesConfig.getReferenceEntities()); FieldToLowerUtil.keyConfigToLower(rulesConfig.getListSortEntities()); + rulesConfig.setScriptCompareConfigMap( + FieldToLowerUtil.mapKeyToLower(rulesConfig.getScriptCompareConfigMap())); } @@ -102,6 +107,8 @@ private static void optionsToRules(CompareOptions compareOptions, RulesConfig ru rulesConfig.setReferenceEntities(referenceConfigConvert(compareOptions.getReferenceConfig())); rulesConfig.setListSortEntities(listSortConfigConvert(compareOptions.getListSortConfig(), rulesConfig.getReferenceEntities())); + rulesConfig.setScriptCompareConfigMap( + scriptCompareConfigConvert(compareOptions.getScriptCompareConfigList())); if (compareOptions.getSelectIgnoreCompare() != null) { rulesConfig.setSelectIgnoreCompare(compareOptions.getSelectIgnoreCompare()); } @@ -222,4 +229,17 @@ private static List listSortConfigConvert( } + private static Map, ScriptMethod> scriptCompareConfigConvert( + List scriptCompareConfigList) { + if (scriptCompareConfigList == null || scriptCompareConfigList.isEmpty()) { + return Collections.emptyMap(); + } + + Map, ScriptMethod> result = new HashMap<>(scriptCompareConfigList.size()); + for (ScriptCompareConfig scriptCompareConfig : scriptCompareConfigList) { + result.put(scriptCompareConfig.getNodePath(), scriptCompareConfig.getScriptMethod()); + } + return result; + } + } diff --git a/arex-compare-core/src/test/java/com/arextest/diff/sdk/CompareSDKTest.java b/arex-compare-core/src/test/java/com/arextest/diff/sdk/CompareSDKTest.java index 03793e1..5e4524d 100644 --- a/arex-compare-core/src/test/java/com/arextest/diff/sdk/CompareSDKTest.java +++ b/arex-compare-core/src/test/java/com/arextest/diff/sdk/CompareSDKTest.java @@ -6,6 +6,9 @@ import com.arextest.diff.model.TransformConfig; import com.arextest.diff.model.TransformConfig.TransformMethod; import com.arextest.diff.model.enumeration.CategoryType; +import com.arextest.diff.model.script.ScriptCompareConfig; +import com.arextest.diff.model.script.ScriptCompareConfig.ScriptMethod; +import com.arextest.diff.model.script.ScriptContentInfo; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -916,4 +919,126 @@ public void testMultiCompare() { Assertions.assertEquals(0, compare.getCode()); } + @Test + public void testScriptCompare() { + CompareSDK compareSDK = new CompareSDK(); + + compareSDK.getGlobalOptions().putCompareScript( + Arrays.asList( + new ScriptContentInfo( + "test", + "tolerance", + "function tolerance(context, baseValue, testValue, arg) {\n" + + " if(Math.abs(baseValue - testValue) <= 3) {\n" + + " return 1;\n" + + " }else{\n" + + " return 2;\n" + + " }\n" + + "}" + ) + ) + ); + + CompareOptions compareOptions = new CompareOptions(); + compareOptions.putScriptCompareConfig( + new ScriptCompareConfig(Arrays.asList("score"), new ScriptMethod("test", "")) + ); + + String baseMsg = "{\n" + + " \"score\": 18" + + "}"; + String testMsg = "{\n" + + " \"score\": 20\n" + + "}"; + CompareResult compare = compareSDK.compare(baseMsg, testMsg, compareOptions); + Assertions.assertEquals(0, compare.getLogs().size()); + } + + @Test + public void testScriptCompare2() { + CompareSDK compareSDK = new CompareSDK(); + + compareSDK.getGlobalOptions().putCompareScript( + Arrays.asList( + new ScriptContentInfo( + "", + "equals", + "function equals(context, baseValue, testValue, arg) {\n" + + " if(baseValue === null && testValue !== null) {\n" + + " return 3;\n" + + " }\n" + + " if(baseValue !== null && testValue === null) {\n" + + " return 4;\n" + + " }\n" + + " if(baseValue !== testValue) {\n" + + " return 2;\n" + + " }\n" + + " return 1;\n" + + "}" + ) + ) + ); + + CompareOptions compareOptions = new CompareOptions(); + compareOptions.putScriptCompareConfig( + new ScriptCompareConfig(Arrays.asList("scores", "maths"), new ScriptMethod("equals", "")) + ); + + String baseMsg = "{\n" + + " \"name\": \"xiaoming\",\n" + + " \"scores\": [\n" + + " {\n" + + " \"maths\": 90\n" + + " },\n" + + " {\n" + + " \"maths\": 70\n" + + " }\n" + + " ],\n" + + " \"alias\": null,\n" + + " \"age\": 18\n" + + "}"; + String testMsg = "{\n" + + " \"name\": \"xiaoming\",\n" + + " \"scores\": [\n" + + " {\n" + + " \"maths\": 18\n" + + " }\n" + + " ],\n" + + " \"alias\": null,\n" + + " \"age\": 18\n" + + "}"; + CompareResult compare = compareSDK.compare(baseMsg, testMsg, compareOptions); + Assertions.assertEquals(2, compare.getLogs().size()); + } + + + @Test + public void testScriptCompare3() { + CompareSDK compareSDK = new CompareSDK(); + + compareSDK.getGlobalOptions().putCompareScript( + Arrays.asList( + new ScriptContentInfo( + "test", + "func_67356dbc7ac2aa763be9f8af", + "function func_67356dbc7ac2aa763be9f8af(context, baseValue, testValue, arg) {return 2;}" + ) + ) + ); + + CompareOptions compareOptions = new CompareOptions(); + compareOptions.putScriptCompareConfig( + new ScriptCompareConfig(Arrays.asList("score"), new ScriptMethod("test", "")) + ); + + String baseMsg = "{\n" + + " \"score\": 18" + + "}"; + String testMsg = "{\n" + + " \"score\": 20\n" + + "}"; + CompareResult compare = compareSDK.quickCompare(baseMsg, testMsg, compareOptions); + Assertions.assertEquals(1, compare.getCode()); + } + } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 92c18cf..6db61ed 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.arextest arex-compare-parent pom - 0.2.17 + 0.2.18 arex-compare-extension arex-compare-core @@ -90,6 +90,11 @@ slf4j-api 1.7.21 + + org.javadelight + delight-nashorn-sandbox + 0.5.0 + org.junit.jupiter junit-jupiter-engine