package jnpf.onlinedev.controller; import feign.RequestTemplate; import jakarta.servlet.http.HttpServletRequest; import jnpf.base.entity.VisualdevEntity; import jnpf.base.entity.VisualdevReleaseEntity; import jnpf.base.model.FormDeleteResult; import jnpf.base.model.VisualDevJsonModel; import jnpf.base.model.online.VisualdevModelDataInfoVO; import jnpf.base.service.VisualdevReleaseService; import jnpf.base.util.FlowFormDataUtil; import jnpf.onlinedev.VisualdevOnlineApiAuditFeignConfig; import jnpf.onlinedev.model.log.VisualLogForm; import jnpf.onlinedev.service.VisualDevInfoService; import jnpf.onlinedev.service.VisualLogService; import jnpf.onlinedev.util.OnlinePublicUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.MockitoAnnotations; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; public class WorkflowDeleteSignatureTest { @Mock private VisualdevReleaseService releaseService; @Mock private FlowFormDataUtil flowDataUtil; @Mock private VisualDevInfoService infoService; @Mock private VisualLogService logService; @Mock private HttpServletRequest request; @InjectMocks private VisualdevForFlowController controller; private AutoCloseable mocks; private MockedStatic onlineUtils; private VisualDevJsonModel model; @Before public void setUp() throws Exception { mocks = MockitoAnnotations.openMocks(this); onlineUtils = mockStatic(OnlinePublicUtils.class); RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); VisualdevReleaseEntity form = new VisualdevReleaseEntity(); form.setId("form-1"); form.setType(1); when(releaseService.getById("form-1")).thenReturn(form); model = new VisualDevJsonModel(); onlineUtils.when(() -> OnlinePublicUtils.getVisualJsonModel(any(VisualdevEntity.class))).thenReturn(model); when(flowDataUtil.resolveMainId("task-1", model, null)).thenReturn("business-1"); when(flowDataUtil.deleteTable("task-1", model, null)).thenReturn(FormDeleteResult.of("business-1", 1)); VisualdevModelDataInfoVO info = new VisualdevModelDataInfoVO(); info.setData("{\"id\":\"business-1\",\"biz_sign\":\"historical-sign\"}"); when(infoService.getEditDataInfo(eq("business-1"), any(), any())).thenReturn(info); } @After public void tearDown() throws Exception { RequestContextHolder.resetRequestAttributes(); onlineUtils.close(); mocks.close(); } @Test public void signedDeletePublishesFreshSignatureAlongsideHistoricalSnapshot() { when(request.getHeader("X-Audit-Biz-Sign")).thenReturn("delete-sign"); RequestTemplate outbound = new RequestTemplate(); new VisualdevOnlineApiAuditFeignConfig().auditRequestHeaderInterceptor().apply(outbound); assertTrue(outbound.headers().get("X-Audit-Biz-Sign").contains("delete-sign")); assertTrue(controller.delete("form-1", "task-1")); VisualLogForm event = publishedEvent(); assertEquals("delete-sign", event.getBizSign()); assertEquals("historical-sign", event.getNewData().get("biz_sign")); assertEquals("business-1", event.getDataId()); assertEquals(Integer.valueOf(2), event.getType()); } @Test public void unsignedDeleteDoesNotReuseHistoricalSignatureAsCurrentSignature() { assertTrue(controller.delete("form-1", "task-1")); VisualLogForm event = publishedEvent(); assertNull(event.getBizSign()); assertEquals("historical-sign", event.getNewData().get("biz_sign")); } @Test public void nonexistentRecordDoesNotPublishASignedDeleteEvent() throws Exception { when(request.getHeader("X-Audit-Biz-Sign")).thenReturn("delete-sign"); when(flowDataUtil.deleteTable("task-1", model, null)).thenReturn(FormDeleteResult.notFound()); assertTrue(controller.delete("form-1", "task-1")); verifyNoInteractions(logService); } @Test public void failedDeleteDoesNotPublishASignedDeleteEvent() throws Exception { when(flowDataUtil.deleteTable("task-1", model, null)).thenThrow(new IllegalStateException("delete failed")); assertFalse(controller.delete("form-1", "task-1")); verifyNoInteractions(logService); } private VisualLogForm publishedEvent() { ArgumentCaptor event = ArgumentCaptor.forClass(VisualLogForm.class); verify(logService).createEventLog(event.capture()); return event.getValue(); } }