package jnpf.dmsService;
|
|
import jnpf.base.UserInfo;
|
import jnpf.dmsEntity.permission.entity.DmsDocumentEntity;
|
import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity;
|
import jnpf.dmsEntity.permission.entity.DmsPermissionResourceEntity;
|
import jnpf.dmsEntity.storage.entity.DmsFileObjectEntity;
|
import jnpf.dmsEntity.storage.form.DmsFileRevisionRegisterForm;
|
import jnpf.dmsEntity.storage.vo.DmsFileUploadVO;
|
import jnpf.dmsIntegration.audit.DmsAuditAdapter;
|
import jnpf.dmsMapper.DmsDocumentMapper;
|
import jnpf.dmsMapper.DmsFileObjectMapper;
|
import jnpf.dmsMapper.DmsFileVersionMapper;
|
import jnpf.dmsMapper.DmsPermissionResourceMapper;
|
import jnpf.dmsMapper.DmsVersionStateMapper;
|
import jnpf.dmsPermission.DmsCurrentIdentity;
|
import jnpf.dmsPermission.DmsPermissionException;
|
import org.junit.jupiter.api.Test;
|
import org.mockito.ArgumentCaptor;
|
|
import java.time.LocalDate;
|
import java.util.UUID;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.when;
|
|
class DmsFileRevisionServiceTest {
|
|
@Test
|
void createsNewVersionAndAtomicallySwitchesEffectiveState() {
|
Fixture fixture = new Fixture();
|
DmsFileRevisionRegisterForm form = fixture.form();
|
DmsFileUploadVO created = fixture.view(form);
|
when(fixture.fileObjectMapper.selectUploadBySource("tenant-1", "jnpf-file", "revision-1"))
|
.thenReturn(null, created);
|
|
DmsFileUploadVO result = fixture.service.register(form, "jnpf-file");
|
|
assertSame(created, result);
|
verify(fixture.fileObjectMapper).lockSource("tenant-1", "jnpf-file", "revision-1");
|
verify(fixture.decisionService).requireAllowed(any(), any(), any());
|
ArgumentCaptor<DmsFileVersionEntity> versionCaptor =
|
ArgumentCaptor.forClass(DmsFileVersionEntity.class);
|
verify(fixture.fileVersionMapper).insert(versionCaptor.capture());
|
assertEquals(2L, versionCaptor.getValue().getVersionNo());
|
assertEquals("D(01)", versionCaptor.getValue().getVersionLabel());
|
verify(fixture.resourceMapper).insert(any(DmsPermissionResourceEntity.class));
|
verify(fixture.fileObjectMapper).insert(any(DmsFileObjectEntity.class));
|
verify(fixture.versionStateMapper).supersedeCurrent("tenant-1", form.getDocumentId(),
|
form.getBaseFileVersionId(), "D(01)", "user-1");
|
verify(fixture.versionStateMapper).insertRevisionEffective("tenant-1", form.getDocumentId(),
|
form.getBaseFileVersionId(), form.getFileVersionId(), "revision-1",
|
"更新质量职责", "user-1");
|
}
|
|
@Test
|
void returnsExactIdempotentRetryWithoutWritingAgain() {
|
Fixture fixture = new Fixture();
|
DmsFileRevisionRegisterForm form = fixture.form();
|
DmsFileUploadVO existing = fixture.view(form);
|
when(fixture.fileObjectMapper.selectUploadBySource("tenant-1", "jnpf-file", "revision-1"))
|
.thenReturn(existing);
|
|
DmsFileUploadVO result = fixture.service.register(form, "jnpf-file");
|
|
assertSame(existing, result);
|
verify(fixture.documentMapper, never()).selectByTenantAndIdForUpdate(any(), any());
|
verify(fixture.fileVersionMapper, never()).insert(any(DmsFileVersionEntity.class));
|
verify(fixture.versionStateMapper, never()).supersedeCurrent(any(), any(), any(), any(), any());
|
}
|
|
@Test
|
void rejectsRetryWhenRevisionReasonChanges() {
|
Fixture fixture = new Fixture();
|
DmsFileRevisionRegisterForm form = fixture.form();
|
DmsFileUploadVO existing = fixture.view(form);
|
form.setRevisionReason("另一个原因");
|
when(fixture.fileObjectMapper.selectUploadBySource("tenant-1", "jnpf-file", "revision-1"))
|
.thenReturn(existing);
|
|
assertThrows(DmsPermissionException.class,
|
() -> fixture.service.register(form, "jnpf-file"));
|
|
verify(fixture.fileVersionMapper, never()).insert(any(DmsFileVersionEntity.class));
|
}
|
|
@Test
|
void rejectsWhenSelectedVersionIsNoLongerCurrent() {
|
Fixture fixture = new Fixture();
|
DmsFileRevisionRegisterForm form = fixture.form();
|
DmsFileVersionEntity anotherCurrent = new DmsFileVersionEntity();
|
anotherCurrent.setId(UUID.fromString("018f0000-0000-7000-8000-000000000599"));
|
when(fixture.fileVersionMapper.selectCurrentEffective("tenant-1", form.getDocumentId()))
|
.thenReturn(anotherCurrent);
|
|
assertThrows(DmsPermissionException.class,
|
() -> fixture.service.register(form, "jnpf-file"));
|
|
verify(fixture.fileVersionMapper, never()).insert(any(DmsFileVersionEntity.class));
|
verify(fixture.versionStateMapper, never()).supersedeCurrent(any(), any(), any(), any(), any());
|
}
|
|
private static class Fixture {
|
private final DmsCurrentIdentity currentIdentity = mock(DmsCurrentIdentity.class);
|
private final DmsPermissionDecisionService decisionService = mock(DmsPermissionDecisionService.class);
|
private final DmsDocumentMapper documentMapper = mock(DmsDocumentMapper.class);
|
private final DmsFileVersionMapper fileVersionMapper = mock(DmsFileVersionMapper.class);
|
private final DmsPermissionResourceMapper resourceMapper = mock(DmsPermissionResourceMapper.class);
|
private final DmsFileObjectMapper fileObjectMapper = mock(DmsFileObjectMapper.class);
|
private final DmsVersionStateMapper versionStateMapper = mock(DmsVersionStateMapper.class);
|
private final DmsAuditAdapter auditAdapter = mock(DmsAuditAdapter.class);
|
private final DmsFileRevisionService service = new DmsFileRevisionService(currentIdentity,
|
decisionService, documentMapper, fileVersionMapper, resourceMapper, fileObjectMapper,
|
versionStateMapper, auditAdapter);
|
private final UUID documentId = UUID.fromString("018f0000-0000-7000-8000-000000000501");
|
private final UUID baseVersionId = UUID.fromString("018f0000-0000-7000-8000-000000000502");
|
|
private Fixture() {
|
UserInfo user = new UserInfo();
|
user.setUserId("user-1");
|
user.setTenantId("tenant-1");
|
when(currentIdentity.requireUser()).thenReturn(user);
|
when(currentIdentity.tenantId(user)).thenReturn("tenant-1");
|
DmsDocumentEntity document = new DmsDocumentEntity();
|
document.setId(documentId);
|
when(documentMapper.selectByTenantAndIdForUpdate("tenant-1", documentId))
|
.thenReturn(document);
|
DmsFileVersionEntity current = new DmsFileVersionEntity();
|
current.setId(baseVersionId);
|
when(fileVersionMapper.selectCurrentEffective("tenant-1", documentId)).thenReturn(current);
|
when(fileVersionMapper.selectNextVersionNo("tenant-1", documentId)).thenReturn(2L);
|
when(versionStateMapper.supersedeCurrent(any(), any(), any(), any(), any())).thenReturn(1);
|
}
|
|
private DmsFileRevisionRegisterForm form() {
|
DmsFileRevisionRegisterForm form = new DmsFileRevisionRegisterForm();
|
form.setDocumentId(documentId);
|
form.setBaseFileVersionId(baseVersionId);
|
form.setFileVersionId(UUID.fromString("018f0000-0000-7000-8000-000000000503"));
|
form.setFileObjectId(UUID.fromString("018f0000-0000-7000-8000-000000000504"));
|
form.setVersionLabel("D(01)");
|
form.setFileName("quality-manual-v2.docx");
|
form.setMimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
form.setSizeBytes(1024L);
|
form.setChecksumSha256("b".repeat(64));
|
form.setPreparedBy("author-1");
|
form.setPreparedOn(LocalDate.of(2026, 8, 22));
|
form.setRevisionReason("更新质量职责");
|
form.setStoragePlatform("seaweedfs-1");
|
form.setBucketName("jnpf-dms");
|
form.setBasePath("dms/");
|
form.setObjectPath("2026/08/22/document/");
|
form.setObjectName("version-v2.docx");
|
form.setSourceId("revision-1");
|
return form;
|
}
|
|
private DmsFileUploadVO view(DmsFileRevisionRegisterForm form) {
|
DmsFileUploadVO view = new DmsFileUploadVO();
|
view.setDocumentId(form.getDocumentId());
|
view.setBaseFileVersionId(form.getBaseFileVersionId());
|
view.setFileVersionId(form.getFileVersionId());
|
view.setFileObjectId(form.getFileObjectId());
|
view.setVersionNo(2L);
|
view.setVersionLabel(form.getVersionLabel());
|
view.setFileName(form.getFileName());
|
view.setMimeType(form.getMimeType());
|
view.setSizeBytes(form.getSizeBytes());
|
view.setChecksumSha256(form.getChecksumSha256());
|
view.setPreparedBy(form.getPreparedBy());
|
view.setPreparedOn(form.getPreparedOn());
|
view.setRevisionReason(form.getRevisionReason());
|
view.setStoragePlatform(form.getStoragePlatform());
|
view.setBucketName(form.getBucketName());
|
view.setBasePath(form.getBasePath());
|
view.setObjectPath(form.getObjectPath());
|
view.setObjectName(form.getObjectName());
|
view.setSourceId(form.getSourceId());
|
return view;
|
}
|
}
|
}
|