刘光辉
4 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package jnpf.dmsService;
 
import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity;
import jnpf.dmsEntity.storage.approval.*;
import jnpf.dmsIntegration.audit.DmsAuditAdapter;
import jnpf.dmsMapper.DmsApprovedReadAccessMapper;
import jnpf.dmsPermission.DmsPermissionProperties;
import jnpf.exception.DataException;
import org.junit.jupiter.api.*;
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 DmsApprovedReadAccessServiceTest {
    @Mock DmsApprovedReadAccessMapper mapper;
    @Mock DmsAuditAdapter audit;
    DmsApprovedReadAccessService service;
    DmsApprovedBatch batch;
    @BeforeEach void setup() {
        service = new DmsApprovedReadAccessService(mapper, audit, new DmsPermissionProperties());
        batch = new DmsApprovedBatch(); batch.setTenantId("tenant"); batch.setId(UUID.randomUUID());
        batch.setActivatedAt(new Date()); batch.setAuditId("audit");
    }
    DmsApprovedItem item(String key, String type, String scope) {
        var item = new DmsApprovedItem(); item.setSourceKey(key); item.setChangeType(type);
        item.setFileVersionId(UUID.randomUUID()); item.setReadAccessScope(scope); return item;
    }
    @Test void parsesDepartmentScopesAndRejectsMixedOrDynamicValues() {
        for (String empty : Arrays.asList(null, "", "  ", "null", " null ", "[]"))
            assertEquals("[]", DmsApprovedDepartmentScope.normalize(empty));
        assertEquals("[\"a--progenyOrg\",\"b--subOrg\",\"c\"]", DmsApprovedDepartmentScope.normalize(
                "[\"b--subOrg\",\"a--org\",\"a--progenyOrg\",\"c\",\"b\"]"));
        for (String input : List.of("{}", "[null]", "[1]", "[\"u--user\"]", "[\"p--position\"]", "[\"@department\"]", "[\"--org\"]"))
            assertThrows(DataException.class, () -> DmsApprovedDepartmentScope.parse(input));
    }
    @Test void mainAndRecordReceiveIndependentReadOnlyVersionGrants() {
        var main = item("main", "CREATE", "[\"a\"]");
        var record = item("record", "CREATE", "[\"b--subOrg\"]");
        when(mapper.departments("tenant", List.of("a", "b"))).thenReturn(List.of(
                new DmsApprovedReadAccessMapper.Department("a"), new DmsApprovedReadAccessMapper.Department("b")));
        when(mapper.insert(any())).thenAnswer(i -> i.getArgument(0));
        service.apply(batch, List.of(main, record), List.of(main, record));
        var captor = ArgumentCaptor.forClass(DmsFilePermissionEntity.class);
        verify(mapper, times(2)).insert(captor.capture());
        var grants = captor.getAllValues();
        assertEquals(List.of(main.getFileVersionId(), record.getFileVersionId()), grants.stream().map(DmsFilePermissionEntity::getResourceId).toList());
        assertEquals(List.of("a", "b"), grants.stream().map(DmsFilePermissionEntity::getPrincipalId).toList());
        assertEquals(List.of("SELF", "CHILDREN"), grants.stream().map(DmsFilePermissionEntity::getApprovedOrgScope).toList());
        for (var p : grants) {
            assertEquals("READ",p.getActionCode()); assertEquals("ORG",p.getPrincipalType());
            assertEquals("FILE_VERSION",p.getResourceType()); assertEquals(batch.getActivatedAt(),p.getValidFrom());
            assertFalse(p.getIncludeChildOrgs()); assertNull(p.getMaxUseCount());
        }
        verify(mapper, never()).revoke(any(), any());
    }
    @Test void emptyScopeOnNewTargetNeverTouchesSourceVersionPermissions() {
        for (String type : List.of("CREATE", "REVISE")) {
            var target = item("main", type, "[]");
            target.setBaseFileVersionId(UUID.randomUUID());
            service.apply(batch, List.of(target), List.of(target));
            verify(mapper).owned("tenant", target.getFileVersionId());
            verifyNoMoreInteractions(mapper);
            verifyNoInteractions(audit);
            reset(mapper);
        }
    }
    @Test void emptyScopeClearsOnlyApprovalGrantsOfCurrentReviewTarget() {
        for (String scope : Arrays.asList("[]", null, "null", "", "  ")) {
            var target = item("main", "REUSE", scope);
            target.setBaseFileVersionId(target.getFileVersionId());
            var old = new DmsFilePermissionEntity();
            old.setId(UUID.randomUUID()); old.setResourceId(target.getFileVersionId());
            old.setSourceId("approved-read:previous-review");
            when(mapper.owned("tenant", target.getFileVersionId())).thenReturn(List.of(old));
            when(mapper.revoke("tenant", old.getId())).thenReturn(1);
            service.apply(batch, List.of(target), List.of(target));
            verify(mapper).revoke("tenant", old.getId());
            verify(mapper, never()).insert(any());
            verify(audit).permissionChange(eq("PERMISSION_GRANT"), anyString(), anyList(), anyList(), anyList());
            reset(mapper, audit);
        }
    }
    @Test void mainAndRecordApplyIndependentScopesToTheirOwnTargetVersions() {
        var main = item("main", "REUSE", "[\"a\"]");
        var record = item("record", "REUSE", "[]");
        var old = new DmsFilePermissionEntity();
        old.setId(UUID.randomUUID()); old.setSourceId("approved-read:older");
        when(mapper.departments("tenant", List.of("a"))).thenReturn(List.of(
                new DmsApprovedReadAccessMapper.Department("a")));
        when(mapper.owned("tenant", main.getFileVersionId())).thenReturn(List.of(old));
        var oldRecord = new DmsFilePermissionEntity();
        oldRecord.setId(UUID.randomUUID()); oldRecord.setResourceId(record.getFileVersionId());
        oldRecord.setSourceId("approved-read:previous-record-review");
        when(mapper.owned("tenant", record.getFileVersionId())).thenReturn(List.of(oldRecord));
        when(mapper.revoke("tenant", oldRecord.getId())).thenReturn(1);
        when(mapper.revoke("tenant", old.getId())).thenReturn(1);
        when(mapper.insert(any())).thenAnswer(i -> i.getArgument(0));
        service.apply(batch, List.of(main, record), List.of(main, record));
        verify(mapper).revoke("tenant", old.getId());
        var captor = ArgumentCaptor.forClass(DmsFilePermissionEntity.class);
        verify(mapper).insert(captor.capture());
        assertEquals(main.getFileVersionId(), captor.getValue().getResourceId());
        assertEquals("a", captor.getValue().getPrincipalId());
        verify(mapper).revoke("tenant", oldRecord.getId());
    }
    @Test void invalidDepartmentFailsBeforeAnyPermissionMutation() {
        var item=item("main","CREATE","[\"foreign\"]");
        assertThrows(DataException.class,()->service.apply(batch,List.of(item),List.of(item)));
        verify(mapper,never()).owned(any(),any()); verify(mapper,never()).insert(any()); verifyNoInteractions(audit);
    }
    @Test void snapshotMismatchAndEarlyActivationAreRejected() {
        var item=item("main","CREATE","[]"); var changed=item("main","CREATE","[\"a\"]");
        assertThrows(DataException.class,()->service.apply(batch,List.of(item),List.of(changed)));
        batch.setActivatedAt(null);
        assertThrows(DataException.class,()->service.apply(batch,List.of(item),List.of(item)));
        verifyNoInteractions(mapper,audit);
    }
    @Test void duplicateActivationNeverResurrectsRevokedGrant() {
        var item=item("main","REUSE","[\"a\"]");
        when(mapper.departments("tenant", List.of("a"))).thenReturn(List.of(
                new DmsApprovedReadAccessMapper.Department("a")));
        var revoked=new DmsFilePermissionEntity();revoked.setRevokedAt(new Date());
        revoked.setSourceId("approved-read:"+batch.getId()+":"+item.getFileVersionId());
        when(mapper.owned("tenant",item.getFileVersionId())).thenReturn(List.of(revoked));
        assertThrows(DataException.class,()->service.apply(batch,List.of(item),List.of(item)));
        verify(mapper,never()).insert(any());verifyNoInteractions(audit);
    }
}