package jnpf.dmsService;
|
|
import jnpf.dmsEntity.permission.entity.*;
|
import jnpf.dmsEntity.storage.approval.*;
|
import jnpf.dmsMapper.*;
|
import jnpf.dmsService.search.DmsSearchIndexJobService;
|
import jnpf.exception.DataException;
|
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.mockito.*;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
import java.util.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
import static org.mockito.Mockito.*;
|
|
@ExtendWith(MockitoExtension.class)
|
class DmsApprovedFileActivationServiceTest {
|
@Mock DmsApprovedBatchMapper receipts;
|
@Mock DmsDocumentMapper documents;
|
@Mock DmsFileVersionMapper versions;
|
@Mock DmsVersionStateMapper states;
|
@Mock DmsSearchIndexJobService search;
|
@Mock DmsApprovedAuditSource source;
|
@Mock DmsApprovedReadAccessService readAccess;
|
DmsQianpiyeRenderSnapshotService qianpiyeSnapshots = new DmsQianpiyeRenderSnapshotService(
|
null, null, null, null, new com.fasterxml.jackson.databind.ObjectMapper());
|
DmsApprovedFileActivationService service;
|
@org.junit.jupiter.api.BeforeEach void setupCenter() {
|
service = new DmsApprovedFileActivationService(receipts,
|
new jnpf.dmsService.center.DmsCenterActivationService(org.mockito.Mockito.mock(jnpf.dmsIntegration.audit.DmsBusinessChangeAudit.class), documents, versions, states, search), source, qianpiyeSnapshots, readAccess,new DmsBusinessLifecycleGuard(null,false));
|
}
|
private jnpf.dmsIntegration.audit.DmsVersionStateAuditRow auditState(String status) {
|
var row = new jnpf.dmsIntegration.audit.DmsVersionStateAuditRow(); row.setLifecycleStatus(status); return row;
|
}
|
DmsApprovedBatch batch() {
|
DmsApprovedBatch b = new DmsApprovedBatch(); b.setId(UUID.randomUUID()); b.setTenantId("tenant"); b.setStatus("WAITING");
|
b.setFlowId("flow"); b.setTaskId("task"); b.setAuditType("xiuding_shenhe"); b.setActorId("actor"); b.setSourceDigest("digest");
|
b.setApprovedAt(new Date()); return b;
|
}
|
DmsApprovedItem item(String type) {
|
DmsApprovedItem i = new DmsApprovedItem(); i.setChangeType(type); i.setDocumentId(UUID.randomUUID());
|
i.setFileVersionId(UUID.randomUUID()); i.setBaseFileVersionId(UUID.randomUUID()); i.setChecksumSha256("hash"); return i;
|
}
|
void arrange(DmsApprovedBatch b, List<DmsApprovedItem> items) {
|
when(receipts.lock("tenant", b.getId())).thenReturn(b);
|
when(receipts.activate("tenant", b.getId())).thenReturn(1);
|
when(receipts.items("tenant", b.getId())).thenReturn(new ArrayList<>(items));
|
b.setActivatedAt(new Date()); b.setItems(items);
|
when(source.load("tenant", "flow", "task", "xiuding_shenhe", "actor", b.getApprovedAt()))
|
.thenReturn(new DmsApprovedAuditSource.Source(b, "author", new Date(), false));
|
}
|
@Test void futureBatchDoesNotTouchVersions() {
|
DmsApprovedBatch b = batch(); when(receipts.lock("tenant", b.getId())).thenReturn(b);
|
assertEquals("WAITING", service.activate("tenant", b.getId()).getStatus());
|
verifyNoInteractions(versions, states, documents, source, search, readAccess);
|
}
|
@Test void effectiveRetryDoesNotGrantAgain() {
|
DmsApprovedBatch b = batch(); b.setStatus("EFFECTIVE");
|
when(receipts.lock("tenant", b.getId())).thenReturn(b);
|
assertSame(b, service.activate("tenant", b.getId()));
|
verifyNoInteractions(versions, states, documents, source, search, readAccess);
|
verify(receipts, never()).activate(any(), any());
|
}
|
@Test void authorizationFailurePropagatesFromTheSameActivationTransaction() {
|
DmsApprovedBatch b = batch(); DmsApprovedItem i = item("REUSE"); arrange(b, List.of(i));
|
when(documents.selectByTenantAndIdForUpdate("tenant", i.getDocumentId())).thenReturn(new DmsDocumentEntity());
|
DmsFileVersionEntity current = new DmsFileVersionEntity(); current.setId(i.getFileVersionId());
|
when(versions.selectCurrentEffective("tenant", i.getDocumentId())).thenReturn(current);
|
doThrow(new DataException("invalid department")).when(readAccess).apply(eq(b), anyList(), anyList());
|
assertThrows(DataException.class, () -> service.activate("tenant", b.getId()));
|
}
|
@Test void reusedItemsNeverCreateOrSwitchVersions() {
|
DmsApprovedBatch b = batch(); DmsApprovedItem i = item("REUSE"); arrange(b, List.of(i));
|
when(documents.selectByTenantAndIdForUpdate("tenant", i.getDocumentId())).thenReturn(new DmsDocumentEntity());
|
DmsFileVersionEntity current = new DmsFileVersionEntity(); current.setId(i.getFileVersionId());
|
when(versions.selectCurrentEffective("tenant", i.getDocumentId())).thenReturn(current);
|
service.activate("tenant", b.getId());
|
verifyNoInteractions(states, search);
|
verify(readAccess).apply(b, List.of(i), List.of(i));
|
}
|
@Test void revisionChecksExactBaseBeforeSwitching() {
|
DmsApprovedBatch b = batch(); DmsApprovedItem i = item("REVISE"); arrange(b, List.of(i));
|
when(documents.selectByTenantAndIdForUpdate("tenant", i.getDocumentId())).thenReturn(new DmsDocumentEntity());
|
DmsFileVersionEntity wrong = new DmsFileVersionEntity(); wrong.setId(UUID.randomUUID());
|
when(versions.selectCurrentEffective("tenant", i.getDocumentId())).thenReturn(wrong);
|
assertThrows(DataException.class, () -> service.activate("tenant", b.getId()));
|
verifyNoInteractions(states, search);
|
}
|
@Test void completeBatchActivatesMainAndRecordAfterValidation() {
|
DmsApprovedBatch b = batch(); DmsApprovedItem main = item("CREATE"); DmsApprovedItem record = item("CREATE"); arrange(b, List.of(main, record));
|
// Historical registered DOCX files have no render snapshot; activation must keep their digest.
|
main.setSourceKey("xiuding_shenhe:a:zhuwenjian");
|
main.setFileJson("[{\"name\":\"main.docx\",\"url\":\"main.docx\"}]");
|
for (DmsApprovedItem i : List.of(main, record)) {
|
when(documents.selectByTenantAndIdForUpdate("tenant", i.getDocumentId())).thenReturn(new DmsDocumentEntity());
|
DmsFileVersionEntity registered = new DmsFileVersionEntity();
|
registered.setId(i.getFileVersionId()); registered.setDocumentId(i.getDocumentId());
|
when(versions.selectByTenantAndId("tenant", i.getFileVersionId())).thenReturn(registered);
|
when(states.activateApproved("tenant", i.getFileVersionId(), "actor")).thenReturn(1);
|
when(states.selectAuditState("tenant", i.getFileVersionId())).thenReturn(auditState("PENDING_EFFECTIVE"), auditState("EFFECTIVE"));
|
}
|
service.activate("tenant", b.getId());
|
for (DmsApprovedItem i : List.of(main, record)) {
|
verify(states).activateApproved("tenant", i.getFileVersionId(), "actor");
|
verify(search).enqueueContentUpsert("tenant", i.getDocumentId(), i.getFileVersionId(), "hash");
|
}
|
}
|
|
@Test void approvalPageSnapshotIsIncludedWhenActivatingRegisteredFiles() {
|
DmsApprovedBatch b = batch();
|
DmsApprovedItem main = item("CREATE");
|
main.setSourceKey("xiuding_shenhe:a:zhuwenjian");
|
main.setApprovalPageFileJson("[{\"fileId\":\"page.docx\"}]");
|
arrange(b, List.of(main));
|
String snapshot = "{\"protocolVersion\":1,\"taskId\":\"task\",\"flowId\":\"flow\","
|
+ "\"valuesByTag\":{\"dms.qianpiye.flow.approve-1.approver\":\"审核人\"}}";
|
qianpiyeSnapshots.attach(b, snapshot, "author", new Date());
|
DmsApprovedBatch currentSource = batch();
|
currentSource.setItems(List.of(main));
|
when(source.load("tenant", "flow", "task", "xiuding_shenhe", "actor", b.getApprovedAt()))
|
.thenReturn(new DmsApprovedAuditSource.Source(currentSource, "author", new Date(), false));
|
when(documents.selectByTenantAndIdForUpdate("tenant", main.getDocumentId())).thenReturn(new DmsDocumentEntity());
|
DmsFileVersionEntity registered = new DmsFileVersionEntity();
|
registered.setId(main.getFileVersionId()); registered.setDocumentId(main.getDocumentId());
|
when(versions.selectByTenantAndId("tenant", main.getFileVersionId())).thenReturn(registered);
|
when(states.activateApproved("tenant", main.getFileVersionId(), "actor")).thenReturn(1);
|
when(states.selectAuditState("tenant", main.getFileVersionId())).thenReturn(auditState("PENDING_EFFECTIVE"), auditState("EFFECTIVE"));
|
|
service.activate("tenant", b.getId());
|
|
verify(states).activateApproved("tenant", main.getFileVersionId(), "actor");
|
}
|
|
@Test void changedApprovedSourceIsRejectedBeforeTouchingCenterVersions() {
|
DmsApprovedBatch b = batch();
|
when(receipts.lock("tenant", b.getId())).thenReturn(b);
|
when(receipts.activate("tenant", b.getId())).thenReturn(1);
|
DmsApprovedBatch changed = batch();
|
changed.setSourceDigest("changed-content");
|
when(source.load("tenant", "flow", "task", "xiuding_shenhe", "actor", b.getApprovedAt()))
|
.thenReturn(new DmsApprovedAuditSource.Source(changed, "author", new Date(), false));
|
assertThrows(DataException.class, () -> service.activate("tenant", b.getId()));
|
verifyNoInteractions(documents, versions, states, search);
|
}
|
}
|