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/AuditFieldValueSemanticsProbe.java | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 267 insertions(+), 0 deletions(-)
diff --git a/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/AuditFieldValueSemanticsProbe.java b/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/AuditFieldValueSemanticsProbe.java
new file mode 100644
index 0000000..6be9d29
--- /dev/null
+++ b/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/AuditFieldValueSemanticsProbe.java
@@ -0,0 +1,267 @@
+package jnpf.bizcommon.audit.service;
+
+import jnpf.bizcommon.audit.entity.AuditEventEntity;
+import jnpf.audit.diff.AuditFieldDiff;
+import jnpf.bizcommon.audit.entity.model.AuditFieldDiffViewVO;
+import jnpf.bizcommon.audit.service.support.AuditQueryResponseSanitizer;
+import jnpf.bizcommon.audit.service.value.AuditFieldValueResolver;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/** fieldDiffList 濂戠害銆佹棩鏈�/鏋氫妇灞曠ず銆佽劚鏁忓拰鏃犳剰涔� diff 杩囨护鎺㈤拡銆� */
+public final class AuditFieldValueSemanticsProbe {
+
+ private static int passed;
+ private static int failed;
+
+ public static void main(String[] args) {
+ String formData = "{\"fields\":["
+ + "{\"__vModel__\":\"biz_status\",\"__config__\":{\"label\":\"鐘舵�丠\","
+ + "\"noShow\":true,\"jnpfKey\":\"select\",\"dataType\":\"dictionary\"},"
+ + "\"options\":[{\"enCode\":\"created\",\"fullName\":\"宸插垱寤篭"}],"
+ + "\"props\":{\"value\":\"enCode\",\"label\":\"fullName\"}},"
+ + "{\"__vModel__\":\"shengchan_riqi\",\"__config__\":{\"label\":\"鐢熶骇鏃ユ湡\","
+ + "\"jnpfKey\":\"datePicker\"},\"format\":\"yyyy-MM-dd\"},"
+ + "{\"__vModel__\":\"jiance_xiangmu\",\"__config__\":{\"label\":\"妫�娴嬮」鐩甛","
+ + "\"jnpfKey\":\"checkbox\",\"dataType\":\"dynamic\"},\"options\":[]},"
+ + "{\"__vModel__\":\"external_status\",\"__config__\":{\"label\":\"澶栭儴鐘舵�乗","
+ + "\"jnpfKey\":\"select\",\"dataType\":\"dictionary\","
+ + "\"dictionaryType\":\"bizStatus\"}},"
+ + "{\"__vModel__\":\"approvalEvidence\",\"__config__\":{\"label\":\"瀹℃壒鍑瘉\","
+ + "\"jnpfKey\":\"signature\"}}] }";
+ Map<String, AuditFieldDiff.FieldMeta> published =
+ AuditFormRegistry.parsePublishedFieldMetadata(formData);
+ check("鐪熷疄 __vModel__/__config__ 鍙В鏋�", published.containsKey("biz_status"), published.toString());
+ check("闅愯棌琛ㄥ崟鏍囩涓嶈鐩� COMMENT", published.get("biz_status").label() == null,
+ String.valueOf(published.get("biz_status").label()));
+ check("瀛楀吀瀛楁绫诲瀷涓� enum", "enum".equals(published.get("biz_status").valueType()),
+ published.get("biz_status").valueType());
+ check("瀛楀吀 options 鍥哄寲灞曠ず蹇収", "宸插垱寤�".equals(
+ published.get("biz_status").optionDisplay("created")), "鏈В鏋�");
+ check("鍔ㄦ�佸閫夊紩鐢ㄧ被鍨嬫槑纭�", "multiReference".equals(
+ published.get("jiance_xiangmu").valueType()), published.get("jiance_xiangmu").valueType());
+ check("鏃犲唴鑱� options 鐨� dictionaryType 琚繚鐣�",
+ "bizStatus".equals(published.get("external_status").dictionaryType()),
+ published.get("external_status").dictionaryType());
+ check("闈炵害瀹氬瓧娈靛悕鐨勭鍚嶆帶浠剁敱鍏冩暟鎹爣璁拌劚鏁�",
+ AuditFieldDiff.isCredentialMetadata(published.get("approvalevidence")),
+ String.valueOf(published.get("approvalevidence").valueType()));
+
+ Map<String, AuditFieldDiff.FieldMeta> comments = new LinkedHashMap<>();
+ comments.put("biz_status", new AuditFieldDiff.FieldMeta(
+ "璇烽獙鐘舵��", null, null, "text", "input", null, Collections.emptyMap()));
+ Map<String, AuditFieldDiff.FieldMeta> metadata =
+ AuditFormRegistry.mergeFieldMetadata(comments, published);
+ check("COMMENT 鍚嶇О涓庡彂甯冭〃鍗曠被鍨嬫寜灞炴�у悎骞�", "璇烽獙鐘舵��".equals(
+ metadata.get("biz_status").label())
+ && "enum".equals(metadata.get("biz_status").valueType()),
+ String.valueOf(metadata.get("biz_status").label()));
+ Map<String, AuditFieldDiff.FieldMeta> eventLabels = new LinkedHashMap<>();
+ eventLabels.put("biz_status", new AuditFieldDiff.FieldMeta("鐘舵�丠", "select", true));
+ Map<String, AuditFieldDiff.FieldMeta> mergedEvent =
+ AuditFormRegistry.mergeFieldMetadata(metadata, eventLabels);
+ check("闅愯棌瀛楁鐨� listLog 鏍囩涓嶈鐩� COMMENT",
+ "璇烽獙鐘舵��".equals(mergedEvent.get("biz_status").label()),
+ mergedEvent.get("biz_status").label());
+
+ Map<String, Object> createRow = new LinkedHashMap<>();
+ createRow.put("flowId", "");
+ createRow.put("biz_status", "created");
+ createRow.put("external_status", "created");
+ createRow.put("approvalEvidence", "credential-from-control");
+ String produced = AuditFieldDiff.diff(null, createRow, Collections.emptySet(), metadata);
+ check("CREATE 绌哄�煎瓧娈典笉鐢熸垚 diff", !produced.contains("flowId"), produced);
+ check("鏈潵浜嬩欢鍥哄寲 valueType/componentType", produced.contains("\"valueType\":\"enum\"")
+ && produced.contains("\"componentType\":\"select\""), produced);
+ check("鏈潵浜嬩欢鍥哄寲瀛楀吀灞曠ず蹇収", produced.contains("\"newDisplay\":\"宸插垱寤篭""), produced);
+ check("鏈潵浜嬩欢鍥哄寲 dictionaryType",
+ produced.contains("\"dictionaryType\":\"bizStatus\""), produced);
+ check("鍏冩暟鎹鍚嶆帶浠跺啓鍏� fieldDiffs 鍓嶅凡鑴辨晱",
+ !produced.contains("credential-from-control") && produced.contains(AuditFieldDiff.MASKED),
+ produced);
+ String snapshot = AuditFieldDiff.snapshot(createRow, Collections.emptySet(), metadata);
+ check("鍏冩暟鎹鍚嶆帶浠跺啓鍏� dataSnapshot 鍓嶅凡鑴辨晱",
+ !snapshot.contains("credential-from-control") && snapshot.contains(AuditFieldDiff.MASKED),
+ snapshot);
+
+ String raw = "["
+ + "{\"field\":\"biz_status\",\"fieldName\":\"biz_status\",\"type\":0,"
+ + "\"oldData\":\"\",\"newData\":\"created\"},"
+ + "{\"field\":\"shengchan_riqi\",\"fieldName\":\"shengchan_riqi\",\"type\":0,"
+ + "\"oldData\":\"\",\"newData\":\"1782835200000\"},"
+ + "{\"field\":\"jianyan_biaozhun\",\"fieldName\":\"妫�楠屾爣鍑哱",\"type\":0,"
+ + "\"oldData\":\"\",\"newData\":\"standard-1\"},"
+ + "{\"field\":\"biz_sign\",\"fieldName\":\"biz_sign\",\"type\":0,"
+ + "\"oldData\":\"\",\"newData\":\"credential-raw\"},"
+ + "{\"field\":\"flowId\",\"fieldName\":\"flowId\",\"type\":0,"
+ + "\"oldData\":\"\",\"newData\":\"\"}]";
+ metadata.put("shengchan_riqi", published.get("shengchan_riqi"));
+ metadata.put("jianyan_biaozhun", new AuditFieldDiff.FieldMeta(
+ "妫�楠屾爣鍑�", "select", true, "reference", "select", null, Collections.emptyMap()));
+ String sanitized = AuditQueryResponseSanitizer.sanitizeFieldDiffs(raw, metadata);
+ check("鍏煎 fieldDiffs 杩囨护绌哄埌绌�", !sanitized.contains("flowId"), sanitized);
+ check("鍏煎 fieldDiffs 浠嶈劚鏁忕鍚�", !sanitized.contains("credential-raw")
+ && sanitized.contains(AuditFieldDiff.MASKED), sanitized);
+ check("diffCount 浣跨敤鏈夋晥椤�", AuditQueryResponseSanitizer.effectiveDiffCount(raw) == 4,
+ String.valueOf(AuditQueryResponseSanitizer.effectiveDiffCount(raw)));
+ String malformedItem = "[{\"oldData\":\"a\",\"newData\":\"b\"}]";
+ check("缂� field 鐨勬崯鍧忛」涓嶈鍏� diffCount",
+ AuditQueryResponseSanitizer.effectiveDiffCount(malformedItem) == 0,
+ String.valueOf(AuditQueryResponseSanitizer.effectiveDiffCount(malformedItem)));
+ String whitespaceChange = "[{\"field\":\"remark\",\"oldData\":\" A \",\"newData\":\"A\"}]";
+ check("闈炵┖鏂囨湰鐨勭┖鐧藉彉鍖栦粛淇濈暀",
+ AuditQueryResponseSanitizer.effectiveDiffCount(whitespaceChange) == 1,
+ String.valueOf(AuditQueryResponseSanitizer.effectiveDiffCount(whitespaceChange)));
+
+ AtomicInteger resolverCalls = new AtomicInteger();
+ AuditFieldValueResolver failingResolver = new AuditFieldValueResolver() {
+ @Override
+ public boolean supports(String targetTable) {
+ return true;
+ }
+
+ @Override
+ public void resolve(jnpf.bizcommon.audit.service.value.AuditFieldValueContext context,
+ List<AuditFieldDiffViewVO> fields) {
+ throw new IllegalStateException("expected-probe-failure");
+ }
+ };
+ AuditFieldValueResolver fakeResolver = new AuditFieldValueResolver() {
+ @Override
+ public boolean supports(String targetTable) {
+ return "lims_qingyandan".equals(targetTable);
+ }
+
+ @Override
+ public void resolve(jnpf.bizcommon.audit.service.value.AuditFieldValueContext context,
+ List<AuditFieldDiffViewVO> fields) {
+ resolverCalls.incrementAndGet();
+ for (AuditFieldDiffViewVO field : fields) {
+ if ("jianyan_biaozhun".equals(field.getField())) {
+ field.setNewDisplay("GB2 路 闃胯帿瑗挎灄鑳跺泭");
+ }
+ }
+ }
+ };
+ AuditEventEntity event = new AuditEventEntity();
+ event.setTargetTable("lims_qingyandan");
+ event.setTenantId("0");
+ event.setActionCode("CREATE");
+ AuditFieldDiffViewService viewService = new AuditFieldDiffViewService(
+ Arrays.asList(failingResolver, fakeResolver), "Asia/Shanghai");
+ List<AuditFieldDiffViewVO> views = viewService.build(event, sanitized, metadata);
+ check("鍗曚釜 resolver 澶辫触涓嶅奖鍝嶈鎯�", !views.isEmpty(), String.valueOf(views.size()));
+ check("缁撴瀯鍖栧垪琛ㄥ彧璋冪敤涓�娆℃壒閲� resolver", resolverCalls.get() == 1,
+ String.valueOf(resolverCalls.get()));
+ check("缁撴瀯鍖栧垪琛ㄩ」鏁颁笌 diffCount 涓�鑷�", views.size() == 4, String.valueOf(views.size()));
+ check("type=0 鏄庣‘杞崲 created", "created".equals(find(views, "biz_status").getChangeType()),
+ find(views, "biz_status").getChangeType());
+ check("鐘舵�佸睍绀轰娇鐢� options 蹇収", "宸插垱寤�".equals(find(views, "biz_status").getNewDisplay()),
+ find(views, "biz_status").getNewDisplay());
+ check("epoch 姣鎸変笟鍔℃椂鍖烘牸寮忓寲", "2026-07-01".equals(
+ find(views, "shengchan_riqi").getNewDisplay()),
+ find(views, "shengchan_riqi").getNewDisplay());
+ check("鏄惧紡寮曠敤瑙f瀽鍣ㄦ彁渚涙爣鍑嗗睍绀�", "GB2 路 闃胯帿瑗挎灄鑳跺泭".equals(
+ find(views, "jianyan_biaozhun").getNewDisplay()),
+ find(views, "jianyan_biaozhun").getNewDisplay());
+ String enriched = viewService.enrichForPersistence(event, sanitized, metadata);
+ check("鏈潵寮曠敤瀛楁鍥哄寲浜嬩欢鍙戠敓鏃跺睍绀哄揩鐓�",
+ enriched.contains("\"newDisplay\":\"GB2 路 闃胯帿瑗挎灄鑳跺泭\""), enriched);
+ check("灞曠ず蹇収澧炲己淇濈暀鏃� type 濂戠害", enriched.contains("\"type\":0"), enriched);
+ AuditFieldDiffViewVO sign = find(views, "biz_sign");
+ check("masked 缁撴瀯鍖栭」涓嶅惈鍘熷鍊�", Boolean.TRUE.equals(sign.getMasked())
+ && sign.getOldData() == null && sign.getNewData() == null
+ && sign.getOldDisplay() == null && sign.getNewDisplay() == null, String.valueOf(sign));
+
+ String metadataSignRaw = "[{\"field\":\"approvalEvidence\",\"fieldName\":\"瀹℃壒鍑瘉\","
+ + "\"jnpfKey\":\"signature\",\"type\":1,\"oldData\":\"old-secret\","
+ + "\"newData\":\"new-secret\",\"oldDisplay\":\"old-secret\","
+ + "\"newDisplay\":\"new-secret\"}]";
+ String metadataSignSanitized = AuditQueryResponseSanitizer.sanitizeFieldDiffs(
+ metadataSignRaw, metadata);
+ List<AuditFieldDiffViewVO> metadataSignViews = viewService.build(
+ event, metadataSignSanitized, metadata);
+ AuditFieldDiffViewVO metadataSign = find(metadataSignViews, "approvalEvidence");
+ check("鏌ヨ渚ф寜鎺т欢鍏冩暟鎹劚鏁忛潪绾﹀畾绛惧悕瀛楁",
+ !metadataSignSanitized.contains("secret")
+ && Boolean.TRUE.equals(metadataSign.getMasked())
+ && metadataSign.getOldData() == null && metadataSign.getNewData() == null,
+ metadataSignSanitized);
+ String sanitizedSnapshot = AuditQueryResponseSanitizer.sanitizeJson(
+ "{\"approvalEvidence\":\"snapshot-secret\"}", metadata);
+ check("鍘嗗彶 dataSnapshot 鎸夊綋鍓嶇鍚嶅厓鏁版嵁鍝嶅簲绾ц劚鏁�",
+ !sanitizedSnapshot.contains("snapshot-secret")
+ && sanitizedSnapshot.contains(AuditFieldDiff.MASKED), sanitizedSnapshot);
+
+ String legacyTime = "["
+ + "{\"field\":\"legacyDate\",\"fieldName\":\"鏃ユ湡\",\"jnpfKey\":\"datePicker\","
+ + "\"type\":0,\"oldData\":\"\",\"newData\":\"1782835200000\"},"
+ + "{\"field\":\"legacyTime\",\"fieldName\":\"鏃堕棿\",\"jnpfKey\":\"timePicker\","
+ + "\"type\":0,\"oldData\":\"\",\"newData\":\"1782835200000\"}]";
+ AuditFieldDiffViewService noResolverService = new AuditFieldDiffViewService(
+ Collections.emptyList(), "Asia/Shanghai");
+ List<AuditFieldDiffViewVO> legacyTimeViews = noResolverService.build(
+ event, legacyTime, Collections.emptyMap());
+ check("鏃犲綋鍓嶅厓鏁版嵁鐨� datePicker 浠嶆牸寮忓寲 epoch",
+ "2026-07-01".equals(find(legacyTimeViews, "legacyDate").getNewDisplay()),
+ find(legacyTimeViews, "legacyDate").getNewDisplay());
+ check("timePicker fallback 浣跨敤 datetime 鑰岄潪 date",
+ "datetime".equals(find(legacyTimeViews, "legacyTime").getValueType())
+ && "2026-07-01 00:00:00".equals(
+ find(legacyTimeViews, "legacyTime").getNewDisplay()),
+ find(legacyTimeViews, "legacyTime").getNewDisplay());
+
+ AuditFieldValueResolver partialFailure = new AuditFieldValueResolver() {
+ @Override
+ public boolean supports(String targetTable) {
+ return true;
+ }
+
+ @Override
+ public void resolve(jnpf.bizcommon.audit.service.value.AuditFieldValueContext context,
+ List<AuditFieldDiffViewVO> fields) {
+ fields.get(0).setNewDisplay("涓嶅簲淇濈暀鐨勫崐鎴愬搧");
+ throw new IllegalStateException("expected-after-mutation");
+ }
+ };
+ AuditFieldDiffViewService atomicService = new AuditFieldDiffViewService(
+ Collections.singletonList(partialFailure), "Asia/Shanghai");
+ List<AuditFieldDiffViewVO> atomicViews = atomicService.build(event,
+ "[{\"field\":\"remark\",\"fieldName\":\"澶囨敞\",\"type\":0,"
+ + "\"oldData\":\"\",\"newData\":\"鍘熷鍊糪"}]",
+ Collections.emptyMap());
+ check("resolver 淇敼鍚庢姏閿欎細鍘熷瓙鍥炴粴灞曠ず缁撴灉",
+ "鍘熷鍊�".equals(find(atomicViews, "remark").getNewDisplay()),
+ find(atomicViews, "remark").getNewDisplay());
+
+ System.out.println("=== 瀛楁鍊艰涔夋柇瑷�锛�" + passed + " 閫氳繃 / " + failed + " 澶辫触 ===");
+ System.exit(failed == 0 ? 0 : 1);
+ }
+
+ private static AuditFieldDiffViewVO find(List<AuditFieldDiffViewVO> views, String field) {
+ for (AuditFieldDiffViewVO view : views) {
+ if (field.equals(view.getField())) {
+ return view;
+ }
+ }
+ throw new IllegalStateException("缂哄皯瀛楁锛�" + field);
+ }
+
+ private static void check(String name, boolean ok, String detail) {
+ if (ok) {
+ passed++;
+ System.out.println(" [PASS] " + name);
+ } else {
+ failed++;
+ System.out.println(" [FAIL] " + name + " -- " + detail);
+ }
+ }
+
+ private AuditFieldValueSemanticsProbe() {
+ }
+}
--
Gitblit v1.8.0