From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-dms/jnpf-dms-biz/src/test/java/jnpf/dmsService/DmsFileRevisionServiceTest.java |  188 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 188 insertions(+), 0 deletions(-)

diff --git a/jnpf-dms/jnpf-dms-biz/src/test/java/jnpf/dmsService/DmsFileRevisionServiceTest.java b/jnpf-dms/jnpf-dms-biz/src/test/java/jnpf/dmsService/DmsFileRevisionServiceTest.java
new file mode 100644
index 0000000..54a3ee0
--- /dev/null
+++ b/jnpf-dms/jnpf-dms-biz/src/test/java/jnpf/dmsService/DmsFileRevisionServiceTest.java
@@ -0,0 +1,188 @@
+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;
+        }
+    }
+}

--
Gitblit v1.8.0