package vip.mate.wiki.tool; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import vip.mate.wiki.model.WikiAgentPageTypePermissionEntity; import vip.mate.wiki.model.WikiKnowledgeBaseEntity; import vip.mate.wiki.model.WikiPageEntity; import vip.mate.wiki.repository.WikiAgentPageTypePermissionMapper; import vip.mate.wiki.service.HybridRetriever; import vip.mate.wiki.service.WikiKnowledgeBaseService; import vip.mate.wiki.service.WikiPageService; import vip.mate.wiki.service.WikiPageTypePermissionService; import vip.mate.wiki.service.WikiRawMaterialService; import java.util.List; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * Verifies the pageType permission gate wired into {@link WikiTool} read and * write tools, using a real {@link WikiPageTypePermissionService} backed by a * mocked mapper so permission rows are controlled directly. */ class WikiToolPermissionTest { private static final long AGENT = 11L; private static final long KB = 7L; private record Harness(WikiTool tool, WikiPageService pageService, WikiAgentPageTypePermissionMapper permMapper) {} private Harness harness(List rows) { WikiPageService pageService = mock(WikiPageService.class); WikiKnowledgeBaseService kbService = mock(WikiKnowledgeBaseService.class); WikiRawMaterialService rawService = mock(WikiRawMaterialService.class); HybridRetriever retriever = mock(HybridRetriever.class); ObjectMapper om = new ObjectMapper(); WikiKnowledgeBaseEntity kb = new WikiKnowledgeBaseEntity(); kb.setId(KB); when(kbService.findVisibleById(AGENT, KB)).thenReturn(kb); when(kbService.getById(KB)).thenReturn(kb); WikiAgentPageTypePermissionMapper permMapper = mock(WikiAgentPageTypePermissionMapper.class); when(permMapper.selectList(any())).thenReturn(rows); WikiPageTypePermissionService permService = new WikiPageTypePermissionService(permMapper, kbService, om); WikiTool tool = new WikiTool(pageService, kbService, rawService, retriever, om, permService); return new Harness(tool, pageService, permMapper); } private WikiAgentPageTypePermissionEntity row(String type, int read, int create, int update, int delete, String writePolicy) { WikiAgentPageTypePermissionEntity e = new WikiAgentPageTypePermissionEntity(); e.setAgentId(AGENT); e.setKbId(KB); e.setPageType(type); e.setCanRead(read); e.setCanCreate(create); e.setCanUpdate(update); e.setCanDelete(delete); e.setWritePolicy(writePolicy); return e; } private WikiPageEntity page(String slug, String type) { WikiPageEntity p = new WikiPageEntity(); p.setId(100L); p.setKbId(KB); p.setSlug(slug); p.setTitle("T " + slug); p.setContent("body"); p.setPageType(type); p.setLastUpdatedBy("ai"); return p; } @Test void readPage_unreadableType_reportsNotFound() { Harness h = harness(List.of(row("*", 0, 0, 0, 0, "deny"))); when(h.pageService().getBySlug(KB, "secret")).thenReturn(page("secret", "analysis")); String out = h.tool().wiki_read_page(AGENT, "secret", null, null, null, KB); assertTrue(out.contains("Page not found"), out); } @Test void readPage_readableType_returnsContent() { Harness h = harness(List.of(row("*", 1, 0, 0, 0, "deny"))); when(h.pageService().getBySlug(KB, "ok")).thenReturn(page("ok", "concept")); String out = h.tool().wiki_read_page(AGENT, "ok", null, null, null, KB); assertTrue(out.contains("\"content\""), out); assertFalse(out.contains("Page not found"), out); } @Test void deletePage_denied_doesNotDelete() { // can read, but delete flag off → DENY Harness h = harness(List.of(row("concept", 1, 0, 0, 0, "deny"))); when(h.pageService().getBySlug(KB, "p")).thenReturn(page("p", "concept")); String out = h.tool().wiki_delete_page(AGENT, "p", null, KB); assertTrue(out.contains("Not permitted"), out); verify(h.pageService(), never()).delete(anyLong(), any()); } @Test void deletePage_approvalRequired_blocksAndDoesNotDelete() { Harness h = harness(List.of(row("concept", 1, 0, 0, 1, "approval_required"))); when(h.pageService().getBySlug(KB, "p")).thenReturn(page("p", "concept")); String out = h.tool().wiki_delete_page(AGENT, "p", null, KB); assertTrue(out.contains("Approval required"), out); verify(h.pageService(), never()).delete(anyLong(), any()); } @Test void deletePage_allowed_deletes() { Harness h = harness(List.of(row("concept", 1, 1, 1, 1, "allow"))); when(h.pageService().getBySlug(KB, "p")).thenReturn(page("p", "concept")); String out = h.tool().wiki_delete_page(AGENT, "p", null, KB); assertTrue(out.contains("\"ok\":true"), out); verify(h.pageService(), times(1)).delete(eq(KB), eq("p")); } @Test void createPage_deniedByWildcard_doesNotCreate() { // a row exists for 'episode' only → KB is gated, wildcard create not granted Harness h = harness(List.of(row("episode", 1, 1, 1, 1, "allow"))); String out = h.tool().wiki_create_page(AGENT, "New Page", "content here", null, KB); assertTrue(out.contains("Not permitted"), out); verify(h.pageService(), never()).createPage(anyLong(), any(), any(), any(), any(), any()); } }