刘光辉
5 小时以前 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
package jnpf.dmsService.search;
 
import jnpf.dmsEntity.permission.vo.DmsPermissionDecisionVO;
import jnpf.dmsEntity.search.form.DmsFullTextSearchForm;
import jnpf.dmsEntity.search.vo.DmsFullTextSearchPageVO;
import jnpf.dmsPermission.DmsCurrentIdentity;
import jnpf.dmsService.DmsPermissionDecisionService;
import jnpf.dmsService.search.meili.DmsMeilisearchClient;
import jnpf.dmsService.search.meili.DmsMeilisearchSearchHit;
import jnpf.dmsService.search.meili.DmsMeilisearchSearchPage;
import jnpf.dmsService.search.meili.DmsSearchIndexDocument;
import org.junit.jupiter.api.Test;
 
import java.util.Arrays;
import java.util.UUID;
 
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
 
class DmsFullTextSearchServiceTest {
    private final jnpf.dmsMapper.DmsSearchIndexSourceMapper sources = mock(jnpf.dmsMapper.DmsSearchIndexSourceMapper.class);
 
    @org.junit.jupiter.api.BeforeEach
    void currentVersions() {
        when(sources.currentVersionIds(org.mockito.ArgumentMatchers.anyString(), anyList()))
                .thenAnswer(call -> call.getArgument(1));
    }
 
    @Test
    void returnsOnlyReadableResultsAndEscapesHighlightedText() throws Exception {
        DmsCurrentIdentity identity = mock(DmsCurrentIdentity.class);
        DmsPermissionDecisionService permissions = mock(DmsPermissionDecisionService.class);
        DmsMeilisearchClient meilisearch = mock(DmsMeilisearchClient.class);
        DmsFullTextSearchService service = new DmsFullTextSearchService(
                identity, permissions, meilisearch, sources);
        DmsMeilisearchSearchHit denied = hit("无权限文件", "正文");
        DmsMeilisearchSearchHit allowed = hit("<script>alert(1)</script>"
                + DmsMeilisearchClient.HIGHLIGHT_START + "规程"
                + DmsMeilisearchClient.HIGHLIGHT_END, "命中正文");
        when(identity.tenantId()).thenReturn("tenant-1");
        when(meilisearch.search("tenant-1", "规程", 0, 100))
                .thenReturn(new DmsMeilisearchSearchPage(Arrays.asList(denied, allowed), 2));
        when(permissions.evaluate(anyList())).thenReturn(Arrays.asList(decision(false), decision(true)));
 
        DmsFullTextSearchForm form = new DmsFullTextSearchForm();
        form.setKeyword("规程");
        DmsFullTextSearchPageVO result = service.search(form);
 
        assertEquals(1, result.getList().size());
        assertEquals("&lt;script&gt;alert(1)&lt;/script&gt;<mark>规程</mark>",
                result.getList().get(0).getHighlightedTitle());
        assertFalse(result.isHasMore());
    }
 
    @Test
    void returnsCursorForNextReadableResult() throws Exception {
        DmsCurrentIdentity identity = mock(DmsCurrentIdentity.class);
        DmsPermissionDecisionService permissions = mock(DmsPermissionDecisionService.class);
        DmsMeilisearchClient meilisearch = mock(DmsMeilisearchClient.class);
        DmsFullTextSearchService service = new DmsFullTextSearchService(
                identity, permissions, meilisearch, sources);
        when(identity.tenantId()).thenReturn("tenant-1");
        when(meilisearch.search("tenant-1", "文件", 0, 100))
                .thenReturn(new DmsMeilisearchSearchPage(
                        Arrays.asList(hit("文件一", ""), hit("文件二", "")), 2));
        when(permissions.evaluate(anyList()))
                .thenReturn(Arrays.asList(decision(true), decision(true)));
        DmsFullTextSearchForm form = new DmsFullTextSearchForm();
        form.setKeyword("文件");
        form.setPageSize(1);
 
        DmsFullTextSearchPageVO result = service.search(form);
 
        assertEquals(1, result.getList().size());
        assertTrue(result.isHasMore());
        assertEquals("1", result.getNextCursor());
    }
 
    private DmsMeilisearchSearchHit hit(String formattedTitle, String formattedContent) {
        DmsSearchIndexDocument document = new DmsSearchIndexDocument();
        UUID versionId = UUID.randomUUID();
        document.setId(versionId.toString());
        document.setTenantId("tenant-1");
        document.setDocumentId(UUID.randomUUID().toString());
        document.setFileVersionId(versionId.toString());
        document.setTitle("文件");
        document.setFileName("file.docx");
        return new DmsMeilisearchSearchHit(document, formattedTitle, formattedContent);
    }
 
    @Test
    void suppressesExpiredIndexHitEvenWhenHistoricalReadIsAllowed() throws Exception {
        DmsCurrentIdentity identity = mock(DmsCurrentIdentity.class);
        DmsPermissionDecisionService permissions = mock(DmsPermissionDecisionService.class);
        DmsMeilisearchClient client = mock(DmsMeilisearchClient.class);
        when(identity.tenantId()).thenReturn("tenant-1");
        when(client.search("tenant-1", "文件", 0, 100)).thenReturn(
                new DmsMeilisearchSearchPage(java.util.List.of(hit("已过期", "历史正文")), 1));
        when(permissions.evaluate(anyList())).thenReturn(java.util.List.of(decision(true)));
        when(sources.currentVersionIds(org.mockito.ArgumentMatchers.anyString(), anyList())).thenReturn(java.util.List.of());
        DmsFullTextSearchForm form = new DmsFullTextSearchForm();
        form.setKeyword("文件");
        assertTrue(new DmsFullTextSearchService(identity, permissions, client, sources).search(form).getList().isEmpty());
    }
 
    private DmsPermissionDecisionVO decision(boolean allowed) {
        DmsPermissionDecisionVO decision = new DmsPermissionDecisionVO();
        decision.setAllowed(allowed);
        return decision;
    }
}