From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/impl/AuditEventIngestMergeProbe.java | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 325 insertions(+), 0 deletions(-)
diff --git a/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/impl/AuditEventIngestMergeProbe.java b/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/impl/AuditEventIngestMergeProbe.java
new file mode 100644
index 0000000..0fdd56a
--- /dev/null
+++ b/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/impl/AuditEventIngestMergeProbe.java
@@ -0,0 +1,325 @@
+package jnpf.bizcommon.audit.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import jnpf.audit.AuditConsts;
+import jnpf.bizcommon.audit.service.support.AuditDiffKey;
+import jnpf.bizcommon.audit.service.support.AuditEventCategories;
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** 鍐欏叆渚т笁鍒嗙被涓� field_diffs 绔偣缁勫悎绾� JVM 鎺㈤拡銆� */
+public final class AuditEventIngestMergeProbe {
+ private static int passed;
+ private static int failed;
+
+ public static void main(String[] args) {
+ check("涓氬姟浜嬩欢鍒嗙被", AuditEventCategories.BUSINESS.equals(
+ AuditEventCategories.resolve(AuditConsts.TYPE_DATA_CHANGE, null)));
+ check("鏄惧紡澶嶅绛惧悕鍒嗙被", AuditEventCategories.REVIEW_SIGN.equals(
+ AuditEventCategories.resolve(AuditConsts.TYPE_E_SIGNATURE,
+ "{\"signatureRole\":\"REVIEW\"}")));
+ check("鍘嗗彶 fuhe_sign 鍒嗙被", AuditEventCategories.REVIEW_SIGN.equals(
+ AuditEventCategories.resolve(AuditConsts.TYPE_E_SIGNATURE,
+ "{\"signField\":\"fuhe_sign\"}")));
+ check("鏅�氱鍚嶉粯璁や富绛惧悕", AuditEventCategories.PRIMARY_SIGN.equals(
+ AuditEventCategories.resolve(AuditConsts.TYPE_E_SIGNATURE, "{}")));
+
+ String existing = "[{\"field\":\"status\",\"fieldName\":\"鐘舵�乗","
+ + "\"oldData\":\"draft\",\"newData\":\"submitted\"},"
+ + "{\"field\":\"amount\",\"oldData\":1,\"newData\":2}]";
+ String later = "[{\"field\":\"status\",\"fieldName\":\"涓氬姟鐘舵�乗","
+ + "\"oldData\":\"submitted\",\"newData\":\"approved\"}]";
+ String mergedLater = AuditEventServiceImpl.mergeFieldDiffs(existing, later, false, true);
+ check("鍚屽瓧娈典繚鐣欐渶鏃╂棫鍊�", mergedLater.contains("\"oldData\":\"draft\""));
+ check("鍚屽瓧娈典娇鐢ㄦ渶鏅氭柊鍊�", mergedLater.contains("\"newData\":\"approved\""));
+ check("涓嶅悓瀛楁缁勬垚骞堕泦", mergedLater.contains("\"field\":\"amount\""));
+ check("杈冩櫄鍏冩暟鎹鐩栧睍绀哄悕", mergedLater.contains("\"fieldName\":\"涓氬姟鐘舵�乗""));
+
+ String earlier = "[{\"field\":\"status\",\"oldData\":\"created\","
+ + "\"newData\":\"draft\"}]";
+ String mergedEarlier = AuditEventServiceImpl.mergeFieldDiffs(existing, earlier, true, false);
+ check("涔卞簭鍒拌揪浠嶄娇鐢ㄧ湡瀹炴渶鏃╂棫鍊�", mergedEarlier.contains("\"oldData\":\"created\""));
+ check("涔卞簭鍒拌揪涓嶈鐩栧綋鍓嶆渶鏅氭柊鍊�", mergedEarlier.contains("\"newData\":\"submitted\""));
+
+ String formCreate = "[{\"field\":\"chanpin_mingcheng\",\"fieldName\":\"浜у搧鍚嶇О\","
+ + "\"oldData\":\"\",\"newData\":\"绾㈢粏鑳瀄"},"
+ + "{\"field\":\"biz_status\",\"fieldName\":\"涓氬姟鐘舵�乗","
+ + "\"oldData\":\"\",\"newData\":\"created\",\"newDisplay\":\"宸插垱寤篭"}]";
+ String apiSubmit = "[{\"field\":\"biz_status\",\"fieldName\":\"biz_status\","
+ + "\"oldData\":\"created\",\"newData\":\"confirmed\"},"
+ + "{\"field\":\"quyang_status\",\"fieldName\":\"quyang_status\","
+ + "\"oldData\":\"\",\"newData\":\"pending_fetch\"}]";
+ String formThenApi = AuditEventServiceImpl.mergeFieldDiffs(
+ formCreate, apiSubmit, false, true, true, false,
+ protectedFields("chanpin_mingcheng", "biz_status"));
+ check("琛ㄥ崟鍏堝埌鏃朵繚鐣欒〃鍗曞垵濮嬪��",
+ hasDiff(formThenApi, "biz_status", "涓氬姟鐘舵��", "", "created"));
+ check("琛ㄥ崟鍏堝埌鏃惰ˉ鍏ユ帴鍙e瓧娈�", formThenApi.contains("\"field\":\"quyang_status\""));
+ check("琛ㄥ崟鏈夋晥鍊间笉琚帴鍙h鐩�",
+ diffHasValue(formThenApi, "biz_status", "newDisplay", "宸插垱寤�"));
+ check("琛ㄥ崟鍏堝埌鏃跺瓧娈甸『搴忎互琛ㄥ崟涓哄噯",
+ formThenApi.indexOf("chanpin_mingcheng") < formThenApi.indexOf("quyang_status"));
+
+ String apiThenForm = AuditEventServiceImpl.mergeFieldDiffs(
+ apiSubmit, formCreate, true, false, false, true,
+ protectedFields("chanpin_mingcheng", "biz_status"));
+ check("琛ㄥ崟鍚庡埌鏃朵粛淇濈暀琛ㄥ崟鍒濆鍊�",
+ hasDiff(apiThenForm, "biz_status", "涓氬姟鐘舵��", "", "created"));
+ check("琛ㄥ崟鍚庡埌鏃朵粛琛ュ叆鎺ュ彛瀛楁", apiThenForm.contains("\"field\":\"quyang_status\""));
+ check("琛ㄥ崟鍚庡埌鏃堕噸鏂版寜琛ㄥ崟瀛楁鎺掑簭",
+ apiThenForm.indexOf("chanpin_mingcheng") < apiThenForm.indexOf("quyang_status"));
+
+ String formEmpty = "[{\"field\":\"unit\",\"fieldName\":\"鍗曚綅\","
+ + "\"oldData\":\"\",\"newData\":\"\"},"
+ + "{\"field\":\"amount\",\"fieldName\":\"鏁伴噺\","
+ + "\"oldData\":\"\",\"newData\":\"0\"}]";
+ String apiFilled = "[{\"field\":\"unit\",\"oldData\":\"\",\"newData\":\"绮抃"},"
+ + "{\"field\":\"amount\",\"oldData\":\"0\",\"newData\":\"2\"}]";
+ String filled = AuditEventServiceImpl.mergeFieldDiffs(
+ formEmpty, apiFilled, true, false, true, false, protectedFields());
+ check("琛ㄥ崟绌哄�煎厑璁告帴鍙hˉ鍏�", hasDiff(filled, "unit", "鍗曚綅", "", "绮�"));
+ check("琛ㄥ崟闆跺�煎厑璁告帴鍙hˉ鍏�", hasDiff(filled, "amount", "鏁伴噺", "", "2"));
+ String olderApiIgnored = AuditEventServiceImpl.mergeFieldDiffs(
+ filled, apiFilled.replace("\"newData\":\"2\"", "\"newData\":\"1\""),
+ false, false, true, false, protectedFields());
+ check("涔卞簭鍒拌揪鐨勬棫鎺ュ彛涓嶈鐩栬緝鏂板瓧娈佃ˉ鍏呭��",
+ hasDiff(olderApiIgnored, "amount", "鏁伴噺", "", "2"));
+
+ String childForm = "[{\"field\":\"tableField1\",\"jnpfKey\":\"table\","
+ + "\"chidField\":[{\"prop\":\"name\",\"label\":\"鍚嶇О\"}],"
+ + "\"chidData\":[{\"name\":\"鏂板�糪",\"jnpf_old_name\":\"鏃у�糪",\"jnpf_type\":1}]}]";
+ String childApi = "[{\"field\":\"tableField1\",\"oldData\":\"api-old\",\"newData\":\"api-new\"}]";
+ String childMerged = AuditEventServiceImpl.mergeFieldDiffs(
+ childForm, childApi, false, true, true, false,
+ protectedFields("tableField1"));
+ check("琛ㄥ崟瀛愯〃鏄庣粏涓嶈鎺ュ彛鍚屽悕瀛楁瑕嗙洊", childMerged.contains("\"chidData\"")
+ && !childMerged.contains("api-new"));
+
+ String formSnapshot = "{\"name\":\"闄堢毊\",\"amount\":\"0\",\"unit\":\"\","
+ + "\"biz_status\":\"created\"}";
+ String apiSnapshot1 = "{\"name\":\"鎺ュ彛鍚嶇О\",\"amount\":\"2\",\"unit\":\"绮抃","
+ + "\"biz_status\":\"confirmed\",\"api_field\":\"first\"}";
+ String apiSnapshot2 = "{\"amount\":\"3\",\"api_field\":\"latest\"}";
+ String mergedSnapshot = AuditEventServiceImpl.mergeFormFirstSnapshots(
+ formSnapshot, apiSnapshot1, apiSnapshot2);
+ check("蹇収淇濈暀琛ㄥ崟鏈夋晥鍊�", snapshotHasValue(mergedSnapshot, "name", "闄堢毊")
+ && snapshotHasValue(mergedSnapshot, "biz_status", "created"));
+ check("蹇収绌哄�煎拰闆跺�煎厑璁告帴鍙hˉ鍏�", snapshotHasValue(mergedSnapshot, "amount", "3")
+ && snapshotHasValue(mergedSnapshot, "unit", "绮�"));
+ check("蹇収琛ュ叆琛ㄥ崟缂哄け瀛楁骞朵娇鐢ㄦ帴鍙f渶鏂板��",
+ snapshotHasValue(mergedSnapshot, "api_field", "latest"));
+ check("涓氬姟灞曠ず鏉ユ簮灞�0琛ㄥ崟浼樺厛浜庡眰2鎺ュ彛",
+ AuditEventServiceImpl.sourcePriority(AuditEventCategories.BUSINESS, 0)
+ > AuditEventServiceImpl.sourcePriority(AuditEventCategories.BUSINESS, 2));
+
+ String apiThenFormSnapshot = AuditEventServiceImpl.mergeSnapshots(
+ apiSnapshot1, formSnapshot, false, false, true,
+ false, true, formSnapshot);
+ String formThenApiSnapshot = AuditEventServiceImpl.mergeSnapshots(
+ formSnapshot, apiSnapshot1, true, true, true,
+ true, false, formSnapshot);
+ check("琛ㄥ崟鍜屾帴鍙h姹傚厛鍚庝笉褰卞搷蹇収鍩哄噯",
+ JSON.parseObject(apiThenFormSnapshot).equals(JSON.parseObject(formThenApiSnapshot)));
+ String newerApiKept = AuditEventServiceImpl.mergeSnapshots(
+ mergedSnapshot, apiSnapshot1, false, false, true,
+ true, false, formSnapshot);
+ check("涔卞簭鍒拌揪鐨勬棫鎺ュ彛涓嶈鐩栬緝鏂拌ˉ鍏呭��",
+ snapshotHasValue(newerApiKept, "amount", "3")
+ && snapshotHasValue(newerApiKept, "api_field", "latest"));
+
+ String noFormSnapshot = AuditEventServiceImpl.mergeSnapshots(
+ apiSnapshot2, apiSnapshot1, false, false, false,
+ false, false, null);
+ check("鏃犺〃鍗曞満鏅户缁寜杈冩柊浜嬩欢閫夋嫨蹇収",
+ JSON.parseObject(apiSnapshot2).equals(JSON.parseObject(noFormSnapshot)));
+
+ String scopedDiffs = "[{\"field\":\"name\",\"newData\":\"涓昏〃\"},"
+ + "{\"field\":\"ghost\",\"newData\":\"涓嶅瓨鍦╘"},"
+ + "{\"field\":\"tableField1\",\"jnpfKey\":\"table\","
+ + "\"targetTable\":\"child_table\","
+ + "\"chidField\":[{\"prop\":\"item_name\",\"label\":\"鍚嶇О\"},"
+ + "{\"prop\":\"ghost_child\",\"label\":\"闈炴硶\"}],"
+ + "\"chidData\":[{\"item_name\":\"A\",\"jnpf_old_item_name\":\"\","
+ + "\"ghost_child\":\"X\",\"jnpf_old_ghost_child\":\"Y\",\"jnpf_type\":0}]}]";
+ String filteredDiffs = AuditEventServiceImpl.filterFieldDiffs(
+ scopedDiffs, "main_table", table -> columns(table));
+ check("杩囨护涓昏〃涓嶅瓨鍦ㄥ瓧娈�", diffCount(filteredDiffs, "ghost") == 0
+ && diffCount(filteredDiffs, "name") == 1);
+ check("瀛愯〃瀛楁鍙寜瀵瑰簲瀛愯〃鍒楄繃婊�", filteredDiffs.contains("item_name")
+ && !filteredDiffs.contains("ghost_child")
+ && filteredDiffs.contains("\"targetTable\":\"child_table\""));
+
+ String sameNameDifferentTables = AuditEventServiceImpl.mergeFieldDiffs(
+ "[{\"field\":\"name\",\"targetTable\":\"main_table\",\"newData\":\"涓籠"}]",
+ "[{\"field\":\"name\",\"targetTable\":\"child_table\",\"newData\":\"瀛怽"}]",
+ false, true);
+ check("涓昏〃鍜屽瓙琛ㄥ悓鍚嶅瓧娈典笉浜掔浉瑕嗙洊", diffCount(sameNameDifferentTables, "name") == 2);
+
+ String firstBatchRow = batchRowDiff("row-1", "draft", "done");
+ String batchMerged = firstBatchRow;
+ for (int i = 2; i <= 10; i++) {
+ batchMerged = AuditEventServiceImpl.mergeFieldDiffs(
+ batchMerged, batchRowDiff("row-" + i, "pending-" + i, "done"), false, true);
+ }
+ boolean allTargetIdsRetained = true;
+ for (int i = 1; i <= 10; i++) {
+ allTargetIdsRetained &= batchMerged.contains("\"targetId\":\"row-" + i + "\"");
+ }
+ check("鎵归噺鎿嶄綔10鏉¤褰曠殑鍚屽瓧娈垫寜 targetId 鍏ㄩ儴淇濈暀",
+ diffCount(batchMerged, "status") == 10 && allTargetIdsRetained);
+
+ String sameBatchRowLater = "[{\"field\":\"status\",\"targetTable\":\"lims_task\","
+ + "\"targetId\":\"row-1\",\"oldData\":\"done\",\"newData\":\"archived\"}]";
+ String sameRowMerged = AuditEventServiceImpl.mergeFieldDiffs(
+ firstBatchRow, sameBatchRowLater, false, true);
+ check("鍚屼竴 targetId 鐨勫悓瀛楁浠嶅悎骞舵椂闂寸鐐�",
+ diffCount(sameRowMerged, "status") == 1
+ && sameRowMerged.contains("\"oldData\":\"draft\"")
+ && sameRowMerged.contains("\"newData\":\"archived\""));
+
+ String legacyBatchMerged = AuditEventServiceImpl.mergeFieldDiffs(
+ "[{\"field\":\"status\",\"targetTable\":\"lims_task\","
+ + "\"oldData\":\"draft\",\"newData\":\"done\"}]",
+ "[{\"field\":\"status\",\"targetTable\":\"lims_task\","
+ + "\"oldData\":\"done\",\"newData\":\"archived\"}]",
+ false, true);
+ check("鏃ф棩蹇楃己灏� targetId 鏃朵繚鎸佸師鍚堝苟瑙勫垯",
+ diffCount(legacyBatchMerged, "status") == 1);
+
+ String upgradedLegacy = AuditEventServiceImpl.scopeFieldDiffs(
+ "[{\"field\":\"status\",\"targetTable\":\"lims_task\","
+ + "\"oldData\":\"draft\",\"newData\":\"done\"}]",
+ "lims_task", "row-1");
+ String legacyRetryMerged = AuditEventServiceImpl.mergeFieldDiffs(
+ upgradedLegacy, sameBatchRowLater, false, true);
+ check("鏃ф棩蹇椾笌甯� targetId 鐨勮繜鍒颁簨浠朵笉浼氱敓鎴愰噸澶嶅瓧娈�",
+ diffCount(legacyRetryMerged, "status") == 1
+ && legacyRetryMerged.contains("\"newData\":\"archived\""));
+
+ String scopedSingle = AuditEventServiceImpl.scopeFieldDiffs(
+ "[{\"field\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"}]",
+ "lims_task", "row-1");
+ check("鍗曡褰曚簨浠惰嚜鍔ㄨˉ鍏� targetTable 鍜� targetId",
+ scopedSingle.contains("\"targetTable\":\"lims_task\"")
+ && scopedSingle.contains("\"targetId\":\"row-1\""));
+ String explicitlyScoped = AuditEventServiceImpl.scopeFieldDiffs(
+ batchRowDiff("row-2", "pending", "done"), "other_table", "other-row");
+ check("鎵归噺宸紓鏄惧紡 targetId 涓嶈椤跺眰棣栨潯璁板綍瑕嗙洊",
+ explicitlyScoped.contains("\"targetTable\":\"lims_task\"")
+ && explicitlyScoped.contains("\"targetId\":\"row-2\"")
+ && !explicitlyScoped.contains("other-row"));
+
+ String formScopedProtection = AuditEventServiceImpl.mergeFieldDiffs(
+ "[{\"field\":\"name\",\"targetTable\":\"main_table\",\"newData\":\"琛ㄥ崟涓昏〃\"},"
+ + "{\"field\":\"name\",\"targetTable\":\"child_table\",\"newData\":\"\"}]",
+ "[{\"field\":\"name\",\"targetTable\":\"main_table\",\"newData\":\"鎺ュ彛涓昏〃\"},"
+ + "{\"field\":\"name\",\"targetTable\":\"child_table\",\"newData\":\"鎺ュ彛瀛愯〃\"}]",
+ false, true, true, false,
+ protectedFields(AuditDiffKey.of("main_table", "name")));
+ check("琛ㄥ崟淇濇姢瀛楁鎸夌墿鐞嗚〃闅旂",
+ diffHasScopedValue(formScopedProtection, "main_table", "name", "琛ㄥ崟涓昏〃")
+ && diffHasScopedValue(formScopedProtection, "child_table", "name", "鎺ュ彛瀛愯〃"));
+
+ Set<String> normalizedLegacyKeys = AuditEventServiceImpl.normalizedProtectedFields(
+ Arrays.asList("main_table" + Character.MIN_VALUE + "name"));
+ String persistedKeys = JSON.toJSONString(normalizedLegacyKeys);
+ check("鏃� NUL 澶嶅悎閿啓鍥炲墠杞崲涓哄彲鎵撳嵃鏍煎紡",
+ normalizedLegacyKeys.contains(AuditDiffKey.of("main_table", "name"))
+ && AuditDiffKey.isScoped(AuditDiffKey.of("main_table", "name"))
+ && !AuditDiffKey.isScoped("@table:2147483647:x:name")
+ && persistedKeys.indexOf(Character.MIN_VALUE) < 0
+ && !persistedKeys.contains("\\u0000"));
+
+ System.out.println("=== 鍐欏叆鍚堝苟鏂█锛�" + passed + " 閫氳繃 / " + failed + " 澶辫触 ===");
+ System.exit(failed == 0 ? 0 : 1);
+ }
+
+ private static void check(String name, boolean ok) {
+ if (ok) {
+ passed++;
+ System.out.println(" [PASS] " + name);
+ } else {
+ failed++;
+ System.out.println(" [FAIL] " + name);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static boolean hasDiff(String json, String field, String fieldName,
+ String oldData, String newData) {
+ List<Map> diffs = JSON.parseArray(json, Map.class);
+ for (Map<String, Object> diff : diffs) {
+ if (field.equals(String.valueOf(diff.get("field")))
+ && fieldName.equals(String.valueOf(diff.get("fieldName")))
+ && oldData.equals(String.valueOf(diff.get("oldData")))
+ && newData.equals(String.valueOf(diff.get("newData")))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean diffHasValue(String json, String field, String key, String expected) {
+ List<Map> diffs = JSON.parseArray(json, Map.class);
+ for (Map<?, ?> diff : diffs) {
+ if (field.equals(String.valueOf(diff.get("field")))) {
+ return expected.equals(String.valueOf(diff.get(key)));
+ }
+ }
+ return false;
+ }
+
+ private static boolean snapshotHasValue(String json, String field, String expected) {
+ Map<String, Object> snapshot = JSON.parseObject(json, Map.class);
+ return expected.equals(String.valueOf(snapshot.get(field)));
+ }
+
+ private static Set<String> columns(String table) {
+ if ("main_table".equals(table)) {
+ return protectedFields("id", "name");
+ }
+ if ("child_table".equals(table)) {
+ return protectedFields("f_id", "item_name");
+ }
+ return protectedFields();
+ }
+
+ private static int diffCount(String json, String field) {
+ int count = 0;
+ for (Map<?, ?> diff : JSON.parseArray(json, Map.class)) {
+ if (field.equals(String.valueOf(diff.get("field")))) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private static String batchRowDiff(String targetId, String oldData, String newData) {
+ return "[{\"field\":\"status\",\"targetTable\":\"lims_task\",\"targetId\":\""
+ + targetId + "\",\"oldData\":\"" + oldData + "\",\"newData\":\""
+ + newData + "\"}]";
+ }
+
+ private static boolean diffHasScopedValue(String json, String table, String field, String expected) {
+ for (Map<?, ?> diff : JSON.parseArray(json, Map.class)) {
+ if (table.equals(String.valueOf(diff.get("targetTable")))
+ && field.equals(String.valueOf(diff.get("field")))) {
+ return expected.equals(String.valueOf(diff.get("newData")));
+ }
+ }
+ return false;
+ }
+
+ private static LinkedHashSet<String> protectedFields(String... fields) {
+ LinkedHashSet<String> result = new LinkedHashSet<>();
+ java.util.Collections.addAll(result, fields);
+ return result;
+ }
+
+ private AuditEventIngestMergeProbe() {
+ }
+}
--
Gitblit v1.8.0