Files
flow-center-service/src/test/java/com/yunhai/flowcenter/service/FlowDefAdminServiceUpdateMetaTest.java
T
chenxing 500a9a2fcb release: FL 2.0 候选(C01 记账边界+P2-2 认领协议+D10 变量契约+D11 资格终审+D09 激活代次+T01/T03/T04/T05)
按《FL最终代码审计与上线阻断清单》194 项已审计工作树形成候选,基座 = origin/main 11e0778。

- 源码/测试/资源:沿用已审计工作树内容(96 项相对远端为新增或更新),含未跟踪实现
  CallbackFactStore、CallbackSourcePolicy、VariableContract、FormalApplyCommandService、
  FlowActorContextGate 等;C01 续验夹具修正一并入内。
- CI:保留远端 11e0778 的门禁强化(CI_SOURCE_SHA 核对、容器回收验证、空 schema 反向门禁、
  main ref 才推镜像);ci/flow-test-schema.sql 按当前实体重新生成(14→20 表,补 6 新表与
  6 新列,回调日志复合唯一键 uk_flw_log_event_reg),workflow 表数断言同步 14→20。
- 依据:docs/tasks/evidence/FL-final-audit-20261027(194 项哈希/版本核对)。
2026-10-27 12:05:08 +08:00

141 lines
6.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.yunhai.flowcenter.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yunhai.flowcenter.engine.FlowEngine;
import com.yunhai.flowcenter.entity.FlwDef;
import com.yunhai.flowcenter.repository.FlwAppRepository;
import com.yunhai.flowcenter.repository.FlwDefRepository;
import com.yunhai.flowcenter.repository.FlwRouterRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
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.mock;
import static org.mockito.Mockito.when;
/**
* updateMeta 原地编辑单测(2026-10-10 议题2,拍板 D4):
* 三不变(version/flowGuid/status;contentJson 仅顶层 name)、appKey 白名单校验、
* contentJson 无顶层 name 时补写、name 非空校验。
*/
class FlowDefAdminServiceUpdateMetaTest {
private static final Long SCH = 3L;
private FlwDefRepository defRepository;
private FlwAppRepository appRepository;
private FlowDefAdminService service;
@BeforeEach
void setUp() {
defRepository = mock(FlwDefRepository.class);
appRepository = mock(FlwAppRepository.class);
service = new FlowDefAdminService(defRepository,
mock(FlwRouterRepository.class),
mock(com.yunhai.flowcenter.repository.FlwCallbackRegRepository.class),
appRepository,
mock(com.yunhai.flowcenter.repository.FlwInstanceRepository.class),
mock(com.yunhai.flowcenter.service.FlowDeptAdminService.class),
mock(FlowEngine.class),
new ObjectMapper(),
mock(com.yunhai.flowcenter.service.FormCenterSchemaClient.class));
when(defRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
when(appRepository.isEnabledApp(any(), any())).thenReturn(true);
}
private FlwDef published(String contentJson) {
FlwDef d = new FlwDef();
d.setId(9L);
d.setSchId(SCH);
d.setFlowGuid("guid123");
d.setCode("work-leave");
d.setName("旧名");
d.setAppKey("100002");
d.setVersion(4);
d.setStatus(1);
d.setContentJson(contentJson);
return d;
}
@Test
void 已发布版本_contentJson封存_仅行内元数据可改() throws Exception {
// T03(2026-10-25)发布封存:执行文档不可变——行 name 照改(目录元数据),
// content_json 顶层 name 保持发布时字节(旧断言"同步改 JSON"已按新原则作废)
String json = "{\"code\":\"work-leave\",\"name\":\"旧名\",\"start\":\"start\","
+ "\"nodes\":[{\"id\":\"start\",\"type\":\"START\"}],"
+ "\"edges\":[{\"from\":\"start\",\"to\":\"end\"}]}";
FlwDef def = published(json);
when(defRepository.findById(9L)).thenReturn(Optional.of(def));
FlwDef saved = service.updateMeta(SCH, 9L, "新名称", "100008");
assertEquals(4, saved.getVersion());
assertEquals("guid123", saved.getFlowGuid());
assertEquals(1, saved.getStatus());
assertEquals("work-leave", saved.getCode());
assertEquals("新名称", saved.getName());
assertEquals("100008", saved.getAppKey());
// 发布字节冻结:文档内 name 不随目录改名漂移
assertEquals("旧名", new ObjectMapper().readTree(saved.getContentJson()).path("name").asText());
assertEquals("work-leave", new ObjectMapper().readTree(saved.getContentJson()).path("code").asText());
assertTrue(saved.getContentJson().contains("\"type\":\"START\""));
}
@Test
void 已发布版本_无顶层name_不补写() throws Exception {
// 发布封存:缺顶层 name 的已发布文档维持原样,不补写
FlwDef def = published("{\"code\":\"c\",\"start\":\"start\",\"nodes\":[],\"edges\":[]}");
when(defRepository.findById(9L)).thenReturn(Optional.of(def));
FlwDef saved = service.updateMeta(SCH, 9L, "补写名", null);
assertFalse(new ObjectMapper().readTree(saved.getContentJson()).has("name"));
assertNull(saved.getAppKey());
}
@Test
void 草稿版本_contentJson顶层name仍同步() throws Exception {
// 草稿文档可变:顶层 name 同步保留(与发布封存互为边界)
FlwDef def = published("{\"code\":\"c\",\"name\":\"旧名\",\"start\":\"start\",\"nodes\":[],\"edges\":[]}");
def.setStatus(0); // DRAFT
when(defRepository.findById(9L)).thenReturn(Optional.of(def));
FlwDef saved = service.updateMeta(SCH, 9L, "草稿新名", null);
assertEquals("草稿新名", new ObjectMapper().readTree(saved.getContentJson()).path("name").asText());
}
@Test
void appKey白名单外_被拦() {
when(appRepository.isEnabledApp(SCH, "888888")).thenReturn(false);
when(defRepository.findById(9L)).thenReturn(Optional.of(published("{}")));
Exception e = assertThrows(com.yunhai.platform.apistd.BizException.class,
() -> service.updateMeta(SCH, 9L, "n", "888888"));
assertTrue(e.getMessage().contains("应用设置"));
}
@Test
void name空_被拦() {
when(defRepository.findById(9L)).thenReturn(Optional.of(published("{}")));
assertThrows(com.yunhai.platform.apistd.BizException.class,
() -> service.updateMeta(SCH, 9L, " ", null));
}
@Test
void 跨校_被拒() {
FlwDef other = published("{}");
other.setSchId(2L);
when(defRepository.findById(9L)).thenReturn(Optional.of(other));
assertThrows(com.yunhai.platform.apistd.BizException.class,
() -> service.updateMeta(SCH, 9L, "n", null));
}
}