Merge branch 'codex/project-bank-tagging-logging' into dev
This commit is contained in:
@@ -8,6 +8,7 @@ import com.ruoyi.common.utils.SecurityUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
* 项目流水标签控制器
|
||||
*/
|
||||
@Tag(name = "项目流水标签")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/ccdi/project/tags")
|
||||
public class CcdiBankTagController extends BaseController {
|
||||
@@ -32,6 +34,8 @@ public class CcdiBankTagController extends BaseController {
|
||||
@PostMapping("/rebuild")
|
||||
public AjaxResult rebuild(@Validated @RequestBody CcdiBankTagRebuildDTO dto) {
|
||||
String operator = SecurityUtils.getUsername();
|
||||
log.info("【流水标签】收到手动重算请求: projectId={}, modelCode={}, operator={}",
|
||||
dto.getProjectId(), dto.getModelCode(), operator);
|
||||
return success(bankTagService.submitRebuild(dto, operator));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,13 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 流水标签规则执行参数解析器
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class BankTagRuleConfigResolver {
|
||||
|
||||
@@ -61,11 +64,23 @@ public class BankTagRuleConfigResolver {
|
||||
|
||||
Map<String, String> thresholdValues = new LinkedHashMap<>();
|
||||
Set<String> requiredParamCodes = RULE_PARAM_MAPPING.getOrDefault(ruleMeta.getRuleCode(), Set.of());
|
||||
log.info("【流水标签】解析规则参数: projectId={}, effectiveProjectId={}, ruleCode={}, requiredParams={}",
|
||||
projectId, effectiveProjectId, ruleMeta.getRuleCode(), requiredParamCodes);
|
||||
for (CcdiModelParam param : params) {
|
||||
if (requiredParamCodes.contains(param.getParamCode())) {
|
||||
thresholdValues.put(param.getParamCode(), param.getParamValue());
|
||||
}
|
||||
}
|
||||
log.debug("【流水标签】规则参数解析结果: projectId={}, ruleCode={}, thresholdValues={}",
|
||||
projectId, ruleMeta.getRuleCode(), thresholdValues);
|
||||
|
||||
Set<String> missingParamCodes = requiredParamCodes.stream()
|
||||
.filter(code -> !thresholdValues.containsKey(code))
|
||||
.collect(Collectors.toSet());
|
||||
if (!missingParamCodes.isEmpty()) {
|
||||
log.warn("【流水标签】规则参数缺失: projectId={}, ruleCode={}, missingParams={}",
|
||||
projectId, ruleMeta.getRuleCode(), missingParamCodes);
|
||||
}
|
||||
|
||||
BankTagRuleExecutionConfig config = new BankTagRuleExecutionConfig();
|
||||
config.setProjectId(projectId);
|
||||
|
||||
@@ -24,10 +24,12 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 流水标签服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
||||
|
||||
@@ -85,16 +87,23 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
||||
* @param triggerType 触发方式
|
||||
*/
|
||||
public Long rebuildProject(Long projectId, String modelCode, String operator, TriggerType triggerType) {
|
||||
long taskStartTime = System.currentTimeMillis();
|
||||
CcdiBankTagTask task = buildRunningTask(projectId, modelCode, operator, triggerType);
|
||||
taskMapper.insertTask(task);
|
||||
log.info("【流水标签】任务创建成功: taskId={}, projectId={}, modelCode={}, triggerType={}, operator={}",
|
||||
task.getId(), projectId, modelCode, triggerType, operator);
|
||||
|
||||
try {
|
||||
List<CcdiBankTagRule> rules = ruleMapper.selectEnabledRules(modelCode);
|
||||
log.info("【流水标签】加载启用规则完成: taskId={}, projectId={}, modelCode={}, ruleCount={}",
|
||||
task.getId(), projectId, modelCode, rules.size());
|
||||
log.info("【流水标签】开始清理历史结果: taskId={}, projectId={}, modelCode={}",
|
||||
task.getId(), projectId, modelCode);
|
||||
resultMapper.deleteByProjectAndModel(projectId, modelCode);
|
||||
|
||||
List<CompletableFuture<List<CcdiBankTagResult>>> futures = rules.stream()
|
||||
.map(rule -> CompletableFuture.supplyAsync(
|
||||
() -> executeRule(projectId, rule, operator),
|
||||
() -> executeRule(task.getId(), projectId, rule, operator),
|
||||
tagRuleExecutor
|
||||
))
|
||||
.toList();
|
||||
@@ -105,6 +114,8 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
||||
.toList();
|
||||
|
||||
if (!allResults.isEmpty()) {
|
||||
log.info("【流水标签】批量写入标签结果: taskId={}, projectId={}, resultCount={}",
|
||||
task.getId(), projectId, allResults.size());
|
||||
resultMapper.insertBatch(allResults);
|
||||
}
|
||||
|
||||
@@ -117,6 +128,9 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
||||
task.setUpdateBy(operator);
|
||||
task.setUpdateTime(new Date());
|
||||
taskMapper.updateTask(task);
|
||||
log.info("【流水标签】任务执行成功: taskId={}, projectId={}, modelCode={}, triggerType={}, ruleCount={}, hitCount={}, costMs={}",
|
||||
task.getId(), projectId, modelCode, triggerType, rules.size(), allResults.size(),
|
||||
System.currentTimeMillis() - taskStartTime);
|
||||
return task.getId();
|
||||
} catch (Exception ex) {
|
||||
task.setStatus(STATUS_FAILED);
|
||||
@@ -126,6 +140,8 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
||||
task.setUpdateBy(operator);
|
||||
task.setUpdateTime(new Date());
|
||||
taskMapper.updateTask(task);
|
||||
log.error("【流水标签】任务执行失败: taskId={}, projectId={}, modelCode={}, triggerType={}, error={}",
|
||||
task.getId(), projectId, modelCode, triggerType, ex.getMessage(), ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -149,15 +165,35 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService {
|
||||
return task;
|
||||
}
|
||||
|
||||
private List<CcdiBankTagResult> executeRule(Long projectId, CcdiBankTagRule rule, String operator) {
|
||||
private List<CcdiBankTagResult> executeRule(Long taskId, Long projectId, CcdiBankTagRule rule, String operator) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
log.info("【流水标签】规则开始执行: taskId={}, projectId={}, ruleCode={}, resultType={}",
|
||||
taskId, projectId, rule.getRuleCode(), rule.getResultType());
|
||||
BankTagRuleExecutionConfig config = configResolver.resolve(projectId, rule);
|
||||
log.debug("【流水标签】规则执行参数: taskId={}, ruleCode={}, thresholds={}",
|
||||
taskId, rule.getRuleCode(), config.getThresholdValues());
|
||||
if (RESULT_TYPE_STATEMENT.equals(rule.getResultType())) {
|
||||
List<BankTagStatementHitVO> hits = executeStatementRule(projectId, rule, config);
|
||||
return buildStatementResults(projectId, rule, hits, operator);
|
||||
List<CcdiBankTagResult> results = buildStatementResults(projectId, rule, hits, operator);
|
||||
logRuleCompletion(taskId, projectId, rule.getRuleCode(), results.size(), startTime);
|
||||
return results;
|
||||
}
|
||||
|
||||
List<BankTagObjectHitVO> hits = executeObjectRule(projectId, rule, config);
|
||||
return buildObjectResults(projectId, rule, hits, operator);
|
||||
List<CcdiBankTagResult> results = buildObjectResults(projectId, rule, hits, operator);
|
||||
logRuleCompletion(taskId, projectId, rule.getRuleCode(), results.size(), startTime);
|
||||
return results;
|
||||
}
|
||||
|
||||
private void logRuleCompletion(Long taskId, Long projectId, String ruleCode, int hitCount, long startTime) {
|
||||
long costMs = System.currentTimeMillis() - startTime;
|
||||
if (hitCount == 0) {
|
||||
log.warn("【流水标签】规则无命中: taskId={}, projectId={}, ruleCode={}, costMs={}",
|
||||
taskId, projectId, ruleCode, costMs);
|
||||
return;
|
||||
}
|
||||
log.info("【流水标签】规则执行完成: taskId={}, projectId={}, ruleCode={}, hitCount={}, costMs={}",
|
||||
taskId, projectId, ruleCode, hitCount, costMs);
|
||||
}
|
||||
|
||||
private List<BankTagStatementHitVO> executeStatementRule(Long projectId,
|
||||
|
||||
@@ -679,7 +679,11 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
||||
}
|
||||
|
||||
private void handleTagRebuildAfterBatchCompletion(Long projectId, TriggerType triggerType, Boolean anySuccess) {
|
||||
log.info("【流水标签】批处理完成,准备触发自动重算: projectId={}, triggerType={}, anySuccess={}",
|
||||
projectId, triggerType, anySuccess);
|
||||
if (!Boolean.TRUE.equals(anySuccess)) {
|
||||
log.warn("【流水标签】跳过自动重算: projectId={}, triggerType={}, reason=all_records_failed",
|
||||
projectId, triggerType);
|
||||
return;
|
||||
}
|
||||
bankTagService.submitAutoRebuild(projectId, triggerType);
|
||||
|
||||
@@ -9,10 +9,12 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 项目级流水标签重算协调器
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ProjectBankTagRebuildCoordinator {
|
||||
|
||||
@@ -33,7 +35,11 @@ public class ProjectBankTagRebuildCoordinator {
|
||||
* @param operator 操作人
|
||||
*/
|
||||
public void submitManual(Long projectId, String modelCode, String operator) {
|
||||
log.info("【流水标签】手动重算开始排队: projectId={}, modelCode={}, operator={}",
|
||||
projectId, modelCode, operator);
|
||||
if (isProjectRunning(projectId)) {
|
||||
log.warn("【流水标签】项目已有运行中任务,拒绝手动重算: projectId={}, modelCode={}, operator={}",
|
||||
projectId, modelCode, operator);
|
||||
throw new ServiceException("当前项目标签正在重算中,请稍后再试");
|
||||
}
|
||||
|
||||
@@ -49,6 +55,8 @@ public class ProjectBankTagRebuildCoordinator {
|
||||
public void submitAuto(Long projectId, TriggerType triggerType) {
|
||||
CcdiBankTagTask runningTask = taskMapper.selectRunningTaskByProjectId(projectId);
|
||||
if (runningTask != null || runningProjects.containsKey(projectId)) {
|
||||
log.warn("【流水标签】项目正在重算,已标记完成后补跑: projectId={}, runningTaskId={}, triggerType={}",
|
||||
projectId, runningTask != null ? runningTask.getId() : null, triggerType);
|
||||
markNeedRerun(runningTask);
|
||||
return;
|
||||
}
|
||||
@@ -64,12 +72,15 @@ public class ProjectBankTagRebuildCoordinator {
|
||||
|
||||
private void executeWithLock(Long projectId, Runnable action) {
|
||||
if (runningProjects.putIfAbsent(projectId, Boolean.TRUE) != null) {
|
||||
log.warn("【流水标签】项目已有运行中任务,拒绝获取项目锁: projectId={}", projectId);
|
||||
throw new ServiceException("当前项目标签正在重算中,请稍后再试");
|
||||
}
|
||||
log.info("【流水标签】获取项目重算锁成功: projectId={}", projectId);
|
||||
try {
|
||||
action.run();
|
||||
} finally {
|
||||
runningProjects.remove(projectId);
|
||||
log.info("【流水标签】释放项目重算锁: projectId={}", projectId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.ruoyi.ccdi.project.controller;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.read.ListAppender;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiBankTagRebuildDTO;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiBankTagService;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
@@ -10,8 +13,10 @@ import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -42,4 +47,32 @@ class CcdiBankTagControllerTest {
|
||||
verify(bankTagService).submitRebuild(dto, "admin");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void rebuild_shouldLogManualRebuildRequest() {
|
||||
CcdiBankTagRebuildDTO dto = new CcdiBankTagRebuildDTO();
|
||||
dto.setProjectId(40L);
|
||||
dto.setModelCode("LARGE_TRANSACTION");
|
||||
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(CcdiBankTagController.class);
|
||||
ListAppender<ILoggingEvent> appender = new ListAppender<>();
|
||||
appender.start();
|
||||
logger.addAppender(appender);
|
||||
|
||||
when(bankTagService.submitRebuild(dto, "admin")).thenReturn("标签重算任务已提交");
|
||||
|
||||
try (MockedStatic<SecurityUtils> mocked = mockStatic(SecurityUtils.class)) {
|
||||
mocked.when(SecurityUtils::getUsername).thenReturn("admin");
|
||||
|
||||
controller.rebuild(dto);
|
||||
|
||||
assertTrue(appender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("收到手动重算请求")
|
||||
&& message.contains("projectId=40")
|
||||
&& message.contains("modelCode=LARGE_TRANSACTION")
|
||||
&& message.contains("operator=admin")));
|
||||
} finally {
|
||||
logger.detachAppender(appender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.ruoyi.ccdi.project.service.impl;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.read.ListAppender;
|
||||
import com.ruoyi.ccdi.project.domain.CcdiModelParam;
|
||||
import com.ruoyi.ccdi.project.domain.CcdiProject;
|
||||
import com.ruoyi.ccdi.project.domain.entity.CcdiBankTagRule;
|
||||
@@ -11,10 +14,12 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@@ -49,6 +54,42 @@ class BankTagRuleConfigResolverTest {
|
||||
assertEquals("1111", config.getThresholdValue("SINGLE_TRANSACTION_AMOUNT"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolve_shouldLogThresholdSourceAndMissingParams() {
|
||||
CcdiProject project = new CcdiProject();
|
||||
project.setProjectId(40L);
|
||||
project.setConfigType("default");
|
||||
when(projectMapper.selectById(40L)).thenReturn(project);
|
||||
when(modelParamMapper.selectByProjectAndModel(0L, "LARGE_TRANSACTION")).thenReturn(List.of(
|
||||
buildParam("LARGE_CASH_DEPOSIT", "50000")
|
||||
));
|
||||
|
||||
CcdiBankTagRule ruleMeta = new CcdiBankTagRule();
|
||||
ruleMeta.setModelCode("LARGE_TRANSACTION");
|
||||
ruleMeta.setRuleCode("FREQUENT_CASH_DEPOSIT");
|
||||
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(BankTagRuleConfigResolver.class);
|
||||
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||
logAppender.start();
|
||||
logger.addAppender(logAppender);
|
||||
|
||||
try {
|
||||
resolver.resolve(40L, ruleMeta);
|
||||
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("解析规则参数")
|
||||
&& message.contains("projectId=40")
|
||||
&& message.contains("effectiveProjectId=0")
|
||||
&& message.contains("FREQUENT_CASH_DEPOSIT")));
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("规则参数缺失")
|
||||
&& message.contains("projectId=40")
|
||||
&& message.contains("FREQUENT_CASH_DEPOSIT")));
|
||||
} finally {
|
||||
logger.detachAppender(logAppender);
|
||||
}
|
||||
}
|
||||
|
||||
private CcdiModelParam buildParam(String paramCode, String paramValue) {
|
||||
CcdiModelParam param = new CcdiModelParam();
|
||||
param.setProjectId(0L);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.ruoyi.ccdi.project.service.impl;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.read.ListAppender;
|
||||
import com.ruoyi.ccdi.project.domain.entity.CcdiBankTagRule;
|
||||
import com.ruoyi.ccdi.project.domain.entity.CcdiBankTagTask;
|
||||
import com.ruoyi.ccdi.project.domain.enums.TriggerType;
|
||||
@@ -15,13 +18,17 @@ import org.mockito.InOrder;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -81,4 +88,91 @@ class CcdiBankTagServiceImplTest {
|
||||
inOrder.verify(resultMapper).insertBatch(anyList());
|
||||
verify(taskMapper).insertTask(any(CcdiBankTagTask.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rebuildProject_shouldLogTaskLifecycleAndRuleSummary() {
|
||||
ReflectionTestUtils.setField(service, "tagRuleExecutor", (Executor) Runnable::run);
|
||||
|
||||
CcdiBankTagRule rule = new CcdiBankTagRule();
|
||||
rule.setModelCode("LARGE_TRANSACTION");
|
||||
rule.setModelName("大额交易");
|
||||
rule.setRuleCode("HOUSE_OR_CAR_EXPENSE");
|
||||
rule.setRuleName("房车消费支出交易");
|
||||
rule.setResultType("STATEMENT");
|
||||
|
||||
BankTagRuleExecutionConfig config = new BankTagRuleExecutionConfig();
|
||||
config.setProjectId(40L);
|
||||
config.setRuleMeta(rule);
|
||||
|
||||
BankTagStatementHitVO hit = new BankTagStatementHitVO();
|
||||
hit.setBankStatementId(10L);
|
||||
hit.setGroupId(40);
|
||||
hit.setLogId(40001);
|
||||
hit.setReasonDetail("命中房车消费支出");
|
||||
|
||||
doAnswer(invocation -> {
|
||||
CcdiBankTagTask task = invocation.getArgument(0);
|
||||
task.setId(88L);
|
||||
return 1;
|
||||
}).when(taskMapper).insertTask(any(CcdiBankTagTask.class));
|
||||
|
||||
when(ruleMapper.selectEnabledRules(null)).thenReturn(List.of(rule));
|
||||
when(configResolver.resolve(40L, rule)).thenReturn(config);
|
||||
when(analysisMapper.selectHouseOrCarExpenseStatements(40L)).thenReturn(List.of(hit));
|
||||
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(CcdiBankTagServiceImpl.class);
|
||||
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||
logAppender.start();
|
||||
logger.addAppender(logAppender);
|
||||
|
||||
try {
|
||||
service.rebuildProject(40L, null, "admin", TriggerType.MANUAL);
|
||||
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("任务创建成功")
|
||||
&& message.contains("taskId=88")
|
||||
&& message.contains("projectId=40")));
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("规则执行完成")
|
||||
&& message.contains("ruleCode=HOUSE_OR_CAR_EXPENSE")
|
||||
&& message.contains("hitCount=1")));
|
||||
} finally {
|
||||
logger.detachAppender(logAppender);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void rebuildProject_shouldLogFailureSummaryWhenRuleExecutionFails() {
|
||||
ReflectionTestUtils.setField(service, "tagRuleExecutor", (Executor) Runnable::run);
|
||||
|
||||
CcdiBankTagRule rule = new CcdiBankTagRule();
|
||||
rule.setModelCode("LARGE_TRANSACTION");
|
||||
rule.setRuleCode("HOUSE_OR_CAR_EXPENSE");
|
||||
rule.setResultType("STATEMENT");
|
||||
|
||||
doAnswer(invocation -> {
|
||||
CcdiBankTagTask task = invocation.getArgument(0);
|
||||
task.setId(89L);
|
||||
return 1;
|
||||
}).when(taskMapper).insertTask(any(CcdiBankTagTask.class));
|
||||
|
||||
when(ruleMapper.selectEnabledRules(null)).thenReturn(List.of(rule));
|
||||
when(configResolver.resolve(40L, rule)).thenThrow(new RuntimeException("threshold missing"));
|
||||
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(CcdiBankTagServiceImpl.class);
|
||||
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||
logAppender.start();
|
||||
logger.addAppender(logAppender);
|
||||
|
||||
try {
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> service.rebuildProject(40L, null, "admin", TriggerType.MANUAL));
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("任务执行失败")
|
||||
&& message.contains("taskId=89")
|
||||
&& message.contains("threshold missing")));
|
||||
} finally {
|
||||
logger.detachAppender(logAppender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -167,6 +167,59 @@ class CcdiFileUploadServiceImplTest {
|
||||
assertFalse(Files.exists(batchLogDir));
|
||||
}
|
||||
|
||||
@Test
|
||||
void handleTagRebuildAfterBatchCompletion_shouldLogSkipWhenAllRecordsFailed() {
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(CcdiFileUploadServiceImpl.class);
|
||||
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||
logAppender.start();
|
||||
logger.addAppender(logAppender);
|
||||
|
||||
try {
|
||||
ReflectionTestUtils.invokeMethod(
|
||||
service,
|
||||
"handleTagRebuildAfterBatchCompletion",
|
||||
PROJECT_ID,
|
||||
TriggerType.AUTO_BATCH_UPLOAD,
|
||||
Boolean.FALSE
|
||||
);
|
||||
|
||||
verify(bankTagService, never()).submitAutoRebuild(any(), any());
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("跳过自动重算")
|
||||
&& message.contains("projectId=100")
|
||||
&& message.contains("AUTO_BATCH_UPLOAD")));
|
||||
} finally {
|
||||
logger.detachAppender(logAppender);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void handleTagRebuildAfterBatchCompletion_shouldLogSubmissionWhenAnyRecordSucceeded() {
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(CcdiFileUploadServiceImpl.class);
|
||||
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||
logAppender.start();
|
||||
logger.addAppender(logAppender);
|
||||
|
||||
try {
|
||||
ReflectionTestUtils.invokeMethod(
|
||||
service,
|
||||
"handleTagRebuildAfterBatchCompletion",
|
||||
PROJECT_ID,
|
||||
TriggerType.AUTO_PULL_BANK_INFO,
|
||||
Boolean.TRUE
|
||||
);
|
||||
|
||||
verify(bankTagService).submitAutoRebuild(PROJECT_ID, TriggerType.AUTO_PULL_BANK_INFO);
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("准备触发自动重算")
|
||||
&& message.contains("projectId=100")
|
||||
&& message.contains("AUTO_PULL_BANK_INFO")
|
||||
&& message.contains("anySuccess=true")));
|
||||
} finally {
|
||||
logger.detachAppender(logAppender);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void processFileAsync_shouldKeepParsingUntilBankStatementsSaved() throws IOException {
|
||||
List<String> events = new ArrayList<>();
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.ruoyi.ccdi.project.service.impl;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.read.ListAppender;
|
||||
import com.ruoyi.ccdi.project.domain.entity.CcdiBankTagTask;
|
||||
import com.ruoyi.ccdi.project.domain.enums.TriggerType;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiBankTagTaskMapper;
|
||||
@@ -9,8 +12,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -54,4 +59,54 @@ class ProjectBankTagRebuildCoordinatorTest {
|
||||
verify(taskMapper).updateTask(any(CcdiBankTagTask.class));
|
||||
verify(bankTagService, never()).rebuildProject(40L, null, "system", TriggerType.AUTO_BATCH_UPLOAD);
|
||||
}
|
||||
|
||||
@Test
|
||||
void submitManual_shouldLogRejectWhenProjectAlreadyRunning() {
|
||||
CcdiBankTagTask runningTask = new CcdiBankTagTask();
|
||||
runningTask.setId(1L);
|
||||
runningTask.setProjectId(40L);
|
||||
runningTask.setStatus("RUNNING");
|
||||
when(taskMapper.selectRunningTaskByProjectId(40L)).thenReturn(runningTask);
|
||||
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(ProjectBankTagRebuildCoordinator.class);
|
||||
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||
logAppender.start();
|
||||
logger.addAppender(logAppender);
|
||||
|
||||
try {
|
||||
assertThrows(ServiceException.class, () -> coordinator.submitManual(40L, null, "admin"));
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("拒绝手动重算")
|
||||
&& message.contains("projectId=40")
|
||||
&& message.contains("operator=admin")));
|
||||
} finally {
|
||||
logger.detachAppender(logAppender);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void submitAuto_shouldLogNeedRerunWhenProjectAlreadyRunning() {
|
||||
CcdiBankTagTask runningTask = new CcdiBankTagTask();
|
||||
runningTask.setId(1L);
|
||||
runningTask.setProjectId(40L);
|
||||
runningTask.setStatus("RUNNING");
|
||||
runningTask.setNeedRerun(0);
|
||||
when(taskMapper.selectRunningTaskByProjectId(40L)).thenReturn(runningTask);
|
||||
|
||||
Logger logger = (Logger) LoggerFactory.getLogger(ProjectBankTagRebuildCoordinator.class);
|
||||
ListAppender<ILoggingEvent> logAppender = new ListAppender<>();
|
||||
logAppender.start();
|
||||
logger.addAppender(logAppender);
|
||||
|
||||
try {
|
||||
coordinator.submitAuto(40L, TriggerType.AUTO_BATCH_UPLOAD);
|
||||
assertTrue(logAppender.list.stream().map(ILoggingEvent::getFormattedMessage)
|
||||
.anyMatch(message -> message.contains("已标记完成后补跑")
|
||||
&& message.contains("projectId=40")
|
||||
&& message.contains("runningTaskId=1")
|
||||
&& message.contains("AUTO_BATCH_UPLOAD")));
|
||||
} finally {
|
||||
logger.detachAppender(logAppender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user