package jnpf.base.service; import jnpf.base.UserInfo; import jnpf.base.entity.VisualdevEntity; import jnpf.base.mapper.UploadEditReadMapper; import jnpf.base.model.uploadedit.UploadEditContext; import jnpf.exception.DataException; import jnpf.permissions.PermissionInterfaceImpl; import jnpf.util.UserProvider; import org.junit.*; import org.mockito.MockedStatic; import java.util.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static org.mockito.ArgumentMatchers.*; public class UploadEditReadServiceTest { private UploadEditReadMapper mapper; private UploadEditReadService service; private VisualdevEntity model; private UploadEditContext context; private Map config; private MockedStatic users; private static final String TABLE = "dms_wenjian_xinzeng_shenhe"; @Before public void setup() { jnpf.util.context.SpringContext.setApplicationContext(mock(org.springframework.context.ApplicationContext.class)); mapper = mock(UploadEditReadMapper.class); service = new UploadEditReadService(mapper); model = new VisualdevEntity(); model.setDbLinkId("0"); model.setColumnData("{}"); model.setFormData("{\"tableName\":\""+TABLE+"\",\"logicalDelete\":true,\"primaryKeyPolicy\":1}"); model.setVisualTables("[{\"table\":\""+TABLE+"\",\"typeId\":\"1\",\"fields\":[{\"field\":\"f_id\",\"primaryKey\":1}]}," +"{\"table\":\""+TABLE+"_jilu_mingxi\",\"typeId\":\"0\",\"tableField\":\"f_foreign_id\",\"relationField\":\"f_id\",\"fields\":[{\"field\":\"f_id\",\"primaryKey\":1}]}]"); model.setVisualTables(model.getVisualTables().replace("\"primaryKey\":1}]", "\"primaryKey\":1},{\"field\":\"f_tenant_id\"},{\"field\":\"f_delete_mark\"},{\"field\":\"f_flow_task_id\"},{\"field\":\"wenjian\"},{\"field\":\"f_foreign_id\"},{\"field\":\"jilu_wenjian\"}]")); context = new UploadEditContext(); context.setModelId("model"); context.setRecordId("alias"); context.setField("wenjian"); config = new HashMap<>(); config.put("tableName", TABLE); users = mockStatic(UserProvider.class); UserInfo user = new UserInfo(); user.setTenantId("tenant"); users.when(UserProvider::getUser).thenReturn(user); when(mapper.dmsAttachment(TABLE,"tenant","alias",null)).thenReturn(Map.of("id","record","flowTaskId","task","fileJson","[{\"fileId\":\"file\",\"name\":\"保留名称\",\"uploadReceipt\":\"receipt\"}]")); } @After public void cleanup() { users.close(); } @Test public void projectionRetainsCanonicalMetadataAndTaskAlias() { Map result = service.dmsAttachment(model,context,config); assertEquals("record",result.get("id")); assertEquals("task",result.get("flowTaskId")); assertEquals(Map.of("fileId","file","name","保留名称","uploadReceipt","receipt"), ((List)result.get("wenjian")).get(0)); verify(mapper).dmsAttachment(TABLE,"tenant","alias",null); } @Test public void childProjectionContainsOnlyRequestedRow() { child(); when(mapper.dmsAttachment(TABLE,"tenant","alias","row")).thenReturn(Map.of("id","record","flowTaskId","task","rowId","row","fileJson","[]")); assertEquals(List.of(Map.of("id","row","jilu_wenjian",List.of())), service.dmsAttachment(model,context,config).get("jilu_mingxi")); } @Test public void missingOrWrongChildFailsRatherThanBecomingEmptyFiles() { child(); when(mapper.dmsAttachment(TABLE,"tenant","alias","row")).thenReturn(Map.of("id","record","flowTaskId","task")); assertThrows(DataException.class, () -> service.dmsAttachment(model,context,config)); context.setRowId(null); assertThrows(DataException.class, () -> service.dmsAttachment(model,context,config)); } @Test public void databaseFailureAndMalformedFilesCannotFallBack() { when(mapper.dmsAttachment(TABLE,"tenant","alias",null)).thenThrow(new IllegalStateException("offline")); assertThrows(IllegalStateException.class, () -> service.dmsAttachment(model,context,config)); reset(mapper); when(mapper.dmsAttachment(TABLE,"tenant","alias",null)).thenReturn(Map.of("id","record","fileJson","{}")); assertThrows(RuntimeException.class, () -> service.dmsAttachment(model,context,config)); } @Test public void missingOrDeletedParentFails() { when(mapper.dmsAttachment(TABLE,"tenant","alias",null)).thenReturn(null); assertThrows(DataException.class, () -> service.dmsAttachment(model,context,config)); } @Test public void changedSourceOrNativeRelationUsesOriginalReader() { model.setDbLinkId("external"); assertNull(service.dmsAttachment(model,context,config)); model.setDbLinkId("0"); child(); model.setVisualTables(model.getVisualTables().replace("f_foreign_id","other_fk")); assertNull(service.dmsAttachment(model,context,config)); verifyNoInteractions(mapper); } @Test public void changedPrimaryMappingOrVirtualFieldCannotUseFixedProjection() { model.setVisualTables(model.getVisualTables().replace("f_id","custom_id")); assertNull(service.dmsAttachment(model,context,config)); config.put("isVirtualField",true); assertNull(service.dmsAttachment(model,context,config)); verifyNoInteractions(mapper); } @Test public void nativeMenuFieldPermissionStillApplies() { context.setMenuId("menu"); model.setColumnData("{\"useFormPermission\":true}"); try (MockedStatic permission = mockStatic(PermissionInterfaceImpl.class)) { permission.when(PermissionInterfaceImpl::getFormMap).thenReturn(Map.of()); assertThrows(DataException.class, () -> service.dmsAttachment(model,context,config)); verifyNoInteractions(mapper); permission.when(PermissionInterfaceImpl::getFormMap).thenReturn(Map.of("menu", List.of(Map.of("enCode","wenjian")))); assertNotNull(service.dmsAttachment(model,context,config)); } } @Test public void publishedDefinitionReadIsFreshAndFallbackOnlyWhenAbsent() { when(mapper.releasedModel("model")).thenReturn(model); assertSame(model,service.model("model")); assertSame(model,service.model("model")); verify(mapper,times(2)).releasedModel("model"); verify(mapper,never()).designModel(anyString()); when(mapper.releasedModel("model")).thenReturn(null); when(mapper.designModel("model")).thenReturn(model); assertSame(model,service.model("model")); } private void child() { context.setParentField("jilu_mingxi"); context.setField("jilu_wenjian"); context.setRowId("row"); config.put("relationTable",TABLE+"_jilu_mingxi"); } private static void assertThrows(Class type, Runnable operation) { try { operation.run(); } catch (RuntimeException failure) { if (!type.isInstance(failure)) throw failure; return; } fail("expected " + type.getSimpleName()); } }