package jnpf.flowable.service; import jnpf.flowable.mapper.FilePermissionSnapshotMapper; import jnpf.flowable.model.filepermission.FilePermissionTaskState; import jnpf.flowable.util.ServiceUtil; import jnpf.base.UserInfo; import jnpf.util.UserProvider; import org.junit.Test; import org.mockito.MockedStatic; import java.util.*; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; import static org.mockito.Mockito.*; public class FilePermissionSnapshotServiceTest { @Test public void distinguishesAbsentDeletedAndLegacyTasks() { FilePermissionSnapshotMapper mapper = mock(FilePermissionSnapshotMapper.class); FilePermissionSnapshotService service = new FilePermissionSnapshotService(mapper, mock(ServiceUtil.class)); try { service.find("task"); fail("absence must be explicit"); } catch (FilePermissionSnapshotService.TaskNotFoundException expected) { } FilePermissionTaskState row = new FilePermissionTaskState(); row.setTaskId("task"); row.setDeleteMark(1); when(mapper.find("task")).thenReturn(row); try { service.find("task"); fail("deleted task must fail closed"); } catch (IllegalArgumentException expected) { assertFalse(expected instanceof FilePermissionSnapshotService.TaskNotFoundException); } row.setDeleteMark(null); jnpf.util.context.SpringContext.setApplicationContext(mock(org.springframework.context.ApplicationContext.class)); try (MockedStatic users = mockStatic(UserProvider.class)) { users.when(UserProvider::getUser).thenReturn(new UserInfo()); assertNull(service.find("task")); } } @Test public void databaseFailureIsNeverReportedAsAbsent() { FilePermissionSnapshotMapper mapper = mock(FilePermissionSnapshotMapper.class); FilePermissionSnapshotService service = new FilePermissionSnapshotService(mapper, mock(ServiceUtil.class)); IllegalStateException outage = new IllegalStateException("database unavailable"); when(mapper.find("task")).thenThrow(outage); try { service.find("task"); fail("must propagate outage"); } catch (RuntimeException expected) { assertSame(outage, expected); } } @Test public void casPersistsReleaseRuleActivationReleaseAndReactivation() throws Exception { FilePermissionSnapshotMapper mapper = mock(FilePermissionSnapshotMapper.class); FilePermissionSnapshotService service = new FilePermissionSnapshotService(mapper, mock(ServiceUtil.class)); Map rule = new LinkedHashMap<>(); rule.put("id", "creator-readonly"); rule.put("formId", "form"); rule.put("field", "files"); rule.put("subject", "CREATOR"); rule.put("trigger", "ENTERED"); rule.put("triggerNodeId", "department-review"); rule.put("onReturn", "RELEASE"); rule.put("actions", Collections.singletonMap("EDIT", "DENY")); AtomicReference stored = new AtomicReference<>(jnpf.flowable.util.filepermission.FilePermissionSnapshot.create( "tenant", "task", "flow", Map.of("version", 1, "rules", Collections.singletonList(rule)))); when(mapper.find("task")).thenAnswer(invocation -> { FilePermissionTaskState state = new FilePermissionTaskState(); state.setTaskId("task"); state.setSnapshot(stored.get()); return state; }); when(mapper.compareAndSetSnapshot(eq("task"), anyString(), anyString())).thenAnswer(invocation -> { String expected = invocation.getArgument(1); String updated = invocation.getArgument(2); return stored.compareAndSet(expected, updated) ? 1 : 0; }); jnpf.util.context.SpringContext.setApplicationContext(mock(org.springframework.context.ApplicationContext.class)); UserInfo user = new UserInfo(); user.setTenantId("tenant"); try (MockedStatic users = mockStatic(UserProvider.class)) { users.when(UserProvider::getUser).thenReturn(user); service.markEntered("task", Collections.singleton("department-review")); assertTrue(service.find("task").getActiveReleaseRules().contains("creator-readonly")); service.markReturnedPast("task", Collections.singleton("qa")); assertTrue(service.find("task").getActiveReleaseRules().contains("creator-readonly")); service.markReturnedPast("task", Collections.singleton("department-review")); assertFalse(service.find("task").getActiveReleaseRules().contains("creator-readonly")); service.markEntered("task", Collections.singleton("department-review")); assertTrue(service.find("task").getActiveReleaseRules().contains("creator-readonly")); } verify(mapper, times(3)).compareAndSetSnapshot(eq("task"), anyString(), anyString()); } }