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.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.service.FlowDeptAdminService.class), mock(FlowEngine.class), new ObjectMapper()); 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仅顶层name() throws Exception { 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()); 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 contentJson无顶层name_补写() throws Exception { FlwDef def = published("{\"code\":\"c\",\"start\":\"start\",\"nodes\":[],\"edges\":[]}"); when(defRepository.findById(9L)).thenReturn(Optional.of(def)); FlwDef saved = service.updateMeta(SCH, 9L, "补写名", null); assertEquals("补写名", new ObjectMapper().readTree(saved.getContentJson()).path("name").asText()); assertNull(saved.getAppKey()); } @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)); } }