package jnpf.dmsService;
|
|
import jnpf.dmsEntity.center.*;
|
import jnpf.dmsEntity.storage.approval.DmsDisableRequest;
|
import jnpf.dmsEntity.storage.expiry.DmsFileExpiryResource;
|
import jnpf.dmsMapper.*;
|
import jnpf.dmsService.center.DmsCenterDisableService;
|
import jnpf.exception.DataException;
|
import org.junit.jupiter.api.*;
|
import java.util.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
import static org.mockito.Mockito.*;
|
|
class DmsApprovedInvalidationExecutorTest {
|
DmsInvalidationMapper mapper=mock(DmsInvalidationMapper.class);
|
DmsInvalidationProperties properties=new DmsInvalidationProperties();
|
DmsCenterDisableService center=mock(DmsCenterDisableService.class);
|
DmsFileExpiryProjectionMapper resources=mock(DmsFileExpiryProjectionMapper.class);
|
DmsFileExpiryMapper cleanup=mock(DmsFileExpiryMapper.class);
|
DmsDisableApplicationMapper occupancy=mock(DmsDisableApplicationMapper.class);
|
DmsApprovedInvalidationExecutor executor=new DmsApprovedInvalidationExecutor(mapper,properties,center,resources,cleanup,occupancy,new DmsBusinessLifecycleGuard(null,false));
|
DmsCenterDisableCommand command=new DmsCenterDisableCommand();
|
DmsDisableRequest row=new DmsDisableRequest();
|
Date at=new Date();
|
@BeforeEach void setup() {
|
command.setTenantId("t");command.setRequestId(UUID.randomUUID());command.setMainDocumentId(UUID.randomUUID());
|
command.setExpectedMainVersionId(UUID.randomUUID());command.setReason("yishixiao");command.setActorId("actor");
|
command.setEffectiveAt(new Date(at.getTime()-10000));command.setLeaseToken("lease");
|
row.setId(command.getRequestId());row.setTenantId("t");row.setBatchId(UUID.randomUUID());row.setDocumentId(command.getMainDocumentId());
|
row.setFileVersionId(command.getExpectedMainVersionId());row.setActorId("actor");row.setScheduledAt(command.getEffectiveAt());
|
row.setFileId("file");row.setBusinessVersionId("business-version");row.setTaskId("task");row.setOperation("yishixiao");row.setStatus("WAITING");
|
when(mapper.lockRequest(command)).thenReturn(row);when(mapper.validLease(row,"lease")).thenReturn(true);
|
when(mapper.approvedSource(row)).thenReturn(true);when(mapper.executionTime()).thenReturn(at);
|
properties.setEnabled(true);properties.getAllowedBatches().add("t:"+row.getBatchId());
|
}
|
void target() {
|
DmsInvalidationTarget t=new DmsInvalidationTarget();t.setDocumentId(row.getDocumentId());t.setFileVersionId(row.getFileVersionId());
|
when(center.invalidate(command,at)).thenReturn(List.of(t));
|
DmsFileExpiryResource r=new DmsFileExpiryResource();r.setId("file");r.setCurrentVersionId("business-version");
|
r.setCenterVersionId(row.getFileVersionId().toString());r.setVersionCenterId(r.getCenterVersionId());r.setBizStatus("effective");
|
when(resources.lockResources("t",row.getFileVersionId())).thenReturn(List.of(r));
|
when(mapper.disableResource(row,r,at)).thenReturn(1);when(mapper.invalidateBusinessVersion(row,r,at)).thenReturn(1);when(mapper.recordExecution(row,at)).thenReturn(1);
|
when(occupancy.releaseFile("t","task","yishixiao","file")).thenReturn(1);when(mapper.complete(row,at,"lease")).thenReturn(1);
|
}
|
@Test void completesOnlyAfterEveryBusinessWrite() {
|
target();assertEquals(200,executor.execute(command).getCode());
|
var order=inOrder(center,mapper,occupancy,cleanup);
|
order.verify(center).invalidate(command,at);order.verify(mapper).disableResource(eq(row),any(),eq(at));
|
order.verify(cleanup).enqueueCleanup("t",row.getFileVersionId());order.verify(mapper).recordExecution(row,at);
|
order.verify(occupancy).releaseFile("t","task","yishixiao","file");order.verify(mapper).complete(row,at,"lease");
|
}
|
@Test void independentReceiptReleasesAfterDurableCompletion() {
|
target();
|
var guard=mock(DmsBusinessLifecycleGuard.class);
|
var receipt=new jnpf.dmsBusinessOccupancy.BusinessFileOccupancy();
|
var receipts=List.of(receipt);
|
when(guard.requireExecution("t","task",null,"INVALIDATION",List.of("file"))).thenReturn(receipts);
|
var enabledExecutor=new DmsApprovedInvalidationExecutor(mapper,properties,center,resources,cleanup,occupancy,guard);
|
assertEquals(200,enabledExecutor.execute(command).getCode());
|
var order=inOrder(guard,center,mapper);
|
order.verify(guard).requireExecution("t","task",null,"INVALIDATION",List.of("file"));
|
order.verify(center).invalidate(command,at);
|
order.verify(mapper).complete(row,at,"lease");
|
order.verify(guard).completeExecution(receipts);
|
}
|
@Test void changedIndependentReceiptStopsBeforeCenterMutation() {
|
var guard=mock(DmsBusinessLifecycleGuard.class);
|
when(guard.requireExecution("t","task",null,"INVALIDATION",List.of("file")))
|
.thenThrow(new IllegalStateException("receipt changed"));
|
var enabledExecutor=new DmsApprovedInvalidationExecutor(mapper,properties,center,resources,cleanup,occupancy,guard);
|
assertThrows(IllegalStateException.class,()->enabledExecutor.execute(command));
|
verifyNoInteractions(center);
|
verify(guard,never()).completeExecution(any());
|
}
|
@Test void committedReplayDoesNotTouchVersionsOrOccupancy() {
|
row.setStatus("APPLIED");assertEquals(200,executor.execute(command).getCode());
|
verifyNoInteractions(center,resources,cleanup,occupancy);
|
}
|
@Test void changedSnapshotAndForeignTenantAreRejected() {
|
command.setExpectedMainVersionId(UUID.randomUUID());assertThrows(DataException.class,()->executor.execute(command));
|
verifyNoInteractions(center);
|
}
|
@Test void disabledOrUnlistedBatchNeverExecutes() {
|
properties.setEnabled(false);assertThrows(DataException.class,()->executor.execute(command));
|
properties.setEnabled(true);properties.getAllowedBatches().clear();assertThrows(DataException.class,()->executor.execute(command));
|
verifyNoInteractions(center);
|
}
|
@Test void lostLeaseOrUnapprovedSourceNeverExecutes() {
|
when(mapper.validLease(row,"lease")).thenReturn(false);assertThrows(DataException.class,()->executor.execute(command));
|
when(mapper.validLease(row,"lease")).thenReturn(true);when(mapper.approvedSource(row)).thenReturn(false);
|
assertThrows(DataException.class,()->executor.execute(command));verifyNoInteractions(center);
|
}
|
@Test void legacyMarkerDoesNotPretendToBeSuccess() {
|
row.setStatus("CENTER_APPLIED");assertThrows(DataException.class,()->executor.execute(command));verifyNoInteractions(center);
|
}
|
@Test void businessConflictPreventsCompletionAndRelease() {
|
target();when(resources.lockResources("t",row.getFileVersionId())).thenReturn(List.of());
|
assertThrows(DataException.class,()->executor.execute(command));verifyNoInteractions(occupancy,cleanup);
|
verify(mapper,never()).complete(any(),any(),any());
|
}
|
@Test void revokedOperationIsNotSilentlyImplemented() {
|
command.setReason("yichexiao");assertThrows(DataException.class,()->executor.execute(command));verifyNoInteractions(center);
|
}
|
@Test void finalLeaseLossFailsTheTransaction() {
|
target();when(mapper.complete(row,at,"lease")).thenReturn(0);assertThrows(DataException.class,()->executor.execute(command));
|
}
|
@Test void alreadyIneffectiveCompletesWithoutRewritingFileAndReleasesOwnReceipt() {
|
target();
|
when(center.alreadyIneffective(command,row,at)).thenReturn(true);
|
var guard=mock(DmsBusinessLifecycleGuard.class);
|
var receipts=List.of(new jnpf.dmsBusinessOccupancy.BusinessFileOccupancy());
|
when(guard.requireExecution("t","task",null,"INVALIDATION",List.of("file"))).thenReturn(receipts);
|
var checked=new DmsApprovedInvalidationExecutor(mapper,properties,center,resources,cleanup,occupancy,guard);
|
assertEquals(200,checked.execute(command).getCode());
|
verify(center,never()).invalidate(any(),any());
|
verifyNoInteractions(resources,cleanup);
|
verify(mapper,never()).disableResource(any(),any(),any());
|
var order=inOrder(center,mapper,occupancy,guard);
|
order.verify(center).alreadyIneffective(command,row,at);
|
order.verify(mapper).recordExecution(row,at);
|
order.verify(occupancy).releaseFile("t","task",row.getOperation(),"file");
|
order.verify(mapper).complete(row,at,"lease");
|
order.verify(guard).completeExecution(receipts);
|
}
|
@Test void ineffectiveCompletionLeaseLossDoesNotReleaseIndependentReceipt() {
|
target();when(center.alreadyIneffective(command,row,at)).thenReturn(true);
|
when(mapper.complete(row,at,"lease")).thenReturn(0);
|
var guard=mock(DmsBusinessLifecycleGuard.class);
|
var checked=new DmsApprovedInvalidationExecutor(mapper,properties,center,resources,cleanup,occupancy,guard);
|
assertThrows(DataException.class,()->checked.execute(command));
|
verify(guard,never()).completeExecution(any());
|
verify(center,never()).invalidate(any(),any());
|
verifyNoInteractions(resources,cleanup);
|
}
|
@Test void ineffectiveCheckFailureCannotBeReportedAsSuccess() {
|
when(center.alreadyIneffective(command,row,at)).thenThrow(new DataException("projection changed"));
|
assertThrows(DataException.class,()->executor.execute(command));
|
verify(mapper,never()).recordExecution(any(),any());
|
verify(mapper,never()).complete(any(),any(),any());
|
verifyNoInteractions(occupancy,resources,cleanup);
|
}
|
}
|