package jnpf.base.util;
|
|
import jnpf.base.model.flow.DataModel;
|
import jnpf.base.service.UploadEditDraftService;
|
import jnpf.base.service.UploadFilePermissionService;
|
import jnpf.exception.DataException;
|
import jnpf.exception.WorkFlowException;
|
import org.junit.Test;
|
|
import java.util.*;
|
|
import static org.junit.Assert.*;
|
import static org.mockito.Mockito.*;
|
|
/** 验证首次原生保存与后续受控保存的边界,不替代真实数据库保存验收。 */
|
public class FlowFormFilePermissionBoundaryTest {
|
@Test public void initialCreateKeepsNativeAttachmentsWithoutAdoptingDraftState() throws Exception {
|
UploadEditDraftService drafts = mock(UploadEditDraftService.class);
|
UploadFilePermissionService permissions = mock(UploadFilePermissionService.class);
|
FlowFormDataUtil forms = spy(new FlowFormDataUtil(null, null, null, null, null, null, drafts, permissions));
|
Map<String, Object> mainFile = Collections.singletonMap("fileId", "main-source");
|
Map<String, Object> childFile = Collections.singletonMap("fileId", "child-source");
|
Map<String, Object> data = new HashMap<>();
|
data.put("files", Collections.singletonList(mainFile));
|
data.put("rows", Collections.singletonList(Collections.singletonMap("files", Collections.singletonList(childFile))));
|
Map<String, Object> original = new HashMap<>(data);
|
data.put(UploadEditDraftService.SUBMIT_STATE, Collections.singletonMap("draftId", "untrusted"));
|
DataModel model = new DataModel(); model.setDataNewMap(data);
|
doAnswer(call -> {
|
assertEquals(original, model.getDataNewMap());
|
return Collections.singletonMap("id", "saved-record");
|
}).when(forms).createDataList(model);
|
|
assertEquals("saved-record", forms.create(model).get("id"));
|
verify(forms).createDataList(model);
|
verifyNoInteractions(permissions);
|
verify(drafts).prepareRevisionSave(model);
|
verifyNoMoreInteractions(drafts);
|
}
|
|
@Test public void invalidAuditCopyNeverReachesNativeInsert() throws Exception {
|
UploadEditDraftService drafts = mock(UploadEditDraftService.class);
|
FlowFormDataUtil forms = spy(new FlowFormDataUtil(null, null, null, null, null, null, drafts, mock(UploadFilePermissionService.class)));
|
DataModel model = new DataModel(); model.setDataNewMap(new HashMap<>());
|
doThrow(new DataException("附件来源已失效")).when(drafts).prepareRevisionSave(model);
|
try { forms.create(model); fail("invalid receipt must block native create"); }
|
catch (WorkFlowException expected) { assertTrue(expected.getMessage().contains("来源")); }
|
verify(forms, never()).createDataList(any());
|
}
|
|
@Test public void subsequentSaveDenialNeverFallsBackToCreateOrWritesData() throws Exception {
|
UploadEditDraftService drafts = mock(UploadEditDraftService.class);
|
UploadFilePermissionService permissions = mock(UploadFilePermissionService.class);
|
FlowFormDataUtil forms = spy(new FlowFormDataUtil(null, null, null, null, null, null, drafts, permissions));
|
DataModel model = new DataModel(); model.setDataNewMap(new HashMap<>());
|
when(permissions.prepare(model)).thenThrow(new DataException("当前流程不允许附件操作:ADD"));
|
try {
|
forms.update(model);
|
fail("saved records must remain subject to instance permissions");
|
} catch (WorkFlowException expected) {
|
assertTrue(expected.getMessage().contains("ADD"));
|
}
|
verify(forms, never()).createDataList(any());
|
verify(forms, never()).updateDataList(any());
|
verify(drafts).lockDmsRecord(model.getVisualId(), model.getMainId());
|
verifyNoMoreInteractions(drafts);
|
}
|
@Test public void revisionCreateChecksCanonicalAttachmentBeforeInsert() throws Exception {
|
UploadEditDraftService drafts = mock(UploadEditDraftService.class);
|
FlowFormDataUtil forms = spy(new FlowFormDataUtil(null, null, null, null, null, null, drafts, mock(UploadFilePermissionService.class)));
|
var check = attachCheck(forms);
|
DataModel model = revisionModel();
|
doAnswer(call -> { model.getDataNewMap().put("wenjian", "canonical"); return null; }).when(drafts).prepareRevisionSave(model);
|
doAnswer(call -> {
|
assertEquals("canonical", model.getDataNewMap().get("wenjian"));
|
assertFalse(model.getDataNewMap().containsKey(jnpf.flowable.model.filepermission.DmsRevisionAttachmentCheck.REQUIRED));
|
throw new DataException("内容不同");
|
}).when(check).validate("revision", model.getDataNewMap());
|
try { forms.create(model); fail("changed content"); } catch (WorkFlowException expected) { }
|
var order = inOrder(drafts, check);
|
order.verify(drafts).prepareRevisionSave(model);
|
order.verify(check).validate("revision", model.getDataNewMap());
|
verify(forms, never()).createDataList(any());
|
}
|
@Test public void revisionUpdateChecksAdoptedAuthorizedContentBeforePersistence() throws Exception {
|
UploadEditDraftService drafts = mock(UploadEditDraftService.class);
|
UploadFilePermissionService permissions = mock(UploadFilePermissionService.class);
|
FlowFormDataUtil forms = spy(new FlowFormDataUtil(null, null, null, null, null, null, drafts, permissions));
|
var check = attachCheck(forms);
|
DataModel model = revisionModel();
|
doAnswer(call -> { model.getDataNewMap().put("wenjian", "adopted-B"); return null; })
|
.when(permissions).validate(any(), eq(model), anyList(), any());
|
doAnswer(call -> {
|
assertEquals("adopted-B", model.getDataNewMap().get("wenjian"));
|
throw new DataException("内容不同");
|
}).when(check).validate("revision", model.getDataNewMap());
|
try { forms.update(model); fail("changed content"); } catch (WorkFlowException expected) { }
|
var order = inOrder(drafts, permissions, check);
|
order.verify(drafts).lockDmsRecord("revision", "record");
|
order.verify(permissions).prepare(model);
|
order.verify(drafts).prepareSave(eq(model), any(), any());
|
order.verify(permissions).validate(any(), eq(model), anyList(), any());
|
order.verify(check).validate("revision", model.getDataNewMap());
|
verify(forms, never()).updateDataList(any());
|
verify(drafts, never()).completeSave(any());
|
}
|
private DataModel revisionModel() {
|
DataModel model = new DataModel(); model.setVisualId("revision"); model.setMainId("record");
|
model.setDataNewMap(new HashMap<>());
|
model.getDataNewMap().put(jnpf.flowable.model.filepermission.DmsRevisionAttachmentCheck.REQUIRED, true);
|
return model;
|
}
|
private jnpf.flowable.model.filepermission.DmsRevisionAttachmentCheck attachCheck(FlowFormDataUtil forms) throws Exception {
|
var check = mock(jnpf.flowable.model.filepermission.DmsRevisionAttachmentCheck.class);
|
org.springframework.beans.factory.ObjectProvider provider = mock(org.springframework.beans.factory.ObjectProvider.class);
|
when(provider.getIfAvailable()).thenReturn(check);
|
var field = FlowFormDataUtil.class.getDeclaredField("dmsAttachmentChecks");
|
field.setAccessible(true); field.set(forms, provider); return check;
|
}
|
|
}
|